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

763 lines
21 KiB

  1. /*++
  2. Copyright (C) 1991-5 Microsoft Corporation
  3. Module Name:
  4. parity.cxx
  5. Abstract:
  6. This module contains code specific to the parity io manager.
  7. The purpose of this module is to help serialize parity updates that
  8. overlaps with each other. This class is used by stripes with parity.
  9. Author:
  10. Norbert Kusters 2-Feb-1995
  11. Environment:
  12. kernel mode only
  13. Notes:
  14. Revision History:
  15. --*/
  16. extern "C" {
  17. #include <ntddk.h>
  18. }
  19. #include <ftdisk.h>
  20. #ifdef ALLOC_PRAGMA
  21. #pragma code_seg("PAGE")
  22. #endif
  23. NTSTATUS
  24. PARITY_IO_MANAGER::Initialize(
  25. IN ULONG BucketSize,
  26. IN ULONG SectorSize
  27. )
  28. /*++
  29. Routine Description:
  30. This routine initializes a parity io manager.
  31. Arguments:
  32. BucketSize - Supplies the bucket size. Any I/O to this class may
  33. not span more than one bucket. In the case of stripes
  34. with parity, the bucket size is the stripe size.
  35. SectorSize - Supplies the sector size.
  36. Return Value:
  37. NTSTATUS
  38. --*/
  39. {
  40. ULONG i;
  41. _numQueues = 256;
  42. _bucketSize = BucketSize;
  43. _sectorSize = SectorSize;
  44. _spinLock = (PKSPIN_LOCK)
  45. ExAllocatePool(NonPagedPool, _numQueues*sizeof(KSPIN_LOCK));
  46. if (!_spinLock) {
  47. return STATUS_INSUFFICIENT_RESOURCES;
  48. }
  49. _ioQueue = (PLIST_ENTRY)
  50. ExAllocatePool(NonPagedPool, _numQueues*sizeof(LIST_ENTRY));
  51. if (!_ioQueue) {
  52. ExFreePool(_spinLock);
  53. _spinLock = NULL;
  54. return STATUS_INSUFFICIENT_RESOURCES;
  55. }
  56. for (i = 0; i < _numQueues; i++) {
  57. KeInitializeSpinLock(&_spinLock[i]);
  58. InitializeListHead(&_ioQueue[i]);
  59. }
  60. _ePacket = new PARITY_TP;
  61. if (_ePacket && !_ePacket->AllocateMdl(_bucketSize)) {
  62. delete _ePacket;
  63. _ePacket = NULL;
  64. }
  65. if (!_ePacket) {
  66. ExFreePool(_spinLock);
  67. _spinLock = NULL;
  68. ExFreePool(_ioQueue);
  69. _ioQueue = NULL;
  70. return STATUS_INSUFFICIENT_RESOURCES;
  71. }
  72. _ePacketInUse = FALSE;
  73. _ePacketQueueBeingServiced = FALSE;
  74. InitializeListHead(&_ePacketQueue);
  75. KeInitializeSpinLock(&_ePacketSpinLock);
  76. return STATUS_SUCCESS;
  77. }
  78. #ifdef ALLOC_PRAGMA
  79. #pragma code_seg("PAGELK")
  80. #endif
  81. VOID
  82. UpdateParityCompletionRoutine(
  83. IN OUT PTRANSFER_PACKET TransferPacket
  84. )
  85. /*++
  86. Routine Description:
  87. This routine is the completion routine for the read request associated
  88. with an (or many) update parity request. This routine gets the
  89. update parity requests in the queue that follow it and smash them into
  90. its buffer and then write the parity block out to disk.
  91. Arguments:
  92. TransferPacket - Supplies the transfer packet.
  93. Return Value:
  94. None.
  95. --*/
  96. {
  97. PPARITY_TP transferPacket = (PPARITY_TP) TransferPacket;
  98. PPARITY_IO_MANAGER t = transferPacket->ParityIoManager;
  99. NTSTATUS status = transferPacket->IoStatus.Status;
  100. ULONG queueNumber;
  101. PLIST_ENTRY q, qq;
  102. PKSPIN_LOCK spin;
  103. KIRQL irql, irql2;
  104. PLIST_ENTRY l;
  105. PPARITY_TP p, packet, ep;
  106. PCHAR target;
  107. ULONG bucketOffset;
  108. PVOID source;
  109. BOOLEAN tpRemoved;
  110. BOOLEAN wasIdle, wasReadPacket;
  111. if (!transferPacket->ReadPacket) {
  112. if (!NT_SUCCESS(status) && !transferPacket->OneWriteFailed &&
  113. !FsRtlIsTotalDeviceFailure(status)) {
  114. transferPacket->OneWriteFailed = TRUE;
  115. t->CarefulWrite(transferPacket);
  116. return;
  117. }
  118. q = &transferPacket->UpdateQueue;
  119. while (!IsListEmpty(q)) {
  120. l = RemoveHeadList(q);
  121. p = CONTAINING_RECORD(l, PARITY_TP, UpdateQueue);
  122. p->IoStatus.Status = status;
  123. if (NT_SUCCESS(status)) {
  124. p->IoStatus.Information = p->Length;
  125. } else {
  126. p->IoStatus.Information = 0;
  127. p->ReadPacket = FALSE; // Indicate a write failure.
  128. }
  129. p->CompletionRoutine(p);
  130. }
  131. }
  132. wasReadPacket = transferPacket->ReadPacket;
  133. transferPacket->ReadPacket = FALSE;
  134. queueNumber = (ULONG) (transferPacket->BucketNumber%t->_numQueues);
  135. q = &t->_ioQueue[queueNumber];
  136. spin = &t->_spinLock[queueNumber];
  137. KeAcquireSpinLock(spin, &irql);
  138. for (l = transferPacket->OverlapQueue.Flink; l != q; l = l->Flink) {
  139. p = CONTAINING_RECORD(l, PARITY_TP, OverlapQueue);
  140. if (p->BucketNumber == transferPacket->BucketNumber) {
  141. RemoveEntryList(&p->OverlapQueue);
  142. InsertTailList(&transferPacket->UpdateQueue, &p->UpdateQueue);
  143. if (p->Offset < transferPacket->Offset) {
  144. transferPacket->Length += (ULONG) (transferPacket->Offset - p->Offset);
  145. transferPacket->Offset = p->Offset;
  146. transferPacket->ReadPacket = TRUE;
  147. }
  148. if (p->Offset + p->Length >
  149. transferPacket->Offset + transferPacket->Length) {
  150. transferPacket->Length += (ULONG)
  151. ((p->Offset + p->Length) -
  152. (transferPacket->Offset + transferPacket->Length));
  153. transferPacket->ReadPacket = TRUE;
  154. }
  155. }
  156. }
  157. if (!NT_SUCCESS(status) || IsListEmpty(&transferPacket->UpdateQueue)) {
  158. if (wasReadPacket && IsListEmpty(&transferPacket->UpdateQueue)) {
  159. transferPacket->ReadPacket = TRUE;
  160. transferPacket->Idle = TRUE;
  161. KeReleaseSpinLock(spin, irql);
  162. return;
  163. }
  164. RemoveEntryList(&transferPacket->OverlapQueue);
  165. KeReleaseSpinLock(spin, irql);
  166. tpRemoved = TRUE;
  167. } else {
  168. KeReleaseSpinLock(spin, irql);
  169. tpRemoved = FALSE;
  170. }
  171. if (tpRemoved) {
  172. q = &transferPacket->UpdateQueue;
  173. while (!IsListEmpty(q)) {
  174. l = RemoveHeadList(q);
  175. p = CONTAINING_RECORD(l, PARITY_TP, UpdateQueue);
  176. p->IoStatus.Status = status;
  177. p->IoStatus.Information = 0;
  178. p->ReadPacket = wasReadPacket; // Indicate whether a read failure.
  179. p->CompletionRoutine(p);
  180. }
  181. if (transferPacket != t->_ePacket) {
  182. delete transferPacket;
  183. }
  184. KeAcquireSpinLock(&t->_ePacketSpinLock, &irql);
  185. if (t->_ePacketInUse && !t->_ePacketQueueBeingServiced) {
  186. t->_ePacketQueueBeingServiced = TRUE;
  187. } else {
  188. if (transferPacket == t->_ePacket) {
  189. t->_ePacketInUse = FALSE;
  190. }
  191. KeReleaseSpinLock(&t->_ePacketSpinLock, irql);
  192. return;
  193. }
  194. KeReleaseSpinLock(&t->_ePacketSpinLock, irql);
  195. for (;;) {
  196. KeAcquireSpinLock(&t->_ePacketSpinLock, &irql);
  197. if (IsListEmpty(&t->_ePacketQueue)) {
  198. if (transferPacket == t->_ePacket) {
  199. t->_ePacketInUse = FALSE;
  200. }
  201. t->_ePacketQueueBeingServiced = FALSE;
  202. KeReleaseSpinLock(&t->_ePacketSpinLock, irql);
  203. break;
  204. }
  205. l = RemoveHeadList(&t->_ePacketQueue);
  206. KeReleaseSpinLock(&t->_ePacketSpinLock, irql);
  207. ep = CONTAINING_RECORD(l, PARITY_TP, OverlapQueue);
  208. queueNumber = (ULONG) (ep->BucketNumber%t->_numQueues);
  209. q = &t->_ioQueue[queueNumber];
  210. spin = &t->_spinLock[queueNumber];
  211. KeAcquireSpinLock(spin, &irql);
  212. for (l = q->Blink; l != q; l = l->Blink) {
  213. p = CONTAINING_RECORD(l, PARITY_TP, OverlapQueue);
  214. if (p->BucketNumber == ep->BucketNumber) {
  215. break;
  216. }
  217. }
  218. if (l != q) {
  219. InsertTailList(q, &ep->OverlapQueue);
  220. wasIdle = p->Idle;
  221. p->Idle = FALSE;
  222. KeReleaseSpinLock(spin, irql);
  223. if (wasIdle) {
  224. p->CompletionRoutine(p);
  225. }
  226. continue;
  227. }
  228. packet = new PARITY_TP;
  229. if (packet && !packet->AllocateMdl(t->_bucketSize)) {
  230. delete packet;
  231. packet = NULL;
  232. }
  233. if (!packet) {
  234. if (transferPacket != t->_ePacket) {
  235. KeAcquireSpinLock(&t->_ePacketSpinLock, &irql2);
  236. if (t->_ePacketInUse) {
  237. InsertHeadList(&t->_ePacketQueue, &ep->OverlapQueue);
  238. t->_ePacketQueueBeingServiced = FALSE;
  239. KeReleaseSpinLock(&t->_ePacketSpinLock, irql2);
  240. KeReleaseSpinLock(spin, irql);
  241. break;
  242. }
  243. t->_ePacketInUse = TRUE;
  244. KeReleaseSpinLock(&t->_ePacketSpinLock, irql2);
  245. }
  246. packet = t->_ePacket;
  247. }
  248. packet->Length = t->_bucketSize;
  249. packet->Offset = ep->BucketNumber*t->_bucketSize;
  250. packet->CompletionRoutine = UpdateParityCompletionRoutine;
  251. packet->TargetVolume = ep->TargetVolume;
  252. packet->Thread = ep->Thread;
  253. packet->IrpFlags = ep->IrpFlags;
  254. packet->ReadPacket = TRUE;
  255. packet->Idle = FALSE;
  256. packet->OneWriteFailed = FALSE;
  257. InitializeListHead(&packet->UpdateQueue);
  258. packet->ParityIoManager = t;
  259. packet->BucketNumber = ep->BucketNumber;
  260. InsertTailList(q, &packet->OverlapQueue);
  261. InsertTailList(q, &ep->OverlapQueue);
  262. KeAcquireSpinLock(&t->_ePacketSpinLock, &irql2);
  263. qq = &t->_ePacketQueue;
  264. for (l = qq->Flink; l != qq; ) {
  265. p = CONTAINING_RECORD(l, PARITY_TP, OverlapQueue);
  266. l = l->Flink;
  267. if (p->BucketNumber == ep->BucketNumber) {
  268. RemoveEntryList(&p->OverlapQueue);
  269. InsertTailList(q, &p->OverlapQueue);
  270. }
  271. }
  272. KeReleaseSpinLock(&t->_ePacketSpinLock, irql2);
  273. KeReleaseSpinLock(spin, irql);
  274. TRANSFER(packet);
  275. if (packet == t->_ePacket) {
  276. KeAcquireSpinLock(&t->_ePacketSpinLock, &irql);
  277. if (!t->_ePacketInUse) {
  278. KeReleaseSpinLock(&t->_ePacketSpinLock, irql);
  279. continue;
  280. }
  281. t->_ePacketQueueBeingServiced = FALSE;
  282. KeReleaseSpinLock(&t->_ePacketSpinLock, irql);
  283. break;
  284. }
  285. }
  286. return;
  287. }
  288. if (!transferPacket->ReadPacket) {
  289. target = (PCHAR) MmGetSystemAddressForMdl(transferPacket->Mdl);
  290. q = &transferPacket->UpdateQueue;
  291. for (l = q->Flink; l != q; l = l->Flink) {
  292. p = CONTAINING_RECORD(l, PARITY_TP, UpdateQueue);
  293. bucketOffset = (ULONG) (p->Offset - transferPacket->Offset);
  294. source = MmGetSystemAddressForMdl(p->Mdl);
  295. FtpComputeParity(target + bucketOffset, source, p->Length);
  296. }
  297. }
  298. TRANSFER(transferPacket);
  299. }
  300. VOID
  301. PARITY_IO_MANAGER::StartReadForUpdateParity(
  302. IN LONGLONG Offset,
  303. IN ULONG Length,
  304. IN PFT_VOLUME TargetVolume,
  305. IN PETHREAD Thread,
  306. IN UCHAR IrpFlags
  307. )
  308. /*++
  309. Routine Description:
  310. This routine lets the parity manager know that an update for the
  311. given offset and length will be coming so that the PARITY_IO_MANAGER
  312. can start the read ahead of the parity buffer.
  313. Arguments:
  314. Offset - Supplies the request offset.
  315. Length - Supplies the request length.
  316. TargetVolume - Supplies the target volume.
  317. Thread - Supplies the thread context for this request.
  318. IrpFlags - Supplies the irp flags for this request.
  319. Return Value:
  320. None.
  321. --*/
  322. {
  323. KIRQL irql;
  324. LONGLONG bucketNumber;
  325. ULONG queueNumber;
  326. PLIST_ENTRY q, l;
  327. PKSPIN_LOCK spin;
  328. PPARITY_TP p;
  329. KeAcquireSpinLock(&_ePacketSpinLock, &irql);
  330. if (_ePacketInUse || _ePacketQueueBeingServiced) {
  331. KeReleaseSpinLock(&_ePacketSpinLock, irql);
  332. return;
  333. }
  334. KeReleaseSpinLock(&_ePacketSpinLock, irql);
  335. bucketNumber = Offset/_bucketSize;
  336. queueNumber = (ULONG) (bucketNumber%_numQueues);
  337. q = &_ioQueue[queueNumber];
  338. spin = &_spinLock[queueNumber];
  339. KeAcquireSpinLock(spin, &irql);
  340. for (l = q->Blink; l != q; l = l->Blink) {
  341. p = CONTAINING_RECORD(l, PARITY_TP, OverlapQueue);
  342. if (bucketNumber == p->BucketNumber) {
  343. KeReleaseSpinLock(spin, irql);
  344. return;
  345. }
  346. }
  347. p = new PARITY_TP;
  348. if (p && !p->AllocateMdl(_bucketSize)) {
  349. delete p;
  350. p = NULL;
  351. }
  352. if (!p) {
  353. KeReleaseSpinLock(spin, irql);
  354. return;
  355. }
  356. p->Length = Length;
  357. p->Offset = Offset;
  358. p->CompletionRoutine = UpdateParityCompletionRoutine;
  359. p->TargetVolume = TargetVolume;
  360. p->Thread = Thread;
  361. p->IrpFlags = IrpFlags;
  362. p->ReadPacket = TRUE;
  363. p->Idle = FALSE;
  364. p->OneWriteFailed = FALSE;
  365. InitializeListHead(&p->UpdateQueue);
  366. p->ParityIoManager = this;
  367. p->BucketNumber = bucketNumber;
  368. InsertTailList(q, &p->OverlapQueue);
  369. KeReleaseSpinLock(spin, irql);
  370. TRANSFER(p);
  371. }
  372. VOID
  373. PARITY_IO_MANAGER::UpdateParity(
  374. IN OUT PPARITY_TP TransferPacket
  375. )
  376. /*++
  377. Routine Description:
  378. This routine xors the given buffer with the corresponding
  379. parity on disk and then writes out the result.
  380. Arguments:
  381. TransferPacket - Supplies the transfer packet containing the parity update.
  382. Return Value:
  383. None.
  384. --*/
  385. {
  386. KIRQL irql, irql2;
  387. ULONG queueNumber;
  388. PLIST_ENTRY q;
  389. PKSPIN_LOCK spin;
  390. BOOLEAN wasIdle;
  391. PLIST_ENTRY l;
  392. PPARITY_TP p, packet;
  393. TransferPacket->ReadPacket = FALSE;
  394. TransferPacket->Idle = FALSE;
  395. TransferPacket->ParityIoManager = this;
  396. TransferPacket->BucketNumber = TransferPacket->Offset/_bucketSize;
  397. queueNumber = (ULONG) (TransferPacket->BucketNumber%_numQueues);
  398. q = &_ioQueue[queueNumber];
  399. spin = &_spinLock[queueNumber];
  400. //
  401. // First figure out if there's already a read in progress for
  402. // the given parity bucket. If there is then there is no
  403. // reason to queue another. In this way, we can increase the
  404. // throughput on the parity section by collapsing the parity
  405. // updates.
  406. //
  407. KeAcquireSpinLock(spin, &irql);
  408. for (l = q->Blink; l != q; l = l->Blink) {
  409. p = CONTAINING_RECORD(l, PARITY_TP, OverlapQueue);
  410. if (p->BucketNumber == TransferPacket->BucketNumber) {
  411. break;
  412. }
  413. }
  414. if (l == q) {
  415. KeAcquireSpinLock(&_ePacketSpinLock, &irql2);
  416. if (_ePacketInUse || _ePacketQueueBeingServiced) {
  417. InsertTailList(&_ePacketQueue, &TransferPacket->OverlapQueue);
  418. KeReleaseSpinLock(&_ePacketSpinLock, irql2);
  419. KeReleaseSpinLock(spin, irql);
  420. return;
  421. }
  422. KeReleaseSpinLock(&_ePacketSpinLock, irql2);
  423. packet = new PARITY_TP;
  424. if (packet && !packet->AllocateMdl(_bucketSize)) {
  425. delete packet;
  426. packet = NULL;
  427. }
  428. if (!packet) {
  429. KeAcquireSpinLock(&_ePacketSpinLock, &irql2);
  430. if (_ePacketInUse || _ePacketQueueBeingServiced) {
  431. InsertTailList(&_ePacketQueue, &TransferPacket->OverlapQueue);
  432. KeReleaseSpinLock(&_ePacketSpinLock, irql2);
  433. KeReleaseSpinLock(spin, irql);
  434. return;
  435. }
  436. _ePacketInUse = TRUE;
  437. KeReleaseSpinLock(&_ePacketSpinLock, irql2);
  438. packet = _ePacket;
  439. }
  440. packet->Length = TransferPacket->Length;
  441. packet->Offset = TransferPacket->Offset;
  442. packet->CompletionRoutine = UpdateParityCompletionRoutine;
  443. packet->TargetVolume = TransferPacket->TargetVolume;
  444. packet->Thread = TransferPacket->Thread;
  445. packet->IrpFlags = TransferPacket->IrpFlags;
  446. packet->ReadPacket = TRUE;
  447. packet->Idle = FALSE;
  448. packet->OneWriteFailed = FALSE;
  449. InitializeListHead(&packet->UpdateQueue);
  450. packet->ParityIoManager = this;
  451. packet->BucketNumber = TransferPacket->BucketNumber;
  452. InsertTailList(q, &packet->OverlapQueue);
  453. InsertTailList(q, &TransferPacket->OverlapQueue);
  454. KeReleaseSpinLock(spin, irql);
  455. TRANSFER(packet);
  456. } else {
  457. wasIdle = p->Idle;
  458. p->Idle = FALSE;
  459. InsertTailList(q, &TransferPacket->OverlapQueue);
  460. KeReleaseSpinLock(spin, irql);
  461. if (wasIdle) {
  462. p->CompletionRoutine(p);
  463. }
  464. }
  465. }
  466. PARITY_IO_MANAGER::~PARITY_IO_MANAGER(
  467. )
  468. {
  469. if (_spinLock) {
  470. ExFreePool(_spinLock);
  471. _spinLock = NULL;
  472. }
  473. if (_ioQueue) {
  474. ExFreePool(_ioQueue);
  475. _ioQueue = NULL;
  476. }
  477. if (_ePacket) {
  478. delete _ePacket;
  479. _ePacket = NULL;
  480. }
  481. }
  482. VOID
  483. ParityCarefulWritePhase2(
  484. IN OUT PTRANSFER_PACKET TransferPacket
  485. )
  486. /*++
  487. Routine Description:
  488. This is the completion routine a sector replacement
  489. for a careful write operation.
  490. Arguments:
  491. TransferPacket - Supplies the subordinate transfer packet.
  492. Return Value:
  493. None.
  494. --*/
  495. {
  496. PPARITY_RECOVER_TP subPacket = (PPARITY_RECOVER_TP) TransferPacket;
  497. subPacket->CompletionRoutine = ParityCarefulWritePhase1;
  498. TRANSFER(subPacket);
  499. }
  500. VOID
  501. ParityCarefulWritePhase1(
  502. IN OUT PTRANSFER_PACKET TransferPacket
  503. )
  504. /*++
  505. Routine Description:
  506. This is the completion routine a first attempt of a single sector write
  507. for a careful write operation.
  508. Arguments:
  509. TransferPacket - Supplies the subordinate transfer packet.
  510. Return Value:
  511. None.
  512. --*/
  513. {
  514. PPARITY_RECOVER_TP subPacket = (PPARITY_RECOVER_TP) TransferPacket;
  515. NTSTATUS status = subPacket->IoStatus.Status;
  516. PPARITY_TP masterPacket = (PPARITY_TP) subPacket->MasterPacket;
  517. PPARITY_IO_MANAGER t = masterPacket->ParityIoManager;
  518. if (FsRtlIsTotalDeviceFailure(status)) {
  519. masterPacket->IoStatus = subPacket->IoStatus;
  520. masterPacket->CompletionRoutine(masterPacket);
  521. delete subPacket;
  522. return;
  523. }
  524. if (!NT_SUCCESS(status)) {
  525. if (!subPacket->OneWriteFailed) {
  526. subPacket->CompletionRoutine = ParityCarefulWritePhase2;
  527. subPacket->OneWriteFailed = TRUE;
  528. subPacket->TargetVolume->ReplaceBadSector(subPacket);
  529. return;
  530. }
  531. masterPacket->IoStatus = subPacket->IoStatus;
  532. }
  533. if (masterPacket->Offset + masterPacket->Length ==
  534. subPacket->Offset + subPacket->Length) {
  535. masterPacket->CompletionRoutine(masterPacket);
  536. delete subPacket;
  537. return;
  538. }
  539. subPacket->Offset += subPacket->Length;
  540. MmPrepareMdlForReuse(subPacket->Mdl);
  541. IoBuildPartialMdl(masterPacket->Mdl, subPacket->Mdl,
  542. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  543. (ULONG) (subPacket->Offset - masterPacket->Offset),
  544. subPacket->Length);
  545. subPacket->OneWriteFailed = FALSE;
  546. TRANSFER(subPacket);
  547. }
  548. VOID
  549. PARITY_IO_MANAGER::CarefulWrite(
  550. IN OUT PPARITY_TP TransferPacket
  551. )
  552. /*++
  553. Routine Description:
  554. This routine writes out the given transfer packet one sector at a time.
  555. Arguments:
  556. TransferPacket - Supplies the transfer packet.
  557. Return Value:
  558. None.
  559. --*/
  560. {
  561. PPARITY_RECOVER_TP subPacket;
  562. KIRQL irql;
  563. ASSERT(!TransferPacket->ReadPacket);
  564. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  565. TransferPacket->IoStatus.Information = TransferPacket->Length;
  566. subPacket = new PARITY_RECOVER_TP;
  567. if (subPacket &&
  568. !subPacket->AllocateMdl((PVOID) (PAGE_SIZE - 1), _sectorSize)) {
  569. delete subPacket;
  570. subPacket = NULL;
  571. }
  572. if (!subPacket) {
  573. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  574. TransferPacket->IoStatus.Information = 0;
  575. TransferPacket->CompletionRoutine(TransferPacket);
  576. return;
  577. }
  578. IoBuildPartialMdl(TransferPacket->Mdl, subPacket->Mdl,
  579. MmGetMdlVirtualAddress(TransferPacket->Mdl),
  580. _sectorSize);
  581. subPacket->Length = _sectorSize;
  582. subPacket->Offset = TransferPacket->Offset;
  583. subPacket->CompletionRoutine = ParityCarefulWritePhase1;
  584. subPacket->TargetVolume = TransferPacket->TargetVolume;
  585. subPacket->Thread = TransferPacket->Thread;
  586. subPacket->IrpFlags = TransferPacket->IrpFlags;
  587. subPacket->ReadPacket = FALSE;
  588. subPacket->OneWriteFailed = FALSE;
  589. subPacket->MasterPacket = TransferPacket;
  590. TRANSFER(subPacket);
  591. }