Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

853 lines
20 KiB

  1. /*++
  2. Copyright (C) 1991-5 Microsoft Corporation
  3. Module Name:
  4. volset.cxx
  5. Abstract:
  6. This module contains the code specific to volume sets for the fault
  7. tolerance driver.
  8. Author:
  9. Bob Rinne (bobri) 2-Feb-1992
  10. Mike Glass (mglass)
  11. Norbert Kusters 2-Feb-1995
  12. Environment:
  13. kernel mode only
  14. Notes:
  15. Revision History:
  16. --*/
  17. extern "C" {
  18. #include <ntddk.h>
  19. }
  20. #include <ftdisk.h>
  21. #ifdef ALLOC_PRAGMA
  22. #pragma code_seg("PAGE")
  23. #endif
  24. NTSTATUS
  25. VOLUME_SET::Initialize(
  26. IN OUT PROOT_EXTENSION RootExtension,
  27. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  28. IN OUT PFT_VOLUME* VolumeArray,
  29. IN USHORT ArraySize,
  30. IN PVOID ConfigInfo,
  31. IN PVOID StateInfo
  32. )
  33. /*++
  34. Routine Description:
  35. Initialize routine for FT_VOLUME of type VOLUME SET.
  36. Arguments:
  37. RootExtension - Supplies the root device extension.
  38. LogicalDiskId - Supplies the logical disk id for this volume.
  39. VolumeArray - Supplies the array of volumes for this volume set.
  40. ArraySize - Supplies the number of volumes in the volume array.
  41. ConfigInfo - Supplies the configuration information.
  42. StateInfo - Supplies the state information.
  43. Return Value:
  44. NTSTATUS
  45. --*/
  46. {
  47. BOOLEAN oneGood;
  48. USHORT i;
  49. NTSTATUS status;
  50. oneGood = FALSE;
  51. for (i = 0; i < ArraySize; i++) {
  52. if (VolumeArray[i]) {
  53. oneGood = TRUE;
  54. }
  55. }
  56. if (!oneGood) {
  57. return STATUS_INVALID_PARAMETER;
  58. }
  59. status = COMPOSITE_FT_VOLUME::Initialize(RootExtension, LogicalDiskId,
  60. VolumeArray, ArraySize,
  61. ConfigInfo, StateInfo);
  62. if (!NT_SUCCESS(status)) {
  63. return status;
  64. }
  65. _volumeSize = 0;
  66. for (i = 0; i < ArraySize; i++) {
  67. if (VolumeArray[i]) {
  68. _volumeSize += VolumeArray[i]->QueryVolumeSize();
  69. }
  70. }
  71. _ePacket = new VOLSET_TP;
  72. if (_ePacket && !_ePacket->AllocateMdl((PVOID) 1, STRIPE_SIZE)) {
  73. delete _ePacket;
  74. _ePacket = NULL;
  75. }
  76. if (!_ePacket) {
  77. return STATUS_INSUFFICIENT_RESOURCES;
  78. }
  79. _ePacketInUse = FALSE;
  80. InitializeListHead(&_ePacketQueue);
  81. return status;
  82. }
  83. FT_LOGICAL_DISK_TYPE
  84. VOLUME_SET::QueryLogicalDiskType(
  85. )
  86. /*++
  87. Routine Description:
  88. This routine returns the type of the logical disk.
  89. Arguments:
  90. None.
  91. Return Value:
  92. The type of the logical disk.
  93. --*/
  94. {
  95. return FtVolumeSet;
  96. }
  97. NTSTATUS
  98. VOLUME_SET::CheckIo(
  99. OUT PBOOLEAN IsIoOk
  100. )
  101. /*++
  102. Routine Description:
  103. This routine returns whether or not IO is possible on the given
  104. logical disk.
  105. Arguments:
  106. IsIoOk - Returns the state of IO.
  107. Return Value:
  108. NTSTATUS
  109. --*/
  110. {
  111. USHORT n, i;
  112. PFT_VOLUME vol;
  113. NTSTATUS status;
  114. n = QueryNumMembers();
  115. for (i = 0; i < n; i++) {
  116. vol = GetMemberUnprotected(i);
  117. if (!vol) {
  118. *IsIoOk = FALSE;
  119. return STATUS_SUCCESS;
  120. }
  121. status = vol->CheckIo(IsIoOk);
  122. if (!NT_SUCCESS(status)) {
  123. return status;
  124. }
  125. if (!(*IsIoOk)) {
  126. return STATUS_SUCCESS;
  127. }
  128. }
  129. return STATUS_SUCCESS;
  130. }
  131. NTSTATUS
  132. VOLUME_SET::QueryPhysicalOffsets(
  133. IN LONGLONG LogicalOffset,
  134. OUT PVOLUME_PHYSICAL_OFFSET* PhysicalOffsets,
  135. OUT PULONG NumberOfPhysicalOffsets
  136. )
  137. /*++
  138. Routine Description:
  139. This routine returns physical disk and offset for a given volume
  140. logical offset.
  141. Arguments:
  142. LogicalOffset - Supplies the logical offset
  143. PhysicalOffsets - Returns the physical offsets
  144. NumberOfPhysicalOffsets - Returns the number of physical offsets
  145. Return Value:
  146. NTSTATUS
  147. --*/
  148. {
  149. USHORT n, i;
  150. PFT_VOLUME vol;
  151. LONGLONG logicalOffsetInMember = LogicalOffset, volumeSize;
  152. if (LogicalOffset < 0) {
  153. return STATUS_INVALID_PARAMETER;
  154. }
  155. n = QueryNumMembers();
  156. for (i = 0; i < n; i++) {
  157. vol = GetMember(i);
  158. if (!vol) {
  159. return STATUS_INVALID_PARAMETER;
  160. }
  161. volumeSize = vol->QueryVolumeSize();
  162. if (logicalOffsetInMember < volumeSize) {
  163. return vol->QueryPhysicalOffsets(logicalOffsetInMember, PhysicalOffsets, NumberOfPhysicalOffsets);
  164. }
  165. logicalOffsetInMember -= volumeSize;
  166. }
  167. return STATUS_INVALID_PARAMETER;
  168. }
  169. NTSTATUS
  170. VOLUME_SET::QueryLogicalOffset(
  171. IN PVOLUME_PHYSICAL_OFFSET PhysicalOffset,
  172. OUT PLONGLONG LogicalOffset
  173. )
  174. /*++
  175. Routine Description:
  176. This routine returns the volume logical offset for a given disk number
  177. and physical offset.
  178. Arguments:
  179. PhysicalOffset - Supplies the physical offset
  180. LogicalOffset - Returns the logical offset
  181. Return Value:
  182. NTSTATUS
  183. --*/
  184. {
  185. USHORT n, i;
  186. PFT_VOLUME vol;
  187. LONGLONG memberStartOffset = 0, logicalOffsetInMember;
  188. NTSTATUS status;
  189. n = QueryNumMembers();
  190. for (i = 0; i < n; i++) {
  191. vol = GetMember(i);
  192. if (!vol) {
  193. return STATUS_INVALID_PARAMETER;
  194. }
  195. status = vol->QueryLogicalOffset(PhysicalOffset, &logicalOffsetInMember);
  196. if (NT_SUCCESS(status)) {
  197. *LogicalOffset = memberStartOffset + logicalOffsetInMember;
  198. return status;
  199. }
  200. memberStartOffset += vol->QueryVolumeSize();
  201. }
  202. return STATUS_INVALID_PARAMETER;
  203. }
  204. #ifdef ALLOC_PRAGMA
  205. #pragma code_seg("PAGELK")
  206. #endif
  207. VOLUME_SET::~VOLUME_SET(
  208. )
  209. {
  210. if (_ePacket) {
  211. delete _ePacket;
  212. _ePacket = NULL;
  213. }
  214. }
  215. VOID
  216. VOLUME_SET::Transfer(
  217. IN OUT PTRANSFER_PACKET TransferPacket
  218. )
  219. /*++
  220. Routine Description:
  221. Transfer routine for STRIPE type FT_VOLUME. Figure out
  222. which volumes this request needs to be dispatched to.
  223. Arguments:
  224. TransferPacket - Supplies the transfer packet.
  225. Return Value:
  226. None.
  227. --*/
  228. {
  229. KIRQL irql;
  230. if (TransferPacket->Offset + TransferPacket->Length > _volumeSize) {
  231. TransferPacket->IoStatus.Status = STATUS_INVALID_PARAMETER;
  232. TransferPacket->IoStatus.Information = 0;
  233. TransferPacket->CompletionRoutine(TransferPacket);
  234. return;
  235. }
  236. if (!LaunchParallel(TransferPacket)) {
  237. if (!TransferPacket->Mdl) {
  238. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  239. TransferPacket->IoStatus.Information = 0;
  240. TransferPacket->CompletionRoutine(TransferPacket);
  241. return;
  242. }
  243. KeAcquireSpinLock(&_spinLock, &irql);
  244. if (_ePacketInUse) {
  245. InsertTailList(&_ePacketQueue, &TransferPacket->QueueEntry);
  246. KeReleaseSpinLock(&_spinLock, irql);
  247. return;
  248. }
  249. _ePacketInUse = TRUE;
  250. KeReleaseSpinLock(&_spinLock, irql);
  251. LaunchSequential(TransferPacket);
  252. }
  253. }
  254. VOID
  255. VolsetReplaceCompletionRoutine(
  256. IN OUT PTRANSFER_PACKET TransferPacket
  257. )
  258. /*++
  259. Routine Description:
  260. This is the completion routine for a replace request.
  261. Arguments:
  262. TransferPacket - Supplies the transfer packet.
  263. Return Value:
  264. None.
  265. --*/
  266. {
  267. PVOLSET_TP transferPacket = (PVOLSET_TP) TransferPacket;
  268. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  269. masterPacket->IoStatus = transferPacket->IoStatus;
  270. delete transferPacket;
  271. masterPacket->CompletionRoutine(masterPacket);
  272. }
  273. VOID
  274. VOLUME_SET::ReplaceBadSector(
  275. IN OUT PTRANSFER_PACKET TransferPacket
  276. )
  277. /*++
  278. Routine Description:
  279. This routine attempts to fix the given bad sector by routing
  280. the request to the appropriate sub-volume.
  281. Arguments:
  282. TransferPacket - Supplies the transfer packet.
  283. Return Value:
  284. None.
  285. --*/
  286. {
  287. LONGLONG offset = TransferPacket->Offset;
  288. USHORT n, i;
  289. PVOLSET_TP p;
  290. LONGLONG volumeSize;
  291. n = QueryNumMembers();
  292. for (i = 0; i < n; i++) {
  293. volumeSize = GetMemberUnprotected(i)->QueryVolumeSize();
  294. if (offset < volumeSize) {
  295. break;
  296. }
  297. offset -= volumeSize;
  298. }
  299. p = new VOLSET_TP;
  300. if (!p) {
  301. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  302. TransferPacket->IoStatus.Information = 0;
  303. TransferPacket->CompletionRoutine(TransferPacket);
  304. return;
  305. }
  306. p->Length = TransferPacket->Length;
  307. p->Offset = offset;
  308. p->CompletionRoutine = VolsetReplaceCompletionRoutine;
  309. p->TargetVolume = GetMemberUnprotected(i);
  310. p->Thread = TransferPacket->Thread;
  311. p->IrpFlags = TransferPacket->IrpFlags;
  312. p->MasterPacket = TransferPacket;
  313. p->VolumeSet = this;
  314. p->WhichMember = i;
  315. p->TargetVolume->ReplaceBadSector(p);
  316. }
  317. LONGLONG
  318. VOLUME_SET::QueryVolumeSize(
  319. )
  320. /*++
  321. Routine Description:
  322. Returns the number of bytes on the entire volume.
  323. Arguments:
  324. None.
  325. Return Value:
  326. The volume size in bytes.
  327. --*/
  328. {
  329. return _volumeSize;
  330. }
  331. VOID
  332. VOLUME_SET::CompleteNotification(
  333. IN BOOLEAN IoPending
  334. )
  335. /*++
  336. Routine Description:
  337. This routine is called to notify the volume that it is complete and
  338. to therefore prepare for incoming requests.
  339. Arguments:
  340. IoPending - Supplies whether or not there is IO pending.
  341. Return Value:
  342. None.
  343. --*/
  344. {
  345. USHORT n, i;
  346. PFT_VOLUME vol;
  347. COMPOSITE_FT_VOLUME::CompleteNotification(IoPending);
  348. _volumeSize = 0;
  349. n = QueryNumMembers();
  350. for (i = 0; i < n; i++) {
  351. vol = GetMember(i);
  352. _volumeSize += vol->QueryVolumeSize();
  353. }
  354. }
  355. VOID
  356. VolsetTransferParallelCompletionRoutine(
  357. IN PTRANSFER_PACKET TransferPacket
  358. )
  359. /*++
  360. Routine Description:
  361. Completion routine for VOLUME_SET::Transfer function.
  362. Arguments:
  363. TransferPacket - Supplies the transfer packet.
  364. Return Value:
  365. None.
  366. --*/
  367. {
  368. PVOLSET_TP transferPacket = (PVOLSET_TP) TransferPacket;
  369. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  370. NTSTATUS status = transferPacket->IoStatus.Status;
  371. KIRQL irql;
  372. if (!NT_SUCCESS(status)) {
  373. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  374. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  375. masterPacket->IoStatus.Status = status;
  376. }
  377. KeReleaseSpinLock(&masterPacket->SpinLock, irql);
  378. }
  379. delete transferPacket;
  380. if (!InterlockedDecrement(&masterPacket->RefCount)) {
  381. masterPacket->CompletionRoutine(masterPacket);
  382. }
  383. }
  384. BOOLEAN
  385. VOLUME_SET::LaunchParallel(
  386. IN OUT PTRANSFER_PACKET TransferPacket
  387. )
  388. /*++
  389. Routine Description:
  390. This routine lauches the given transfer packet in parallel accross
  391. all members. If memory cannot be allocated to launch this request
  392. in parallel then a return value of FALSE will be returned.
  393. Arguments:
  394. TransferPacket - Supplies the transfer packet to launch.
  395. Return Value:
  396. FALSE - The packet was not launched because of insufficient resources.
  397. TRUE - Success.
  398. --*/
  399. {
  400. USHORT arraySize, i;
  401. ULONG length, len;
  402. LONGLONG offset, volumeSize;
  403. BOOLEAN multiple;
  404. PCHAR vp;
  405. LIST_ENTRY q;
  406. PVOLSET_TP p;
  407. PLIST_ENTRY l;
  408. KeInitializeSpinLock(&TransferPacket->SpinLock);
  409. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  410. TransferPacket->IoStatus.Information = TransferPacket->Length;
  411. TransferPacket->RefCount = 0;
  412. arraySize = QueryNumMembers();
  413. offset = TransferPacket->Offset;
  414. length = TransferPacket->Length;
  415. for (i = 0; i < arraySize; i++) {
  416. volumeSize = GetMemberUnprotected(i)->QueryVolumeSize();
  417. if (offset < volumeSize) {
  418. if (offset + length <= volumeSize) {
  419. multiple = FALSE;
  420. } else {
  421. multiple = TRUE;
  422. }
  423. break;
  424. }
  425. offset -= volumeSize;
  426. }
  427. if (TransferPacket->Mdl && multiple) {
  428. vp = (PCHAR) MmGetMdlVirtualAddress(TransferPacket->Mdl);
  429. }
  430. InitializeListHead(&q);
  431. for (;;) {
  432. len = length;
  433. if (len > volumeSize - offset) {
  434. len = (ULONG) (volumeSize - offset);
  435. }
  436. p = new VOLSET_TP;
  437. if (p) {
  438. if (TransferPacket->Mdl && multiple) {
  439. if (p->AllocateMdl(vp, len)) {
  440. IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl, vp, len);
  441. } else {
  442. delete p;
  443. p = NULL;
  444. }
  445. vp += len;
  446. } else {
  447. p->Mdl = TransferPacket->Mdl;
  448. p->OriginalIrp = TransferPacket->OriginalIrp;
  449. }
  450. }
  451. if (!p) {
  452. while (!IsListEmpty(&q)) {
  453. l = RemoveHeadList(&q);
  454. p = CONTAINING_RECORD(l, VOLSET_TP, QueueEntry);
  455. delete p;
  456. }
  457. return FALSE;
  458. }
  459. p->Length = len;
  460. p->Offset = offset;
  461. p->CompletionRoutine = VolsetTransferParallelCompletionRoutine;
  462. p->TargetVolume = GetMemberUnprotected(i);
  463. p->Thread = TransferPacket->Thread;
  464. p->IrpFlags = TransferPacket->IrpFlags;
  465. p->ReadPacket = TransferPacket->ReadPacket;
  466. p->SpecialRead = TransferPacket->SpecialRead;
  467. p->MasterPacket = TransferPacket;
  468. p->VolumeSet = this;
  469. p->WhichMember = i;
  470. InsertTailList(&q, &p->QueueEntry);
  471. TransferPacket->RefCount++;
  472. if (len == length) {
  473. break;
  474. }
  475. offset = 0;
  476. length -= p->Length;
  477. volumeSize = GetMemberUnprotected(++i)->QueryVolumeSize();
  478. }
  479. while (!IsListEmpty(&q)) {
  480. l = RemoveHeadList(&q);
  481. p = CONTAINING_RECORD(l, VOLSET_TP, QueueEntry);
  482. TRANSFER(p);
  483. }
  484. return TRUE;
  485. }
  486. VOID
  487. VolsetTransferSequentialCompletionRoutine(
  488. IN PTRANSFER_PACKET TransferPacket
  489. )
  490. /*++
  491. Routine Description:
  492. Completion routine for VOLUME_SET::Transfer function.
  493. Arguments:
  494. TransferPacket - Supplies the transfer packet.
  495. Return Value:
  496. None.
  497. --*/
  498. {
  499. PVOLSET_TP transferPacket = (PVOLSET_TP) TransferPacket;
  500. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  501. NTSTATUS status = transferPacket->IoStatus.Status;
  502. PVOLUME_SET t = transferPacket->VolumeSet;
  503. LONGLONG masterOffset, volumeSize;
  504. USHORT i;
  505. KIRQL irql;
  506. PLIST_ENTRY l;
  507. PTRANSFER_PACKET p;
  508. if (NT_SUCCESS(status)) {
  509. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  510. masterPacket->IoStatus.Information +=
  511. transferPacket->IoStatus.Information;
  512. }
  513. } else {
  514. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  515. masterPacket->IoStatus.Status = status;
  516. }
  517. }
  518. MmPrepareMdlForReuse(transferPacket->Mdl);
  519. masterOffset = 0;
  520. for (i = 0; i < transferPacket->WhichMember; i++) {
  521. masterOffset += t->GetMemberUnprotected(i)->QueryVolumeSize();
  522. }
  523. masterOffset += transferPacket->Offset;
  524. masterOffset += transferPacket->Length;
  525. if (masterOffset == masterPacket->Offset + masterPacket->Length) {
  526. masterPacket->CompletionRoutine(masterPacket);
  527. for (;;) {
  528. KeAcquireSpinLock(&t->_spinLock, &irql);
  529. if (IsListEmpty(&t->_ePacketQueue)) {
  530. t->_ePacketInUse = FALSE;
  531. KeReleaseSpinLock(&t->_spinLock, irql);
  532. break;
  533. }
  534. l = RemoveHeadList(&t->_ePacketQueue);
  535. KeReleaseSpinLock(&t->_spinLock, irql);
  536. p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
  537. if (!t->LaunchParallel(p)) {
  538. t->LaunchSequential(p);
  539. break;
  540. }
  541. }
  542. return;
  543. }
  544. volumeSize = transferPacket->TargetVolume->QueryVolumeSize();
  545. transferPacket->Offset += transferPacket->Length;
  546. transferPacket->Length = STRIPE_SIZE;
  547. if (transferPacket->Offset >= volumeSize) {
  548. transferPacket->Offset -= volumeSize;
  549. transferPacket->WhichMember++;
  550. transferPacket->TargetVolume =
  551. t->GetMemberUnprotected(transferPacket->WhichMember);
  552. volumeSize = transferPacket->TargetVolume->QueryVolumeSize();
  553. }
  554. if (masterOffset + transferPacket->Length >
  555. masterPacket->Offset + masterPacket->Length) {
  556. transferPacket->Length = (ULONG) (masterPacket->Offset +
  557. masterPacket->Length - masterOffset);
  558. }
  559. if (transferPacket->Offset + transferPacket->Length > volumeSize) {
  560. transferPacket->Length = (ULONG) (volumeSize - transferPacket->Offset);
  561. }
  562. IoBuildPartialMdl(masterPacket->Mdl, transferPacket->Mdl,
  563. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  564. (ULONG) (masterOffset - masterPacket->Offset),
  565. transferPacket->Length);
  566. TRANSFER(transferPacket);
  567. }
  568. VOID
  569. VOLUME_SET::LaunchSequential(
  570. IN OUT PTRANSFER_PACKET TransferPacket
  571. )
  572. /*++
  573. Routine Description:
  574. This routine lauches the given transfer packet in sequence accross
  575. all members using the emergency stripe transfer packet.
  576. Arguments:
  577. TransferPacket - Supplies the transfer packet to launch.
  578. Return Value:
  579. FALSE - The packet was not launched because of insufficient resources.
  580. TRUE - Success.
  581. --*/
  582. {
  583. USHORT arraySize, i;
  584. ULONG length;
  585. LONGLONG offset, volumeSize;
  586. PVOLSET_TP p;
  587. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  588. TransferPacket->IoStatus.Information = 0;
  589. arraySize = QueryNumMembers();
  590. offset = TransferPacket->Offset;
  591. length = TransferPacket->Length;
  592. for (i = 0; i < arraySize; i++) {
  593. volumeSize = GetMemberUnprotected(i)->QueryVolumeSize();
  594. if (offset < volumeSize) {
  595. break;
  596. }
  597. offset -= volumeSize;
  598. }
  599. p = _ePacket;
  600. p->Length = STRIPE_SIZE;
  601. p->Offset = offset;
  602. p->CompletionRoutine = VolsetTransferSequentialCompletionRoutine;
  603. p->Thread = TransferPacket->Thread;
  604. p->IrpFlags = TransferPacket->IrpFlags;
  605. p->ReadPacket = TransferPacket->ReadPacket;
  606. p->SpecialRead = TransferPacket->SpecialRead;
  607. p->MasterPacket = TransferPacket;
  608. p->VolumeSet = this;
  609. p->WhichMember = i;
  610. if (p->Length > TransferPacket->Length) {
  611. p->Length = TransferPacket->Length;
  612. }
  613. if (p->Offset + p->Length > volumeSize) {
  614. p->Length = (ULONG) (volumeSize - p->Offset);
  615. }
  616. IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl,
  617. MmGetMdlVirtualAddress(TransferPacket->Mdl), p->Length);
  618. TRANSFER(p);
  619. }