Source code of Windows XP (NT5)
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.

4699 lines
121 KiB

  1. /*++
  2. Copyright (C) 1991-5 Microsoft Corporation
  3. Module Name:
  4. stripewp.cxx
  5. Abstract:
  6. This module contains the code specific to stripes with parity 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. STRIPE_WP::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 STRIPE with PARITY.
  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. None.
  45. --*/
  46. {
  47. PFT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION configInfo;
  48. NTSTATUS status;
  49. USHORT i;
  50. if (ArraySize < 3) {
  51. return STATUS_INVALID_PARAMETER;
  52. }
  53. status = COMPOSITE_FT_VOLUME::Initialize(RootExtension, LogicalDiskId,
  54. VolumeArray, ArraySize,
  55. ConfigInfo, StateInfo);
  56. if (!NT_SUCCESS(status)) {
  57. return status;
  58. }
  59. configInfo = (PFT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION) ConfigInfo;
  60. _stripeSize = configInfo->StripeSize;
  61. if (_stripeSize < QuerySectorSize()) {
  62. return STATUS_INVALID_PARAMETER;
  63. }
  64. for (i = 0; _stripeSize%2 == 0; i++) {
  65. _stripeSize /= 2;
  66. }
  67. if (_stripeSize != 1) {
  68. return STATUS_INVALID_PARAMETER;
  69. }
  70. _stripeSize = configInfo->StripeSize;
  71. _memberSize = configInfo->MemberSize;
  72. for (i = 0; i < ArraySize; i++) {
  73. if (VolumeArray[i] &&
  74. VolumeArray[i]->QueryVolumeSize() < _memberSize) {
  75. break;
  76. }
  77. }
  78. if (i < ArraySize) {
  79. return STATUS_INVALID_PARAMETER;
  80. }
  81. _memberSize = _memberSize/_stripeSize*_stripeSize;
  82. _volumeSize = _memberSize*(ArraySize - 1);
  83. RtlCopyMemory(&_state, StateInfo, sizeof(_state));
  84. _originalDirtyBit = _state.IsDirty;
  85. _orphanedBecauseOfMissingMember = FALSE;
  86. _syncOk = TRUE;
  87. _stopSyncs = FALSE;
  88. status = _overlappedIoManager.Initialize(_stripeSize);
  89. if (!NT_SUCCESS(status)) {
  90. return status;
  91. }
  92. status = _parityIoManager.Initialize(_stripeSize, QuerySectorSize());
  93. if (!NT_SUCCESS(status)) {
  94. return status;
  95. }
  96. _ePacket = new SWP_WRITE_TP;
  97. if (!_ePacket ||
  98. !_ePacket->AllocateMdls(_stripeSize) ||
  99. !_ePacket->AllocateMdl((PVOID) 1, _stripeSize)) {
  100. return STATUS_INSUFFICIENT_RESOURCES;
  101. }
  102. _ePacketInUse = FALSE;
  103. _ePacketQueueBeingServiced = FALSE;
  104. InitializeListHead(&_ePacketQueue);
  105. _eRegeneratePacket = new SWP_REGENERATE_TP;
  106. if (!_eRegeneratePacket ||
  107. !_eRegeneratePacket->AllocateMdl(_stripeSize)) {
  108. return STATUS_INSUFFICIENT_RESOURCES;
  109. }
  110. _eRegeneratePacketInUse = FALSE;
  111. InitializeListHead(&_eRegeneratePacketQueue);
  112. _eRecoverPacket = new SWP_RECOVER_TP;
  113. if (!_eRecoverPacket ||
  114. !_eRecoverPacket->AllocateMdls(QuerySectorSize())) {
  115. return STATUS_INSUFFICIENT_RESOURCES;
  116. }
  117. _eRecoverPacketInUse = FALSE;
  118. InitializeListHead(&_eRecoverPacketQueue);
  119. return STATUS_SUCCESS;
  120. }
  121. FT_LOGICAL_DISK_TYPE
  122. STRIPE_WP::QueryLogicalDiskType(
  123. )
  124. /*++
  125. Routine Description:
  126. This routine returns the type of the logical disk.
  127. Arguments:
  128. None.
  129. Return Value:
  130. The type of the logical disk.
  131. --*/
  132. {
  133. return FtStripeSetWithParity;
  134. }
  135. NTSTATUS
  136. STRIPE_WP::QueryPhysicalOffsets(
  137. IN LONGLONG LogicalOffset,
  138. OUT PVOLUME_PHYSICAL_OFFSET* PhysicalOffsets,
  139. OUT PULONG NumberOfPhysicalOffsets
  140. )
  141. /*++
  142. Routine Description:
  143. This routine returns physical disk and offset for a given volume
  144. logical offset.
  145. Arguments:
  146. LogicalOffset - Supplies the logical offset
  147. PhysicalOffsets - Returns the physical offsets
  148. NumberOfPhysicalOffsets - Returns the number of physical offsets
  149. Return Value:
  150. NTSTATUS
  151. --*/
  152. {
  153. USHORT n, whichMember, parityStripe;
  154. LONGLONG whichStripe, whichRow, logicalOffsetInMember;
  155. PFT_VOLUME vol;
  156. if (LogicalOffset < 0 ||
  157. _volumeSize <= LogicalOffset) {
  158. return STATUS_INVALID_PARAMETER;
  159. }
  160. n = QueryNumMembers();
  161. ASSERT(n > 1);
  162. ASSERT(_stripeSize);
  163. whichStripe = LogicalOffset/_stripeSize;
  164. whichRow = whichStripe/(n - 1);
  165. whichMember = (USHORT) (whichStripe%(n - 1));
  166. parityStripe = (USHORT) (whichRow%n);
  167. if (whichMember >= parityStripe) {
  168. whichMember++;
  169. }
  170. vol = GetMember(whichMember);
  171. if (!vol) {
  172. return STATUS_INVALID_PARAMETER;
  173. }
  174. logicalOffsetInMember = whichRow*_stripeSize + LogicalOffset%_stripeSize;
  175. return vol->QueryPhysicalOffsets(logicalOffsetInMember, PhysicalOffsets, NumberOfPhysicalOffsets);
  176. }
  177. NTSTATUS
  178. STRIPE_WP::QueryLogicalOffset(
  179. IN PVOLUME_PHYSICAL_OFFSET PhysicalOffset,
  180. OUT PLONGLONG LogicalOffset
  181. )
  182. /*++
  183. Routine Description:
  184. This routine returns the volume logical offset for a given disk number
  185. and physical offset.
  186. Arguments:
  187. PhysicalOffset - Supplies the physical offset
  188. LogicalOffset - Returns the logical offset
  189. Return Value:
  190. NTSTATUS
  191. --*/
  192. {
  193. USHORT n, i, parityStripe;
  194. LONGLONG whichStripe, whichRow;
  195. LONGLONG logicalOffset, logicalOffsetInMember;
  196. NTSTATUS status;
  197. PFT_VOLUME vol;
  198. n = QueryNumMembers();
  199. ASSERT(_stripeSize);
  200. for (i = 0; i < n; i++) {
  201. vol = GetMember(i);
  202. if (!vol) {
  203. continue;
  204. }
  205. status = vol->QueryLogicalOffset(PhysicalOffset, &logicalOffsetInMember);
  206. if (NT_SUCCESS(status)) {
  207. whichRow = logicalOffsetInMember/_stripeSize;
  208. parityStripe = (USHORT) (whichRow%n);
  209. if (i == parityStripe) {
  210. return STATUS_INVALID_PARAMETER;
  211. }
  212. whichStripe = whichRow*(n-1) + i;
  213. if (parityStripe < i) {
  214. whichStripe--;
  215. }
  216. logicalOffset = whichStripe*_stripeSize + logicalOffsetInMember%_stripeSize;
  217. if (_volumeSize <= logicalOffset) {
  218. return STATUS_INVALID_PARAMETER;
  219. }
  220. *LogicalOffset = logicalOffset;
  221. return status;
  222. }
  223. }
  224. return STATUS_INVALID_PARAMETER;
  225. }
  226. #ifdef ALLOC_PRAGMA
  227. #pragma code_seg("PAGELK")
  228. #endif
  229. NTSTATUS
  230. STRIPE_WP::OrphanMember(
  231. IN USHORT MemberNumber,
  232. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  233. IN PVOID Context
  234. )
  235. /*++
  236. Routine Description:
  237. This routine tries to orphan the given member of this logical disk.
  238. A completion routine will be called if and only if this attempt is successful.
  239. Arguments:
  240. MemberNumber - Supplies the member number to orphan.
  241. Return Value:
  242. NTSTATUS
  243. --*/
  244. {
  245. KIRQL irql;
  246. NTSTATUS status = STATUS_SUCCESS;
  247. BOOLEAN b;
  248. if (MemberNumber >= QueryNumMembers()) {
  249. return STATUS_INVALID_PARAMETER;
  250. }
  251. KeAcquireSpinLock(&_spinLock, &irql);
  252. b = SetMemberState(MemberNumber, FtMemberOrphaned);
  253. KeReleaseSpinLock(&_spinLock, irql);
  254. if (b) {
  255. PropogateStateChanges(CompletionRoutine, Context);
  256. Notify();
  257. FtpLogError(_rootExtension, QueryLogicalDiskId(), FT_ORPHANING,
  258. STATUS_SUCCESS, 2);
  259. }
  260. return b ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
  261. }
  262. VOID
  263. StripeWpCompositeVolumeCompletionRoutine(
  264. IN PVOID Context,
  265. IN NTSTATUS Status
  266. )
  267. {
  268. PFT_COMPLETION_ROUTINE_CONTEXT context;
  269. KIRQL irql;
  270. LONG count;
  271. context = (PFT_COMPLETION_ROUTINE_CONTEXT) Context;
  272. KeAcquireSpinLock(&context->SpinLock, &irql);
  273. if (!NT_SUCCESS(Status) &&
  274. FtpIsWorseStatus(Status, context->Status)) {
  275. context->Status = Status;
  276. }
  277. count = --context->RefCount;
  278. KeReleaseSpinLock(&context->SpinLock, irql);
  279. if (!count) {
  280. context->CompletionRoutine(context->Context, STATUS_SUCCESS);
  281. ExFreePool(context);
  282. }
  283. }
  284. VOID
  285. StripeWpSyncCleanup(
  286. IN PSWP_REBUILD_TP TransferPacket
  287. )
  288. /*++
  289. Routine Description:
  290. This is the cleanup routine for the initialize check data process.
  291. Arguments:
  292. TransferPacket - Supplies the transfer packet.
  293. Return Value:
  294. None.
  295. --*/
  296. {
  297. PFT_COMPLETION_ROUTINE_CONTEXT context;
  298. context = TransferPacket->Context;
  299. delete TransferPacket;
  300. StripeWpCompositeVolumeCompletionRoutine(context, STATUS_SUCCESS);
  301. }
  302. VOID
  303. StripeWpSyncCompletionRoutine(
  304. IN PTRANSFER_PACKET TransferPacket
  305. )
  306. /*++
  307. Routine Description:
  308. This is the completion routine for an initialize check data request.
  309. This routine is called over and over again until the volume
  310. is completely initialized.
  311. Arguments:
  312. TransferPacket - Supplies the transfer packet.
  313. Return Value:
  314. None.
  315. --*/
  316. {
  317. PSWP_REBUILD_TP transferPacket = (PSWP_REBUILD_TP) TransferPacket;
  318. PSTRIPE_WP t = transferPacket->StripeWithParity;
  319. NTSTATUS status = transferPacket->IoStatus.Status;
  320. KIRQL irql;
  321. ULONG parityMember;
  322. BOOLEAN b;
  323. KeAcquireSpinLock(&t->_spinLock, &irql);
  324. if (t->_stopSyncs ||
  325. t->QueryMemberState(transferPacket->WhichMember) == FtMemberOrphaned) {
  326. t->_syncOk = TRUE;
  327. KeReleaseSpinLock(&t->_spinLock, irql);
  328. t->_overlappedIoManager.ReleaseIoRegion(transferPacket);
  329. StripeWpSyncCleanup(transferPacket);
  330. return;
  331. }
  332. KeReleaseSpinLock(&t->_spinLock, irql);
  333. if (!NT_SUCCESS(status)) {
  334. // We can't get a VERIFY_REQUIRED because we put IrpFlags equal
  335. // to SL_OVERRIDE_VERIFY_VOLUME.
  336. ASSERT(status != STATUS_VERIFY_REQUIRED);
  337. if (FsRtlIsTotalDeviceFailure(status)) {
  338. if (!transferPacket->ReadPacket) {
  339. KeAcquireSpinLock(&t->_spinLock, &irql);
  340. b = t->SetMemberState(transferPacket->WhichMember,
  341. FtMemberOrphaned);
  342. KeReleaseSpinLock(&t->_spinLock, irql);
  343. if (b) {
  344. t->PropogateStateChanges(NULL, NULL);
  345. t->Notify();
  346. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  347. FT_ORPHANING, STATUS_SUCCESS, 3);
  348. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL,
  349. NULL);
  350. }
  351. }
  352. // The initialize cannot continue.
  353. KeAcquireSpinLock(&t->_spinLock, &irql);
  354. t->_syncOk = TRUE;
  355. KeReleaseSpinLock(&t->_spinLock, irql);
  356. t->_overlappedIoManager.ReleaseIoRegion(transferPacket);
  357. StripeWpSyncCleanup(transferPacket);
  358. return;
  359. }
  360. // Transfer the maximum amount that we can. This will always
  361. // complete successfully and log bad sector errors for
  362. // those sectors that it could not transfer.
  363. t->MaxTransfer(transferPacket);
  364. return;
  365. }
  366. transferPacket->Thread = PsGetCurrentThread();
  367. if (transferPacket->ReadPacket) {
  368. transferPacket->ReadPacket = FALSE;
  369. TRANSFER(transferPacket);
  370. return;
  371. }
  372. t->_overlappedIoManager.ReleaseIoRegion(transferPacket);
  373. transferPacket->ReadPacket = TRUE;
  374. transferPacket->Offset += t->_stripeSize;
  375. if (transferPacket->Initialize) {
  376. transferPacket->WhichMember = (transferPacket->WhichMember + 1)%
  377. t->QueryNumMembers();
  378. transferPacket->TargetVolume = t->GetMemberUnprotected(
  379. transferPacket->WhichMember);
  380. }
  381. if (transferPacket->Offset < t->_memberSize) {
  382. t->RegeneratePacket(transferPacket, TRUE);
  383. return;
  384. }
  385. if (transferPacket->Initialize) {
  386. KeAcquireSpinLock(&t->_spinLock, &irql);
  387. t->_state.IsInitializing = FALSE;
  388. t->_syncOk = TRUE;
  389. t->_originalDirtyBit = FALSE;
  390. KeReleaseSpinLock(&t->_spinLock, irql);
  391. t->PropogateStateChanges(NULL, NULL);
  392. t->Notify();
  393. } else {
  394. KeAcquireSpinLock(&t->_spinLock, &irql);
  395. b = t->SetMemberState(transferPacket->WhichMember, FtMemberHealthy);
  396. t->_syncOk = TRUE;
  397. t->_originalDirtyBit = FALSE;
  398. KeReleaseSpinLock(&t->_spinLock, irql);
  399. if (b) {
  400. t->PropogateStateChanges(NULL, NULL);
  401. t->Notify();
  402. }
  403. }
  404. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  405. FT_REGENERATION_ENDED, STATUS_SUCCESS, 0);
  406. StripeWpSyncCleanup(transferPacket);
  407. }
  408. NTSTATUS
  409. STRIPE_WP::RegenerateMember(
  410. IN USHORT MemberNumber,
  411. IN OUT PFT_VOLUME NewMember,
  412. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  413. IN PVOID Context
  414. )
  415. /*++
  416. Routine Description:
  417. This routine regenerates the given member of this volume with
  418. the given volume.
  419. Arguments:
  420. MemberNumber - Supplies the member number to regenerate.
  421. NewMember - Supplies the new member to regenerate to.
  422. CompletionRoutine - Supplies the completion routine.
  423. Context - Supplies the completion routine context.
  424. Return Value:
  425. NTSTATUS
  426. --*/
  427. {
  428. KIRQL irql;
  429. PFT_COMPLETION_ROUTINE_CONTEXT context;
  430. BOOLEAN b;
  431. PSWP_REBUILD_TP packet;
  432. USHORT i, n;
  433. NTSTATUS status;
  434. n = QueryNumMembers();
  435. if (MemberNumber >= n ||
  436. NewMember->QueryVolumeSize() < _memberSize) {
  437. return STATUS_INVALID_PARAMETER;
  438. }
  439. context = (PFT_COMPLETION_ROUTINE_CONTEXT)
  440. ExAllocatePool(NonPagedPool,
  441. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  442. packet = new SWP_REBUILD_TP;
  443. if (packet && !packet->AllocateMdl(_stripeSize)) {
  444. delete packet;
  445. packet = NULL;
  446. }
  447. if (!context || !packet) {
  448. if (context) {
  449. ExFreePool(context);
  450. }
  451. if (packet) {
  452. delete packet;
  453. }
  454. return STATUS_INSUFFICIENT_RESOURCES;
  455. }
  456. KeInitializeSpinLock(&context->SpinLock);
  457. context->Status = STATUS_SUCCESS;
  458. context->RefCount = 1;
  459. context->CompletionRoutine = CompletionRoutine;
  460. context->Context = Context;
  461. context->ParentVolume = this;
  462. packet->Length = _stripeSize;
  463. packet->Offset = 0;
  464. packet->CompletionRoutine = StripeWpSyncCompletionRoutine;
  465. packet->Thread = PsGetCurrentThread();
  466. packet->IrpFlags = SL_OVERRIDE_VERIFY_VOLUME;
  467. packet->ReadPacket = TRUE;
  468. packet->StripeWithParity = this;
  469. packet->Context = context;
  470. packet->Initialize = FALSE;
  471. KeAcquireSpinLock(&_spinLock, &irql);
  472. if (_syncOk) {
  473. _syncOk = FALSE;
  474. _stopSyncs = FALSE;
  475. } else {
  476. KeReleaseSpinLock(&_spinLock, irql);
  477. delete packet;
  478. ExFreePool(context);
  479. return STATUS_INVALID_PARAMETER;
  480. }
  481. status = STATUS_SUCCESS;
  482. if (_state.IsInitializing) {
  483. status = STATUS_INVALID_PARAMETER;
  484. } else {
  485. if (_state.UnhealthyMemberState != FtMemberHealthy) {
  486. if (MemberNumber == _state.UnhealthyMemberNumber) {
  487. if (_state.UnhealthyMemberState == FtMemberRegenerating) {
  488. status = STATUS_INVALID_PARAMETER;
  489. }
  490. } else {
  491. status = STATUS_INVALID_PARAMETER;
  492. }
  493. }
  494. }
  495. if (!NT_SUCCESS(status)) {
  496. _syncOk = TRUE;
  497. KeReleaseSpinLock(&_spinLock, irql);
  498. ExFreePool(context);
  499. delete packet;
  500. return status;
  501. }
  502. packet->WhichMember = MemberNumber;
  503. packet->TargetVolume = NewMember;
  504. SetMemberUnprotected(MemberNumber, NewMember);
  505. b = SetMemberState(MemberNumber, FtMemberRegenerating);
  506. KeReleaseSpinLock(&_spinLock, irql);
  507. ASSERT(b);
  508. PropogateStateChanges(NULL, NULL);
  509. Notify();
  510. FtpLogError(_rootExtension, QueryLogicalDiskId(), FT_REGENERATION_STARTED,
  511. STATUS_SUCCESS, 0);
  512. RegeneratePacket(packet, TRUE);
  513. return STATUS_SUCCESS;
  514. }
  515. VOID
  516. STRIPE_WP::Transfer(
  517. IN OUT PTRANSFER_PACKET TransferPacket
  518. )
  519. /*++
  520. Routine Description:
  521. Transfer routine for STRIPE_WP type FT_VOLUME. Figure out
  522. which volumes this request needs to be dispatched to.
  523. Arguments:
  524. TransferPacket - Supplies the transfer packet.
  525. Return Value:
  526. None.
  527. --*/
  528. {
  529. KIRQL irql;
  530. if (TransferPacket->Offset + TransferPacket->Length > _volumeSize) {
  531. TransferPacket->IoStatus.Status = STATUS_INVALID_PARAMETER;
  532. TransferPacket->IoStatus.Information = 0;
  533. TransferPacket->CompletionRoutine(TransferPacket);
  534. return;
  535. }
  536. KeAcquireSpinLock(&_spinLock, &irql);
  537. if ((_ePacketInUse || _ePacketQueueBeingServiced) &&
  538. TransferPacket->Mdl) {
  539. InsertTailList(&_ePacketQueue, &TransferPacket->QueueEntry);
  540. KeReleaseSpinLock(&_spinLock, irql);
  541. return;
  542. }
  543. KeReleaseSpinLock(&_spinLock, irql);
  544. if (!TransferPacket->Mdl) {
  545. TransferPacket->ReadPacket = TRUE;
  546. }
  547. if (!LaunchParallel(TransferPacket)) {
  548. if (!TransferPacket->Mdl) {
  549. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  550. TransferPacket->IoStatus.Information = 0;
  551. TransferPacket->CompletionRoutine(TransferPacket);
  552. return;
  553. }
  554. KeAcquireSpinLock(&_spinLock, &irql);
  555. if (_ePacketInUse || _ePacketQueueBeingServiced) {
  556. InsertTailList(&_ePacketQueue, &TransferPacket->QueueEntry);
  557. KeReleaseSpinLock(&_spinLock, irql);
  558. return;
  559. }
  560. _ePacketInUse = TRUE;
  561. KeReleaseSpinLock(&_spinLock, irql);
  562. LaunchSequential(TransferPacket);
  563. }
  564. }
  565. VOID
  566. STRIPE_WP::ReplaceBadSector(
  567. IN OUT PTRANSFER_PACKET TransferPacket
  568. )
  569. /*++
  570. Routine Description:
  571. This is a no-op since replacing bad sectors doesn't make sense
  572. on an FT component with redundancy built in to it.
  573. Arguments:
  574. TransferPacket - Supplies the transfer packet.
  575. Return Value:
  576. None.
  577. --*/
  578. {
  579. TransferPacket->IoStatus.Status = STATUS_UNSUCCESSFUL;
  580. TransferPacket->IoStatus.Information = 0;
  581. TransferPacket->CompletionRoutine(TransferPacket);
  582. }
  583. VOID
  584. STRIPE_WP::StartSyncOperations(
  585. IN BOOLEAN RegenerateOrphans,
  586. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  587. IN PVOID Context
  588. )
  589. /*++
  590. Routine Description:
  591. This aroutine restarts any regenerate or initialize requests that
  592. were suspended because of a reboot. The volume examines the member
  593. state of all of its constituents and restarts any regenerations pending.
  594. Arguments:
  595. RegenerateOrphans - Supplies whether or not to try and regenerate
  596. orphaned members.
  597. CompletionRoutine - Supplies the completion routine.
  598. Context - Supplies the context for the completion routine.
  599. Return Value:
  600. None.
  601. --*/
  602. {
  603. PFT_COMPLETION_ROUTINE_CONTEXT context;
  604. BOOLEAN dirty, regen, init;
  605. KIRQL irql;
  606. PFT_VOLUME vol;
  607. PSWP_REBUILD_TP packet;
  608. PVOID buffer;
  609. LONG regenMember;
  610. context = (PFT_COMPLETION_ROUTINE_CONTEXT)
  611. ExAllocatePool(NonPagedPool,
  612. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  613. if (!context) {
  614. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  615. return;
  616. }
  617. KeInitializeSpinLock(&context->SpinLock);
  618. context->Status = STATUS_SUCCESS;
  619. context->RefCount = 2;
  620. context->CompletionRoutine = CompletionRoutine;
  621. context->Context = Context;
  622. context->ParentVolume = this;
  623. // Kick off the recursive initialize.
  624. COMPOSITE_FT_VOLUME::StartSyncOperations(RegenerateOrphans,
  625. StripeWpCompositeVolumeCompletionRoutine, context);
  626. if (_orphanedBecauseOfMissingMember) {
  627. RegenerateOrphans = TRUE;
  628. _orphanedBecauseOfMissingMember = FALSE;
  629. }
  630. // Make sure that all member are healthy.
  631. dirty = FALSE;
  632. regen = FALSE;
  633. init = FALSE;
  634. KeAcquireSpinLock(&_spinLock, &irql);
  635. if (_syncOk) {
  636. _syncOk = FALSE;
  637. _stopSyncs = FALSE;
  638. } else {
  639. KeReleaseSpinLock(&_spinLock, irql);
  640. StripeWpCompositeVolumeCompletionRoutine(context, STATUS_SUCCESS);
  641. return;
  642. }
  643. if (_state.UnhealthyMemberState == FtMemberOrphaned &&
  644. RegenerateOrphans &&
  645. GetMemberUnprotected(_state.UnhealthyMemberNumber)) {
  646. _state.UnhealthyMemberState = FtMemberRegenerating;
  647. PropogateStateChanges(NULL, NULL);
  648. }
  649. if (_state.IsInitializing) {
  650. regenMember = -1;
  651. init = TRUE;
  652. } else if (_state.UnhealthyMemberState == FtMemberRegenerating) {
  653. regenMember = _state.UnhealthyMemberNumber;
  654. regen = TRUE;
  655. } else if (_originalDirtyBit &&
  656. _state.UnhealthyMemberState == FtMemberHealthy) {
  657. regenMember = -1;
  658. dirty = TRUE;
  659. } else {
  660. regenMember = -2;
  661. }
  662. KeReleaseSpinLock(&_spinLock, irql);
  663. if (dirty) {
  664. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  665. FT_DIRTY_SHUTDOWN, STATUS_SUCCESS, 0);
  666. }
  667. if (regen) {
  668. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  669. FT_REGENERATION_STARTED, STATUS_SUCCESS, 0);
  670. Notify();
  671. }
  672. if (init) {
  673. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  674. FT_PARITY_INITIALIZATION_STARTED, STATUS_SUCCESS, 0);
  675. Notify();
  676. }
  677. if (regenMember == -2) {
  678. KeAcquireSpinLock(&_spinLock, &irql);
  679. _syncOk = TRUE;
  680. KeReleaseSpinLock(&_spinLock, irql);
  681. StripeWpCompositeVolumeCompletionRoutine(context, STATUS_SUCCESS);
  682. return;
  683. }
  684. packet = new SWP_REBUILD_TP;
  685. if (packet && !packet->AllocateMdl(_stripeSize)) {
  686. delete packet;
  687. packet = NULL;
  688. }
  689. if (!packet) {
  690. KeAcquireSpinLock(&_spinLock, &irql);
  691. _syncOk = TRUE;
  692. KeReleaseSpinLock(&_spinLock, irql);
  693. StripeWpCompositeVolumeCompletionRoutine(context,
  694. STATUS_INSUFFICIENT_RESOURCES);
  695. return;
  696. }
  697. packet->Length = _stripeSize;
  698. packet->Offset = 0;
  699. packet->CompletionRoutine = StripeWpSyncCompletionRoutine;
  700. packet->Thread = PsGetCurrentThread();
  701. packet->IrpFlags = SL_OVERRIDE_VERIFY_VOLUME;
  702. packet->ReadPacket = TRUE;
  703. packet->MasterPacket = NULL;
  704. packet->StripeWithParity = this;
  705. packet->Context = context;
  706. if (regenMember >= 0) {
  707. packet->WhichMember = (USHORT) regenMember;
  708. packet->Initialize = FALSE;
  709. } else {
  710. packet->WhichMember = 0;
  711. packet->Initialize = TRUE;
  712. }
  713. packet->TargetVolume = GetMemberUnprotected(packet->WhichMember);
  714. RegeneratePacket(packet, TRUE);
  715. }
  716. VOID
  717. STRIPE_WP::StopSyncOperations(
  718. )
  719. /*++
  720. Routine Description:
  721. This routine stops all sync operations.
  722. Arguments:
  723. None.
  724. Return Value:
  725. None.
  726. --*/
  727. {
  728. KIRQL irql;
  729. COMPOSITE_FT_VOLUME::StopSyncOperations();
  730. KeAcquireSpinLock(&_spinLock, &irql);
  731. if (!_syncOk) {
  732. _stopSyncs = TRUE;
  733. }
  734. KeReleaseSpinLock(&_spinLock, irql);
  735. }
  736. LONGLONG
  737. STRIPE_WP::QueryVolumeSize(
  738. )
  739. /*++
  740. Routine Description:
  741. Returns the number of bytes on the entire volume.
  742. Arguments:
  743. None.
  744. Return Value:
  745. The volume size in bytes.
  746. --*/
  747. {
  748. return _volumeSize;
  749. }
  750. VOID
  751. STRIPE_WP::SetDirtyBit(
  752. IN BOOLEAN IsDirty,
  753. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  754. IN PVOID Context
  755. )
  756. /*++
  757. Routine Description:
  758. This routine sets the dirty bit on the volume. This bit is used at
  759. startup to determine whether or not there was a clean shutdown.
  760. Arguments:
  761. IsDirty - Supplies the value of the dirty bit.
  762. Return Value:
  763. None.
  764. --*/
  765. {
  766. PFT_COMPLETION_ROUTINE_CONTEXT context;
  767. KIRQL irql;
  768. if (CompletionRoutine) {
  769. context = (PFT_COMPLETION_ROUTINE_CONTEXT)
  770. ExAllocatePool(NonPagedPool,
  771. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  772. if (!context) {
  773. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  774. return;
  775. }
  776. KeInitializeSpinLock(&context->SpinLock);
  777. context->Status = STATUS_SUCCESS;
  778. context->RefCount = 2;
  779. context->CompletionRoutine = CompletionRoutine;
  780. context->Context = Context;
  781. context->ParentVolume = this;
  782. COMPOSITE_FT_VOLUME::SetDirtyBit(IsDirty,
  783. StripeWpCompositeVolumeCompletionRoutine, context);
  784. } else {
  785. COMPOSITE_FT_VOLUME::SetDirtyBit(IsDirty, NULL, NULL);
  786. }
  787. KeAcquireSpinLock(&_spinLock, &irql);
  788. if (IsDirty || _syncOk) {
  789. if (!_stopSyncs) {
  790. _state.IsDirty = IsDirty;
  791. }
  792. }
  793. KeReleaseSpinLock(&_spinLock, irql);
  794. if (CompletionRoutine) {
  795. PropogateStateChanges(StripeWpCompositeVolumeCompletionRoutine, context);
  796. } else {
  797. PropogateStateChanges(NULL, NULL);
  798. }
  799. }
  800. BOOLEAN
  801. STRIPE_WP::IsComplete(
  802. IN BOOLEAN IoPending
  803. )
  804. /*++
  805. Routine Description:
  806. This routine computes whether or not this volume has either all
  807. (if IoPending is FALSE) of its members or enough (if IoPending is TRUE) of
  808. its members.
  809. Arguments:
  810. IoPending - Supplies whether or not there is IO pending.
  811. Return Value:
  812. None.
  813. --*/
  814. {
  815. BOOLEAN b;
  816. USHORT n, i, orphanMember;
  817. PFT_VOLUME vol;
  818. b = COMPOSITE_FT_VOLUME::IsComplete(IoPending);
  819. if (b) {
  820. return TRUE;
  821. }
  822. if (!IoPending || _state.IsInitializing) {
  823. return FALSE;
  824. }
  825. n = QueryNumMembers();
  826. orphanMember = n;
  827. for (i = 0; i < n; i++) {
  828. vol = GetMember(i);
  829. if (!vol || !vol->IsComplete(IoPending)) {
  830. if (orphanMember < n) {
  831. return FALSE;
  832. }
  833. orphanMember = i;
  834. }
  835. }
  836. if (orphanMember < n) {
  837. if (_state.UnhealthyMemberState != FtMemberHealthy &&
  838. _state.UnhealthyMemberNumber != orphanMember) {
  839. return FALSE;
  840. }
  841. }
  842. return TRUE;
  843. }
  844. VOID
  845. STRIPE_WP::CompleteNotification(
  846. IN BOOLEAN IoPending
  847. )
  848. /*++
  849. Routine Description:
  850. This routine is called to notify the volume that it is complete and
  851. to therefore prepare for incoming requests.
  852. Arguments:
  853. IoPending - Supplies whether or not there is IO pending.
  854. Return Value:
  855. None.
  856. --*/
  857. {
  858. USHORT n, i, orphanMember;
  859. PFT_VOLUME vol;
  860. COMPOSITE_FT_VOLUME::CompleteNotification(IoPending);
  861. n = QueryNumMembers();
  862. orphanMember = n;
  863. for (i = 0; i < n; i++) {
  864. vol = GetMember(i);
  865. if (!vol || !vol->IsComplete(IoPending)) {
  866. orphanMember = i;
  867. break;
  868. }
  869. }
  870. if (orphanMember < n) {
  871. if (SetMemberState(orphanMember, FtMemberOrphaned)) {
  872. PropogateStateChanges(NULL, NULL);
  873. Notify();
  874. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  875. FT_ORPHANING, STATUS_SUCCESS, 1);
  876. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  877. _orphanedBecauseOfMissingMember = TRUE;
  878. }
  879. }
  880. }
  881. NTSTATUS
  882. STRIPE_WP::CheckIo(
  883. OUT PBOOLEAN IsIoOk
  884. )
  885. /*++
  886. Routine Description:
  887. This routine returns whether or not IO is possible on the given
  888. logical disk.
  889. Arguments:
  890. IsIoOk - Returns the state of IO.
  891. Return Value:
  892. NTSTATUS
  893. --*/
  894. {
  895. NTSTATUS status;
  896. KIRQL irql;
  897. USHORT n, numOk, skipVol, i;
  898. PFT_VOLUME vol;
  899. BOOLEAN ok, b;
  900. n = QueryNumMembers();
  901. numOk = 0;
  902. KeAcquireSpinLock(&_spinLock, &irql);
  903. if (_state.UnhealthyMemberState == FtMemberHealthy) {
  904. skipVol = n;
  905. } else {
  906. skipVol = _state.UnhealthyMemberNumber;
  907. }
  908. KeReleaseSpinLock(&_spinLock, irql);
  909. for (i = 0; i < n; i++) {
  910. if (i == skipVol) {
  911. continue;
  912. }
  913. vol = GetMemberUnprotected(i);
  914. if (!vol) {
  915. continue;
  916. }
  917. status = vol->CheckIo(&ok);
  918. if (!NT_SUCCESS(status)) {
  919. return status;
  920. }
  921. if (ok) {
  922. numOk++;
  923. }
  924. }
  925. if (numOk >= n - 1) {
  926. *IsIoOk = TRUE;
  927. } else {
  928. *IsIoOk = FALSE;
  929. }
  930. return STATUS_SUCCESS;
  931. }
  932. BOOLEAN
  933. STRIPE_WP::IsVolumeSuitableForRegenerate(
  934. IN USHORT MemberNumber,
  935. IN PFT_VOLUME Volume
  936. )
  937. /*++
  938. Routine Description:
  939. This routine computes whether or not the given volume is suitable
  940. for a regenerate operation.
  941. Arguments:
  942. MemberNumber - Supplies the member number.
  943. Volume - Supplies the volume.
  944. Return Value:
  945. FALSE - The volume is not suitable.
  946. TRUE - The volume is suitable.
  947. --*/
  948. {
  949. KIRQL irql;
  950. if (Volume->QueryVolumeSize() < _memberSize) {
  951. return FALSE;
  952. }
  953. KeAcquireSpinLock(&_spinLock, &irql);
  954. if (!_syncOk ||
  955. _state.IsInitializing ||
  956. _state.UnhealthyMemberState != FtMemberOrphaned ||
  957. _state.UnhealthyMemberNumber != MemberNumber) {
  958. KeReleaseSpinLock(&_spinLock, irql);
  959. return FALSE;
  960. }
  961. KeReleaseSpinLock(&_spinLock, irql);
  962. return TRUE;
  963. }
  964. VOID
  965. STRIPE_WP::NewStateArrival(
  966. IN PVOID NewStateInstance
  967. )
  968. /*++
  969. Routine Description:
  970. This routine takes the new state instance arrival combined with its
  971. current state to come up with the new current state for the volume.
  972. If the two states cannot be reconciled then this routine returns FALSE
  973. indicating that the volume is invalid and should be broken into its
  974. constituant parts.
  975. Arguments:
  976. NewStateInstance - Supplies the new state instance.
  977. Return Value:
  978. None.
  979. --*/
  980. {
  981. BOOLEAN changed = FALSE;
  982. BOOLEAN severeInconsistency = FALSE;
  983. PFT_MIRROR_AND_SWP_STATE_INFORMATION state;
  984. state = (PFT_MIRROR_AND_SWP_STATE_INFORMATION) NewStateInstance;
  985. if (state->IsDirty) {
  986. if (!_state.IsDirty) {
  987. _originalDirtyBit = _state.IsDirty = state->IsDirty;
  988. changed = TRUE;
  989. }
  990. }
  991. if (state->IsInitializing) {
  992. if (_state.UnhealthyMemberState == FtMemberHealthy) {
  993. if (!_state.IsInitializing) {
  994. _state.IsInitializing = TRUE;
  995. changed = TRUE;
  996. }
  997. } else {
  998. severeInconsistency = TRUE;
  999. }
  1000. } else if (state->UnhealthyMemberState != FtMemberHealthy) {
  1001. if (state->UnhealthyMemberNumber >= QueryNumMembers()) {
  1002. severeInconsistency = TRUE;
  1003. } else if (_state.IsInitializing) {
  1004. severeInconsistency = TRUE;
  1005. } else if (_state.UnhealthyMemberState == FtMemberHealthy) {
  1006. _state.UnhealthyMemberState = state->UnhealthyMemberState;
  1007. _state.UnhealthyMemberNumber = state->UnhealthyMemberNumber;
  1008. changed = TRUE;
  1009. } else if (_state.UnhealthyMemberNumber == state->UnhealthyMemberNumber) {
  1010. if (state->UnhealthyMemberState == FtMemberOrphaned) {
  1011. if (_state.UnhealthyMemberState != FtMemberOrphaned) {
  1012. _state.UnhealthyMemberState = FtMemberOrphaned;
  1013. changed = TRUE;
  1014. }
  1015. }
  1016. } else {
  1017. severeInconsistency = TRUE;
  1018. }
  1019. }
  1020. if (severeInconsistency) {
  1021. _state.IsInitializing = TRUE;
  1022. _state.UnhealthyMemberState = FtMemberHealthy;
  1023. changed = TRUE;
  1024. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  1025. FT_SWP_STATE_CORRUPTION, STATUS_SUCCESS,
  1026. 0);
  1027. }
  1028. if (changed) {
  1029. PropogateStateChanges(NULL, NULL);
  1030. }
  1031. }
  1032. BOOLEAN
  1033. STRIPE_WP::QueryVolumeState(
  1034. IN PFT_VOLUME Volume,
  1035. OUT PFT_MEMBER_STATE State
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. This routine returns the state of the given volume considered as a
  1040. member of this volume.
  1041. Arguments:
  1042. Volume - Supplies the volume to query the state for.
  1043. State - Returns the state.
  1044. Return Value:
  1045. FALSE - The given Volume is not a member of this volume.
  1046. TRUE - The state was successfully computed.
  1047. --*/
  1048. {
  1049. USHORT n, i;
  1050. PFT_VOLUME vol;
  1051. KIRQL irql;
  1052. FT_MEMBER_STATE state;
  1053. n = QueryNumMembers();
  1054. for (i = 0; i < n; i++) {
  1055. vol = GetMember(i);
  1056. if (!vol) {
  1057. continue;
  1058. }
  1059. if (!vol->QueryVolumeState(Volume, State)) {
  1060. continue;
  1061. }
  1062. KeAcquireSpinLock(&_spinLock, &irql);
  1063. state = QueryMemberState(i);
  1064. if (state != FtMemberHealthy) {
  1065. if (*State != FtMemberOrphaned) {
  1066. *State = state;
  1067. }
  1068. }
  1069. KeReleaseSpinLock(&_spinLock, irql);
  1070. return TRUE;
  1071. }
  1072. return FALSE;
  1073. }
  1074. STRIPE_WP::STRIPE_WP(
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. Constructor.
  1079. Arguments:
  1080. None.
  1081. Return Value:
  1082. None.
  1083. --*/
  1084. {
  1085. _ePacket = NULL;
  1086. _eRegeneratePacket = NULL;
  1087. _eRecoverPacket = NULL;
  1088. }
  1089. STRIPE_WP::~STRIPE_WP(
  1090. )
  1091. /*++
  1092. Routine Description:
  1093. Routine called to cleanup resources being used by the object.
  1094. Arguments:
  1095. None.
  1096. Return Value:
  1097. None.
  1098. --*/
  1099. {
  1100. if (_ePacket) {
  1101. delete _ePacket;
  1102. _ePacket = NULL;
  1103. }
  1104. if (_eRegeneratePacket) {
  1105. delete _eRegeneratePacket;
  1106. _eRegeneratePacket = NULL;
  1107. }
  1108. if (_eRecoverPacket) {
  1109. delete _eRecoverPacket;
  1110. _eRecoverPacket = NULL;
  1111. }
  1112. }
  1113. BOOLEAN
  1114. STRIPE_WP::SetMemberState(
  1115. IN USHORT MemberNumber,
  1116. IN FT_MEMBER_STATE MemberState
  1117. )
  1118. /*++
  1119. Routine Description:
  1120. This routine sets the given member to the given state.
  1121. Arguments:
  1122. MemberNumber - Supplies the member number.
  1123. MemberState - Supplies the member state.
  1124. Return Value:
  1125. FALSE - There was no state change.
  1126. TRUE - A state change took place.
  1127. Notes:
  1128. The caller must be holding the class spin lock.
  1129. --*/
  1130. {
  1131. if (_state.IsInitializing) {
  1132. return FALSE;
  1133. }
  1134. if (_state.UnhealthyMemberState == FtMemberHealthy) {
  1135. if (MemberNumber >= QueryNumMembers()) {
  1136. KeBugCheckEx(FTDISK_INTERNAL_ERROR, (ULONG_PTR) this,
  1137. MemberNumber, MemberState, 0);
  1138. }
  1139. _state.UnhealthyMemberNumber = MemberNumber;
  1140. _state.UnhealthyMemberState = MemberState;
  1141. return TRUE;
  1142. }
  1143. if (_state.UnhealthyMemberNumber == MemberNumber &&
  1144. _state.UnhealthyMemberState != MemberState) {
  1145. _state.UnhealthyMemberState = MemberState;
  1146. return TRUE;
  1147. }
  1148. return FALSE;
  1149. }
  1150. VOID
  1151. StripeWpParallelTransferCompletionRoutine(
  1152. IN PTRANSFER_PACKET TransferPacket
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. Completion routine for STRIPE_WP::Transfer function.
  1157. Arguments:
  1158. TransferPacket - Supplies the transfer packet.
  1159. Return Value:
  1160. None.
  1161. --*/
  1162. {
  1163. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  1164. PSTRIPE_WP t = (PSTRIPE_WP) transferPacket->StripeWithParity;
  1165. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  1166. NTSTATUS status = transferPacket->IoStatus.Status;
  1167. KIRQL irql;
  1168. PLIST_ENTRY l;
  1169. PTRANSFER_PACKET p;
  1170. LONG count;
  1171. BOOLEAN b, serviceQueue;
  1172. PSWP_WRITE_TP writePacket;
  1173. if (NT_SUCCESS(status)) {
  1174. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  1175. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  1176. masterPacket->IoStatus.Information +=
  1177. transferPacket->IoStatus.Information;
  1178. }
  1179. if (transferPacket->OneReadFailed &&
  1180. FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  1181. masterPacket->IoStatus.Status = status;
  1182. }
  1183. } else {
  1184. // Should we orphan the drive?
  1185. if (transferPacket->ReadPacket &&
  1186. !transferPacket->OneReadFailed &&
  1187. status != STATUS_VERIFY_REQUIRED) {
  1188. if (FsRtlIsTotalDeviceFailure(status)) {
  1189. KeAcquireSpinLock(&t->_spinLock, &irql);
  1190. b = t->SetMemberState(transferPacket->WhichMember,
  1191. FtMemberOrphaned);
  1192. KeReleaseSpinLock(&t->_spinLock, irql);
  1193. if (b) {
  1194. t->PropogateStateChanges(NULL, NULL);
  1195. t->Notify();
  1196. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  1197. FT_ORPHANING, STATUS_SUCCESS, 4);
  1198. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL,
  1199. NULL);
  1200. }
  1201. t->RegeneratePacket(transferPacket, TRUE);
  1202. return;
  1203. }
  1204. // Is this something that we should retry for bad sectors?
  1205. if (transferPacket->Mdl) {
  1206. transferPacket->OneReadFailed = TRUE;
  1207. t->Recover(transferPacket, TRUE);
  1208. return;
  1209. }
  1210. }
  1211. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  1212. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  1213. masterPacket->IoStatus.Status = status;
  1214. masterPacket->IoStatus.Information = 0;
  1215. }
  1216. }
  1217. count = --masterPacket->RefCount;
  1218. KeReleaseSpinLock(&masterPacket->SpinLock, irql);
  1219. serviceQueue = FALSE;
  1220. KeAcquireSpinLock(&t->_spinLock, &irql);
  1221. if (t->_ePacketInUse && !t->_ePacketQueueBeingServiced) {
  1222. t->_ePacketQueueBeingServiced = TRUE;
  1223. serviceQueue = TRUE;
  1224. }
  1225. KeReleaseSpinLock(&t->_spinLock, irql);
  1226. delete transferPacket;
  1227. if (!count) {
  1228. masterPacket->CompletionRoutine(masterPacket);
  1229. }
  1230. if (serviceQueue) {
  1231. for (;;) {
  1232. KeAcquireSpinLock(&t->_spinLock, &irql);
  1233. if (IsListEmpty(&t->_ePacketQueue)) {
  1234. t->_ePacketQueueBeingServiced = FALSE;
  1235. KeReleaseSpinLock(&t->_spinLock, irql);
  1236. break;
  1237. }
  1238. l = RemoveHeadList(&t->_ePacketQueue);
  1239. KeReleaseSpinLock(&t->_spinLock, irql);
  1240. p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
  1241. if (!t->LaunchParallel(p)) {
  1242. KeAcquireSpinLock(&t->_spinLock, &irql);
  1243. if (t->_ePacketInUse) {
  1244. InsertHeadList(&t->_ePacketQueue, l);
  1245. t->_ePacketQueueBeingServiced = FALSE;
  1246. KeReleaseSpinLock(&t->_spinLock, irql);
  1247. } else {
  1248. t->_ePacketInUse = TRUE;
  1249. KeReleaseSpinLock(&t->_spinLock, irql);
  1250. t->LaunchSequential(p);
  1251. KeAcquireSpinLock(&t->_spinLock, &irql);
  1252. if (!t->_ePacketInUse) {
  1253. KeReleaseSpinLock(&t->_spinLock, irql);
  1254. continue;
  1255. }
  1256. t->_ePacketQueueBeingServiced = FALSE;
  1257. KeReleaseSpinLock(&t->_spinLock, irql);
  1258. }
  1259. break;
  1260. }
  1261. }
  1262. }
  1263. }
  1264. BOOLEAN
  1265. STRIPE_WP::LaunchParallel(
  1266. IN OUT PTRANSFER_PACKET TransferPacket
  1267. )
  1268. /*++
  1269. Routine Description:
  1270. This routine launches a transfer packet in parallel accross the
  1271. stripe members.
  1272. Arguments:
  1273. TransferPacket - Supplies the transfer packet.
  1274. Return Value:
  1275. FALSE - Insufficient resources.
  1276. TRUE - Success.
  1277. --*/
  1278. {
  1279. LONGLONG offset, whichStripe, whichRow, off;
  1280. ULONG length, stripeRemainder, numRequests, arraySize;
  1281. USHORT whichMember, parityStripe;
  1282. ULONG len;
  1283. PSWP_TP p;
  1284. ULONG i;
  1285. PCHAR vp;
  1286. LIST_ENTRY q;
  1287. PLIST_ENTRY l;
  1288. // Compute the number of pieces for this transfer.
  1289. offset = TransferPacket->Offset;
  1290. length = TransferPacket->Length;
  1291. stripeRemainder = _stripeSize - (ULONG) (offset%_stripeSize);
  1292. if (length > stripeRemainder) {
  1293. length -= stripeRemainder;
  1294. numRequests = length/_stripeSize;
  1295. length -= numRequests*_stripeSize;
  1296. if (length) {
  1297. numRequests += 2;
  1298. } else {
  1299. numRequests++;
  1300. }
  1301. } else {
  1302. numRequests = 1;
  1303. }
  1304. KeInitializeSpinLock(&TransferPacket->SpinLock);
  1305. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  1306. TransferPacket->IoStatus.Information = 0;
  1307. TransferPacket->RefCount = numRequests;
  1308. length = TransferPacket->Length;
  1309. if (TransferPacket->Mdl && numRequests > 1) {
  1310. vp = (PCHAR) MmGetMdlVirtualAddress(TransferPacket->Mdl);
  1311. }
  1312. whichStripe = offset/_stripeSize;
  1313. arraySize = QueryNumMembers();
  1314. InitializeListHead(&q);
  1315. for (i = 0; i < numRequests; i++, whichStripe++) {
  1316. whichRow = whichStripe/(arraySize - 1);
  1317. whichMember = (USHORT) (whichStripe%(arraySize - 1));
  1318. parityStripe = (USHORT) (whichRow%arraySize);
  1319. if (whichMember >= parityStripe) {
  1320. whichMember++;
  1321. }
  1322. if (i == 0) {
  1323. off = whichRow*_stripeSize + offset%_stripeSize;
  1324. len = stripeRemainder > length ? length : stripeRemainder;
  1325. } else if (i == numRequests - 1) {
  1326. off = whichRow*_stripeSize;
  1327. len = length;
  1328. } else {
  1329. off = whichRow*_stripeSize;
  1330. len = _stripeSize;
  1331. }
  1332. length -= len;
  1333. if (TransferPacket->ReadPacket) {
  1334. p = new SWP_TP;
  1335. } else {
  1336. p = new SWP_WRITE_TP;
  1337. if (p && !((PSWP_WRITE_TP) p)->AllocateMdls(len)) {
  1338. delete p;
  1339. p = NULL;
  1340. }
  1341. }
  1342. if (p) {
  1343. if (TransferPacket->Mdl && numRequests > 1) {
  1344. if (p->AllocateMdl(vp, len)) {
  1345. IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl, vp, len);
  1346. } else {
  1347. delete p;
  1348. p = NULL;
  1349. }
  1350. vp += len;
  1351. } else {
  1352. p->Mdl = TransferPacket->Mdl;
  1353. }
  1354. }
  1355. if (!p) {
  1356. while (!IsListEmpty(&q)) {
  1357. l = RemoveHeadList(&q);
  1358. p = CONTAINING_RECORD(l, SWP_TP, QueueEntry);
  1359. delete p;
  1360. }
  1361. return FALSE;
  1362. }
  1363. p->Length = len;
  1364. p->Offset = off;
  1365. p->CompletionRoutine = StripeWpParallelTransferCompletionRoutine;
  1366. p->Thread = TransferPacket->Thread;
  1367. p->IrpFlags = TransferPacket->IrpFlags;
  1368. p->ReadPacket = TransferPacket->ReadPacket;
  1369. p->MasterPacket = TransferPacket;
  1370. p->StripeWithParity = this;
  1371. p->WhichMember = whichMember;
  1372. p->SavedCompletionRoutine = StripeWpParallelTransferCompletionRoutine;
  1373. p->OneReadFailed = FALSE;
  1374. InsertTailList(&q, &p->QueueEntry);
  1375. }
  1376. while (!IsListEmpty(&q)) {
  1377. l = RemoveHeadList(&q);
  1378. p = CONTAINING_RECORD(l, SWP_TP, QueueEntry);
  1379. ASSERT(p->ReadPacket == TransferPacket->ReadPacket);
  1380. if (p->ReadPacket) {
  1381. ReadPacket(p);
  1382. } else {
  1383. WritePacket((PSWP_WRITE_TP) p);
  1384. }
  1385. }
  1386. return TRUE;
  1387. }
  1388. VOID
  1389. StripeWpSequentialTransferCompletionRoutine(
  1390. IN PTRANSFER_PACKET TransferPacket
  1391. )
  1392. /*++
  1393. Routine Description:
  1394. Completion routine for STRIPE::Transfer function.
  1395. Arguments:
  1396. TransferPacket - Supplies the transfer packet.
  1397. Return Value:
  1398. None.
  1399. --*/
  1400. {
  1401. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  1402. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  1403. NTSTATUS status = transferPacket->IoStatus.Status;
  1404. PSTRIPE_WP t = transferPacket->StripeWithParity;
  1405. LONGLONG rowNumber, stripeNumber, masterOffset;
  1406. KIRQL irql;
  1407. PLIST_ENTRY l;
  1408. PTRANSFER_PACKET p;
  1409. USHORT parityStripe;
  1410. BOOLEAN b;
  1411. PSWP_WRITE_TP writePacket;
  1412. if (NT_SUCCESS(status)) {
  1413. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  1414. masterPacket->IoStatus.Information +=
  1415. transferPacket->IoStatus.Information;
  1416. }
  1417. if (transferPacket->OneReadFailed &&
  1418. FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  1419. masterPacket->IoStatus.Status = status;
  1420. }
  1421. } else {
  1422. // Should we orphan the drive?
  1423. if (transferPacket->ReadPacket &&
  1424. !transferPacket->OneReadFailed &&
  1425. status != STATUS_VERIFY_REQUIRED) {
  1426. if (FsRtlIsTotalDeviceFailure(status)) {
  1427. KeAcquireSpinLock(&t->_spinLock, &irql);
  1428. b = t->SetMemberState(transferPacket->WhichMember,
  1429. FtMemberOrphaned);
  1430. KeReleaseSpinLock(&t->_spinLock, irql);
  1431. if (b) {
  1432. t->PropogateStateChanges(NULL, NULL);
  1433. t->Notify();
  1434. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  1435. FT_ORPHANING, STATUS_SUCCESS, 5);
  1436. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL,
  1437. NULL);
  1438. }
  1439. t->RegeneratePacket(transferPacket, TRUE);
  1440. return;
  1441. }
  1442. // Is this something that we should retry for bad sectors.
  1443. if (transferPacket->Mdl) {
  1444. transferPacket->OneReadFailed = TRUE;
  1445. t->Recover(transferPacket, TRUE);
  1446. return;
  1447. }
  1448. }
  1449. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  1450. masterPacket->IoStatus.Status = status;
  1451. masterPacket->IoStatus.Information = 0;
  1452. }
  1453. }
  1454. MmPrepareMdlForReuse(transferPacket->Mdl);
  1455. t->_overlappedIoManager.ReleaseIoRegion(transferPacket);
  1456. rowNumber = transferPacket->Offset/t->_stripeSize;
  1457. parityStripe = (USHORT) rowNumber%t->QueryNumMembers();
  1458. stripeNumber = rowNumber*(t->QueryNumMembers() - 1) +
  1459. transferPacket->WhichMember;
  1460. if (transferPacket->WhichMember > parityStripe) {
  1461. stripeNumber--;
  1462. }
  1463. masterOffset = stripeNumber*t->_stripeSize +
  1464. transferPacket->Offset%t->_stripeSize +
  1465. transferPacket->Length;
  1466. if (masterOffset == masterPacket->Offset + masterPacket->Length) {
  1467. masterPacket->CompletionRoutine(masterPacket);
  1468. KeAcquireSpinLock(&t->_spinLock, &irql);
  1469. if (t->_ePacketQueueBeingServiced) {
  1470. t->_ePacketInUse = FALSE;
  1471. KeReleaseSpinLock(&t->_spinLock, irql);
  1472. return;
  1473. }
  1474. t->_ePacketQueueBeingServiced = TRUE;
  1475. KeReleaseSpinLock(&t->_spinLock, irql);
  1476. for (;;) {
  1477. KeAcquireSpinLock(&t->_spinLock, &irql);
  1478. if (IsListEmpty(&t->_ePacketQueue)) {
  1479. t->_ePacketInUse = FALSE;
  1480. t->_ePacketQueueBeingServiced = FALSE;
  1481. KeReleaseSpinLock(&t->_spinLock, irql);
  1482. break;
  1483. }
  1484. l = RemoveHeadList(&t->_ePacketQueue);
  1485. KeReleaseSpinLock(&t->_spinLock, irql);
  1486. p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
  1487. if (!t->LaunchParallel(p)) {
  1488. t->LaunchSequential(p);
  1489. KeAcquireSpinLock(&t->_spinLock, &irql);
  1490. if (!t->_ePacketInUse) {
  1491. KeReleaseSpinLock(&t->_spinLock, irql);
  1492. continue;
  1493. }
  1494. t->_ePacketQueueBeingServiced = FALSE;
  1495. KeReleaseSpinLock(&t->_spinLock, irql);
  1496. break;
  1497. }
  1498. }
  1499. return;
  1500. }
  1501. transferPacket->WhichMember++;
  1502. if (transferPacket->WhichMember == t->QueryNumMembers()) {
  1503. transferPacket->WhichMember = 0;
  1504. rowNumber++;
  1505. } else if (transferPacket->WhichMember == parityStripe) {
  1506. transferPacket->WhichMember++;
  1507. if (transferPacket->WhichMember == t->QueryNumMembers()) {
  1508. transferPacket->WhichMember = 1;
  1509. rowNumber++;
  1510. }
  1511. }
  1512. transferPacket->Offset = rowNumber*t->_stripeSize;
  1513. transferPacket->Length = t->_stripeSize;
  1514. if (masterOffset + transferPacket->Length >
  1515. masterPacket->Offset + masterPacket->Length) {
  1516. transferPacket->Length = (ULONG) (masterPacket->Offset +
  1517. masterPacket->Length - masterOffset);
  1518. }
  1519. IoBuildPartialMdl(masterPacket->Mdl, transferPacket->Mdl,
  1520. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  1521. (ULONG) (masterOffset - masterPacket->Offset),
  1522. transferPacket->Length);
  1523. if (transferPacket->ReadPacket) {
  1524. t->ReadPacket(transferPacket);
  1525. } else {
  1526. t->WritePacket((PSWP_WRITE_TP) transferPacket);
  1527. }
  1528. }
  1529. VOID
  1530. STRIPE_WP::LaunchSequential(
  1531. IN OUT PTRANSFER_PACKET TransferPacket
  1532. )
  1533. /*++
  1534. Routine Description:
  1535. This routine launches a transfer packet sequentially accross the
  1536. stripe members using the emergency packet.
  1537. Arguments:
  1538. TransferPacket - Supplies the transfer packet.
  1539. Return Value:
  1540. FALSE - Insufficient resources.
  1541. TRUE - Success.
  1542. --*/
  1543. {
  1544. PSWP_WRITE_TP p;
  1545. LONGLONG offset, whichStripe, whichRow, o;
  1546. USHORT whichMember, arraySize, parityStripe;
  1547. ULONG l, stripeRemainder;
  1548. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  1549. TransferPacket->IoStatus.Information = 0;
  1550. offset = TransferPacket->Offset;
  1551. p = _ePacket;
  1552. arraySize = QueryNumMembers();
  1553. stripeRemainder = _stripeSize - (ULONG) (offset%_stripeSize);
  1554. whichStripe = offset/_stripeSize;
  1555. whichRow = whichStripe/(arraySize - 1);
  1556. whichMember = (USHORT) (whichStripe%(arraySize - 1));
  1557. parityStripe = (USHORT) (whichRow%arraySize);
  1558. if (whichMember >= parityStripe) {
  1559. whichMember++;
  1560. }
  1561. o = whichRow*_stripeSize + offset%_stripeSize;
  1562. l = stripeRemainder;
  1563. if (l > TransferPacket->Length) {
  1564. l = TransferPacket->Length;
  1565. }
  1566. IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl,
  1567. MmGetMdlVirtualAddress(TransferPacket->Mdl), l);
  1568. p->Length = l;
  1569. p->Offset = o;
  1570. p->CompletionRoutine = StripeWpSequentialTransferCompletionRoutine;
  1571. p->Thread = TransferPacket->Thread;
  1572. p->IrpFlags = TransferPacket->IrpFlags;
  1573. p->ReadPacket = TransferPacket->ReadPacket;
  1574. p->MasterPacket = TransferPacket;
  1575. p->StripeWithParity = this;
  1576. p->WhichMember = whichMember;
  1577. p->SavedCompletionRoutine = StripeWpSequentialTransferCompletionRoutine;
  1578. p->OneReadFailed = FALSE;
  1579. if (p->ReadPacket) {
  1580. ReadPacket(p);
  1581. } else {
  1582. WritePacket(p);
  1583. }
  1584. }
  1585. VOID
  1586. STRIPE_WP::ReadPacket(
  1587. IN OUT PSWP_TP TransferPacket
  1588. )
  1589. /*++
  1590. Routine Description:
  1591. This routine takes a packet that is restricted to a single
  1592. stripe region and reads that data.
  1593. Arguments:
  1594. TransferPacket - Supplies the main read packet.
  1595. Return Value:
  1596. None.
  1597. --*/
  1598. {
  1599. PTRANSFER_PACKET masterPacket = TransferPacket->MasterPacket;
  1600. KIRQL irql;
  1601. TransferPacket->TargetVolume = GetMemberUnprotected(TransferPacket->WhichMember);
  1602. KeAcquireSpinLock(&_spinLock, &irql);
  1603. if (QueryMemberState(TransferPacket->WhichMember) != FtMemberHealthy ||
  1604. masterPacket->SpecialRead == TP_SPECIAL_READ_SECONDARY) {
  1605. KeReleaseSpinLock(&_spinLock, irql);
  1606. RegeneratePacket(TransferPacket, TRUE);
  1607. } else {
  1608. KeReleaseSpinLock(&_spinLock, irql);
  1609. TRANSFER(TransferPacket);
  1610. }
  1611. }
  1612. VOID
  1613. StripeWpWritePhase31(
  1614. IN OUT PTRANSFER_PACKET Packet
  1615. )
  1616. /*++
  1617. Routine Description:
  1618. This is the completion routine for the final data write and the
  1619. final parity write of the write process. This packet's master packet
  1620. is the original write packet. This write packet exists because the data
  1621. has to be copied from the original write packet so that parity
  1622. may be correctly computed.
  1623. Arguments:
  1624. Packet - Supplies the update parity packet.
  1625. Return Value:
  1626. None.
  1627. --*/
  1628. {
  1629. PSWP_WRITE_TP masterPacket;
  1630. PSTRIPE_WP t;
  1631. KIRQL irql;
  1632. LONG count;
  1633. masterPacket = CONTAINING_RECORD(Packet, SWP_WRITE_TP, ParityPacket);
  1634. t = masterPacket->StripeWithParity;
  1635. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  1636. count = --masterPacket->RefCount;
  1637. KeReleaseSpinLock(&masterPacket->SpinLock, irql);
  1638. if (!count) {
  1639. t->CompleteWrite(masterPacket);
  1640. }
  1641. }
  1642. VOID
  1643. StripeWpWritePhase30(
  1644. IN OUT PTRANSFER_PACKET Packet
  1645. )
  1646. /*++
  1647. Routine Description:
  1648. This is the completion routine for the final data write and the
  1649. final parity write of the write process. This packet's master packet
  1650. is the original write packet. This write packet exists because the data
  1651. has to be copied from the original write packet so that parity
  1652. may be correctly computed.
  1653. Arguments:
  1654. Packet - Supplies the write packet.
  1655. Return Value:
  1656. None.
  1657. --*/
  1658. {
  1659. PSWP_TP writePacket = (PSWP_TP) Packet;
  1660. PSWP_WRITE_TP masterPacket = (PSWP_WRITE_TP) writePacket->MasterPacket;
  1661. PSTRIPE_WP t = masterPacket->StripeWithParity;
  1662. KIRQL irql;
  1663. LONG count;
  1664. BOOLEAN b;
  1665. PPARITY_TP parityPacket;
  1666. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  1667. count = --masterPacket->RefCount;
  1668. b = (masterPacket->IrpFlags&SL_FT_SEQUENTIAL_WRITE) ? TRUE : FALSE;
  1669. KeReleaseSpinLock(&masterPacket->SpinLock, irql);
  1670. if (count) {
  1671. if (b) {
  1672. parityPacket = &masterPacket->ParityPacket;
  1673. t->_parityIoManager.UpdateParity(parityPacket);
  1674. }
  1675. } else {
  1676. t->CompleteWrite(masterPacket);
  1677. }
  1678. }
  1679. VOID
  1680. StripeWpWriteRecover(
  1681. IN OUT PTRANSFER_PACKET MasterPacket
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. A bad sector on a read before write caused a promote to all members
  1686. in preparation for a recover.
  1687. Arguments:
  1688. TransferPacket - Supplies the master write packet.
  1689. Return Value:
  1690. None.
  1691. --*/
  1692. {
  1693. PSWP_WRITE_TP masterPacket = (PSWP_WRITE_TP) MasterPacket;
  1694. PSWP_TP readPacket = &masterPacket->ReadWritePacket;
  1695. PSTRIPE_WP t = (PSTRIPE_WP) readPacket->StripeWithParity;
  1696. masterPacket->CompletionRoutine = masterPacket->SavedCompletionRoutine;
  1697. readPacket->CompletionRoutine = StripeWpWritePhase2;
  1698. t->Recover(readPacket, FALSE);
  1699. }
  1700. VOID
  1701. StripeWpWritePhase2(
  1702. IN OUT PTRANSFER_PACKET ReadPacket
  1703. )
  1704. /*++
  1705. Routine Description:
  1706. This routine describes phase 3 of the write process. The region
  1707. that we are about to write has been preread. If the read was
  1708. successful then queue write and parity requests. If the read
  1709. was not successful then propogate the error and cleanup.
  1710. Arguments:
  1711. TransferPacket - Supplies the read packet.
  1712. Return Value:
  1713. None.
  1714. --*/
  1715. {
  1716. PSWP_TP readPacket = (PSWP_TP) ReadPacket;
  1717. PSTRIPE_WP t = readPacket->StripeWithParity;
  1718. PSWP_WRITE_TP masterPacket = (PSWP_WRITE_TP) readPacket->MasterPacket;
  1719. PPARITY_TP parityPacket = &masterPacket->ParityPacket;
  1720. PSWP_TP writePacket = &masterPacket->ReadWritePacket;
  1721. NTSTATUS status;
  1722. KIRQL irql;
  1723. FT_PARTITION_STATE state;
  1724. BOOLEAN b;
  1725. status = readPacket->IoStatus.Status;
  1726. if (!NT_SUCCESS(status)) {
  1727. if (!readPacket->OneReadFailed && status != STATUS_VERIFY_REQUIRED) {
  1728. if (FsRtlIsTotalDeviceFailure(status)) {
  1729. // Orphan this unit and then try again with a regenerate.
  1730. KeAcquireSpinLock(&t->_spinLock, &irql);
  1731. b = t->SetMemberState(readPacket->WhichMember, FtMemberOrphaned);
  1732. KeReleaseSpinLock(&t->_spinLock, irql);
  1733. if (b) {
  1734. t->PropogateStateChanges(NULL, NULL);
  1735. t->Notify();
  1736. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  1737. FT_ORPHANING, STATUS_SUCCESS, 6);
  1738. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL,
  1739. NULL);
  1740. }
  1741. readPacket->OneReadFailed = TRUE;
  1742. masterPacket->CompletionRoutine = StripeWpWritePhase1;
  1743. t->_overlappedIoManager.PromoteToAllMembers(masterPacket);
  1744. return;
  1745. }
  1746. // Bad sector case.
  1747. readPacket->OneReadFailed = TRUE;
  1748. masterPacket->SavedCompletionRoutine = masterPacket->CompletionRoutine;
  1749. masterPacket->CompletionRoutine = StripeWpWriteRecover;
  1750. t->_overlappedIoManager.PromoteToAllMembers(masterPacket);
  1751. return;
  1752. }
  1753. masterPacket->IoStatus = readPacket->IoStatus;
  1754. masterPacket->CompletionRoutine(masterPacket);
  1755. return;
  1756. }
  1757. KeInitializeSpinLock(&masterPacket->SpinLock);
  1758. masterPacket->IoStatus.Status = STATUS_SUCCESS;
  1759. masterPacket->IoStatus.Information = 0;
  1760. writePacket->Mdl = masterPacket->WriteMdl;
  1761. writePacket->CompletionRoutine = StripeWpWritePhase30;
  1762. writePacket->ReadPacket = FALSE;
  1763. parityPacket->Mdl = masterPacket->ReadAndParityMdl;
  1764. parityPacket->CompletionRoutine = StripeWpWritePhase31;
  1765. if (masterPacket->TargetState != FtMemberOrphaned) {
  1766. RtlCopyMemory(MmGetSystemAddressForMdl(writePacket->Mdl),
  1767. MmGetSystemAddressForMdl(masterPacket->Mdl),
  1768. writePacket->Length);
  1769. if (parityPacket->TargetVolume) {
  1770. FtpComputeParity(MmGetSystemAddressForMdl(parityPacket->Mdl),
  1771. MmGetSystemAddressForMdl(writePacket->Mdl),
  1772. parityPacket->Length);
  1773. masterPacket->RefCount = 2;
  1774. if (!(masterPacket->IrpFlags&SL_FT_SEQUENTIAL_WRITE)) {
  1775. t->_parityIoManager.UpdateParity(parityPacket);
  1776. }
  1777. } else {
  1778. masterPacket->RefCount = 1;
  1779. parityPacket->IoStatus.Status = STATUS_SUCCESS;
  1780. parityPacket->IoStatus.Information = parityPacket->Length;
  1781. }
  1782. TRANSFER(writePacket);
  1783. } else if (parityPacket->TargetVolume) {
  1784. FtpComputeParity(MmGetSystemAddressForMdl(parityPacket->Mdl),
  1785. MmGetSystemAddressForMdl(masterPacket->Mdl),
  1786. readPacket->Length);
  1787. masterPacket->RefCount = 1;
  1788. writePacket->IoStatus.Status = STATUS_SUCCESS;
  1789. writePacket->IoStatus.Information = writePacket->Length;
  1790. t->_parityIoManager.UpdateParity(parityPacket);
  1791. } else {
  1792. masterPacket->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  1793. masterPacket->IoStatus.Information = 0;
  1794. masterPacket->CompletionRoutine(masterPacket);
  1795. }
  1796. }
  1797. VOID
  1798. StripeWpWritePhase1(
  1799. IN OUT PTRANSFER_PACKET TransferPacket
  1800. )
  1801. /*++
  1802. Routine Description:
  1803. This routine describes phase 2 of the write process. This io
  1804. region has been acquired. We now send out the read packet and
  1805. wait until it completes.
  1806. Arguments:
  1807. TransferPacket - Supplies the main write packet.
  1808. Return Value:
  1809. None.
  1810. --*/
  1811. {
  1812. PSWP_WRITE_TP transferPacket = (PSWP_WRITE_TP) TransferPacket;
  1813. PSTRIPE_WP t = transferPacket->StripeWithParity;
  1814. PSWP_TP readPacket;
  1815. PPARITY_TP parityPacket;
  1816. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  1817. parityPacket = &transferPacket->ParityPacket;
  1818. if (parityPacket->TargetVolume) {
  1819. t->_parityIoManager.StartReadForUpdateParity(
  1820. parityPacket->Offset, parityPacket->Length,
  1821. parityPacket->TargetVolume, parityPacket->Thread,
  1822. parityPacket->IrpFlags);
  1823. }
  1824. readPacket = &transferPacket->ReadWritePacket;
  1825. readPacket->CompletionRoutine = StripeWpWritePhase2;
  1826. if (readPacket->OneReadFailed) {
  1827. t->RegeneratePacket(readPacket, FALSE);
  1828. } else {
  1829. TRANSFER(readPacket);
  1830. }
  1831. }
  1832. VOID
  1833. STRIPE_WP::WritePacket(
  1834. IN OUT PSWP_WRITE_TP TransferPacket
  1835. )
  1836. /*++
  1837. Routine Description:
  1838. This routine takes a packet that is restricted to a single
  1839. stripe region and writes out that data along with the parity.
  1840. Arguments:
  1841. TransferPacket - Supplies the main write packet.
  1842. Return Value:
  1843. None.
  1844. --*/
  1845. {
  1846. USHORT parityMember;
  1847. KIRQL irql;
  1848. FT_MEMBER_STATE state, parityState;
  1849. PSWP_TP readPacket;
  1850. PPARITY_TP parityPacket;
  1851. parityMember = (USHORT) ((TransferPacket->Offset/_stripeSize)%
  1852. QueryNumMembers());
  1853. TransferPacket->TargetVolume =
  1854. GetMemberUnprotected(TransferPacket->WhichMember);
  1855. KeAcquireSpinLock(&_spinLock, &irql);
  1856. state = QueryMemberState(TransferPacket->WhichMember);
  1857. parityState = QueryMemberState(parityMember);
  1858. KeReleaseSpinLock(&_spinLock, irql);
  1859. readPacket = &TransferPacket->ReadWritePacket;
  1860. readPacket->Mdl = TransferPacket->ReadAndParityMdl;
  1861. readPacket->Length = TransferPacket->Length;
  1862. readPacket->Offset = TransferPacket->Offset;
  1863. readPacket->TargetVolume = TransferPacket->TargetVolume;
  1864. readPacket->Thread = TransferPacket->Thread;
  1865. readPacket->IrpFlags = TransferPacket->IrpFlags;
  1866. readPacket->ReadPacket = TRUE;
  1867. readPacket->MasterPacket = TransferPacket;
  1868. readPacket->StripeWithParity = this;
  1869. readPacket->WhichMember = TransferPacket->WhichMember;
  1870. readPacket->OneReadFailed = FALSE;
  1871. parityPacket = &TransferPacket->ParityPacket;
  1872. parityPacket->Length = TransferPacket->Length;
  1873. parityPacket->Offset = TransferPacket->Offset;
  1874. if (parityState != FtMemberOrphaned) {
  1875. parityPacket->TargetVolume = GetMemberUnprotected(parityMember);
  1876. } else {
  1877. parityPacket->TargetVolume = NULL;
  1878. }
  1879. parityPacket->Thread = TransferPacket->Thread;
  1880. parityPacket->IrpFlags = TransferPacket->IrpFlags;
  1881. parityPacket->ReadPacket = FALSE;
  1882. TransferPacket->CompletionRoutine = StripeWpWritePhase1;
  1883. TransferPacket->TargetState = state;
  1884. TransferPacket->ParityMember = parityMember;
  1885. if (state == FtMemberHealthy) {
  1886. if (TransferPacket->IrpFlags&SL_FT_SEQUENTIAL_WRITE) {
  1887. _overlappedIoManager.AcquireIoRegion(TransferPacket, TRUE);
  1888. } else {
  1889. _overlappedIoManager.AcquireIoRegion(TransferPacket, FALSE);
  1890. }
  1891. } else {
  1892. readPacket->OneReadFailed = TRUE;
  1893. _overlappedIoManager.AcquireIoRegion(TransferPacket, TRUE);
  1894. }
  1895. }
  1896. VOID
  1897. StripeWpSequentialRegenerateCompletion(
  1898. IN OUT PTRANSFER_PACKET TransferPacket
  1899. )
  1900. /*++
  1901. Routine Description:
  1902. This is the completion routine a regenerate operation where all of
  1903. the reads are being performed sequentially.
  1904. Arguments:
  1905. TransferPacket - Supplies the completed transfer packet.
  1906. Return Value:
  1907. None.
  1908. --*/
  1909. {
  1910. PSWP_REGENERATE_TP transferPacket = (PSWP_REGENERATE_TP) TransferPacket;
  1911. PSWP_TP masterPacket = transferPacket->MasterPacket;
  1912. PSTRIPE_WP t = masterPacket->StripeWithParity;
  1913. NTSTATUS status = transferPacket->IoStatus.Status;
  1914. KIRQL irql;
  1915. ULONG count;
  1916. PLIST_ENTRY l;
  1917. PTRANSFER_PACKET packet;
  1918. USHORT i, n;
  1919. BOOLEAN b;
  1920. ULONG parityMember;
  1921. if (NT_SUCCESS(status)) {
  1922. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  1923. masterPacket->IoStatus = transferPacket->IoStatus;
  1924. }
  1925. } else {
  1926. if (FsRtlIsTotalDeviceFailure(status) &&
  1927. status != STATUS_VERIFY_REQUIRED) {
  1928. KeAcquireSpinLock(&t->_spinLock, &irql);
  1929. b = t->SetMemberState(transferPacket->WhichMember,
  1930. FtMemberOrphaned);
  1931. KeReleaseSpinLock(&t->_spinLock, irql);
  1932. if (b) {
  1933. t->PropogateStateChanges(NULL, NULL);
  1934. t->Notify();
  1935. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  1936. FT_ORPHANING, STATUS_SUCCESS, 7);
  1937. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  1938. }
  1939. }
  1940. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  1941. masterPacket->IoStatus.Status = status;
  1942. masterPacket->IoStatus.Information = 0;
  1943. }
  1944. }
  1945. count = (ULONG) (--masterPacket->RefCount);
  1946. if (masterPacket->Mdl) {
  1947. FtpComputeParity(MmGetSystemAddressForMdl(masterPacket->Mdl),
  1948. MmGetSystemAddressForMdl(transferPacket->Mdl),
  1949. masterPacket->Length);
  1950. }
  1951. n = t->QueryNumMembers();
  1952. if (count) {
  1953. transferPacket->WhichMember++;
  1954. if (transferPacket->WhichMember == masterPacket->WhichMember) {
  1955. transferPacket->WhichMember++;
  1956. }
  1957. transferPacket->TargetVolume = t->GetMemberUnprotected(
  1958. transferPacket->WhichMember);
  1959. TRANSFER(transferPacket);
  1960. return;
  1961. }
  1962. masterPacket->CompletionRoutine(masterPacket);
  1963. KeAcquireSpinLock(&t->_spinLock, &irql);
  1964. if (IsListEmpty(&t->_eRegeneratePacketQueue)) {
  1965. t->_eRegeneratePacketInUse = FALSE;
  1966. packet = NULL;
  1967. } else {
  1968. l = RemoveHeadList(&t->_eRegeneratePacketQueue);
  1969. packet = CONTAINING_RECORD(l, SWP_TP, QueueEntry);
  1970. }
  1971. KeReleaseSpinLock(&t->_spinLock, irql);
  1972. if (packet) {
  1973. packet->CompletionRoutine(packet);
  1974. }
  1975. }
  1976. VOID
  1977. StripeWpSequentialEmergencyCompletion(
  1978. IN OUT PTRANSFER_PACKET TransferPacket
  1979. )
  1980. /*++
  1981. Routine Description:
  1982. This is the completion routine after waiting for an emergency
  1983. regenerate buffer.
  1984. Arguments:
  1985. TransferPacket - Supplies the completed transfer packet.
  1986. Return Value:
  1987. None.
  1988. --*/
  1989. {
  1990. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  1991. PSTRIPE_WP t = transferPacket->StripeWithParity;
  1992. PSWP_REGENERATE_TP p = t->_eRegeneratePacket;
  1993. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  1994. p->Length = transferPacket->Length;
  1995. p->Offset = transferPacket->Offset;
  1996. p->CompletionRoutine = StripeWpSequentialRegenerateCompletion;
  1997. p->TargetVolume = t->GetMemberUnprotected(0);
  1998. p->Thread = transferPacket->Thread;
  1999. p->IrpFlags = transferPacket->IrpFlags;
  2000. p->ReadPacket = TRUE;
  2001. p->MasterPacket = transferPacket;
  2002. p->WhichMember = 0;
  2003. if (transferPacket->TargetVolume == p->TargetVolume) {
  2004. p->WhichMember = 1;
  2005. p->TargetVolume = t->GetMemberUnprotected(1);
  2006. }
  2007. TRANSFER(p);
  2008. }
  2009. VOID
  2010. StripeWpParallelRegenerateCompletion(
  2011. IN OUT PTRANSFER_PACKET TransferPacket
  2012. )
  2013. /*++
  2014. Routine Description:
  2015. This is the completion routine a regenerate operation where all of
  2016. the reads are being performed in parallel.
  2017. Arguments:
  2018. TransferPacket - Supplies the completed transfer packet.
  2019. Return Value:
  2020. None.
  2021. --*/
  2022. {
  2023. PSWP_REGENERATE_TP transferPacket = (PSWP_REGENERATE_TP) TransferPacket;
  2024. PSWP_TP masterPacket = transferPacket->MasterPacket;
  2025. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2026. NTSTATUS status = transferPacket->IoStatus.Status;
  2027. KIRQL irql;
  2028. LONG count;
  2029. PLIST_ENTRY l, s;
  2030. PTRANSFER_PACKET packet;
  2031. PVOID target, source;
  2032. BOOLEAN b;
  2033. USHORT i, n;
  2034. if (NT_SUCCESS(status)) {
  2035. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  2036. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  2037. masterPacket->IoStatus = transferPacket->IoStatus;
  2038. }
  2039. } else {
  2040. if (FsRtlIsTotalDeviceFailure(status) &&
  2041. status != STATUS_VERIFY_REQUIRED) {
  2042. KeAcquireSpinLock(&t->_spinLock, &irql);
  2043. b = t->SetMemberState(transferPacket->WhichMember,
  2044. FtMemberOrphaned);
  2045. KeReleaseSpinLock(&t->_spinLock, irql);
  2046. if (b) {
  2047. t->PropogateStateChanges(NULL, NULL);
  2048. t->Notify();
  2049. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  2050. FT_ORPHANING, STATUS_SUCCESS, 8);
  2051. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  2052. }
  2053. }
  2054. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  2055. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  2056. masterPacket->IoStatus.Status = status;
  2057. masterPacket->IoStatus.Information = 0;
  2058. }
  2059. }
  2060. count = --masterPacket->RefCount;
  2061. KeReleaseSpinLock(&masterPacket->SpinLock, irql);
  2062. if (count) {
  2063. return;
  2064. }
  2065. s = &masterPacket->QueueEntry;
  2066. l = RemoveHeadList(s);
  2067. packet = CONTAINING_RECORD(l, SWP_REGENERATE_TP, RegenPacketList);
  2068. if (masterPacket->Mdl) {
  2069. target = MmGetSystemAddressForMdl(masterPacket->Mdl);
  2070. source = MmGetSystemAddressForMdl(packet->Mdl);
  2071. RtlCopyMemory(target, source, masterPacket->Length);
  2072. }
  2073. for (;;) {
  2074. delete packet;
  2075. if (IsListEmpty(s)) {
  2076. break;
  2077. }
  2078. l = RemoveHeadList(s);
  2079. packet = CONTAINING_RECORD(l, SWP_REGENERATE_TP, RegenPacketList);
  2080. if (masterPacket->Mdl) {
  2081. source = MmGetSystemAddressForMdl(packet->Mdl);
  2082. FtpComputeParity(target, source, masterPacket->Length);
  2083. }
  2084. }
  2085. masterPacket->CompletionRoutine(masterPacket);
  2086. }
  2087. VOID
  2088. StripeWpRegeneratePacketPhase1(
  2089. IN OUT PTRANSFER_PACKET TransferPacket
  2090. )
  2091. /*++
  2092. Routine Description:
  2093. This routine is called after the io regions necessary for a regenerate
  2094. have been allocated. This routine spawns the reads necessary for
  2095. regeneration.
  2096. Arguments:
  2097. TransferPacket - Supplies the main write packet.
  2098. Return Value:
  2099. None.
  2100. --*/
  2101. {
  2102. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  2103. PSTRIPE_WP t = transferPacket->StripeWithParity;
  2104. USHORT i, n;
  2105. PSWP_REGENERATE_TP packet;
  2106. BOOLEAN sequential;
  2107. PLIST_ENTRY l, s;
  2108. ULONG r;
  2109. ULONG parityMember;
  2110. KIRQL irql;
  2111. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  2112. // Determine whether we're going to do this in parallel or
  2113. // sequentially by trying to allocate the memory.
  2114. n = t->QueryNumMembers();
  2115. InitializeListHead(&transferPacket->QueueEntry);
  2116. for (i = 0; i < n; i++) {
  2117. if (i == transferPacket->WhichMember) {
  2118. continue;
  2119. }
  2120. packet = new SWP_REGENERATE_TP;
  2121. if (packet && !packet->AllocateMdl(transferPacket->Length)) {
  2122. delete packet;
  2123. packet = NULL;
  2124. }
  2125. if (!packet) {
  2126. break;
  2127. }
  2128. packet->Length = transferPacket->Length;
  2129. packet->Offset = transferPacket->Offset;
  2130. packet->CompletionRoutine = StripeWpParallelRegenerateCompletion;
  2131. packet->TargetVolume = t->GetMemberUnprotected(i);
  2132. packet->Thread = transferPacket->Thread;
  2133. packet->IrpFlags = transferPacket->IrpFlags;
  2134. packet->ReadPacket = TRUE;
  2135. packet->MasterPacket = transferPacket;
  2136. packet->WhichMember = i;
  2137. InsertTailList(&transferPacket->QueueEntry, &packet->RegenPacketList);
  2138. }
  2139. if (i < n) {
  2140. sequential = TRUE;
  2141. s = &transferPacket->QueueEntry;
  2142. while (!IsListEmpty(s)) {
  2143. l = RemoveHeadList(s);
  2144. packet = CONTAINING_RECORD(l, SWP_REGENERATE_TP, RegenPacketList);
  2145. delete packet;
  2146. }
  2147. } else {
  2148. sequential = FALSE;
  2149. }
  2150. KeInitializeSpinLock(&transferPacket->SpinLock);
  2151. transferPacket->IoStatus.Status = STATUS_SUCCESS;
  2152. transferPacket->IoStatus.Information = 0;
  2153. transferPacket->RefCount = n - 1;
  2154. if (sequential) {
  2155. transferPacket->CompletionRoutine = StripeWpSequentialEmergencyCompletion;
  2156. RtlZeroMemory(MmGetSystemAddressForMdl(transferPacket->Mdl),
  2157. transferPacket->Length);
  2158. KeAcquireSpinLock(&t->_spinLock, &irql);
  2159. if (t->_eRegeneratePacketInUse) {
  2160. InsertTailList(&t->_eRegeneratePacketQueue, &transferPacket->QueueEntry);
  2161. KeReleaseSpinLock(&t->_spinLock, irql);
  2162. return;
  2163. }
  2164. t->_eRegeneratePacketInUse = TRUE;
  2165. KeReleaseSpinLock(&t->_spinLock, irql);
  2166. transferPacket->CompletionRoutine(transferPacket);
  2167. } else {
  2168. s = &transferPacket->QueueEntry;
  2169. l = s->Flink;
  2170. for (;;) {
  2171. packet = CONTAINING_RECORD(l, SWP_REGENERATE_TP, RegenPacketList);
  2172. l = l->Flink;
  2173. if (l == s) {
  2174. TRANSFER(packet);
  2175. break;
  2176. }
  2177. TRANSFER(packet);
  2178. }
  2179. }
  2180. }
  2181. VOID
  2182. STRIPE_WP::RegeneratePacket(
  2183. IN OUT PSWP_TP TransferPacket,
  2184. IN BOOLEAN AllocateRegion
  2185. )
  2186. /*++
  2187. Routine Description:
  2188. This routine regenerate the given transfer packet by reading
  2189. from the other drives and performing the xor. This routine first
  2190. attempts to do all of the read concurently but if the memory is
  2191. not available then the reads are done sequentially.
  2192. Arguments:
  2193. TransferPacket - Supplies the transfer packet to regenerate.
  2194. AllocateRegion - Supplies whether or not we need to acquire the
  2195. io region via the overlapped io manager before
  2196. starting the regenerate operation. This should
  2197. usually be set to TRUE unless the region has
  2198. already been allocated.
  2199. Return Value:
  2200. None.
  2201. --*/
  2202. {
  2203. USHORT i, n, parityMember;
  2204. KIRQL irql;
  2205. PFT_VOLUME vol;
  2206. BOOLEAN ok;
  2207. TransferPacket->OneReadFailed = TRUE;
  2208. // First make sure that all of the members are healthy.
  2209. n = QueryNumMembers();
  2210. parityMember = (USHORT) ((TransferPacket->Offset/_stripeSize)%n);
  2211. KeAcquireSpinLock(&_spinLock, &irql);
  2212. if (_state.IsInitializing) {
  2213. if (parityMember == TransferPacket->WhichMember) {
  2214. ok = TRUE;
  2215. } else {
  2216. ok = FALSE;
  2217. }
  2218. } else if (_state.UnhealthyMemberState == FtMemberHealthy ||
  2219. _state.UnhealthyMemberNumber == TransferPacket->WhichMember) {
  2220. ok = TRUE;
  2221. } else {
  2222. ok = FALSE;
  2223. }
  2224. KeReleaseSpinLock(&_spinLock, irql);
  2225. if (!ok) {
  2226. TransferPacket->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  2227. TransferPacket->IoStatus.Information = 0;
  2228. TransferPacket->CompletionRoutine(TransferPacket);
  2229. return;
  2230. }
  2231. TransferPacket->SavedCompletionRoutine = TransferPacket->CompletionRoutine;
  2232. TransferPacket->CompletionRoutine = StripeWpRegeneratePacketPhase1;
  2233. if (AllocateRegion) {
  2234. _overlappedIoManager.AcquireIoRegion(TransferPacket, TRUE);
  2235. } else {
  2236. TransferPacket->CompletionRoutine(TransferPacket);
  2237. }
  2238. }
  2239. VOID
  2240. StripeWpRecoverPhase8(
  2241. IN OUT PTRANSFER_PACKET TransferPacket
  2242. )
  2243. /*++
  2244. Routine Description:
  2245. This is the completion routine for a single sector read
  2246. of the main member after a write was done to check for
  2247. data integrity.
  2248. Arguments:
  2249. TransferPacket - Supplies the transfer packet.
  2250. Return Value:
  2251. None.
  2252. --*/
  2253. {
  2254. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  2255. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  2256. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2257. NTSTATUS status = subPacket->IoStatus.Status;
  2258. if (FsRtlIsTotalDeviceFailure(status)) {
  2259. masterPacket->OneReadFailed = FALSE;
  2260. masterPacket->IoStatus = subPacket->IoStatus;
  2261. t->RecycleRecoverTp(subPacket);
  2262. masterPacket->CompletionRoutine(masterPacket);
  2263. return;
  2264. }
  2265. if (!NT_SUCCESS(status) ||
  2266. RtlCompareMemory(MmGetSystemAddressForMdl(subPacket->PartialMdl),
  2267. MmGetSystemAddressForMdl(subPacket->VerifyMdl),
  2268. subPacket->Length) != subPacket->Length) {
  2269. masterPacket->IoStatus.Status = STATUS_FT_READ_RECOVERY_FROM_BACKUP;
  2270. FtpLogError(t->_rootExtension,
  2271. subPacket->TargetVolume->QueryLogicalDiskId(),
  2272. FT_SECTOR_FAILURE, status,
  2273. (ULONG) (subPacket->Offset/t->QuerySectorSize()));
  2274. }
  2275. if (subPacket->Offset + subPacket->Length ==
  2276. masterPacket->Offset + masterPacket->Length) {
  2277. t->RecycleRecoverTp(subPacket);
  2278. masterPacket->CompletionRoutine(masterPacket);
  2279. return;
  2280. }
  2281. subPacket->Mdl = subPacket->PartialMdl;
  2282. subPacket->Offset += subPacket->Length;
  2283. subPacket->CompletionRoutine = StripeWpRecoverPhase2;
  2284. subPacket->ReadPacket = TRUE;
  2285. MmPrepareMdlForReuse(subPacket->Mdl);
  2286. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  2287. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  2288. (ULONG) (subPacket->Offset - masterPacket->Offset),
  2289. subPacket->Length);
  2290. TRANSFER(subPacket);
  2291. }
  2292. VOID
  2293. StripeWpRecoverPhase7(
  2294. IN OUT PTRANSFER_PACKET TransferPacket
  2295. )
  2296. /*++
  2297. Routine Description:
  2298. This is the completion routine for a single sector write
  2299. of the main member after a replace sector was done.
  2300. Arguments:
  2301. TransferPacket - Supplies the transfer packet.
  2302. Return Value:
  2303. None.
  2304. --*/
  2305. {
  2306. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  2307. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  2308. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2309. NTSTATUS status = subPacket->IoStatus.Status;
  2310. if (FsRtlIsTotalDeviceFailure(status)) {
  2311. masterPacket->OneReadFailed = FALSE;
  2312. masterPacket->IoStatus = subPacket->IoStatus;
  2313. t->RecycleRecoverTp(subPacket);
  2314. masterPacket->CompletionRoutine(masterPacket);
  2315. return;
  2316. }
  2317. if (!NT_SUCCESS(status)) {
  2318. masterPacket->IoStatus.Status = STATUS_FT_READ_RECOVERY_FROM_BACKUP;
  2319. FtpLogError(t->_rootExtension,
  2320. subPacket->TargetVolume->QueryLogicalDiskId(),
  2321. FT_SECTOR_FAILURE, status,
  2322. (ULONG) (subPacket->Offset/t->QuerySectorSize()));
  2323. if (subPacket->Offset + subPacket->Length ==
  2324. masterPacket->Offset + masterPacket->Length) {
  2325. t->RecycleRecoverTp(subPacket);
  2326. masterPacket->CompletionRoutine(masterPacket);
  2327. return;
  2328. }
  2329. subPacket->Mdl = subPacket->PartialMdl;
  2330. subPacket->Offset += subPacket->Length;
  2331. subPacket->CompletionRoutine = StripeWpRecoverPhase2;
  2332. subPacket->ReadPacket = TRUE;
  2333. MmPrepareMdlForReuse(subPacket->Mdl);
  2334. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  2335. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  2336. (ULONG) (subPacket->Offset - masterPacket->Offset),
  2337. subPacket->Length);
  2338. TRANSFER(subPacket);
  2339. return;
  2340. }
  2341. subPacket->Mdl = subPacket->VerifyMdl;
  2342. subPacket->CompletionRoutine = StripeWpRecoverPhase8;
  2343. subPacket->ReadPacket = TRUE;
  2344. TRANSFER(subPacket);
  2345. }
  2346. VOID
  2347. StripeWpRecoverPhase6(
  2348. IN OUT PTRANSFER_PACKET TransferPacket
  2349. )
  2350. /*++
  2351. Routine Description:
  2352. This is the completion routine for a single sector replace
  2353. of the main member.
  2354. Arguments:
  2355. TransferPacket - Supplies the transfer packet.
  2356. Return Value:
  2357. None.
  2358. --*/
  2359. {
  2360. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  2361. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  2362. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2363. NTSTATUS status = subPacket->IoStatus.Status;
  2364. if (!NT_SUCCESS(status)) {
  2365. masterPacket->IoStatus.Status = STATUS_FT_READ_RECOVERY_FROM_BACKUP;
  2366. FtpLogError(t->_rootExtension,
  2367. subPacket->TargetVolume->QueryLogicalDiskId(),
  2368. FT_SECTOR_FAILURE, status,
  2369. (ULONG) (subPacket->Offset/t->QuerySectorSize()));
  2370. if (subPacket->Offset + subPacket->Length ==
  2371. masterPacket->Offset + masterPacket->Length) {
  2372. t->RecycleRecoverTp(subPacket);
  2373. masterPacket->CompletionRoutine(masterPacket);
  2374. return;
  2375. }
  2376. subPacket->Mdl = subPacket->PartialMdl;
  2377. subPacket->Offset += subPacket->Length;
  2378. subPacket->CompletionRoutine = StripeWpRecoverPhase2;
  2379. subPacket->ReadPacket = TRUE;
  2380. MmPrepareMdlForReuse(subPacket->Mdl);
  2381. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  2382. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  2383. (ULONG) (subPacket->Offset - masterPacket->Offset),
  2384. subPacket->Length);
  2385. TRANSFER(subPacket);
  2386. return;
  2387. }
  2388. // We were able to relocate the bad sector so now do a write and
  2389. // then read to make sure it's ok.
  2390. subPacket->Mdl = subPacket->PartialMdl;
  2391. subPacket->CompletionRoutine = StripeWpRecoverPhase7;
  2392. subPacket->ReadPacket = FALSE;
  2393. TRANSFER(subPacket);
  2394. }
  2395. VOID
  2396. StripeWpRecoverPhase5(
  2397. IN OUT PTRANSFER_PACKET TransferPacket
  2398. )
  2399. /*++
  2400. Routine Description:
  2401. This is the completion routine for a single sector read
  2402. of the main member after a successful write to check and
  2403. see if the write was successful.
  2404. Arguments:
  2405. TransferPacket - Supplies the transfer packet.
  2406. Return Value:
  2407. None.
  2408. --*/
  2409. {
  2410. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  2411. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  2412. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2413. NTSTATUS status = subPacket->IoStatus.Status;
  2414. if (FsRtlIsTotalDeviceFailure(status)) {
  2415. masterPacket->OneReadFailed = FALSE;
  2416. masterPacket->IoStatus = subPacket->IoStatus;
  2417. t->RecycleRecoverTp(subPacket);
  2418. masterPacket->CompletionRoutine(masterPacket);
  2419. return;
  2420. }
  2421. if (!NT_SUCCESS(status) ||
  2422. RtlCompareMemory(MmGetSystemAddressForMdl(subPacket->PartialMdl),
  2423. MmGetSystemAddressForMdl(subPacket->VerifyMdl),
  2424. subPacket->Length) != subPacket->Length) {
  2425. subPacket->Mdl = subPacket->PartialMdl;
  2426. subPacket->CompletionRoutine = StripeWpRecoverPhase6;
  2427. subPacket->TargetVolume->ReplaceBadSector(subPacket);
  2428. return;
  2429. }
  2430. if (subPacket->Offset + subPacket->Length ==
  2431. masterPacket->Offset + masterPacket->Length) {
  2432. t->RecycleRecoverTp(subPacket);
  2433. masterPacket->CompletionRoutine(masterPacket);
  2434. return;
  2435. }
  2436. subPacket->Mdl = subPacket->PartialMdl;
  2437. subPacket->Offset += subPacket->Length;
  2438. subPacket->CompletionRoutine = StripeWpRecoverPhase2;
  2439. MmPrepareMdlForReuse(subPacket->Mdl);
  2440. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  2441. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  2442. (ULONG) (subPacket->Offset - masterPacket->Offset),
  2443. subPacket->Length);
  2444. TRANSFER(subPacket);
  2445. }
  2446. VOID
  2447. StripeWpRecoverPhase4(
  2448. IN OUT PTRANSFER_PACKET TransferPacket
  2449. )
  2450. /*++
  2451. Routine Description:
  2452. This is the completion routine for a single sector write
  2453. of the main member.
  2454. Arguments:
  2455. TransferPacket - Supplies the transfer packet.
  2456. Return Value:
  2457. None.
  2458. --*/
  2459. {
  2460. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  2461. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  2462. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2463. NTSTATUS status = subPacket->IoStatus.Status;
  2464. if (FsRtlIsTotalDeviceFailure(status)) {
  2465. masterPacket->OneReadFailed = FALSE;
  2466. masterPacket->IoStatus = subPacket->IoStatus;
  2467. t->RecycleRecoverTp(subPacket);
  2468. masterPacket->CompletionRoutine(masterPacket);
  2469. return;
  2470. }
  2471. if (!NT_SUCCESS(status)) {
  2472. subPacket->CompletionRoutine = StripeWpRecoverPhase6;
  2473. subPacket->TargetVolume->ReplaceBadSector(subPacket);
  2474. return;
  2475. }
  2476. // Write was successful so try a read and then compare.
  2477. subPacket->Mdl = subPacket->VerifyMdl;
  2478. subPacket->CompletionRoutine = StripeWpRecoverPhase5;
  2479. subPacket->ReadPacket = TRUE;
  2480. TRANSFER(subPacket);
  2481. }
  2482. VOID
  2483. StripeWpRecoverPhase3(
  2484. IN OUT PTRANSFER_PACKET TransferPacket
  2485. )
  2486. /*++
  2487. Routine Description:
  2488. This is the completion routine for a single sector read
  2489. of the other member.
  2490. Arguments:
  2491. TransferPacket - Supplies the transfer packet.
  2492. Return Value:
  2493. None.
  2494. --*/
  2495. {
  2496. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  2497. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  2498. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2499. NTSTATUS status = subPacket->IoStatus.Status;
  2500. KIRQL irql;
  2501. BOOLEAN b;
  2502. if (!NT_SUCCESS(status)) {
  2503. if (status != STATUS_VERIFY_REQUIRED) {
  2504. status = STATUS_DEVICE_DATA_ERROR;
  2505. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  2506. FT_DOUBLE_FAILURE, status,
  2507. (ULONG) (subPacket->Offset/t->QuerySectorSize()));
  2508. }
  2509. masterPacket->IoStatus.Status = status;
  2510. masterPacket->IoStatus.Information = 0;
  2511. t->RecycleRecoverTp(subPacket);
  2512. masterPacket->CompletionRoutine(masterPacket);
  2513. return;
  2514. }
  2515. // We have the data required in the subpacket partial mdl.
  2516. // Try writting it back to where the read failed and see
  2517. // if the sector just fixes itself.
  2518. subPacket->CompletionRoutine = StripeWpRecoverPhase4;
  2519. subPacket->ReadPacket = FALSE;
  2520. TRANSFER(subPacket);
  2521. }
  2522. VOID
  2523. StripeWpRecoverPhase2(
  2524. IN OUT PTRANSFER_PACKET TransferPacket
  2525. )
  2526. /*++
  2527. Routine Description:
  2528. This is the completion routine for a single sector transfer
  2529. that is part of a larger recover operation.
  2530. Arguments:
  2531. TransferPacket - Supplies the transfer packet.
  2532. Return Value:
  2533. None.
  2534. --*/
  2535. {
  2536. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  2537. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  2538. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2539. NTSTATUS status = subPacket->IoStatus.Status;
  2540. KIRQL irql;
  2541. if (FsRtlIsTotalDeviceFailure(status)) {
  2542. masterPacket->OneReadFailed = FALSE;
  2543. masterPacket->IoStatus = subPacket->IoStatus;
  2544. t->RecycleRecoverTp(subPacket);
  2545. masterPacket->CompletionRoutine(masterPacket);
  2546. return;
  2547. }
  2548. if (NT_SUCCESS(status)) {
  2549. if (subPacket->Offset + subPacket->Length ==
  2550. masterPacket->Offset + masterPacket->Length) {
  2551. t->RecycleRecoverTp(subPacket);
  2552. masterPacket->CompletionRoutine(masterPacket);
  2553. return;
  2554. }
  2555. subPacket->Offset += subPacket->Length;
  2556. MmPrepareMdlForReuse(subPacket->Mdl);
  2557. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  2558. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  2559. (ULONG) (subPacket->Offset - masterPacket->Offset),
  2560. subPacket->Length);
  2561. TRANSFER(subPacket);
  2562. return;
  2563. }
  2564. // This read sector failed from a bad sector error. Try
  2565. // regenerating the data from the other members.
  2566. subPacket->CompletionRoutine = StripeWpRecoverPhase3;
  2567. t->RegeneratePacket(subPacket, FALSE);
  2568. }
  2569. VOID
  2570. StripeWpRecoverEmergencyCompletion(
  2571. IN OUT PTRANSFER_PACKET TransferPacket
  2572. )
  2573. /*++
  2574. Routine Description:
  2575. This routine is the completion for use of the emergency recover packet
  2576. in a recover operation.
  2577. Arguments:
  2578. TransferPacket - Supplies the transfer packet.
  2579. Return Value:
  2580. None.
  2581. --*/
  2582. {
  2583. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  2584. PSTRIPE_WP t = transferPacket->StripeWithParity;
  2585. PSWP_RECOVER_TP subPacket = t->_eRecoverPacket;
  2586. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  2587. subPacket->Mdl = subPacket->PartialMdl;
  2588. IoBuildPartialMdl(transferPacket->Mdl, subPacket->Mdl,
  2589. MmGetMdlVirtualAddress(transferPacket->Mdl),
  2590. t->QuerySectorSize());
  2591. subPacket->Length = t->QuerySectorSize();
  2592. subPacket->Offset = transferPacket->Offset;
  2593. subPacket->CompletionRoutine = StripeWpRecoverPhase2;
  2594. subPacket->TargetVolume = transferPacket->TargetVolume;
  2595. subPacket->Thread = transferPacket->Thread;
  2596. subPacket->IrpFlags = transferPacket->IrpFlags;
  2597. subPacket->ReadPacket = TRUE;
  2598. subPacket->MasterPacket = transferPacket;
  2599. subPacket->StripeWithParity = t;
  2600. subPacket->WhichMember = transferPacket->WhichMember;
  2601. TRANSFER(subPacket);
  2602. }
  2603. VOID
  2604. StripeWpRecoverPhase1(
  2605. IN OUT PTRANSFER_PACKET TransferPacket
  2606. )
  2607. /*++
  2608. Routine Description:
  2609. This is the completion routine for an acquire io region
  2610. to a recover operation.
  2611. Arguments:
  2612. TransferPacket - Supplies the transfer packet.
  2613. Return Value:
  2614. None.
  2615. --*/
  2616. {
  2617. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  2618. PSTRIPE_WP t = transferPacket->StripeWithParity;
  2619. PSWP_RECOVER_TP subPacket;
  2620. KIRQL irql;
  2621. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  2622. transferPacket->IoStatus.Status = STATUS_SUCCESS;
  2623. transferPacket->IoStatus.Information = transferPacket->Length;
  2624. subPacket = new SWP_RECOVER_TP;
  2625. if (subPacket && !subPacket->AllocateMdls(t->QuerySectorSize())) {
  2626. delete subPacket;
  2627. subPacket = NULL;
  2628. }
  2629. if (!subPacket) {
  2630. KeAcquireSpinLock(&t->_spinLock, &irql);
  2631. if (t->_eRecoverPacketInUse) {
  2632. transferPacket->SavedCompletionRoutine =
  2633. transferPacket->CompletionRoutine;
  2634. transferPacket->CompletionRoutine = StripeWpRecoverEmergencyCompletion;
  2635. InsertTailList(&t->_eRecoverPacketQueue, &transferPacket->QueueEntry);
  2636. KeReleaseSpinLock(&t->_spinLock, irql);
  2637. return;
  2638. }
  2639. t->_eRecoverPacketInUse = TRUE;
  2640. KeReleaseSpinLock(&t->_spinLock, irql);
  2641. subPacket = t->_eRecoverPacket;
  2642. }
  2643. subPacket->Mdl = subPacket->PartialMdl;
  2644. IoBuildPartialMdl(transferPacket->Mdl, subPacket->Mdl,
  2645. MmGetMdlVirtualAddress(transferPacket->Mdl),
  2646. t->QuerySectorSize());
  2647. subPacket->Length = t->QuerySectorSize();
  2648. subPacket->Offset = transferPacket->Offset;
  2649. subPacket->CompletionRoutine = StripeWpRecoverPhase2;
  2650. subPacket->TargetVolume = transferPacket->TargetVolume;
  2651. subPacket->Thread = transferPacket->Thread;
  2652. subPacket->IrpFlags = transferPacket->IrpFlags;
  2653. subPacket->ReadPacket = TRUE;
  2654. subPacket->MasterPacket = transferPacket;
  2655. subPacket->StripeWithParity = t;
  2656. subPacket->WhichMember = transferPacket->WhichMember;
  2657. TRANSFER(subPacket);
  2658. }
  2659. VOID
  2660. STRIPE_WP::Recover(
  2661. IN OUT PSWP_TP TransferPacket,
  2662. IN BOOLEAN NeedAcquire
  2663. )
  2664. {
  2665. ASSERT(TransferPacket->ReadPacket);
  2666. TransferPacket->SavedCompletionRoutine = TransferPacket->CompletionRoutine;
  2667. TransferPacket->CompletionRoutine = StripeWpRecoverPhase1;
  2668. if (NeedAcquire) {
  2669. _overlappedIoManager.AcquireIoRegion(TransferPacket, TRUE);
  2670. } else {
  2671. TransferPacket->CompletionRoutine(TransferPacket);
  2672. }
  2673. }
  2674. VOID
  2675. StripeWpMaxTransferCompletionRoutine(
  2676. IN OUT PTRANSFER_PACKET TransferPacket
  2677. )
  2678. /*++
  2679. Routine Description:
  2680. This is the completion routine for a sector transfer subordinate
  2681. to a MAX transfer operation.
  2682. Arguments:
  2683. TransferPacket - Supplies the subordinate transfer packet.
  2684. Return Value:
  2685. None.
  2686. --*/
  2687. {
  2688. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  2689. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  2690. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2691. NTSTATUS status = subPacket->IoStatus.Status;
  2692. if (FsRtlIsTotalDeviceFailure(status)) {
  2693. masterPacket->IoStatus = subPacket->IoStatus;
  2694. t->RecycleRecoverTp(subPacket);
  2695. masterPacket->CompletionRoutine(masterPacket);
  2696. return;
  2697. }
  2698. if (subPacket->Offset + subPacket->Length ==
  2699. masterPacket->Offset + masterPacket->Length) {
  2700. t->RecycleRecoverTp(subPacket);
  2701. masterPacket->CompletionRoutine(masterPacket);
  2702. return;
  2703. }
  2704. subPacket->Offset += subPacket->Length;
  2705. MmPrepareMdlForReuse(subPacket->Mdl);
  2706. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  2707. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  2708. (ULONG) (subPacket->Offset - masterPacket->Offset),
  2709. subPacket->Length);
  2710. if (subPacket->ReadPacket) {
  2711. t->RegeneratePacket(subPacket, FALSE);
  2712. } else {
  2713. TRANSFER(subPacket);
  2714. }
  2715. }
  2716. VOID
  2717. StripeWpMaxTransferEmergencyCompletion(
  2718. IN OUT PTRANSFER_PACKET TransferPacket
  2719. )
  2720. /*++
  2721. Routine Description:
  2722. This routine is the completion for use of the emergency recover packet
  2723. in a max transfer operation.
  2724. Arguments:
  2725. TransferPacket - Supplies the transfer packet.
  2726. Return Value:
  2727. None.
  2728. --*/
  2729. {
  2730. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  2731. PSTRIPE_WP t = transferPacket->StripeWithParity;
  2732. PSWP_RECOVER_TP subPacket = t->_eRecoverPacket;
  2733. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  2734. subPacket->Mdl = subPacket->PartialMdl;
  2735. IoBuildPartialMdl(transferPacket->Mdl, subPacket->Mdl,
  2736. MmGetMdlVirtualAddress(transferPacket->Mdl),
  2737. t->QuerySectorSize());
  2738. subPacket->Length = t->QuerySectorSize();
  2739. subPacket->Offset = transferPacket->Offset;
  2740. subPacket->CompletionRoutine = StripeWpMaxTransferCompletionRoutine;
  2741. subPacket->TargetVolume = transferPacket->TargetVolume;
  2742. subPacket->Thread = transferPacket->Thread;
  2743. subPacket->IrpFlags = transferPacket->IrpFlags;
  2744. subPacket->ReadPacket = transferPacket->ReadPacket;
  2745. subPacket->MasterPacket = transferPacket;
  2746. subPacket->StripeWithParity = t;
  2747. subPacket->WhichMember = transferPacket->WhichMember;
  2748. if (subPacket->ReadPacket) {
  2749. t->RegeneratePacket(subPacket, FALSE);
  2750. } else {
  2751. TRANSFER(subPacket);
  2752. }
  2753. }
  2754. VOID
  2755. STRIPE_WP::MaxTransfer(
  2756. IN OUT PSWP_TP TransferPacket
  2757. )
  2758. /*++
  2759. Routine Description:
  2760. This routine transfers the maximum possible subset of the given transfer
  2761. by doing it one sector at a time.
  2762. Arguments:
  2763. TransferPacket - Supplies the transfer packet.
  2764. Return Value:
  2765. None.
  2766. --*/
  2767. {
  2768. PSWP_RECOVER_TP subPacket;
  2769. KIRQL irql;
  2770. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  2771. TransferPacket->IoStatus.Information = TransferPacket->Length;
  2772. subPacket = new SWP_RECOVER_TP;
  2773. if (subPacket && !subPacket->AllocateMdls(QuerySectorSize())) {
  2774. delete subPacket;
  2775. subPacket = NULL;
  2776. }
  2777. if (!subPacket) {
  2778. KeAcquireSpinLock(&_spinLock, &irql);
  2779. if (_eRecoverPacketInUse) {
  2780. TransferPacket->SavedCompletionRoutine =
  2781. TransferPacket->CompletionRoutine;
  2782. TransferPacket->CompletionRoutine = StripeWpMaxTransferEmergencyCompletion;
  2783. InsertTailList(&_eRecoverPacketQueue, &TransferPacket->QueueEntry);
  2784. KeReleaseSpinLock(&_spinLock, irql);
  2785. return;
  2786. }
  2787. _eRecoverPacketInUse = TRUE;
  2788. KeReleaseSpinLock(&_spinLock, irql);
  2789. subPacket = _eRecoverPacket;
  2790. }
  2791. subPacket->Mdl = subPacket->PartialMdl;
  2792. IoBuildPartialMdl(TransferPacket->Mdl, subPacket->Mdl,
  2793. MmGetMdlVirtualAddress(TransferPacket->Mdl),
  2794. QuerySectorSize());
  2795. subPacket->Length = QuerySectorSize();
  2796. subPacket->Offset = TransferPacket->Offset;
  2797. subPacket->CompletionRoutine = StripeWpMaxTransferCompletionRoutine;
  2798. subPacket->TargetVolume = TransferPacket->TargetVolume;
  2799. subPacket->Thread = TransferPacket->Thread;
  2800. subPacket->IrpFlags = TransferPacket->IrpFlags;
  2801. subPacket->ReadPacket = TransferPacket->ReadPacket;
  2802. subPacket->MasterPacket = TransferPacket;
  2803. subPacket->StripeWithParity = this;
  2804. subPacket->WhichMember = TransferPacket->WhichMember;
  2805. if (subPacket->ReadPacket) {
  2806. RegeneratePacket(subPacket, FALSE);
  2807. } else {
  2808. TRANSFER(subPacket);
  2809. }
  2810. }
  2811. VOID
  2812. STRIPE_WP::RecycleRecoverTp(
  2813. IN OUT PSWP_RECOVER_TP TransferPacket
  2814. )
  2815. /*++
  2816. Routine Description:
  2817. This routine recycles the given recover transfer packet and services
  2818. the emergency queue if need be.
  2819. Arguments:
  2820. TransferPacket - Supplies the transfer packet.
  2821. Return Value:
  2822. None.
  2823. --*/
  2824. {
  2825. KIRQL irql;
  2826. PLIST_ENTRY l;
  2827. PTRANSFER_PACKET p;
  2828. if (TransferPacket != _eRecoverPacket) {
  2829. delete TransferPacket;
  2830. return;
  2831. }
  2832. MmPrepareMdlForReuse(_eRecoverPacket->PartialMdl);
  2833. KeAcquireSpinLock(&_spinLock, &irql);
  2834. if (IsListEmpty(&_eRecoverPacketQueue)) {
  2835. _eRecoverPacketInUse = FALSE;
  2836. KeReleaseSpinLock(&_spinLock, irql);
  2837. return;
  2838. }
  2839. l = RemoveHeadList(&_eRecoverPacketQueue);
  2840. KeReleaseSpinLock(&_spinLock, irql);
  2841. p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
  2842. p->CompletionRoutine(p);
  2843. return;
  2844. }
  2845. class FTP_SWP_STATE_WORK_ITEM : public WORK_QUEUE_ITEM {
  2846. public:
  2847. FT_COMPLETION_ROUTINE CompletionRoutine;
  2848. PVOID Context;
  2849. PSTRIPE_WP StripeWp;
  2850. };
  2851. typedef FTP_SWP_STATE_WORK_ITEM* PFTP_SWP_STATE_WORK_ITEM;
  2852. VOID
  2853. StripeWpPropogateStateChangesWorker(
  2854. IN PVOID Context
  2855. )
  2856. /*++
  2857. Routine Description:
  2858. This routine is a worker thread routine for propogating state changes.
  2859. Arguments:
  2860. Context - Supplies the context of the worker item
  2861. Return Value:
  2862. None.
  2863. --*/
  2864. {
  2865. PFTP_SWP_STATE_WORK_ITEM context = (PFTP_SWP_STATE_WORK_ITEM) Context;
  2866. PSTRIPE_WP t = context->StripeWp;
  2867. KIRQL irql;
  2868. FT_MIRROR_AND_SWP_STATE_INFORMATION state;
  2869. NTSTATUS status;
  2870. FtpAcquire(t->_rootExtension);
  2871. KeAcquireSpinLock(&t->_spinLock, &irql);
  2872. RtlCopyMemory(&state, &t->_state, sizeof(state));
  2873. KeReleaseSpinLock(&t->_spinLock, irql);
  2874. status = t->_diskInfoSet->WriteStateInformation(t->QueryLogicalDiskId(),
  2875. &state, sizeof(state));
  2876. FtpRelease(t->_rootExtension);
  2877. if (context->CompletionRoutine) {
  2878. context->CompletionRoutine(context->Context, status);
  2879. }
  2880. }
  2881. VOID
  2882. STRIPE_WP::PropogateStateChanges(
  2883. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  2884. IN PVOID Context
  2885. )
  2886. /*++
  2887. Routine Description:
  2888. This routine propogates the changes in the local memory state to
  2889. the on disk state.
  2890. Arguments:
  2891. CompletionRoutine - Supplies the completion routine.
  2892. Context - Supplies the completion routine context.
  2893. Return Value:
  2894. None.
  2895. --*/
  2896. {
  2897. PFTP_SWP_STATE_WORK_ITEM workItem;
  2898. workItem = (PFTP_SWP_STATE_WORK_ITEM)
  2899. ExAllocatePool(NonPagedPool,
  2900. sizeof(FTP_SWP_STATE_WORK_ITEM));
  2901. if (!workItem) {
  2902. return;
  2903. }
  2904. ExInitializeWorkItem(workItem, StripeWpPropogateStateChangesWorker,
  2905. workItem);
  2906. workItem->CompletionRoutine = CompletionRoutine;
  2907. workItem->Context = Context;
  2908. workItem->StripeWp = this;
  2909. FtpQueueWorkItem(_rootExtension, workItem);
  2910. }
  2911. VOID
  2912. StripeWpCompleteWritePhase4(
  2913. IN OUT PTRANSFER_PACKET TransferPacket
  2914. )
  2915. /*++
  2916. Routine Description:
  2917. This routine is the completion for a careful update of the parity block.
  2918. Arguments:
  2919. TransferPacket - Supplies the parity packet.
  2920. Return Value:
  2921. None.
  2922. --*/
  2923. {
  2924. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  2925. PSWP_WRITE_TP masterPacket = (PSWP_WRITE_TP) transferPacket->MasterPacket;
  2926. NTSTATUS status = transferPacket->IoStatus.Status;
  2927. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2928. KIRQL irql;
  2929. BOOLEAN b;
  2930. if (NT_SUCCESS(status)) {
  2931. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  2932. masterPacket->IoStatus = transferPacket->IoStatus;
  2933. }
  2934. } else if (status == STATUS_VERIFY_REQUIRED) {
  2935. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  2936. masterPacket->IoStatus.Status = status;
  2937. masterPacket->IoStatus.Information = 0;
  2938. }
  2939. } else if (FsRtlIsTotalDeviceFailure(status)) {
  2940. KeAcquireSpinLock(&t->_spinLock, &irql);
  2941. b = t->SetMemberState(masterPacket->ParityMember, FtMemberOrphaned);
  2942. KeReleaseSpinLock(&t->_spinLock, irql);
  2943. if (b) {
  2944. t->PropogateStateChanges(NULL, NULL);
  2945. t->Notify();
  2946. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  2947. FT_ORPHANING, STATUS_SUCCESS, 9);
  2948. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  2949. }
  2950. } else {
  2951. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  2952. masterPacket->IoStatus.Status = status;
  2953. masterPacket->IoStatus.Information = 0;
  2954. }
  2955. }
  2956. masterPacket->CompletionRoutine(masterPacket);
  2957. }
  2958. VOID
  2959. StripeWpCompleteWritePhase3(
  2960. IN OUT PTRANSFER_PACKET TransferPacket
  2961. )
  2962. /*++
  2963. Routine Description:
  2964. This routine is the completion for a recover of the parity block.
  2965. Arguments:
  2966. TransferPacket - Supplies the recover packet.
  2967. Return Value:
  2968. None.
  2969. --*/
  2970. {
  2971. PSWP_TP recoverPacket = (PSWP_TP) TransferPacket;
  2972. PSWP_WRITE_TP masterPacket = (PSWP_WRITE_TP) recoverPacket->MasterPacket;
  2973. NTSTATUS status = recoverPacket->IoStatus.Status;
  2974. PSTRIPE_WP t = masterPacket->StripeWithParity;
  2975. KIRQL irql;
  2976. BOOLEAN b;
  2977. if (status == STATUS_VERIFY_REQUIRED) {
  2978. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  2979. masterPacket->IoStatus.Status = status;
  2980. masterPacket->IoStatus.Information = 0;
  2981. }
  2982. masterPacket->CompletionRoutine(masterPacket);
  2983. return;
  2984. }
  2985. if (FsRtlIsTotalDeviceFailure(status)) {
  2986. KeAcquireSpinLock(&t->_spinLock, &irql);
  2987. b = t->SetMemberState(recoverPacket->WhichMember, FtMemberOrphaned);
  2988. KeReleaseSpinLock(&t->_spinLock, irql);
  2989. if (b) {
  2990. t->PropogateStateChanges(NULL, NULL);
  2991. t->Notify();
  2992. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  2993. FT_ORPHANING, STATUS_SUCCESS, 10);
  2994. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  2995. }
  2996. masterPacket->CompletionRoutine(masterPacket);
  2997. return;
  2998. }
  2999. recoverPacket->CompletionRoutine = StripeWpCompleteWritePhase4;
  3000. t->CarefulUpdate(recoverPacket);
  3001. }
  3002. VOID
  3003. StripeWpCompleteWritePhase2(
  3004. IN OUT PTRANSFER_PACKET TransferPacket
  3005. )
  3006. /*++
  3007. Routine Description:
  3008. This routine is the completion for the careful write.
  3009. Arguments:
  3010. TransferPacket - Supplies the write packet.
  3011. Return Value:
  3012. None.
  3013. --*/
  3014. {
  3015. PSWP_TP writePacket = (PSWP_TP) TransferPacket;
  3016. PSWP_WRITE_TP masterPacket = (PSWP_WRITE_TP) writePacket->MasterPacket;
  3017. NTSTATUS status = writePacket->IoStatus.Status;
  3018. PPARITY_TP parityPacket = &masterPacket->ParityPacket;
  3019. PSTRIPE_WP t = masterPacket->StripeWithParity;
  3020. if (NT_SUCCESS(status)) {
  3021. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  3022. masterPacket->IoStatus = writePacket->IoStatus;
  3023. }
  3024. } else {
  3025. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  3026. masterPacket->IoStatus.Status = status;
  3027. masterPacket->IoStatus.Information = 0;
  3028. }
  3029. }
  3030. if (!NT_SUCCESS(parityPacket->IoStatus.Status)) {
  3031. writePacket->Mdl = parityPacket->Mdl;
  3032. writePacket->CompletionRoutine = StripeWpCompleteWritePhase3;
  3033. writePacket->TargetVolume = parityPacket->TargetVolume;
  3034. writePacket->ReadPacket = TRUE;
  3035. writePacket->WhichMember = masterPacket->ParityMember;
  3036. t->Recover(writePacket, FALSE);
  3037. return;
  3038. }
  3039. masterPacket->CompletionRoutine(masterPacket);
  3040. }
  3041. VOID
  3042. StripeWpCompleteWritePhase1(
  3043. IN OUT PTRANSFER_PACKET TransferPacket
  3044. )
  3045. /*++
  3046. Routine Description:
  3047. This routine is the first phase after a bad sector error during the write
  3048. or update parity phase of a SWP write operation.
  3049. Arguments:
  3050. TransferPacket - Supplies the main write packet.
  3051. Return Value:
  3052. None.
  3053. --*/
  3054. {
  3055. PSWP_WRITE_TP transferPacket = (PSWP_WRITE_TP) TransferPacket;
  3056. PSWP_TP writePacket = &transferPacket->ReadWritePacket;
  3057. PPARITY_TP parityPacket = &transferPacket->ParityPacket;
  3058. PSTRIPE_WP t = transferPacket->StripeWithParity;
  3059. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  3060. if (!NT_SUCCESS(writePacket->IoStatus.Status)) {
  3061. writePacket->CompletionRoutine = StripeWpCompleteWritePhase2;
  3062. t->CarefulWrite(writePacket);
  3063. return;
  3064. }
  3065. ASSERT(!NT_SUCCESS(parityPacket->IoStatus.Status));
  3066. writePacket->Mdl = parityPacket->Mdl;
  3067. writePacket->CompletionRoutine = StripeWpCompleteWritePhase3;
  3068. writePacket->TargetVolume = parityPacket->TargetVolume;
  3069. writePacket->ReadPacket = TRUE;
  3070. writePacket->WhichMember = transferPacket->ParityMember;
  3071. t->Recover(writePacket, FALSE);
  3072. }
  3073. VOID
  3074. STRIPE_WP::CompleteWrite(
  3075. IN OUT PSWP_WRITE_TP TransferPacket
  3076. )
  3077. /*++
  3078. Routine Description:
  3079. This routine completes the given write master packets after verifying
  3080. the status of the block write and the parity update.
  3081. Arguments:
  3082. TransferPacket - Supplies a write master packet.
  3083. Return Value:
  3084. None.
  3085. --*/
  3086. {
  3087. PSWP_TP writePacket = &TransferPacket->ReadWritePacket;
  3088. PPARITY_TP parityPacket = &TransferPacket->ParityPacket;
  3089. BOOLEAN doCarefulWrite = FALSE;
  3090. BOOLEAN doRecover = FALSE;
  3091. NTSTATUS status;
  3092. KIRQL irql;
  3093. BOOLEAN b;
  3094. // Check on the write status.
  3095. status = writePacket->IoStatus.Status;
  3096. if (NT_SUCCESS(status)) {
  3097. if (NT_SUCCESS(TransferPacket->IoStatus.Status)) {
  3098. TransferPacket->IoStatus = writePacket->IoStatus;
  3099. }
  3100. } else if (status == STATUS_VERIFY_REQUIRED) {
  3101. if (FtpIsWorseStatus(status, TransferPacket->IoStatus.Status)) {
  3102. TransferPacket->IoStatus.Status = status;
  3103. TransferPacket->IoStatus.Information = 0;
  3104. }
  3105. } else if (FsRtlIsTotalDeviceFailure(status)) {
  3106. KeAcquireSpinLock(&_spinLock, &irql);
  3107. b = SetMemberState(writePacket->WhichMember, FtMemberOrphaned);
  3108. KeReleaseSpinLock(&_spinLock, irql);
  3109. if (b) {
  3110. PropogateStateChanges(NULL, NULL);
  3111. Notify();
  3112. FtpLogError(_rootExtension, QueryLogicalDiskId(), FT_ORPHANING,
  3113. STATUS_SUCCESS, 11);
  3114. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  3115. }
  3116. } else {
  3117. doCarefulWrite = TRUE;
  3118. }
  3119. // Check on the update parity status.
  3120. status = parityPacket->IoStatus.Status;
  3121. if (NT_SUCCESS(status)) {
  3122. if (NT_SUCCESS(TransferPacket->IoStatus.Status)) {
  3123. TransferPacket->IoStatus = parityPacket->IoStatus;
  3124. }
  3125. } else if (status == STATUS_VERIFY_REQUIRED) {
  3126. if (FtpIsWorseStatus(status, TransferPacket->IoStatus.Status)) {
  3127. TransferPacket->IoStatus.Status = status;
  3128. TransferPacket->IoStatus.Information = 0;
  3129. }
  3130. } else if (FsRtlIsTotalDeviceFailure(status)) {
  3131. KeAcquireSpinLock(&_spinLock, &irql);
  3132. b = SetMemberState(TransferPacket->ParityMember, FtMemberOrphaned);
  3133. KeReleaseSpinLock(&_spinLock, irql);
  3134. if (b) {
  3135. PropogateStateChanges(NULL, NULL);
  3136. Notify();
  3137. FtpLogError(_rootExtension, QueryLogicalDiskId(), FT_ORPHANING,
  3138. STATUS_SUCCESS, 12);
  3139. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  3140. }
  3141. } else {
  3142. // Bad sector case.
  3143. if (parityPacket->ReadPacket) { // Bad sector on read?
  3144. doRecover = TRUE;
  3145. } else {
  3146. if (FtpIsWorseStatus(status, TransferPacket->IoStatus.Status)) {
  3147. TransferPacket->IoStatus.Status = status;
  3148. TransferPacket->IoStatus.Information = 0;
  3149. }
  3150. }
  3151. }
  3152. // Complete the request if no bad sector handling is required.
  3153. if (!doCarefulWrite && !doRecover) {
  3154. TransferPacket->CompletionRoutine(TransferPacket);
  3155. return;
  3156. }
  3157. // Handling for bad sectors is required.
  3158. if (!doCarefulWrite) {
  3159. writePacket->IoStatus.Status = STATUS_SUCCESS;
  3160. }
  3161. if (!doRecover) {
  3162. parityPacket->IoStatus.Status = STATUS_SUCCESS;
  3163. }
  3164. TransferPacket->SavedCompletionRoutine = TransferPacket->CompletionRoutine;
  3165. TransferPacket->CompletionRoutine = StripeWpCompleteWritePhase1;
  3166. _overlappedIoManager.PromoteToAllMembers(TransferPacket);
  3167. }
  3168. VOID
  3169. StripeWpCarefulWritePhase2(
  3170. IN OUT PTRANSFER_PACKET TransferPacket
  3171. )
  3172. /*++
  3173. Routine Description:
  3174. This is the completion routine a sector replacement
  3175. for a careful write operation.
  3176. Arguments:
  3177. TransferPacket - Supplies the subordinate transfer packet.
  3178. Return Value:
  3179. None.
  3180. --*/
  3181. {
  3182. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  3183. subPacket->CompletionRoutine = StripeWpCarefulWritePhase1;
  3184. TRANSFER(subPacket);
  3185. }
  3186. VOID
  3187. StripeWpCarefulWritePhase1(
  3188. IN OUT PTRANSFER_PACKET TransferPacket
  3189. )
  3190. /*++
  3191. Routine Description:
  3192. This is the completion routine a first attempt of a single sector write
  3193. for a careful write operation.
  3194. Arguments:
  3195. TransferPacket - Supplies the subordinate transfer packet.
  3196. Return Value:
  3197. None.
  3198. --*/
  3199. {
  3200. PSWP_RECOVER_TP subPacket = (PSWP_RECOVER_TP) TransferPacket;
  3201. NTSTATUS status = subPacket->IoStatus.Status;
  3202. PSWP_TP masterPacket = (PSWP_TP) subPacket->MasterPacket;
  3203. PSTRIPE_WP t = subPacket->StripeWithParity;
  3204. if (FsRtlIsTotalDeviceFailure(status)) {
  3205. masterPacket->IoStatus = subPacket->IoStatus;
  3206. masterPacket->CompletionRoutine(masterPacket);
  3207. t->RecycleRecoverTp(subPacket);
  3208. return;
  3209. }
  3210. if (!NT_SUCCESS(status)) {
  3211. if (!subPacket->OneReadFailed) {
  3212. subPacket->CompletionRoutine = StripeWpCarefulWritePhase2;
  3213. subPacket->OneReadFailed = TRUE;
  3214. subPacket->TargetVolume->ReplaceBadSector(subPacket);
  3215. return;
  3216. }
  3217. masterPacket->IoStatus = subPacket->IoStatus;
  3218. }
  3219. if (masterPacket->Offset + masterPacket->Length ==
  3220. subPacket->Offset + subPacket->Length) {
  3221. masterPacket->CompletionRoutine(masterPacket);
  3222. t->RecycleRecoverTp(subPacket);
  3223. return;
  3224. }
  3225. subPacket->Offset += subPacket->Length;
  3226. MmPrepareMdlForReuse(subPacket->Mdl);
  3227. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  3228. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  3229. (ULONG) (subPacket->Offset - masterPacket->Offset),
  3230. subPacket->Length);
  3231. subPacket->OneReadFailed = FALSE;
  3232. TRANSFER(subPacket);
  3233. }
  3234. VOID
  3235. StripeWpCarefulWriteEmergencyCompletion(
  3236. IN OUT PTRANSFER_PACKET TransferPacket
  3237. )
  3238. /*++
  3239. Routine Description:
  3240. This routine is the completion for use of the emergency recover packet
  3241. in a careful write operation.
  3242. Arguments:
  3243. TransferPacket - Supplies the transfer packet.
  3244. Return Value:
  3245. None.
  3246. --*/
  3247. {
  3248. PSWP_TP transferPacket = (PSWP_TP) TransferPacket;
  3249. PSTRIPE_WP t = transferPacket->StripeWithParity;
  3250. PSWP_RECOVER_TP subPacket = t->_eRecoverPacket;
  3251. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  3252. subPacket->Mdl = subPacket->PartialMdl;
  3253. IoBuildPartialMdl(transferPacket->Mdl, subPacket->Mdl,
  3254. MmGetMdlVirtualAddress(transferPacket->Mdl),
  3255. t->QuerySectorSize());
  3256. subPacket->Length = t->QuerySectorSize();
  3257. subPacket->Offset = transferPacket->Offset;
  3258. subPacket->CompletionRoutine = StripeWpCarefulWritePhase1;
  3259. subPacket->TargetVolume = transferPacket->TargetVolume;
  3260. subPacket->Thread = transferPacket->Thread;
  3261. subPacket->IrpFlags = transferPacket->IrpFlags;
  3262. subPacket->ReadPacket = FALSE;
  3263. subPacket->MasterPacket = transferPacket;
  3264. subPacket->StripeWithParity = t;
  3265. subPacket->WhichMember = transferPacket->WhichMember;
  3266. subPacket->OneReadFailed = FALSE;
  3267. TRANSFER(subPacket);
  3268. }
  3269. VOID
  3270. STRIPE_WP::CarefulWrite(
  3271. IN OUT PSWP_TP TransferPacket
  3272. )
  3273. /*++
  3274. Routine Description:
  3275. This routine writes the given transfer packet one sector at a time.
  3276. Arguments:
  3277. TransferPacket - Supplies a write packet.
  3278. Return Value:
  3279. None.
  3280. --*/
  3281. {
  3282. PSWP_RECOVER_TP subPacket;
  3283. KIRQL irql;
  3284. ASSERT(!TransferPacket->ReadPacket);
  3285. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  3286. TransferPacket->IoStatus.Information = TransferPacket->Length;
  3287. subPacket = new SWP_RECOVER_TP;
  3288. if (subPacket && !subPacket->AllocateMdls(QuerySectorSize())) {
  3289. delete subPacket;
  3290. subPacket = NULL;
  3291. }
  3292. if (!subPacket) {
  3293. KeAcquireSpinLock(&_spinLock, &irql);
  3294. if (_eRecoverPacketInUse) {
  3295. TransferPacket->SavedCompletionRoutine =
  3296. TransferPacket->CompletionRoutine;
  3297. TransferPacket->CompletionRoutine = StripeWpCarefulWriteEmergencyCompletion;
  3298. InsertTailList(&_eRecoverPacketQueue, &TransferPacket->QueueEntry);
  3299. KeReleaseSpinLock(&_spinLock, irql);
  3300. return;
  3301. }
  3302. _eRecoverPacketInUse = TRUE;
  3303. KeReleaseSpinLock(&_spinLock, irql);
  3304. subPacket = _eRecoverPacket;
  3305. }
  3306. subPacket->Mdl = subPacket->PartialMdl;
  3307. IoBuildPartialMdl(TransferPacket->Mdl, subPacket->Mdl,
  3308. MmGetMdlVirtualAddress(TransferPacket->Mdl),
  3309. QuerySectorSize());
  3310. subPacket->Length = QuerySectorSize();
  3311. subPacket->Offset = TransferPacket->Offset;
  3312. subPacket->CompletionRoutine = StripeWpCarefulWritePhase1;
  3313. subPacket->TargetVolume = TransferPacket->TargetVolume;
  3314. subPacket->Thread = TransferPacket->Thread;
  3315. subPacket->IrpFlags = TransferPacket->IrpFlags;
  3316. subPacket->ReadPacket = FALSE;
  3317. subPacket->MasterPacket = TransferPacket;
  3318. subPacket->StripeWithParity = this;
  3319. subPacket->WhichMember = TransferPacket->WhichMember;
  3320. subPacket->OneReadFailed = FALSE;
  3321. TRANSFER(subPacket);
  3322. }
  3323. VOID
  3324. StripeWpCarefulUpdateCompletion(
  3325. IN OUT PTRANSFER_PACKET TransferPacket
  3326. )
  3327. /*++
  3328. Routine Description:
  3329. This is the completion routine a single sector update parity
  3330. for a careful update operation.
  3331. Arguments:
  3332. TransferPacket - Supplies the subordinate transfer packet.
  3333. Return Value:
  3334. None.
  3335. --*/
  3336. {
  3337. PPARITY_TP subPacket = (PPARITY_TP) TransferPacket;
  3338. NTSTATUS status = subPacket->IoStatus.Status;
  3339. PSWP_RECOVER_TP rPacket;
  3340. PSWP_TP masterPacket;
  3341. PSTRIPE_WP t;
  3342. rPacket = CONTAINING_RECORD(subPacket, SWP_RECOVER_TP, ParityPacket);
  3343. masterPacket = (PSWP_TP) rPacket->MasterPacket;
  3344. t = masterPacket->StripeWithParity;
  3345. if (FsRtlIsTotalDeviceFailure(status)) {
  3346. masterPacket->IoStatus = subPacket->IoStatus;
  3347. masterPacket->CompletionRoutine(masterPacket);
  3348. t->RecycleRecoverTp(rPacket);
  3349. return;
  3350. }
  3351. if (!NT_SUCCESS(status)) {
  3352. masterPacket->IoStatus = subPacket->IoStatus;
  3353. }
  3354. if (masterPacket->Offset + masterPacket->Length ==
  3355. subPacket->Offset + subPacket->Length) {
  3356. masterPacket->CompletionRoutine(masterPacket);
  3357. t->RecycleRecoverTp(rPacket);
  3358. return;
  3359. }
  3360. subPacket->Offset += subPacket->Length;
  3361. MmPrepareMdlForReuse(subPacket->Mdl);
  3362. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  3363. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  3364. (ULONG) (subPacket->Offset - masterPacket->Offset),
  3365. subPacket->Length);
  3366. t->_parityIoManager.UpdateParity(subPacket);
  3367. }
  3368. VOID
  3369. StripeWpCarefulUpdateEmergencyCompletion(
  3370. IN OUT PTRANSFER_PACKET TransferPacket
  3371. )
  3372. /*++
  3373. Routine Description:
  3374. This routine is the completion for use of the emergency recover packet
  3375. in a careful udpate operation.
  3376. Arguments:
  3377. TransferPacket - Supplies the transfer packet.
  3378. Return Value:
  3379. None.
  3380. --*/
  3381. {
  3382. PSWP_TP parityPacket = (PSWP_TP) TransferPacket;
  3383. PSTRIPE_WP t = parityPacket->StripeWithParity;
  3384. PSWP_RECOVER_TP rPacket = t->_eRecoverPacket;
  3385. PPARITY_TP subPacket = &rPacket->ParityPacket;
  3386. parityPacket->CompletionRoutine = parityPacket->SavedCompletionRoutine;
  3387. rPacket->MasterPacket = parityPacket;
  3388. rPacket->StripeWithParity = t;
  3389. rPacket->WhichMember = parityPacket->WhichMember;
  3390. subPacket = &rPacket->ParityPacket;
  3391. subPacket->Mdl = rPacket->PartialMdl;
  3392. IoBuildPartialMdl(parityPacket->Mdl, subPacket->Mdl,
  3393. MmGetMdlVirtualAddress(parityPacket->Mdl),
  3394. t->QuerySectorSize());
  3395. subPacket->Length = t->QuerySectorSize();
  3396. subPacket->Offset = parityPacket->Offset;
  3397. subPacket->CompletionRoutine = StripeWpCarefulUpdateCompletion;
  3398. subPacket->TargetVolume = parityPacket->TargetVolume;
  3399. subPacket->Thread = parityPacket->Thread;
  3400. subPacket->IrpFlags = parityPacket->IrpFlags;
  3401. subPacket->ReadPacket = FALSE;
  3402. t->_parityIoManager.UpdateParity(subPacket);
  3403. }
  3404. VOID
  3405. STRIPE_WP::CarefulUpdate(
  3406. IN OUT PSWP_TP ParityPacket
  3407. )
  3408. /*++
  3409. Routine Description:
  3410. This routine updates the given parity block one sector at a time.
  3411. Arguments:
  3412. ParityPacket - Supplies an update parity packet.
  3413. Return Value:
  3414. None.
  3415. --*/
  3416. {
  3417. PSWP_RECOVER_TP rPacket;
  3418. KIRQL irql;
  3419. PPARITY_TP subPacket;
  3420. ParityPacket->IoStatus.Status = STATUS_SUCCESS;
  3421. ParityPacket->IoStatus.Information = ParityPacket->Length;
  3422. rPacket = new SWP_RECOVER_TP;
  3423. if (rPacket && !rPacket->AllocateMdls(QuerySectorSize())) {
  3424. delete rPacket;
  3425. rPacket = NULL;
  3426. }
  3427. if (!rPacket) {
  3428. KeAcquireSpinLock(&_spinLock, &irql);
  3429. if (_eRecoverPacketInUse) {
  3430. ParityPacket->SavedCompletionRoutine =
  3431. ParityPacket->CompletionRoutine;
  3432. ParityPacket->CompletionRoutine =
  3433. StripeWpCarefulUpdateEmergencyCompletion;
  3434. InsertTailList(&_eRecoverPacketQueue, &ParityPacket->QueueEntry);
  3435. KeReleaseSpinLock(&_spinLock, irql);
  3436. return;
  3437. }
  3438. _eRecoverPacketInUse = TRUE;
  3439. KeReleaseSpinLock(&_spinLock, irql);
  3440. rPacket = _eRecoverPacket;
  3441. }
  3442. rPacket->MasterPacket = ParityPacket;
  3443. rPacket->StripeWithParity = this;
  3444. rPacket->WhichMember = ParityPacket->WhichMember;
  3445. subPacket = &rPacket->ParityPacket;
  3446. subPacket->Mdl = rPacket->PartialMdl;
  3447. IoBuildPartialMdl(ParityPacket->Mdl, subPacket->Mdl,
  3448. MmGetMdlVirtualAddress(ParityPacket->Mdl),
  3449. QuerySectorSize());
  3450. subPacket->Length = QuerySectorSize();
  3451. subPacket->Offset = ParityPacket->Offset;
  3452. subPacket->CompletionRoutine = StripeWpCarefulUpdateCompletion;
  3453. subPacket->TargetVolume = ParityPacket->TargetVolume;
  3454. subPacket->Thread = ParityPacket->Thread;
  3455. subPacket->IrpFlags = ParityPacket->IrpFlags;
  3456. subPacket->ReadPacket = FALSE;
  3457. _parityIoManager.UpdateParity(subPacket);
  3458. }
  3459. VOID
  3460. STRIPE_WP::ModifyStateForUser(
  3461. IN OUT PVOID State
  3462. )
  3463. /*++
  3464. Routine Description:
  3465. This routine modifies the state for the user to see, possibly adding
  3466. non-persistant state different than what is stored on disk.
  3467. Arguments:
  3468. State - Supplies and returns the state for the logical disk.
  3469. Return Value:
  3470. None.
  3471. --*/
  3472. {
  3473. KIRQL irql;
  3474. BOOLEAN isDirty;
  3475. PFT_MIRROR_AND_SWP_STATE_INFORMATION state;
  3476. KeAcquireSpinLock(&_spinLock, &irql);
  3477. if (_syncOk && !_stopSyncs) {
  3478. isDirty = FALSE;
  3479. } else {
  3480. isDirty = TRUE;
  3481. }
  3482. KeReleaseSpinLock(&_spinLock, irql);
  3483. if (!isDirty) {
  3484. return;
  3485. }
  3486. state = (PFT_MIRROR_AND_SWP_STATE_INFORMATION) State;
  3487. if (state->UnhealthyMemberState == FtMemberHealthy) {
  3488. state->IsInitializing = TRUE;
  3489. }
  3490. }