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.

3237 lines
81 KiB

  1. /*++
  2. Copyright (C) 1991-5 Microsoft Corporation
  3. Module Name:
  4. mirror.cxx
  5. Abstract:
  6. This module contains the code specific to mirrors 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. MIRROR::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 MIRROR.
  36. Arguments:
  37. RootExtension - Supplies the root device extension.
  38. LogicalDiskId - Supplies the logical disk id for this volume.
  39. VolumeArray - Supplies the array of volumes for this volume set.
  40. ArraySize - Supplies the number of volumes in the volume array.
  41. ConfigInfo - Supplies the configuration information.
  42. StateInfo - Supplies the state information.
  43. Return Value:
  44. NTSTATUS
  45. --*/
  46. {
  47. NTSTATUS status;
  48. PFT_MIRROR_SET_CONFIGURATION_INFORMATION config;
  49. if (ArraySize != 2) {
  50. return STATUS_INVALID_PARAMETER;
  51. }
  52. if (!VolumeArray[0] && !VolumeArray[1]) {
  53. return STATUS_INVALID_PARAMETER;
  54. }
  55. status = COMPOSITE_FT_VOLUME::Initialize(RootExtension, LogicalDiskId,
  56. VolumeArray, ArraySize,
  57. ConfigInfo, StateInfo);
  58. if (!NT_SUCCESS(status)) {
  59. return status;
  60. }
  61. config = (PFT_MIRROR_SET_CONFIGURATION_INFORMATION) ConfigInfo;
  62. _volumeSize = config->MemberSize;
  63. _requestCount[0] = 0;
  64. _requestCount[1] = 0;
  65. _lastPosition[0] = 0;
  66. _lastPosition[1] = 0;
  67. if (VolumeArray[0] && VolumeArray[0]->QueryVolumeSize() < _volumeSize) {
  68. return STATUS_INVALID_PARAMETER;
  69. }
  70. if (VolumeArray[1] && VolumeArray[1]->QueryVolumeSize() < _volumeSize) {
  71. return STATUS_INVALID_PARAMETER;
  72. }
  73. RtlCopyMemory(&_state, StateInfo,
  74. sizeof(FT_MIRROR_AND_SWP_STATE_INFORMATION));
  75. _originalDirtyBit = _state.IsDirty;
  76. _orphanedBecauseOfMissingMember = FALSE;
  77. _syncOk = TRUE;
  78. _balancedReads = _state.IsDirty ? FALSE : TRUE;
  79. _stopSyncs = FALSE;
  80. _ePacket = new MIRROR_TP;
  81. if (!_ePacket) {
  82. return STATUS_INSUFFICIENT_RESOURCES;
  83. }
  84. _ePacket2 = new MIRROR_TP;
  85. if (!_ePacket2) {
  86. return STATUS_INSUFFICIENT_RESOURCES;
  87. }
  88. _ePacketInUse = FALSE;
  89. InitializeListHead(&_ePacketQueue);
  90. _eRecoverPacket = new MIRROR_RECOVER_TP;
  91. if (!_eRecoverPacket) {
  92. return STATUS_INSUFFICIENT_RESOURCES;
  93. }
  94. if (!_eRecoverPacket->AllocateMdls(QuerySectorSize())) {
  95. return STATUS_INSUFFICIENT_RESOURCES;
  96. }
  97. _eRecoverPacketInUse = FALSE;
  98. InitializeListHead(&_eRecoverPacketQueue);
  99. status = _overlappedIoManager.Initialize(0);
  100. return status;
  101. }
  102. FT_LOGICAL_DISK_TYPE
  103. MIRROR::QueryLogicalDiskType(
  104. )
  105. /*++
  106. Routine Description:
  107. This routine returns the type of the logical disk.
  108. Arguments:
  109. None.
  110. Return Value:
  111. The type of the logical disk.
  112. --*/
  113. {
  114. return FtMirrorSet;
  115. }
  116. #ifdef ALLOC_PRAGMA
  117. #pragma code_seg("PAGELK")
  118. #endif
  119. MIRROR::~MIRROR(
  120. )
  121. {
  122. if (_ePacket) {
  123. delete _ePacket;
  124. _ePacket = NULL;
  125. }
  126. if (_ePacket2) {
  127. delete _ePacket2;
  128. _ePacket2 = NULL;
  129. }
  130. if (_eRecoverPacket) {
  131. delete _eRecoverPacket;
  132. _eRecoverPacket = NULL;
  133. }
  134. }
  135. NTSTATUS
  136. MIRROR::OrphanMember(
  137. IN USHORT MemberNumber,
  138. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  139. IN PVOID Context
  140. )
  141. /*++
  142. Routine Description:
  143. This routine tries to orphan the given member of this logical disk.
  144. A completion routine will be called if and only if this attempt is successful.
  145. Arguments:
  146. MemberNumber - Supplies the member number to orphan.
  147. CompletionRoutine - Supplies the completion routine.
  148. Context - Supplies the completion routine context.
  149. Return Value:
  150. NTSTATUS
  151. --*/
  152. {
  153. KIRQL irql;
  154. NTSTATUS status = STATUS_SUCCESS;
  155. BOOLEAN b;
  156. if (MemberNumber >= 2) {
  157. return STATUS_INVALID_PARAMETER;
  158. }
  159. KeAcquireSpinLock(&_spinLock, &irql);
  160. b = SetMemberState(MemberNumber, FtMemberOrphaned);
  161. KeReleaseSpinLock(&_spinLock, irql);
  162. if (b) {
  163. PropogateStateChanges(CompletionRoutine, Context);
  164. Notify();
  165. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  166. FT_ORPHANING, STATUS_SUCCESS, 2);
  167. }
  168. return b ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
  169. }
  170. VOID
  171. MirrorCompositeVolumeCompletionRoutine(
  172. IN PVOID Context,
  173. IN NTSTATUS Status
  174. )
  175. {
  176. PFT_COMPLETION_ROUTINE_CONTEXT context;
  177. KIRQL irql;
  178. LONG count;
  179. context = (PFT_COMPLETION_ROUTINE_CONTEXT) Context;
  180. KeAcquireSpinLock(&context->SpinLock, &irql);
  181. if (!NT_SUCCESS(Status) &&
  182. FtpIsWorseStatus(Status, context->Status)) {
  183. context->Status = Status;
  184. }
  185. count = --context->RefCount;
  186. KeReleaseSpinLock(&context->SpinLock, irql);
  187. if (!count) {
  188. context->CompletionRoutine(context->Context, STATUS_SUCCESS);
  189. ExFreePool(context);
  190. }
  191. }
  192. VOID
  193. FinishRegenerate(
  194. IN PMIRROR Mirror,
  195. IN PFT_COMPLETION_ROUTINE_CONTEXT RegenContext,
  196. IN PMIRROR_TP TransferPacket
  197. )
  198. {
  199. PMIRROR t = Mirror;
  200. delete TransferPacket;
  201. MirrorCompositeVolumeCompletionRoutine(RegenContext, STATUS_SUCCESS);
  202. }
  203. VOID
  204. MirrorRegenerateCompletionRoutine(
  205. IN PTRANSFER_PACKET TransferPacket
  206. );
  207. VOID
  208. MirrorRegeneratePhase1(
  209. IN PTRANSFER_PACKET TransferPacket
  210. )
  211. {
  212. TransferPacket->CompletionRoutine = MirrorRegenerateCompletionRoutine;
  213. TRANSFER(TransferPacket);
  214. }
  215. VOID
  216. MirrorRegenerateCompletionRoutine(
  217. IN PTRANSFER_PACKET TransferPacket
  218. )
  219. /*++
  220. Routine Description:
  221. Completion routine for MIRROR::RestartRegenerations routine.
  222. Arguments:
  223. TransferPacket - Supplies the transfer packet.
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. PMIRROR_TP transferPacket = (PMIRROR_TP) TransferPacket;
  229. PFT_COMPLETION_ROUTINE_CONTEXT context = (PFT_COMPLETION_ROUTINE_CONTEXT) transferPacket->MasterPacket;
  230. PMIRROR t = transferPacket->Mirror;
  231. KIRQL irql;
  232. PLIST_ENTRY l;
  233. PMIRROR_TP packet;
  234. BOOLEAN b;
  235. if (!NT_SUCCESS(transferPacket->IoStatus.Status)) {
  236. // We can't get a VERIFY_REQUIRED because we put IrpFlags equal
  237. // to SL_OVERRIDE_VERIFY_VOLUME.
  238. ASSERT(transferPacket->IoStatus.Status != STATUS_VERIFY_REQUIRED);
  239. if (FsRtlIsTotalDeviceFailure(transferPacket->IoStatus.Status)) {
  240. KeAcquireSpinLock(&t->_spinLock, &irql);
  241. b = t->SetMemberState(transferPacket->WhichMember, FtMemberOrphaned);
  242. t->_syncOk = TRUE;
  243. KeReleaseSpinLock(&t->_spinLock, irql);
  244. if (b) {
  245. t->PropogateStateChanges(NULL, NULL);
  246. t->Notify();
  247. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  248. FT_ORPHANING, STATUS_SUCCESS, 3);
  249. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  250. }
  251. FinishRegenerate(t, context, transferPacket);
  252. return;
  253. }
  254. // Transfer the maximum amount that we can. This will always
  255. // complete successfully.
  256. t->MaxTransfer(transferPacket);
  257. return;
  258. }
  259. // Set up for the next packet.
  260. transferPacket->Thread = PsGetCurrentThread();
  261. transferPacket->ReadPacket = !transferPacket->ReadPacket;
  262. transferPacket->WhichMember = (transferPacket->WhichMember + 1)%2;
  263. transferPacket->TargetVolume = t->GetMemberUnprotected(
  264. transferPacket->WhichMember);
  265. KeAcquireSpinLock(&t->_spinLock, &irql);
  266. if (t->QueryMemberState(transferPacket->WhichMember) == FtMemberOrphaned ||
  267. t->_stopSyncs) {
  268. t->_syncOk = TRUE;
  269. KeReleaseSpinLock(&t->_spinLock, irql);
  270. FinishRegenerate(t, context, transferPacket);
  271. return;
  272. }
  273. KeReleaseSpinLock(&t->_spinLock, irql);
  274. if (transferPacket->ReadPacket) {
  275. t->_overlappedIoManager.ReleaseIoRegion(transferPacket);
  276. if (transferPacket->Offset + STRIPE_SIZE >= t->_volumeSize) {
  277. KeAcquireSpinLock(&t->_spinLock, &irql);
  278. b = t->SetMemberState((transferPacket->WhichMember + 1)%2,
  279. FtMemberHealthy);
  280. t->_balancedReads = TRUE;
  281. t->_syncOk = TRUE;
  282. t->_originalDirtyBit = FALSE;
  283. KeReleaseSpinLock(&t->_spinLock, irql);
  284. if (b) {
  285. t->PropogateStateChanges(NULL, NULL);
  286. t->Notify();
  287. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  288. FT_MIRROR_COPY_ENDED, STATUS_SUCCESS, 0);
  289. }
  290. FinishRegenerate(t, context, transferPacket);
  291. return;
  292. }
  293. transferPacket->Offset += STRIPE_SIZE;
  294. if (t->_volumeSize - transferPacket->Offset < STRIPE_SIZE) {
  295. transferPacket->Length = (ULONG) (t->_volumeSize -
  296. transferPacket->Offset);
  297. }
  298. transferPacket->CompletionRoutine = MirrorRegeneratePhase1;
  299. t->_overlappedIoManager.AcquireIoRegion(transferPacket, TRUE);
  300. } else {
  301. TRANSFER(transferPacket);
  302. }
  303. }
  304. NTSTATUS
  305. MIRROR::RegenerateMember(
  306. IN USHORT MemberNumber,
  307. IN OUT PFT_VOLUME NewMember,
  308. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  309. IN PVOID Context
  310. )
  311. /*++
  312. Routine Description:
  313. This routine regenerates the given member of this volume with
  314. the given volume.
  315. Arguments:
  316. MemberNumber - Supplies the member number to regenerate.
  317. NewMember - Supplies the new member to regenerate to.
  318. CompletionRoutine - Supplies the completion routine.
  319. Context - Supplies the completion routine context.
  320. Return Value:
  321. NTSTATUS
  322. --*/
  323. {
  324. PFT_COMPLETION_ROUTINE_CONTEXT context;
  325. PMIRROR_TP packet;
  326. NTSTATUS status;
  327. KIRQL irql;
  328. BOOLEAN b;
  329. if (MemberNumber >= 2 ||
  330. NewMember->QueryVolumeSize() < _volumeSize) {
  331. return STATUS_INVALID_PARAMETER;
  332. }
  333. context = (PFT_COMPLETION_ROUTINE_CONTEXT)
  334. ExAllocatePool(NonPagedPool,
  335. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  336. packet = new MIRROR_TP;
  337. if (packet && !packet->AllocateMdl(STRIPE_SIZE)) {
  338. delete packet;
  339. packet = NULL;
  340. }
  341. if (!context || !packet) {
  342. if (context) {
  343. ExFreePool(context);
  344. }
  345. if (packet) {
  346. delete packet;
  347. }
  348. return STATUS_INSUFFICIENT_RESOURCES;
  349. }
  350. KeInitializeSpinLock(&context->SpinLock);
  351. context->Status = STATUS_SUCCESS;
  352. context->RefCount = 1;
  353. context->CompletionRoutine = CompletionRoutine;
  354. context->Context = Context;
  355. context->ParentVolume = this;
  356. packet->Length = STRIPE_SIZE;
  357. packet->Offset = 0;
  358. packet->CompletionRoutine = MirrorRegeneratePhase1;
  359. packet->Thread = PsGetCurrentThread();
  360. packet->IrpFlags = SL_OVERRIDE_VERIFY_VOLUME;
  361. packet->ReadPacket = TRUE;
  362. packet->MasterPacket = (PTRANSFER_PACKET) context;
  363. packet->Mirror = this;
  364. status = STATUS_SUCCESS;
  365. KeAcquireSpinLock(&_spinLock, &irql);
  366. if (_syncOk) {
  367. _syncOk = FALSE;
  368. _stopSyncs = FALSE;
  369. } else {
  370. KeReleaseSpinLock(&_spinLock, irql);
  371. delete packet;
  372. ExFreePool(context);
  373. return STATUS_INVALID_PARAMETER;
  374. }
  375. if (_state.UnhealthyMemberState != FtMemberHealthy) {
  376. if (MemberNumber == _state.UnhealthyMemberNumber) {
  377. if (_state.UnhealthyMemberState == FtMemberRegenerating) {
  378. status = STATUS_INVALID_PARAMETER;
  379. }
  380. } else {
  381. status = STATUS_INVALID_PARAMETER;
  382. }
  383. }
  384. if (!NT_SUCCESS(status)) {
  385. _syncOk = TRUE;
  386. KeReleaseSpinLock(&_spinLock, irql);
  387. ExFreePool(context);
  388. delete packet;
  389. return status;
  390. }
  391. packet->WhichMember = (MemberNumber + 1)%2;
  392. packet->TargetVolume = GetMemberUnprotected(packet->WhichMember);
  393. SetMemberUnprotected(MemberNumber, NewMember);
  394. b = SetMemberState(MemberNumber, FtMemberRegenerating);
  395. KeReleaseSpinLock(&_spinLock, irql);
  396. ASSERT(b);
  397. PropogateStateChanges(NULL, NULL);
  398. Notify();
  399. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  400. FT_MIRROR_COPY_STARTED, STATUS_SUCCESS, 2);
  401. _overlappedIoManager.AcquireIoRegion(packet, TRUE);
  402. return status;
  403. }
  404. VOID
  405. MIRROR::Transfer(
  406. IN OUT PTRANSFER_PACKET TransferPacket
  407. )
  408. /*++
  409. Routine Description:
  410. Transfer routine for MIRROR type FT_VOLUME. Balance READs as
  411. much as possible and propogate WRITEs to both the primary and
  412. secondary volumes.
  413. Arguments:
  414. TransferPacket - Supplies the transfer packet.
  415. Return Value:
  416. None.
  417. --*/
  418. {
  419. KIRQL irql;
  420. PMIRROR_TP packet1, packet2;
  421. if (TransferPacket->Offset + TransferPacket->Length > _volumeSize) {
  422. TransferPacket->IoStatus.Status = STATUS_INVALID_PARAMETER;
  423. TransferPacket->IoStatus.Information = 0;
  424. TransferPacket->CompletionRoutine(TransferPacket);
  425. return;
  426. }
  427. if (!TransferPacket->Mdl) {
  428. TransferPacket->ReadPacket = FALSE;
  429. }
  430. packet1 = new MIRROR_TP;
  431. if (packet1 && !TransferPacket->ReadPacket) {
  432. packet2 = new MIRROR_TP;
  433. if (!packet2) {
  434. delete packet1;
  435. packet1 = NULL;
  436. }
  437. } else {
  438. packet2 = NULL;
  439. }
  440. if (!packet1) {
  441. if (!TransferPacket->Mdl) {
  442. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  443. TransferPacket->IoStatus.Information = 0;
  444. TransferPacket->CompletionRoutine(TransferPacket);
  445. return;
  446. }
  447. KeAcquireSpinLock(&_spinLock, &irql);
  448. if (_ePacketInUse) {
  449. InsertTailList(&_ePacketQueue, &TransferPacket->QueueEntry);
  450. KeReleaseSpinLock(&_spinLock, irql);
  451. return;
  452. }
  453. _ePacketInUse = TRUE;
  454. KeReleaseSpinLock(&_spinLock, irql);
  455. packet1 = _ePacket;
  456. packet2 = _ePacket2;
  457. }
  458. if (TransferPacket->ReadPacket) {
  459. if (!LaunchRead(TransferPacket, packet1)) {
  460. Recycle(packet1, TRUE);
  461. }
  462. } else {
  463. if (!LaunchWrite(TransferPacket, packet1, packet2)) {
  464. Recycle(packet1, FALSE);
  465. Recycle(packet2, TRUE);
  466. }
  467. }
  468. }
  469. VOID
  470. MIRROR::ReplaceBadSector(
  471. IN OUT PTRANSFER_PACKET TransferPacket
  472. )
  473. /*++
  474. Routine Description:
  475. This is a no-op since replacing bad sectors doesn't make sense
  476. on an FT component with redundancy built in to it.
  477. Arguments:
  478. TransferPacket - Supplies the transfer packet.
  479. Return Value:
  480. None.
  481. --*/
  482. {
  483. TransferPacket->IoStatus.Status = STATUS_UNSUCCESSFUL;
  484. TransferPacket->IoStatus.Information = 0;
  485. TransferPacket->CompletionRoutine(TransferPacket);
  486. }
  487. VOID
  488. MIRROR::StartSyncOperations(
  489. IN BOOLEAN RegenerateOrphans,
  490. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  491. IN PVOID Context
  492. )
  493. /*++
  494. Routine Description:
  495. This routine restarts any regenerate or initialize requests that were
  496. suspended because of a reboot. The volume examines the member state of
  497. all of its constituents and restarts any regenerations pending.
  498. Arguments:
  499. RegenerateOrphans - Supplies whether or not to try and regenerate
  500. orphaned members.
  501. CompletionRoutine - Supplies the completion routine.
  502. Context - Supplies the context for the completion routine.
  503. Return Value:
  504. None.
  505. --*/
  506. {
  507. PFT_COMPLETION_ROUTINE_CONTEXT context;
  508. BOOLEAN dirty, b;
  509. KIRQL irql;
  510. USHORT srcIndex;
  511. PMIRROR_TP packet;
  512. context = (PFT_COMPLETION_ROUTINE_CONTEXT)
  513. ExAllocatePool(NonPagedPool,
  514. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  515. if (!context) {
  516. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  517. return;
  518. }
  519. KeInitializeSpinLock(&context->SpinLock);
  520. context->Status = STATUS_SUCCESS;
  521. context->RefCount = 2;
  522. context->CompletionRoutine = CompletionRoutine;
  523. context->Context = Context;
  524. context->ParentVolume = this;
  525. COMPOSITE_FT_VOLUME::StartSyncOperations(
  526. RegenerateOrphans, MirrorCompositeVolumeCompletionRoutine, context);
  527. if (_orphanedBecauseOfMissingMember) {
  528. RegenerateOrphans = TRUE;
  529. _orphanedBecauseOfMissingMember = FALSE;
  530. }
  531. dirty = FALSE;
  532. b = FALSE;
  533. KeAcquireSpinLock(&_spinLock, &irql);
  534. if (_syncOk) {
  535. _syncOk = FALSE;
  536. _stopSyncs = FALSE;
  537. } else {
  538. KeReleaseSpinLock(&_spinLock, irql);
  539. MirrorCompositeVolumeCompletionRoutine(context, STATUS_SUCCESS);
  540. return;
  541. }
  542. if (_state.UnhealthyMemberState == FtMemberOrphaned &&
  543. RegenerateOrphans &&
  544. GetMemberUnprotected(_state.UnhealthyMemberNumber)) {
  545. _state.UnhealthyMemberState = FtMemberRegenerating;
  546. b = TRUE;
  547. }
  548. if (_state.UnhealthyMemberState == FtMemberHealthy) {
  549. if (_originalDirtyBit) {
  550. srcIndex = 0;
  551. dirty = TRUE;
  552. } else {
  553. _syncOk = TRUE;
  554. KeReleaseSpinLock(&_spinLock, irql);
  555. MirrorCompositeVolumeCompletionRoutine(context, STATUS_SUCCESS);
  556. return;
  557. }
  558. } else if (_state.UnhealthyMemberState == FtMemberRegenerating) {
  559. srcIndex = (_state.UnhealthyMemberNumber + 1)%2;
  560. b = TRUE;
  561. } else {
  562. _syncOk = TRUE;
  563. KeReleaseSpinLock(&_spinLock, irql);
  564. MirrorCompositeVolumeCompletionRoutine(context, STATUS_SUCCESS);
  565. return;
  566. }
  567. KeReleaseSpinLock(&_spinLock, irql);
  568. if (dirty) {
  569. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  570. FT_DIRTY_SHUTDOWN, STATUS_SUCCESS, 0);
  571. }
  572. if (b) {
  573. PropogateStateChanges(NULL, NULL);
  574. Notify();
  575. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  576. FT_MIRROR_COPY_STARTED, STATUS_SUCCESS, 3);
  577. }
  578. packet = new MIRROR_TP;
  579. if (packet && !packet->AllocateMdl(STRIPE_SIZE)) {
  580. delete packet;
  581. packet = NULL;
  582. }
  583. if (!packet) {
  584. MirrorCompositeVolumeCompletionRoutine(context,
  585. STATUS_INSUFFICIENT_RESOURCES);
  586. return;
  587. }
  588. packet->Length = STRIPE_SIZE;
  589. packet->Offset = 0;
  590. packet->CompletionRoutine = MirrorRegeneratePhase1;
  591. packet->Thread = PsGetCurrentThread();
  592. packet->IrpFlags = SL_OVERRIDE_VERIFY_VOLUME;
  593. packet->ReadPacket = TRUE;
  594. packet->MasterPacket = (PMIRROR_TP) context;
  595. packet->Mirror = this;
  596. packet->WhichMember = srcIndex;
  597. packet->TargetVolume = GetMemberUnprotected(packet->WhichMember);
  598. _overlappedIoManager.AcquireIoRegion(packet, TRUE);
  599. }
  600. VOID
  601. MIRROR::StopSyncOperations(
  602. )
  603. /*++
  604. Routine Description:
  605. This routine stops all sync operations.
  606. Arguments:
  607. None.
  608. Return Value:
  609. None.
  610. --*/
  611. {
  612. KIRQL irql;
  613. COMPOSITE_FT_VOLUME::StopSyncOperations();
  614. KeAcquireSpinLock(&_spinLock, &irql);
  615. _stopSyncs = TRUE;
  616. KeReleaseSpinLock(&_spinLock, irql);
  617. }
  618. LONGLONG
  619. MIRROR::QueryVolumeSize(
  620. )
  621. /*++
  622. Routine Description:
  623. Returns the number of bytes on the entire volume.
  624. Arguments:
  625. None.
  626. Return Value:
  627. The volume size in bytes.
  628. --*/
  629. {
  630. return _volumeSize;
  631. }
  632. VOID
  633. MIRROR::SetDirtyBit(
  634. IN BOOLEAN IsDirty,
  635. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  636. IN PVOID Context
  637. )
  638. /*++
  639. Routine Description:
  640. This routine sets the dirty bit on the volume. This bit is used at
  641. startup to determine whether or not there was a clean shutdown.
  642. Arguments:
  643. IsDirty - Supplies the value of the dirty bit.
  644. Return Value:
  645. None.
  646. --*/
  647. {
  648. PFT_COMPLETION_ROUTINE_CONTEXT context;
  649. KIRQL irql;
  650. if (CompletionRoutine) {
  651. context = (PFT_COMPLETION_ROUTINE_CONTEXT)
  652. ExAllocatePool(NonPagedPool,
  653. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  654. if (!context) {
  655. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  656. return;
  657. }
  658. KeInitializeSpinLock(&context->SpinLock);
  659. context->Status = STATUS_SUCCESS;
  660. context->RefCount = 2;
  661. context->CompletionRoutine = CompletionRoutine;
  662. context->Context = Context;
  663. context->ParentVolume = this;
  664. COMPOSITE_FT_VOLUME::SetDirtyBit(IsDirty,
  665. MirrorCompositeVolumeCompletionRoutine, context);
  666. } else {
  667. COMPOSITE_FT_VOLUME::SetDirtyBit(IsDirty, NULL, NULL);
  668. }
  669. KeAcquireSpinLock(&_spinLock, &irql);
  670. if (IsDirty || _syncOk) {
  671. if (!_stopSyncs) {
  672. _state.IsDirty = IsDirty;
  673. }
  674. }
  675. KeReleaseSpinLock(&_spinLock, irql);
  676. if (CompletionRoutine) {
  677. PropogateStateChanges(MirrorCompositeVolumeCompletionRoutine, context);
  678. } else {
  679. PropogateStateChanges(NULL, NULL);
  680. }
  681. }
  682. BOOLEAN
  683. MIRROR::IsComplete(
  684. IN BOOLEAN IoPending
  685. )
  686. /*++
  687. Routine Description:
  688. This routine computes whether or not this volume has either all
  689. (if IoPending is FALSE) of its members or enough (if IoPending is TRUE) of
  690. its members.
  691. Arguments:
  692. IoPending - Supplies whether or not there is IO pending.
  693. Return Value:
  694. None.
  695. --*/
  696. {
  697. BOOLEAN b;
  698. USHORT n, i, orphanMember;
  699. PFT_VOLUME vol;
  700. b = COMPOSITE_FT_VOLUME::IsComplete(IoPending);
  701. if (b) {
  702. return TRUE;
  703. }
  704. if (!IoPending) {
  705. return FALSE;
  706. }
  707. n = QueryNumMembers();
  708. orphanMember = n;
  709. for (i = 0; i < n; i++) {
  710. vol = GetMember(i);
  711. if (!vol || !vol->IsComplete(IoPending)) {
  712. if (orphanMember < n) {
  713. return FALSE;
  714. }
  715. orphanMember = i;
  716. }
  717. }
  718. if (orphanMember < n) {
  719. if (_state.UnhealthyMemberState != FtMemberHealthy &&
  720. _state.UnhealthyMemberNumber != orphanMember) {
  721. return FALSE;
  722. }
  723. }
  724. return TRUE;
  725. }
  726. VOID
  727. MIRROR::CompleteNotification(
  728. IN BOOLEAN IoPending
  729. )
  730. /*++
  731. Routine Description:
  732. This routine is called to notify the volume that it is complete and
  733. to therefore prepare for incoming requests.
  734. Arguments:
  735. IoPending - Supplies whether or not there is IO pending.
  736. Return Value:
  737. None.
  738. --*/
  739. {
  740. USHORT n, i, orphanMember;
  741. PFT_VOLUME vol;
  742. COMPOSITE_FT_VOLUME::CompleteNotification(IoPending);
  743. n = QueryNumMembers();
  744. orphanMember = n;
  745. for (i = 0; i < n; i++) {
  746. vol = GetMember(i);
  747. if (!vol || !vol->IsComplete(IoPending)) {
  748. orphanMember = i;
  749. break;
  750. }
  751. }
  752. if (orphanMember < n) {
  753. if (SetMemberState(orphanMember, FtMemberOrphaned)) {
  754. PropogateStateChanges(NULL, NULL);
  755. Notify();
  756. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  757. FT_ORPHANING, STATUS_SUCCESS, 1);
  758. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  759. _orphanedBecauseOfMissingMember = TRUE;
  760. }
  761. }
  762. }
  763. NTSTATUS
  764. MIRROR::CheckIo(
  765. OUT PBOOLEAN IsIoOk
  766. )
  767. /*++
  768. Routine Description:
  769. This routine returns whether or not IO is possible on the given
  770. logical disk.
  771. Arguments:
  772. IsIoOk - Returns the state of IO.
  773. Return Value:
  774. NTSTATUS
  775. --*/
  776. {
  777. NTSTATUS status;
  778. KIRQL irql;
  779. USHORT n, numOk, skipVol, i;
  780. PFT_VOLUME vol;
  781. BOOLEAN ok, b;
  782. n = QueryNumMembers();
  783. numOk = 0;
  784. KeAcquireSpinLock(&_spinLock, &irql);
  785. if (_state.UnhealthyMemberState == FtMemberHealthy) {
  786. skipVol = n;
  787. } else {
  788. skipVol = _state.UnhealthyMemberNumber;
  789. }
  790. KeReleaseSpinLock(&_spinLock, irql);
  791. for (i = 0; i < n; i++) {
  792. if (i == skipVol) {
  793. continue;
  794. }
  795. vol = GetMemberUnprotected(i);
  796. if (!vol) {
  797. continue;
  798. }
  799. status = vol->CheckIo(&ok);
  800. if (!NT_SUCCESS(status)) {
  801. return status;
  802. }
  803. if (ok) {
  804. numOk++;
  805. }
  806. }
  807. if (numOk >= n - 1) {
  808. *IsIoOk = TRUE;
  809. } else {
  810. *IsIoOk = FALSE;
  811. }
  812. return STATUS_SUCCESS;
  813. }
  814. BOOLEAN
  815. MIRROR::IsVolumeSuitableForRegenerate(
  816. IN USHORT MemberNumber,
  817. IN PFT_VOLUME Volume
  818. )
  819. /*++
  820. Routine Description:
  821. This routine computes whether or not the given volume is suitable
  822. for a regenerate operation.
  823. Arguments:
  824. MemberNumber - Supplies the member number.
  825. Volume - Supplies the volume.
  826. Return Value:
  827. FALSE - The volume is not suitable.
  828. TRUE - The volume is suitable.
  829. --*/
  830. {
  831. KIRQL irql;
  832. if (Volume->QueryVolumeSize() < _volumeSize) {
  833. return FALSE;
  834. }
  835. KeAcquireSpinLock(&_spinLock, &irql);
  836. if (!_syncOk ||
  837. _state.UnhealthyMemberState != FtMemberOrphaned ||
  838. _state.UnhealthyMemberNumber != MemberNumber) {
  839. KeReleaseSpinLock(&_spinLock, irql);
  840. return FALSE;
  841. }
  842. KeReleaseSpinLock(&_spinLock, irql);
  843. return TRUE;
  844. }
  845. VOID
  846. MIRROR::NewStateArrival(
  847. IN PVOID NewStateInstance
  848. )
  849. /*++
  850. Routine Description:
  851. This routine takes the new state instance arrival combined with its
  852. current state to come up with the new current state for the volume.
  853. If the two states cannot be reconciled then this routine returns FALSE
  854. indicating that the volume is invalid and should be broken into its
  855. constituant parts.
  856. Arguments:
  857. NewStateInstance - Supplies the new state instance.
  858. Return Value:
  859. None.
  860. --*/
  861. {
  862. BOOLEAN changed = FALSE;
  863. PFT_MIRROR_AND_SWP_STATE_INFORMATION state;
  864. state = (PFT_MIRROR_AND_SWP_STATE_INFORMATION) NewStateInstance;
  865. if (state->IsDirty) {
  866. if (!_state.IsDirty) {
  867. _originalDirtyBit = _state.IsDirty = state->IsDirty;
  868. _balancedReads = FALSE;
  869. changed = TRUE;
  870. }
  871. }
  872. if (state->UnhealthyMemberState != FtMemberHealthy) {
  873. if (state->UnhealthyMemberNumber >= QueryNumMembers()) {
  874. _state.UnhealthyMemberNumber = 1;
  875. _state.UnhealthyMemberState = FtMemberOrphaned;
  876. changed = TRUE;
  877. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  878. FT_MIRROR_STATE_CORRUPTION,
  879. STATUS_SUCCESS, 0);
  880. } else if (_state.UnhealthyMemberState == FtMemberHealthy) {
  881. _state.UnhealthyMemberState = state->UnhealthyMemberState;
  882. _state.UnhealthyMemberNumber = state->UnhealthyMemberNumber;
  883. changed = TRUE;
  884. } else {
  885. if (_state.UnhealthyMemberNumber == state->UnhealthyMemberNumber) {
  886. if (state->UnhealthyMemberState == FtMemberOrphaned) {
  887. if (_state.UnhealthyMemberState != FtMemberOrphaned) {
  888. _state.UnhealthyMemberState = FtMemberOrphaned;
  889. changed = TRUE;
  890. }
  891. }
  892. } else {
  893. _state.UnhealthyMemberNumber = 1;
  894. _state.UnhealthyMemberState = FtMemberOrphaned;
  895. changed = TRUE;
  896. FtpLogError(_rootExtension, QueryLogicalDiskId(),
  897. FT_MIRROR_STATE_CORRUPTION,
  898. STATUS_SUCCESS, 0);
  899. }
  900. }
  901. }
  902. if (changed) {
  903. PropogateStateChanges(NULL, NULL);
  904. }
  905. }
  906. PDEVICE_OBJECT
  907. MIRROR::GetLeftmostPartitionObject(
  908. )
  909. {
  910. KIRQL irql;
  911. USHORT memberNumber;
  912. PFT_VOLUME vol;
  913. KeAcquireSpinLock(&_spinLock, &irql);
  914. if (_state.UnhealthyMemberState != FtMemberHealthy &&
  915. _state.UnhealthyMemberNumber == 0) {
  916. memberNumber = 1;
  917. } else {
  918. memberNumber = 0;
  919. }
  920. KeReleaseSpinLock(&_spinLock, irql);
  921. vol = GetMember(memberNumber);
  922. if (!vol) {
  923. return NULL;
  924. }
  925. return vol->GetLeftmostPartitionObject();
  926. }
  927. BOOLEAN
  928. MIRROR::QueryVolumeState(
  929. IN PFT_VOLUME Volume,
  930. OUT PFT_MEMBER_STATE State
  931. )
  932. /*++
  933. Routine Description:
  934. This routine returns the state of the given volume considered as a
  935. member of this volume.
  936. Arguments:
  937. Volume - Supplies the volume to query the state for.
  938. State - Returns the state.
  939. Return Value:
  940. FALSE - The given Volume is not a member of this volume.
  941. TRUE - The state was successfully computed.
  942. --*/
  943. {
  944. USHORT n, i;
  945. PFT_VOLUME vol;
  946. KIRQL irql;
  947. FT_MEMBER_STATE state;
  948. n = QueryNumMembers();
  949. for (i = 0; i < n; i++) {
  950. vol = GetMember(i);
  951. if (!vol) {
  952. continue;
  953. }
  954. if (!vol->QueryVolumeState(Volume, State)) {
  955. continue;
  956. }
  957. KeAcquireSpinLock(&_spinLock, &irql);
  958. state = QueryMemberState(i);
  959. if (state != FtMemberHealthy) {
  960. if (*State != FtMemberOrphaned) {
  961. *State = state;
  962. }
  963. }
  964. KeReleaseSpinLock(&_spinLock, irql);
  965. return TRUE;
  966. }
  967. return FALSE;
  968. }
  969. BOOLEAN
  970. MIRROR::SetMemberState(
  971. IN USHORT MemberNumber,
  972. IN FT_MEMBER_STATE MemberState
  973. )
  974. /*++
  975. Routine Description:
  976. This routine sets the given member to the given state.
  977. Arguments:
  978. MemberNumber - Supplies the member number.
  979. MemberState - Supplies the member state.
  980. Return Value:
  981. FALSE - There was no state change.
  982. TRUE - A state change took place.
  983. Notes:
  984. The caller must be holding the class spin lock.
  985. --*/
  986. {
  987. if (_state.UnhealthyMemberState == FtMemberHealthy) {
  988. if (MemberNumber >= QueryNumMembers()) {
  989. KeBugCheckEx(FTDISK_INTERNAL_ERROR, (ULONG_PTR) this,
  990. MemberNumber, MemberState, 0);
  991. }
  992. _state.UnhealthyMemberNumber = MemberNumber;
  993. _state.UnhealthyMemberState = MemberState;
  994. return TRUE;
  995. }
  996. if (_state.UnhealthyMemberNumber == MemberNumber &&
  997. _state.UnhealthyMemberState != MemberState) {
  998. _state.UnhealthyMemberState = MemberState;
  999. return TRUE;
  1000. }
  1001. return FALSE;
  1002. }
  1003. VOID
  1004. MirrorTransferCompletionRoutine(
  1005. IN PTRANSFER_PACKET TransferPacket
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. Completion routine for MIRROR::Transfer function.
  1010. Arguments:
  1011. TransferPacket - Supplies the transfer packet.
  1012. Return Value:
  1013. None.
  1014. --*/
  1015. {
  1016. PMIRROR_TP transferPacket = (PMIRROR_TP) TransferPacket;
  1017. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  1018. NTSTATUS status = transferPacket->IoStatus.Status;
  1019. PMIRROR t = transferPacket->Mirror;
  1020. KIRQL irql;
  1021. LONG count;
  1022. BOOLEAN b;
  1023. PMIRROR_TP otherPacket;
  1024. // Check for the read completion case.
  1025. if (transferPacket->ReadPacket) {
  1026. KeAcquireSpinLock(&t->_spinLock, &irql);
  1027. t->_requestCount[transferPacket->WhichMember]--;
  1028. KeReleaseSpinLock(&t->_spinLock, irql);
  1029. if (!NT_SUCCESS(status) && status != STATUS_VERIFY_REQUIRED) {
  1030. if (FsRtlIsTotalDeviceFailure(status)) {
  1031. // Device failure case.
  1032. KeAcquireSpinLock(&t->_spinLock, &irql);
  1033. b = t->SetMemberState(transferPacket->WhichMember,
  1034. FtMemberOrphaned);
  1035. KeReleaseSpinLock(&t->_spinLock, irql);
  1036. if (b) {
  1037. t->PropogateStateChanges(NULL, NULL);
  1038. t->Notify();
  1039. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  1040. FT_ORPHANING, STATUS_SUCCESS, 4);
  1041. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL,
  1042. NULL);
  1043. }
  1044. if (!transferPacket->OneReadFailed) {
  1045. transferPacket->OneReadFailed = TRUE;
  1046. transferPacket->WhichMember =
  1047. (transferPacket->WhichMember + 1) % 2;
  1048. transferPacket->TargetVolume = t->GetMemberUnprotected(
  1049. transferPacket->WhichMember);
  1050. if (t->_state.UnhealthyMemberNumber !=
  1051. transferPacket->WhichMember) {
  1052. TRANSFER(transferPacket);
  1053. return;
  1054. }
  1055. }
  1056. } else {
  1057. // Bad sector case.
  1058. if (!transferPacket->OneReadFailed) {
  1059. transferPacket->OneReadFailed = TRUE;
  1060. t->Recover(transferPacket);
  1061. return;
  1062. }
  1063. }
  1064. }
  1065. masterPacket->IoStatus = transferPacket->IoStatus;
  1066. masterPacket->CompletionRoutine(masterPacket);
  1067. t->Recycle(transferPacket, TRUE);
  1068. return;
  1069. }
  1070. // This a write or a verify in which two requests may have been sent.
  1071. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  1072. if (NT_SUCCESS(status)) {
  1073. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  1074. masterPacket->IoStatus.Information =
  1075. transferPacket->IoStatus.Information;
  1076. }
  1077. } else {
  1078. if (status == STATUS_VERIFY_REQUIRED) {
  1079. masterPacket->IoStatus.Information = 0;
  1080. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  1081. masterPacket->IoStatus.Status = status;
  1082. }
  1083. } else if (FsRtlIsTotalDeviceFailure(status)) {
  1084. KeAcquireSpinLock(&t->_spinLock, &irql);
  1085. b = t->SetMemberState(transferPacket->WhichMember,
  1086. FtMemberOrphaned);
  1087. KeReleaseSpinLock(&t->_spinLock, irql);
  1088. if (b) {
  1089. t->PropogateStateChanges(NULL, NULL);
  1090. t->Notify();
  1091. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  1092. FT_ORPHANING, STATUS_SUCCESS, 5);
  1093. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  1094. } else {
  1095. masterPacket->IoStatus.Information = 0;
  1096. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  1097. masterPacket->IoStatus.Status = status;
  1098. }
  1099. }
  1100. } else if (!transferPacket->OneReadFailed && transferPacket->Mdl) {
  1101. KeReleaseSpinLock(&masterPacket->SpinLock, irql);
  1102. transferPacket->OneReadFailed = TRUE;
  1103. t->CarefulWrite(transferPacket);
  1104. return;
  1105. } else {
  1106. masterPacket->IoStatus.Information = 0;
  1107. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  1108. masterPacket->IoStatus.Status = status;
  1109. }
  1110. }
  1111. }
  1112. count = --masterPacket->RefCount;
  1113. b = (masterPacket->IrpFlags&SL_FT_SEQUENTIAL_WRITE) ? TRUE : FALSE;
  1114. KeReleaseSpinLock(&masterPacket->SpinLock, irql);
  1115. if (count) {
  1116. if (b) {
  1117. otherPacket = transferPacket->SecondWritePacket;
  1118. otherPacket->CompletionRoutine = MirrorTransferCompletionRoutine;
  1119. TRANSFER(otherPacket);
  1120. }
  1121. } else {
  1122. masterPacket->CompletionRoutine(masterPacket);
  1123. if (transferPacket->SecondWritePacket) {
  1124. t->Recycle(transferPacket->SecondWritePacket, FALSE);
  1125. }
  1126. t->Recycle(transferPacket, TRUE);
  1127. }
  1128. }
  1129. BOOLEAN
  1130. MIRROR::LaunchRead(
  1131. IN OUT PTRANSFER_PACKET TransferPacket,
  1132. IN OUT PMIRROR_TP Packet1
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. This routine lauches the given read transfer packet in parallel accross
  1137. all members using the given mirror transfer packet.
  1138. Arguments:
  1139. TransferPacket - Supplies the transfer packet to launch.
  1140. Packet1 - Supplies a worker transfer packet.
  1141. Return Value:
  1142. FALSE - The read request was not launched.
  1143. TRUE - The read request was launched.
  1144. --*/
  1145. {
  1146. PMIRROR_TP packet;
  1147. KIRQL irql;
  1148. LONG diff;
  1149. LONGLONG seek0, seek1;
  1150. packet = Packet1;
  1151. packet->Mdl = TransferPacket->Mdl;
  1152. packet->OriginalIrp = TransferPacket->OriginalIrp;
  1153. packet->Length = TransferPacket->Length;
  1154. packet->Offset = TransferPacket->Offset;
  1155. packet->CompletionRoutine = MirrorTransferCompletionRoutine;
  1156. packet->Thread = TransferPacket->Thread;
  1157. packet->IrpFlags = TransferPacket->IrpFlags;
  1158. packet->ReadPacket = TransferPacket->ReadPacket;
  1159. packet->MasterPacket = TransferPacket;
  1160. packet->Mirror = this;
  1161. // Determine which member to dispatch this read request to.
  1162. // Balance the load if both members are healthy.
  1163. KeAcquireSpinLock(&_spinLock, &irql);
  1164. if (TransferPacket->SpecialRead) {
  1165. if (TransferPacket->SpecialRead == TP_SPECIAL_READ_PRIMARY) {
  1166. packet->WhichMember = 0;
  1167. } else {
  1168. packet->WhichMember = 1;
  1169. }
  1170. if (QueryMemberState(packet->WhichMember) != FtMemberHealthy) {
  1171. packet->WhichMember = 2;
  1172. }
  1173. } else if (_state.UnhealthyMemberState == FtMemberHealthy) {
  1174. if (!_balancedReads) {
  1175. packet->WhichMember = 0;
  1176. } else {
  1177. diff = _requestCount[1] - _requestCount[0];
  1178. if (diff < -4) {
  1179. packet->WhichMember = 1;
  1180. } else if (diff > 4) {
  1181. packet->WhichMember = 0;
  1182. } else {
  1183. seek0 = _lastPosition[0] - packet->Offset;
  1184. seek1 = _lastPosition[1] - packet->Offset;
  1185. if (seek0 < 0) {
  1186. seek0 = -seek0;
  1187. }
  1188. if (seek1 < 0) {
  1189. seek1 = -seek1;
  1190. }
  1191. if (seek1 < seek0) {
  1192. packet->WhichMember = 1;
  1193. } else {
  1194. packet->WhichMember = 0;
  1195. }
  1196. }
  1197. }
  1198. } else {
  1199. packet->WhichMember = (_state.UnhealthyMemberNumber + 1)%2;
  1200. }
  1201. if (packet->WhichMember < 2) {
  1202. _requestCount[packet->WhichMember]++;
  1203. _lastPosition[packet->WhichMember] = packet->Offset + packet->Length;
  1204. }
  1205. KeReleaseSpinLock(&_spinLock, irql);
  1206. if (packet->WhichMember >= 2) {
  1207. TransferPacket->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  1208. TransferPacket->IoStatus.Information = 0;
  1209. TransferPacket->CompletionRoutine(TransferPacket);
  1210. return FALSE;
  1211. }
  1212. packet->TargetVolume = GetMemberUnprotected(packet->WhichMember);
  1213. TRANSFER(packet);
  1214. return TRUE;
  1215. }
  1216. VOID
  1217. MirrorWritePhase1(
  1218. IN OUT PTRANSFER_PACKET TransferPacket
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. This routine sends down the given transfer packets for a write to
  1223. the volumes.
  1224. Arguments:
  1225. TransferPacket - Supplies the transfer packet.
  1226. Return Value:
  1227. None.
  1228. --*/
  1229. {
  1230. PTRANSFER_PACKET p;
  1231. p = ((PMIRROR_TP) TransferPacket)->SecondWritePacket;
  1232. if (p) {
  1233. p->CompletionRoutine = MirrorTransferCompletionRoutine;
  1234. if (TransferPacket->IrpFlags&SL_FT_SEQUENTIAL_WRITE) {
  1235. TRANSFER(p);
  1236. return;
  1237. }
  1238. TRANSFER(p);
  1239. }
  1240. TransferPacket->CompletionRoutine = MirrorTransferCompletionRoutine;
  1241. TRANSFER(TransferPacket);
  1242. }
  1243. BOOLEAN
  1244. MIRROR::LaunchWrite(
  1245. IN OUT PTRANSFER_PACKET TransferPacket,
  1246. IN OUT PMIRROR_TP Packet1,
  1247. IN OUT PMIRROR_TP Packet2
  1248. )
  1249. /*++
  1250. Routine Description:
  1251. This routine lauches the given write transfer packet in parallel accross
  1252. all members using the given mirror transfer packets.
  1253. Arguments:
  1254. TransferPacket - Supplies the transfer packet to launch.
  1255. Packet1 - Supplies a worker transfer packet.
  1256. Packet2 - Supplies a worker transfer packet.
  1257. Return Value:
  1258. FALSE - The read request was not launched.
  1259. TRUE - The read request was launched.
  1260. --*/
  1261. {
  1262. PMIRROR_TP packet;
  1263. KIRQL irql;
  1264. PFT_VOLUME pri, sec;
  1265. FT_PARTITION_STATE priState, secState;
  1266. LONGLONG rowStart;
  1267. ULONG numRows, length, remainder;
  1268. USHORT source;
  1269. LONG count;
  1270. BOOLEAN b;
  1271. KeInitializeSpinLock(&TransferPacket->SpinLock);
  1272. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  1273. TransferPacket->IoStatus.Information = 0;
  1274. TransferPacket->RefCount = 2;
  1275. // Send down the first request to the primary or to the source
  1276. // if we're doing a regenerate.
  1277. KeAcquireSpinLock(&_spinLock, &irql);
  1278. if (_state.UnhealthyMemberState == FtMemberHealthy) {
  1279. source = 0;
  1280. } else if (_state.UnhealthyMemberState == FtMemberRegenerating) {
  1281. source = (_state.UnhealthyMemberNumber + 1)%2;
  1282. } else {
  1283. TransferPacket->RefCount = 1;
  1284. source = (_state.UnhealthyMemberNumber + 1)%2;
  1285. }
  1286. KeReleaseSpinLock(&_spinLock, irql);
  1287. packet = Packet1;
  1288. packet->Mdl = TransferPacket->Mdl;
  1289. packet->Length = TransferPacket->Length;
  1290. packet->Offset = TransferPacket->Offset;
  1291. packet->CompletionRoutine = MirrorWritePhase1;
  1292. packet->Thread = TransferPacket->Thread;
  1293. packet->IrpFlags = TransferPacket->IrpFlags;
  1294. packet->ReadPacket = TransferPacket->ReadPacket;
  1295. packet->MasterPacket = TransferPacket;
  1296. packet->Mirror = this;
  1297. packet->WhichMember = source;
  1298. packet->SecondWritePacket = NULL;
  1299. packet->TargetVolume = GetMemberUnprotected(packet->WhichMember);
  1300. if (TransferPacket->RefCount == 1) {
  1301. _overlappedIoManager.AcquireIoRegion(packet, TRUE);
  1302. if (Packet2 != _ePacket && Packet2 != _ePacket2) {
  1303. delete Packet2;
  1304. }
  1305. return TRUE;
  1306. }
  1307. packet->SecondWritePacket = Packet2;
  1308. packet = Packet2;
  1309. packet->Mdl = TransferPacket->Mdl;
  1310. packet->Length = TransferPacket->Length;
  1311. packet->Offset = TransferPacket->Offset;
  1312. packet->CompletionRoutine = MirrorWritePhase1;
  1313. packet->Thread = TransferPacket->Thread;
  1314. packet->IrpFlags = TransferPacket->IrpFlags;
  1315. packet->ReadPacket = TransferPacket->ReadPacket;
  1316. packet->MasterPacket = TransferPacket;
  1317. packet->Mirror = this;
  1318. packet->WhichMember = (source + 1)%2;
  1319. packet->SecondWritePacket = Packet1;
  1320. packet->TargetVolume = GetMemberUnprotected(packet->WhichMember);
  1321. _overlappedIoManager.AcquireIoRegion(packet, TRUE);
  1322. return TRUE;
  1323. }
  1324. VOID
  1325. MIRROR::Recycle(
  1326. IN OUT PMIRROR_TP TransferPacket,
  1327. IN BOOLEAN ServiceEmergencyQueue
  1328. )
  1329. /*++
  1330. Routine Description:
  1331. This routine recycles the given transfer packet and services
  1332. the emergency queue if need be.
  1333. Arguments:
  1334. TransferPacket - Supplies the transfer packet.
  1335. ServiceEmergencyQueue - Supplies whether or not to service the
  1336. emergency queue.
  1337. Return Value:
  1338. None.
  1339. --*/
  1340. {
  1341. KIRQL irql;
  1342. PLIST_ENTRY l;
  1343. PTRANSFER_PACKET p;
  1344. PMIRROR_TP packet1, packet2;
  1345. if (TransferPacket != _ePacket &&
  1346. TransferPacket != _ePacket2 &&
  1347. TransferPacket != _eRecoverPacket) {
  1348. delete TransferPacket;
  1349. return;
  1350. }
  1351. TransferPacket->OriginalIrp = NULL;
  1352. TransferPacket->SpecialRead = 0;
  1353. TransferPacket->OneReadFailed = FALSE;
  1354. _overlappedIoManager.ReleaseIoRegion(TransferPacket);
  1355. if (TransferPacket == _eRecoverPacket) {
  1356. MmPrepareMdlForReuse(_eRecoverPacket->PartialMdl);
  1357. KeAcquireSpinLock(&_spinLock, &irql);
  1358. if (IsListEmpty(&_eRecoverPacketQueue)) {
  1359. _eRecoverPacketInUse = FALSE;
  1360. KeReleaseSpinLock(&_spinLock, irql);
  1361. return;
  1362. }
  1363. l = RemoveHeadList(&_eRecoverPacketQueue);
  1364. KeReleaseSpinLock(&_spinLock, irql);
  1365. p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
  1366. p->CompletionRoutine(p);
  1367. return;
  1368. }
  1369. if (!ServiceEmergencyQueue) {
  1370. return;
  1371. }
  1372. for (;;) {
  1373. KeAcquireSpinLock(&_spinLock, &irql);
  1374. if (IsListEmpty(&_ePacketQueue)) {
  1375. _ePacketInUse = FALSE;
  1376. KeReleaseSpinLock(&_spinLock, irql);
  1377. break;
  1378. }
  1379. l = RemoveHeadList(&_ePacketQueue);
  1380. KeReleaseSpinLock(&_spinLock, irql);
  1381. p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
  1382. packet1 = new MIRROR_TP;
  1383. if (packet1 && !TransferPacket->ReadPacket) {
  1384. packet2 = new MIRROR_TP;
  1385. if (!packet2) {
  1386. delete packet1;
  1387. packet1 = NULL;
  1388. }
  1389. } else {
  1390. packet2 = NULL;
  1391. }
  1392. if (!packet1) {
  1393. packet1 = _ePacket;
  1394. packet2 = _ePacket2;
  1395. }
  1396. if (TransferPacket->ReadPacket) {
  1397. if (!LaunchRead(TransferPacket, packet1)) {
  1398. if (packet1 != _ePacket) {
  1399. delete packet1;
  1400. packet1 = NULL;
  1401. }
  1402. }
  1403. } else {
  1404. if (!LaunchWrite(TransferPacket, packet1, packet2)) {
  1405. if (packet1 != _ePacket) {
  1406. delete packet1;
  1407. delete packet2;
  1408. packet1 = NULL;
  1409. }
  1410. }
  1411. }
  1412. if (packet1 == _ePacket) {
  1413. break;
  1414. }
  1415. }
  1416. }
  1417. VOID
  1418. MirrorRecoverPhase8(
  1419. IN OUT PTRANSFER_PACKET TransferPacket
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. This is the completion routine for a single sector read
  1424. of the main member after a write was done to check for
  1425. data integrity.
  1426. Arguments:
  1427. TransferPacket - Supplies the transfer packet.
  1428. Return Value:
  1429. None.
  1430. --*/
  1431. {
  1432. PMIRROR_RECOVER_TP subPacket = (PMIRROR_RECOVER_TP) TransferPacket;
  1433. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  1434. PMIRROR t = masterPacket->Mirror;
  1435. NTSTATUS status = subPacket->IoStatus.Status;
  1436. if (FsRtlIsTotalDeviceFailure(status)) {
  1437. masterPacket->OneReadFailed = FALSE;
  1438. masterPacket->IoStatus = subPacket->IoStatus;
  1439. t->Recycle(subPacket, TRUE);
  1440. masterPacket->CompletionRoutine(masterPacket);
  1441. return;
  1442. }
  1443. if (!NT_SUCCESS(status) ||
  1444. RtlCompareMemory(MmGetSystemAddressForMdl(subPacket->PartialMdl),
  1445. MmGetSystemAddressForMdl(subPacket->VerifyMdl),
  1446. subPacket->Length) != subPacket->Length) {
  1447. masterPacket->IoStatus.Status = STATUS_FT_READ_RECOVERY_FROM_BACKUP;
  1448. FtpLogError(t->_rootExtension,
  1449. subPacket->TargetVolume->QueryLogicalDiskId(),
  1450. FT_SECTOR_FAILURE, status,
  1451. (ULONG) (subPacket->Offset/t->QuerySectorSize()));
  1452. }
  1453. if (subPacket->Offset + subPacket->Length ==
  1454. masterPacket->Offset + masterPacket->Length) {
  1455. t->Recycle(subPacket, TRUE);
  1456. masterPacket->CompletionRoutine(masterPacket);
  1457. return;
  1458. }
  1459. subPacket->Mdl = subPacket->PartialMdl;
  1460. subPacket->Offset += subPacket->Length;
  1461. subPacket->CompletionRoutine = MirrorRecoverPhase2;
  1462. subPacket->ReadPacket = TRUE;
  1463. MmPrepareMdlForReuse(subPacket->Mdl);
  1464. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  1465. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  1466. (ULONG) (subPacket->Offset - masterPacket->Offset),
  1467. subPacket->Length);
  1468. TRANSFER(subPacket);
  1469. }
  1470. VOID
  1471. MirrorRecoverPhase7(
  1472. IN OUT PTRANSFER_PACKET TransferPacket
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. This is the completion routine for a single sector write
  1477. of the main member after a replace sector was done.
  1478. Arguments:
  1479. TransferPacket - Supplies the transfer packet.
  1480. Return Value:
  1481. None.
  1482. --*/
  1483. {
  1484. PMIRROR_RECOVER_TP subPacket = (PMIRROR_RECOVER_TP) TransferPacket;
  1485. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  1486. PMIRROR t = masterPacket->Mirror;
  1487. NTSTATUS status = subPacket->IoStatus.Status;
  1488. if (FsRtlIsTotalDeviceFailure(status)) {
  1489. masterPacket->OneReadFailed = FALSE;
  1490. masterPacket->IoStatus = subPacket->IoStatus;
  1491. t->Recycle(subPacket, TRUE);
  1492. masterPacket->CompletionRoutine(masterPacket);
  1493. return;
  1494. }
  1495. if (!NT_SUCCESS(status)) {
  1496. masterPacket->IoStatus.Status = STATUS_FT_READ_RECOVERY_FROM_BACKUP;
  1497. FtpLogError(t->_rootExtension,
  1498. subPacket->TargetVolume->QueryLogicalDiskId(),
  1499. FT_SECTOR_FAILURE, status,
  1500. (ULONG) (subPacket->Offset/t->QuerySectorSize()));
  1501. if (subPacket->Offset + subPacket->Length ==
  1502. masterPacket->Offset + masterPacket->Length) {
  1503. t->Recycle(subPacket, TRUE);
  1504. masterPacket->CompletionRoutine(masterPacket);
  1505. return;
  1506. }
  1507. subPacket->Mdl = subPacket->PartialMdl;
  1508. subPacket->Offset += subPacket->Length;
  1509. subPacket->CompletionRoutine = MirrorRecoverPhase2;
  1510. subPacket->ReadPacket = TRUE;
  1511. MmPrepareMdlForReuse(subPacket->Mdl);
  1512. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  1513. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  1514. (ULONG) (subPacket->Offset - masterPacket->Offset),
  1515. subPacket->Length);
  1516. TRANSFER(subPacket);
  1517. return;
  1518. }
  1519. subPacket->Mdl = subPacket->VerifyMdl;
  1520. subPacket->CompletionRoutine = MirrorRecoverPhase8;
  1521. subPacket->ReadPacket = TRUE;
  1522. TRANSFER(subPacket);
  1523. }
  1524. VOID
  1525. MirrorRecoverPhase6(
  1526. IN OUT PTRANSFER_PACKET TransferPacket
  1527. )
  1528. /*++
  1529. Routine Description:
  1530. This is the completion routine for a single sector replace
  1531. of the main member.
  1532. Arguments:
  1533. TransferPacket - Supplies the transfer packet.
  1534. Return Value:
  1535. None.
  1536. --*/
  1537. {
  1538. PMIRROR_RECOVER_TP subPacket = (PMIRROR_RECOVER_TP) TransferPacket;
  1539. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  1540. PMIRROR t = masterPacket->Mirror;
  1541. NTSTATUS status = subPacket->IoStatus.Status;
  1542. if (!NT_SUCCESS(status)) {
  1543. masterPacket->IoStatus.Status = STATUS_FT_READ_RECOVERY_FROM_BACKUP;
  1544. FtpLogError(t->_rootExtension,
  1545. subPacket->TargetVolume->QueryLogicalDiskId(),
  1546. FT_SECTOR_FAILURE, status,
  1547. (ULONG) (subPacket->Offset/t->QuerySectorSize()));
  1548. if (subPacket->Offset + subPacket->Length ==
  1549. masterPacket->Offset + masterPacket->Length) {
  1550. t->Recycle(subPacket, TRUE);
  1551. masterPacket->CompletionRoutine(masterPacket);
  1552. return;
  1553. }
  1554. subPacket->Mdl = subPacket->PartialMdl;
  1555. subPacket->Offset += subPacket->Length;
  1556. subPacket->CompletionRoutine = MirrorRecoverPhase2;
  1557. subPacket->ReadPacket = TRUE;
  1558. MmPrepareMdlForReuse(subPacket->Mdl);
  1559. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  1560. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  1561. (ULONG) (subPacket->Offset - masterPacket->Offset),
  1562. subPacket->Length);
  1563. TRANSFER(subPacket);
  1564. return;
  1565. }
  1566. // We were able to relocate the bad sector so now do a write and
  1567. // then read to make sure it's ok.
  1568. subPacket->Mdl = subPacket->PartialMdl;
  1569. subPacket->CompletionRoutine = MirrorRecoverPhase7;
  1570. subPacket->ReadPacket = FALSE;
  1571. TRANSFER(subPacket);
  1572. }
  1573. VOID
  1574. MirrorRecoverPhase5(
  1575. IN OUT PTRANSFER_PACKET TransferPacket
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. This is the completion routine for a single sector read
  1580. of the main member after a successful write to check and
  1581. see if the write was successful.
  1582. Arguments:
  1583. TransferPacket - Supplies the transfer packet.
  1584. Return Value:
  1585. None.
  1586. --*/
  1587. {
  1588. PMIRROR_RECOVER_TP subPacket = (PMIRROR_RECOVER_TP) TransferPacket;
  1589. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  1590. PMIRROR t = masterPacket->Mirror;
  1591. NTSTATUS status = subPacket->IoStatus.Status;
  1592. if (FsRtlIsTotalDeviceFailure(status)) {
  1593. masterPacket->OneReadFailed = FALSE;
  1594. masterPacket->IoStatus = subPacket->IoStatus;
  1595. t->Recycle(subPacket, TRUE);
  1596. masterPacket->CompletionRoutine(masterPacket);
  1597. return;
  1598. }
  1599. if (!NT_SUCCESS(status) ||
  1600. RtlCompareMemory(MmGetSystemAddressForMdl(subPacket->PartialMdl),
  1601. MmGetSystemAddressForMdl(subPacket->VerifyMdl),
  1602. subPacket->Length) != subPacket->Length) {
  1603. subPacket->Mdl = subPacket->PartialMdl;
  1604. subPacket->CompletionRoutine = MirrorRecoverPhase6;
  1605. subPacket->TargetVolume->ReplaceBadSector(subPacket);
  1606. return;
  1607. }
  1608. if (subPacket->Offset + subPacket->Length ==
  1609. masterPacket->Offset + masterPacket->Length) {
  1610. t->Recycle(subPacket, TRUE);
  1611. masterPacket->CompletionRoutine(masterPacket);
  1612. return;
  1613. }
  1614. subPacket->Mdl = subPacket->PartialMdl;
  1615. subPacket->Offset += subPacket->Length;
  1616. subPacket->CompletionRoutine = MirrorRecoverPhase2;
  1617. MmPrepareMdlForReuse(subPacket->Mdl);
  1618. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  1619. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  1620. (ULONG) (subPacket->Offset - masterPacket->Offset),
  1621. subPacket->Length);
  1622. TRANSFER(subPacket);
  1623. }
  1624. VOID
  1625. MirrorRecoverPhase4(
  1626. IN OUT PTRANSFER_PACKET TransferPacket
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This is the completion routine for a single sector write
  1631. of the main member.
  1632. Arguments:
  1633. TransferPacket - Supplies the transfer packet.
  1634. Return Value:
  1635. None.
  1636. --*/
  1637. {
  1638. PMIRROR_RECOVER_TP subPacket = (PMIRROR_RECOVER_TP) TransferPacket;
  1639. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  1640. PMIRROR t = masterPacket->Mirror;
  1641. NTSTATUS status = subPacket->IoStatus.Status;
  1642. if (FsRtlIsTotalDeviceFailure(status)) {
  1643. masterPacket->OneReadFailed = FALSE;
  1644. masterPacket->IoStatus = subPacket->IoStatus;
  1645. t->Recycle(subPacket, TRUE);
  1646. masterPacket->CompletionRoutine(masterPacket);
  1647. return;
  1648. }
  1649. if (!NT_SUCCESS(status)) {
  1650. subPacket->CompletionRoutine = MirrorRecoverPhase6;
  1651. subPacket->TargetVolume->ReplaceBadSector(subPacket);
  1652. return;
  1653. }
  1654. // Write was successful so try a read and then compare.
  1655. subPacket->Mdl = subPacket->VerifyMdl;
  1656. subPacket->CompletionRoutine = MirrorRecoverPhase5;
  1657. subPacket->ReadPacket = TRUE;
  1658. TRANSFER(subPacket);
  1659. }
  1660. VOID
  1661. MirrorRecoverPhase3(
  1662. IN OUT PTRANSFER_PACKET TransferPacket
  1663. )
  1664. /*++
  1665. Routine Description:
  1666. This is the completion routine for a single sector read
  1667. of the other member.
  1668. Arguments:
  1669. TransferPacket - Supplies the transfer packet.
  1670. Return Value:
  1671. None.
  1672. --*/
  1673. {
  1674. PMIRROR_RECOVER_TP subPacket = (PMIRROR_RECOVER_TP) TransferPacket;
  1675. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  1676. PMIRROR t = masterPacket->Mirror;
  1677. NTSTATUS status = subPacket->IoStatus.Status;
  1678. KIRQL irql;
  1679. BOOLEAN b;
  1680. if (!NT_SUCCESS(status)) {
  1681. if (FsRtlIsTotalDeviceFailure(status) &&
  1682. status != STATUS_VERIFY_REQUIRED) {
  1683. masterPacket->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
  1684. masterPacket->IoStatus.Information = 0;
  1685. KeAcquireSpinLock(&t->_spinLock, &irql);
  1686. b = t->SetMemberState(subPacket->WhichMember, FtMemberOrphaned);
  1687. KeReleaseSpinLock(&t->_spinLock, irql);
  1688. if (b) {
  1689. t->PropogateStateChanges(NULL, NULL);
  1690. t->Notify();
  1691. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  1692. FT_ORPHANING, STATUS_SUCCESS, 6);
  1693. IoRaiseInformationalHardError(STATUS_FT_ORPHANING, NULL, NULL);
  1694. }
  1695. } else {
  1696. masterPacket->IoStatus = subPacket->IoStatus;
  1697. if (status != STATUS_VERIFY_REQUIRED) {
  1698. FtpLogError(t->_rootExtension, t->QueryLogicalDiskId(),
  1699. FT_DOUBLE_FAILURE, status,
  1700. (ULONG) (subPacket->Offset/t->QuerySectorSize()));
  1701. }
  1702. }
  1703. t->Recycle(subPacket, TRUE);
  1704. masterPacket->CompletionRoutine(masterPacket);
  1705. return;
  1706. }
  1707. // We have the data required in the subpacket partial mdl.
  1708. // Try writting it back to where the read failed and see
  1709. // if the sector just fixes itself.
  1710. subPacket->WhichMember = (subPacket->WhichMember + 1)%2;
  1711. subPacket->CompletionRoutine = MirrorRecoverPhase4;
  1712. subPacket->TargetVolume = t->GetMemberUnprotected(subPacket->WhichMember);
  1713. subPacket->ReadPacket = FALSE;
  1714. TRANSFER(subPacket);
  1715. }
  1716. VOID
  1717. MirrorRecoverPhase2(
  1718. IN OUT PTRANSFER_PACKET TransferPacket
  1719. )
  1720. /*++
  1721. Routine Description:
  1722. This is the completion routine for a single sector transfer
  1723. that is part of a larger recover operation.
  1724. Arguments:
  1725. TransferPacket - Supplies the transfer packet.
  1726. Return Value:
  1727. None.
  1728. --*/
  1729. {
  1730. PMIRROR_RECOVER_TP subPacket = (PMIRROR_RECOVER_TP) TransferPacket;
  1731. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  1732. PMIRROR t = masterPacket->Mirror;
  1733. NTSTATUS status = subPacket->IoStatus.Status;
  1734. KIRQL irql;
  1735. if (FsRtlIsTotalDeviceFailure(status)) {
  1736. masterPacket->OneReadFailed = FALSE;
  1737. masterPacket->IoStatus = subPacket->IoStatus;
  1738. t->Recycle(subPacket, TRUE);
  1739. masterPacket->CompletionRoutine(masterPacket);
  1740. return;
  1741. }
  1742. if (NT_SUCCESS(status)) {
  1743. if (subPacket->Offset + subPacket->Length ==
  1744. masterPacket->Offset + masterPacket->Length) {
  1745. t->Recycle(subPacket, TRUE);
  1746. masterPacket->CompletionRoutine(masterPacket);
  1747. return;
  1748. }
  1749. subPacket->Offset += subPacket->Length;
  1750. MmPrepareMdlForReuse(subPacket->Mdl);
  1751. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  1752. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  1753. (ULONG) (subPacket->Offset - masterPacket->Offset),
  1754. subPacket->Length);
  1755. TRANSFER(subPacket);
  1756. return;
  1757. }
  1758. // This read sector failed from a bad sector error. Try
  1759. // reading the data from the other member.
  1760. subPacket->WhichMember = (subPacket->WhichMember + 1)%2;
  1761. subPacket->TargetVolume = t->GetMemberUnprotected(subPacket->WhichMember);
  1762. KeAcquireSpinLock(&t->_spinLock, &irql);
  1763. if (t->QueryMemberState(subPacket->WhichMember) != FtMemberHealthy) {
  1764. KeReleaseSpinLock(&t->_spinLock, irql);
  1765. masterPacket->IoStatus = subPacket->IoStatus;
  1766. t->Recycle(subPacket, TRUE);
  1767. masterPacket->CompletionRoutine(masterPacket);
  1768. return;
  1769. }
  1770. KeReleaseSpinLock(&t->_spinLock, irql);
  1771. subPacket->CompletionRoutine = MirrorRecoverPhase3;
  1772. TRANSFER(subPacket);
  1773. }
  1774. VOID
  1775. MirrorRecoverEmergencyCompletion(
  1776. IN OUT PTRANSFER_PACKET TransferPacket
  1777. )
  1778. /*++
  1779. Routine Description:
  1780. This routine is the completion for use of the emergency recover packet
  1781. in a recover operation.
  1782. Arguments:
  1783. TransferPacket - Supplies the transfer packet.
  1784. Return Value:
  1785. None.
  1786. --*/
  1787. {
  1788. PMIRROR_TP transferPacket = (PMIRROR_TP) TransferPacket;
  1789. PMIRROR t = transferPacket->Mirror;
  1790. PMIRROR_RECOVER_TP subPacket = t->_eRecoverPacket;
  1791. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  1792. subPacket->Mdl = subPacket->PartialMdl;
  1793. IoBuildPartialMdl(transferPacket->Mdl, subPacket->Mdl,
  1794. MmGetMdlVirtualAddress(transferPacket->Mdl),
  1795. t->QuerySectorSize());
  1796. subPacket->Length = t->QuerySectorSize();
  1797. subPacket->Offset = transferPacket->Offset;
  1798. subPacket->CompletionRoutine = MirrorRecoverPhase2;
  1799. subPacket->TargetVolume = transferPacket->TargetVolume;
  1800. subPacket->Thread = transferPacket->Thread;
  1801. subPacket->IrpFlags = transferPacket->IrpFlags;
  1802. subPacket->ReadPacket = TRUE;
  1803. subPacket->MasterPacket = transferPacket;
  1804. subPacket->Mirror = t;
  1805. subPacket->WhichMember = transferPacket->WhichMember;
  1806. TRANSFER(subPacket);
  1807. }
  1808. VOID
  1809. MirrorRecoverPhase1(
  1810. IN OUT PTRANSFER_PACKET TransferPacket
  1811. )
  1812. /*++
  1813. Routine Description:
  1814. This is the completion routine for an acquire io region
  1815. to a recover operation.
  1816. Arguments:
  1817. TransferPacket - Supplies the transfer packet.
  1818. Return Value:
  1819. None.
  1820. --*/
  1821. {
  1822. PMIRROR_TP transferPacket = (PMIRROR_TP) TransferPacket;
  1823. PMIRROR t = transferPacket->Mirror;
  1824. PMIRROR_RECOVER_TP subPacket;
  1825. KIRQL irql;
  1826. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  1827. transferPacket->IoStatus.Status = STATUS_SUCCESS;
  1828. transferPacket->IoStatus.Information = transferPacket->Length;
  1829. subPacket = new MIRROR_RECOVER_TP;
  1830. if (subPacket && !subPacket->AllocateMdls(t->QuerySectorSize())) {
  1831. delete subPacket;
  1832. subPacket = NULL;
  1833. }
  1834. if (!subPacket) {
  1835. KeAcquireSpinLock(&t->_spinLock, &irql);
  1836. if (t->_eRecoverPacketInUse) {
  1837. transferPacket->SavedCompletionRoutine =
  1838. transferPacket->CompletionRoutine;
  1839. transferPacket->CompletionRoutine = MirrorRecoverEmergencyCompletion;
  1840. InsertTailList(&t->_eRecoverPacketQueue, &transferPacket->QueueEntry);
  1841. KeReleaseSpinLock(&t->_spinLock, irql);
  1842. return;
  1843. }
  1844. t->_eRecoverPacketInUse = TRUE;
  1845. KeReleaseSpinLock(&t->_spinLock, irql);
  1846. subPacket = t->_eRecoverPacket;
  1847. }
  1848. subPacket->Mdl = subPacket->PartialMdl;
  1849. IoBuildPartialMdl(transferPacket->Mdl, subPacket->Mdl,
  1850. MmGetMdlVirtualAddress(transferPacket->Mdl),
  1851. t->QuerySectorSize());
  1852. subPacket->Length = t->QuerySectorSize();
  1853. subPacket->Offset = transferPacket->Offset;
  1854. subPacket->CompletionRoutine = MirrorRecoverPhase2;
  1855. subPacket->TargetVolume = transferPacket->TargetVolume;
  1856. subPacket->Thread = transferPacket->Thread;
  1857. subPacket->IrpFlags = transferPacket->IrpFlags;
  1858. subPacket->ReadPacket = TRUE;
  1859. subPacket->MasterPacket = transferPacket;
  1860. subPacket->Mirror = t;
  1861. subPacket->WhichMember = transferPacket->WhichMember;
  1862. TRANSFER(subPacket);
  1863. }
  1864. VOID
  1865. MIRROR::Recover(
  1866. IN OUT PMIRROR_TP TransferPacket
  1867. )
  1868. /*++
  1869. Routine Description:
  1870. This routine attempts the given read packet sector by sector. Every
  1871. sector that fails to read because of a bad sector error is retried
  1872. on the other member and then the good data is written back to the
  1873. failed sector if possible.
  1874. Arguments:
  1875. TransferPacket - Supplies the transfer packet.
  1876. Return Value:
  1877. None.
  1878. --*/
  1879. {
  1880. ASSERT(TransferPacket->ReadPacket);
  1881. TransferPacket->SavedCompletionRoutine = TransferPacket->CompletionRoutine;
  1882. TransferPacket->CompletionRoutine = MirrorRecoverPhase1;
  1883. _overlappedIoManager.AcquireIoRegion(TransferPacket, TRUE);
  1884. }
  1885. VOID
  1886. MirrorMaxTransferCompletionRoutine(
  1887. IN OUT PTRANSFER_PACKET TransferPacket
  1888. )
  1889. /*++
  1890. Routine Description:
  1891. This is the completion routine for a sector transfer subordinate
  1892. to a MAX transfer operation.
  1893. Arguments:
  1894. TransferPacket - Supplies the subordinate transfer packet.
  1895. Return Value:
  1896. None.
  1897. --*/
  1898. {
  1899. PMIRROR_RECOVER_TP subPacket = (PMIRROR_RECOVER_TP) TransferPacket;
  1900. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  1901. PMIRROR t = masterPacket->Mirror;
  1902. NTSTATUS status = subPacket->IoStatus.Status;
  1903. if (FsRtlIsTotalDeviceFailure(status)) {
  1904. masterPacket->IoStatus = subPacket->IoStatus;
  1905. t->Recycle(subPacket, TRUE);
  1906. masterPacket->CompletionRoutine(masterPacket);
  1907. return;
  1908. }
  1909. if (subPacket->Offset + subPacket->Length ==
  1910. masterPacket->Offset + masterPacket->Length) {
  1911. t->Recycle(subPacket, TRUE);
  1912. masterPacket->CompletionRoutine(masterPacket);
  1913. return;
  1914. }
  1915. subPacket->Offset += subPacket->Length;
  1916. MmPrepareMdlForReuse(subPacket->Mdl);
  1917. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  1918. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  1919. (ULONG) (subPacket->Offset - masterPacket->Offset),
  1920. subPacket->Length);
  1921. TRANSFER(subPacket);
  1922. }
  1923. VOID
  1924. MirrorMaxTransferEmergencyCompletion(
  1925. IN OUT PTRANSFER_PACKET TransferPacket
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. This routine is the completion for use of the emergency recover packet
  1930. in a max transfer operation.
  1931. Arguments:
  1932. TransferPacket - Supplies the transfer packet.
  1933. Return Value:
  1934. None.
  1935. --*/
  1936. {
  1937. PMIRROR_TP transferPacket = (PMIRROR_TP) TransferPacket;
  1938. PMIRROR t = transferPacket->Mirror;
  1939. PMIRROR_RECOVER_TP subPacket = t->_eRecoverPacket;
  1940. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  1941. subPacket->Mdl = subPacket->PartialMdl;
  1942. IoBuildPartialMdl(transferPacket->Mdl, subPacket->Mdl,
  1943. MmGetMdlVirtualAddress(transferPacket->Mdl),
  1944. t->QuerySectorSize());
  1945. subPacket->Length = t->QuerySectorSize();
  1946. subPacket->Offset = transferPacket->Offset;
  1947. subPacket->CompletionRoutine = MirrorMaxTransferCompletionRoutine;
  1948. subPacket->TargetVolume = transferPacket->TargetVolume;
  1949. subPacket->Thread = transferPacket->Thread;
  1950. subPacket->IrpFlags = transferPacket->IrpFlags;
  1951. subPacket->ReadPacket = transferPacket->ReadPacket;
  1952. subPacket->MasterPacket = transferPacket;
  1953. subPacket->Mirror = t;
  1954. subPacket->WhichMember = transferPacket->WhichMember;
  1955. TRANSFER(subPacket);
  1956. }
  1957. VOID
  1958. MIRROR::MaxTransfer(
  1959. IN OUT PMIRROR_TP TransferPacket
  1960. )
  1961. /*++
  1962. Routine Description:
  1963. This routine transfers the maximum possible subset of the given transfer
  1964. by doing it one sector at a time.
  1965. Arguments:
  1966. TransferPacket - Supplies the transfer packet.
  1967. Return Value:
  1968. None.
  1969. --*/
  1970. {
  1971. PMIRROR_RECOVER_TP subPacket;
  1972. KIRQL irql;
  1973. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  1974. TransferPacket->IoStatus.Information = TransferPacket->Length;
  1975. subPacket = new MIRROR_RECOVER_TP;
  1976. if (subPacket && !subPacket->AllocateMdls(QuerySectorSize())) {
  1977. delete subPacket;
  1978. subPacket = NULL;
  1979. }
  1980. if (!subPacket) {
  1981. KeAcquireSpinLock(&_spinLock, &irql);
  1982. if (_eRecoverPacketInUse) {
  1983. TransferPacket->SavedCompletionRoutine =
  1984. TransferPacket->CompletionRoutine;
  1985. TransferPacket->CompletionRoutine = MirrorMaxTransferEmergencyCompletion;
  1986. InsertTailList(&_eRecoverPacketQueue, &TransferPacket->QueueEntry);
  1987. KeReleaseSpinLock(&_spinLock, irql);
  1988. return;
  1989. }
  1990. _eRecoverPacketInUse = TRUE;
  1991. KeReleaseSpinLock(&_spinLock, irql);
  1992. subPacket = _eRecoverPacket;
  1993. }
  1994. subPacket->Mdl = subPacket->PartialMdl;
  1995. IoBuildPartialMdl(TransferPacket->Mdl, subPacket->Mdl,
  1996. MmGetMdlVirtualAddress(TransferPacket->Mdl),
  1997. QuerySectorSize());
  1998. subPacket->Length = QuerySectorSize();
  1999. subPacket->Offset = TransferPacket->Offset;
  2000. subPacket->CompletionRoutine = MirrorMaxTransferCompletionRoutine;
  2001. subPacket->TargetVolume = TransferPacket->TargetVolume;
  2002. subPacket->Thread = TransferPacket->Thread;
  2003. subPacket->IrpFlags = TransferPacket->IrpFlags;
  2004. subPacket->ReadPacket = TransferPacket->ReadPacket;
  2005. subPacket->MasterPacket = TransferPacket;
  2006. subPacket->Mirror = this;
  2007. subPacket->WhichMember = TransferPacket->WhichMember;
  2008. TRANSFER(subPacket);
  2009. }
  2010. class FTP_MIRROR_STATE_WORK_ITEM : public WORK_QUEUE_ITEM {
  2011. public:
  2012. FT_COMPLETION_ROUTINE CompletionRoutine;
  2013. PVOID Context;
  2014. PMIRROR Mirror;
  2015. };
  2016. typedef FTP_MIRROR_STATE_WORK_ITEM* PFTP_MIRROR_STATE_WORK_ITEM;
  2017. VOID
  2018. MirrorPropogateStateChangesWorker(
  2019. IN PVOID Context
  2020. )
  2021. /*++
  2022. Routine Description:
  2023. This routine is a worker thread routine for propogating state changes.
  2024. Arguments:
  2025. Mirror - Supplies a pointer to the mirror object.
  2026. Return Value:
  2027. None.
  2028. --*/
  2029. {
  2030. PFTP_MIRROR_STATE_WORK_ITEM context = (PFTP_MIRROR_STATE_WORK_ITEM) Context;
  2031. PMIRROR t = context->Mirror;
  2032. KIRQL irql;
  2033. FT_MIRROR_AND_SWP_STATE_INFORMATION state;
  2034. NTSTATUS status;
  2035. FtpAcquire(t->_rootExtension);
  2036. KeAcquireSpinLock(&t->_spinLock, &irql);
  2037. RtlCopyMemory(&state, &t->_state, sizeof(state));
  2038. KeReleaseSpinLock(&t->_spinLock, irql);
  2039. status = t->_diskInfoSet->WriteStateInformation(t->QueryLogicalDiskId(),
  2040. &state, sizeof(state));
  2041. FtpRelease(t->_rootExtension);
  2042. if (context->CompletionRoutine) {
  2043. context->CompletionRoutine(context->Context, status);
  2044. }
  2045. }
  2046. VOID
  2047. MIRROR::PropogateStateChanges(
  2048. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  2049. IN PVOID Context
  2050. )
  2051. /*++
  2052. Routine Description:
  2053. This routine propogates the changes in the local memory state to
  2054. the on disk state.
  2055. Arguments:
  2056. CompletionRoutine - Supplies the completion routine.
  2057. Context - Supplies the completion routine context.
  2058. Return Value:
  2059. None.
  2060. --*/
  2061. {
  2062. PFTP_MIRROR_STATE_WORK_ITEM workItem;
  2063. workItem = (PFTP_MIRROR_STATE_WORK_ITEM)
  2064. ExAllocatePool(NonPagedPool,
  2065. sizeof(FTP_MIRROR_STATE_WORK_ITEM));
  2066. if (!workItem) {
  2067. return;
  2068. }
  2069. ExInitializeWorkItem(workItem, MirrorPropogateStateChangesWorker, workItem);
  2070. workItem->CompletionRoutine = CompletionRoutine;
  2071. workItem->Context = Context;
  2072. workItem->Mirror = this;
  2073. FtpQueueWorkItem(_rootExtension, workItem);
  2074. }
  2075. VOID
  2076. MirrorCarefulWritePhase2(
  2077. IN OUT PTRANSFER_PACKET TransferPacket
  2078. )
  2079. /*++
  2080. Routine Description:
  2081. This is the completion routine a sector replacement
  2082. for a careful write operation.
  2083. Arguments:
  2084. TransferPacket - Supplies the subordinate transfer packet.
  2085. Return Value:
  2086. None.
  2087. --*/
  2088. {
  2089. PMIRROR_TP subPacket = (PMIRROR_TP) TransferPacket;
  2090. subPacket->CompletionRoutine = MirrorCarefulWritePhase1;
  2091. TRANSFER(subPacket);
  2092. }
  2093. VOID
  2094. MirrorCarefulWritePhase1(
  2095. IN OUT PTRANSFER_PACKET TransferPacket
  2096. )
  2097. /*++
  2098. Routine Description:
  2099. This is the completion routine a first attempt of a single sector write
  2100. for a careful write operation.
  2101. Arguments:
  2102. TransferPacket - Supplies the subordinate transfer packet.
  2103. Return Value:
  2104. None.
  2105. --*/
  2106. {
  2107. PMIRROR_TP subPacket = (PMIRROR_TP) TransferPacket;
  2108. NTSTATUS status = subPacket->IoStatus.Status;
  2109. PMIRROR_TP masterPacket = (PMIRROR_TP) subPacket->MasterPacket;
  2110. PMIRROR t = subPacket->Mirror;
  2111. if (FsRtlIsTotalDeviceFailure(status)) {
  2112. masterPacket->IoStatus = subPacket->IoStatus;
  2113. masterPacket->CompletionRoutine(masterPacket);
  2114. t->Recycle(subPacket, TRUE);
  2115. return;
  2116. }
  2117. if (!NT_SUCCESS(status)) {
  2118. if (!subPacket->OneReadFailed) {
  2119. subPacket->CompletionRoutine = MirrorCarefulWritePhase2;
  2120. subPacket->OneReadFailed = TRUE;
  2121. subPacket->TargetVolume->ReplaceBadSector(subPacket);
  2122. return;
  2123. }
  2124. masterPacket->IoStatus = subPacket->IoStatus;
  2125. }
  2126. if (masterPacket->Offset + masterPacket->Length ==
  2127. subPacket->Offset + subPacket->Length) {
  2128. masterPacket->CompletionRoutine(masterPacket);
  2129. t->Recycle(subPacket, TRUE);
  2130. return;
  2131. }
  2132. subPacket->Offset += subPacket->Length;
  2133. MmPrepareMdlForReuse(subPacket->Mdl);
  2134. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  2135. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  2136. (ULONG) (subPacket->Offset - masterPacket->Offset),
  2137. subPacket->Length);
  2138. subPacket->OneReadFailed = FALSE;
  2139. TRANSFER(subPacket);
  2140. }
  2141. VOID
  2142. MirrorCarefulWriteEmergencyCompletion(
  2143. IN OUT PTRANSFER_PACKET TransferPacket
  2144. )
  2145. /*++
  2146. Routine Description:
  2147. This routine is the completion for use of the emergency recover packet
  2148. in a careful write operation.
  2149. Arguments:
  2150. TransferPacket - Supplies the transfer packet.
  2151. Return Value:
  2152. None.
  2153. --*/
  2154. {
  2155. PMIRROR_TP transferPacket = (PMIRROR_TP) TransferPacket;
  2156. PMIRROR t = transferPacket->Mirror;
  2157. PMIRROR_RECOVER_TP subPacket = t->_eRecoverPacket;
  2158. transferPacket->CompletionRoutine = transferPacket->SavedCompletionRoutine;
  2159. subPacket->Mdl = subPacket->PartialMdl;
  2160. IoBuildPartialMdl(transferPacket->Mdl, subPacket->Mdl,
  2161. MmGetMdlVirtualAddress(transferPacket->Mdl),
  2162. t->QuerySectorSize());
  2163. subPacket->Length = t->QuerySectorSize();
  2164. subPacket->Offset = transferPacket->Offset;
  2165. subPacket->CompletionRoutine = MirrorCarefulWritePhase1;
  2166. subPacket->TargetVolume = transferPacket->TargetVolume;
  2167. subPacket->Thread = transferPacket->Thread;
  2168. subPacket->IrpFlags = transferPacket->IrpFlags;
  2169. subPacket->ReadPacket = FALSE;
  2170. subPacket->MasterPacket = transferPacket;
  2171. subPacket->Mirror = t;
  2172. subPacket->WhichMember = transferPacket->WhichMember;
  2173. subPacket->OneReadFailed = FALSE;
  2174. TRANSFER(subPacket);
  2175. }
  2176. VOID
  2177. MIRROR::CarefulWrite(
  2178. IN OUT PMIRROR_TP TransferPacket
  2179. )
  2180. /*++
  2181. Routine Description:
  2182. This routine goes through the transfer packet sector by sector
  2183. and fixes write failures when possible.
  2184. Arguments:
  2185. TransferPacket - Supplies the transfer packet.
  2186. Return Value:
  2187. None.
  2188. --*/
  2189. {
  2190. PMIRROR_RECOVER_TP subPacket;
  2191. KIRQL irql;
  2192. ASSERT(!TransferPacket->ReadPacket);
  2193. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  2194. TransferPacket->IoStatus.Information = TransferPacket->Length;
  2195. subPacket = new MIRROR_RECOVER_TP;
  2196. if (subPacket && !subPacket->AllocateMdls(QuerySectorSize())) {
  2197. delete subPacket;
  2198. subPacket = NULL;
  2199. }
  2200. if (!subPacket) {
  2201. KeAcquireSpinLock(&_spinLock, &irql);
  2202. if (_eRecoverPacketInUse) {
  2203. TransferPacket->SavedCompletionRoutine =
  2204. TransferPacket->CompletionRoutine;
  2205. TransferPacket->CompletionRoutine = MirrorCarefulWriteEmergencyCompletion;
  2206. InsertTailList(&_eRecoverPacketQueue, &TransferPacket->QueueEntry);
  2207. KeReleaseSpinLock(&_spinLock, irql);
  2208. return;
  2209. }
  2210. _eRecoverPacketInUse = TRUE;
  2211. KeReleaseSpinLock(&_spinLock, irql);
  2212. subPacket = _eRecoverPacket;
  2213. }
  2214. subPacket->Mdl = subPacket->PartialMdl;
  2215. IoBuildPartialMdl(TransferPacket->Mdl, subPacket->Mdl,
  2216. MmGetMdlVirtualAddress(TransferPacket->Mdl),
  2217. QuerySectorSize());
  2218. subPacket->Length = QuerySectorSize();
  2219. subPacket->Offset = TransferPacket->Offset;
  2220. subPacket->CompletionRoutine = MirrorCarefulWritePhase1;
  2221. subPacket->TargetVolume = TransferPacket->TargetVolume;
  2222. subPacket->Thread = TransferPacket->Thread;
  2223. subPacket->IrpFlags = TransferPacket->IrpFlags;
  2224. subPacket->ReadPacket = FALSE;
  2225. subPacket->MasterPacket = TransferPacket;
  2226. subPacket->Mirror = this;
  2227. subPacket->WhichMember = TransferPacket->WhichMember;
  2228. subPacket->OneReadFailed = FALSE;
  2229. TRANSFER(subPacket);
  2230. }
  2231. NTSTATUS
  2232. MIRROR::QueryPhysicalOffsets(
  2233. IN LONGLONG LogicalOffset,
  2234. OUT PVOLUME_PHYSICAL_OFFSET* PhysicalOffsets,
  2235. OUT PULONG NumberOfPhysicalOffsets
  2236. )
  2237. /*++
  2238. Routine Description:
  2239. This routine returns physical disk and offset for a given volume
  2240. logical offset.
  2241. Arguments:
  2242. LogicalOffset - Supplies the logical offset
  2243. PhysicalOffsets - Returns the physical offsets
  2244. NumberOfPhysicalOffsets - Returns the number of physical offsets
  2245. Return Value:
  2246. NTSTATUS
  2247. --*/
  2248. {
  2249. PFT_VOLUME vol;
  2250. KIRQL irql;
  2251. USHORT n, i, numberOfArrays = 0;
  2252. PVOLUME_PHYSICAL_OFFSET* arrayOfArrays;
  2253. PULONG arrayOfSizes;
  2254. ULONG currentSize = 0;
  2255. NTSTATUS status;
  2256. FT_MEMBER_STATE memberState;
  2257. if (LogicalOffset < 0 ||
  2258. _volumeSize <= LogicalOffset) {
  2259. return STATUS_INVALID_PARAMETER;
  2260. }
  2261. n = QueryNumMembers();
  2262. arrayOfArrays = (PVOLUME_PHYSICAL_OFFSET*) ExAllocatePool(PagedPool, n*sizeof(PVOLUME_PHYSICAL_OFFSET));
  2263. if (!arrayOfArrays) {
  2264. return STATUS_INSUFFICIENT_RESOURCES;
  2265. }
  2266. arrayOfSizes = (PULONG) ExAllocatePool(PagedPool, n*sizeof(ULONG));
  2267. if (!arrayOfSizes) {
  2268. return STATUS_INSUFFICIENT_RESOURCES;
  2269. }
  2270. for (i = 0; i < n; i++) {
  2271. vol = GetMember(i);
  2272. if (!vol) {
  2273. continue;
  2274. }
  2275. KeAcquireSpinLock(&_spinLock, &irql);
  2276. memberState = QueryMemberState(i);
  2277. KeReleaseSpinLock(&_spinLock, irql);
  2278. if (memberState != FtMemberHealthy) {
  2279. continue;
  2280. }
  2281. status = vol->QueryPhysicalOffsets(LogicalOffset, &(arrayOfArrays[numberOfArrays]),
  2282. &(arrayOfSizes[numberOfArrays]) );
  2283. if (NT_SUCCESS(status)) {
  2284. currentSize += arrayOfSizes[numberOfArrays++];
  2285. }
  2286. }
  2287. if (numberOfArrays > 1) {
  2288. *PhysicalOffsets = (PVOLUME_PHYSICAL_OFFSET) ExAllocatePool(PagedPool, currentSize*sizeof(VOLUME_PHYSICAL_OFFSET));
  2289. if (!(*PhysicalOffsets)) {
  2290. for (i = 0; i < numberOfArrays; i++) {
  2291. ExFreePool(arrayOfArrays[i]);
  2292. }
  2293. status = STATUS_INSUFFICIENT_RESOURCES;
  2294. goto cleanup;
  2295. }
  2296. *NumberOfPhysicalOffsets = currentSize;
  2297. currentSize = 0;
  2298. for (i = 0; i < numberOfArrays; i++) {
  2299. RtlCopyMemory(&((*PhysicalOffsets)[currentSize]), arrayOfArrays[i], arrayOfSizes[i]*sizeof(VOLUME_PHYSICAL_OFFSET));
  2300. currentSize += arrayOfSizes[i];
  2301. ExFreePool(arrayOfArrays[i]);
  2302. }
  2303. status = STATUS_SUCCESS;
  2304. goto cleanup;
  2305. }
  2306. if (numberOfArrays == 1) {
  2307. *PhysicalOffsets = arrayOfArrays[0];
  2308. ASSERT(arrayOfSizes[0] == currentSize);
  2309. *NumberOfPhysicalOffsets = currentSize;
  2310. status = STATUS_SUCCESS;
  2311. goto cleanup;
  2312. }
  2313. ASSERT(numberOfArrays == 0);
  2314. status = STATUS_INVALID_PARAMETER;
  2315. cleanup:
  2316. ExFreePool(arrayOfArrays);
  2317. ExFreePool(arrayOfSizes);
  2318. return status;
  2319. }
  2320. NTSTATUS
  2321. MIRROR::QueryLogicalOffset(
  2322. IN PVOLUME_PHYSICAL_OFFSET PhysicalOffset,
  2323. OUT PLONGLONG LogicalOffset
  2324. )
  2325. /*++
  2326. Routine Description:
  2327. This routine returns the volume logical offset for a given disk number
  2328. and physical offset.
  2329. Arguments:
  2330. PhysicalOffset - Supplies the physical offset
  2331. LogicalOffset - Returns the logical offset
  2332. Return Value:
  2333. NTSTATUS
  2334. --*/
  2335. {
  2336. USHORT n, i;
  2337. LONGLONG logicalOffsetInMember;
  2338. NTSTATUS status;
  2339. PFT_VOLUME vol;
  2340. KIRQL irql;
  2341. FT_MEMBER_STATE memberState;
  2342. n = QueryNumMembers();
  2343. for (i = 0; i < n; i++) {
  2344. vol = GetMember(i);
  2345. if (!vol) {
  2346. continue;
  2347. }
  2348. KeAcquireSpinLock(&_spinLock, &irql);
  2349. memberState = QueryMemberState(i);
  2350. KeReleaseSpinLock(&_spinLock, irql);
  2351. if (memberState != FtMemberHealthy) {
  2352. continue;
  2353. }
  2354. status = vol->QueryLogicalOffset(PhysicalOffset, &logicalOffsetInMember);
  2355. if (NT_SUCCESS(status)) {
  2356. if (_volumeSize <= logicalOffsetInMember) {
  2357. return STATUS_INVALID_PARAMETER;
  2358. }
  2359. *LogicalOffset = logicalOffsetInMember;
  2360. return status;
  2361. }
  2362. }
  2363. return STATUS_INVALID_PARAMETER;
  2364. }
  2365. VOID
  2366. MIRROR::ModifyStateForUser(
  2367. IN OUT PVOID State
  2368. )
  2369. /*++
  2370. Routine Description:
  2371. This routine modifies the state for the user to see, possibly adding
  2372. non-persistant state different than what is stored on disk.
  2373. Arguments:
  2374. State - Supplies and returns the state for the logical disk.
  2375. Return Value:
  2376. None.
  2377. --*/
  2378. {
  2379. KIRQL irql;
  2380. BOOLEAN isDirty;
  2381. PFT_MIRROR_AND_SWP_STATE_INFORMATION state;
  2382. KeAcquireSpinLock(&_spinLock, &irql);
  2383. if (_syncOk && !_stopSyncs) {
  2384. isDirty = FALSE;
  2385. } else {
  2386. isDirty = TRUE;
  2387. }
  2388. KeReleaseSpinLock(&_spinLock, irql);
  2389. if (!isDirty) {
  2390. return;
  2391. }
  2392. state = (PFT_MIRROR_AND_SWP_STATE_INFORMATION) State;
  2393. if (state->UnhealthyMemberState == FtMemberHealthy) {
  2394. state->UnhealthyMemberState = FtMemberRegenerating;
  2395. state->UnhealthyMemberNumber = 1;
  2396. }
  2397. }