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.

1188 lines
22 KiB

  1. /*++
  2. Copyright (C) 1991-5 Microsoft Corporation
  3. Module Name:
  4. composit.cxx
  5. Abstract:
  6. This module contains the code specific to all composite volume objects.
  7. Author:
  8. Norbert Kusters 2-Feb-1995
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. This code assumes that the volume array is static. If these values
  13. changes (as in Stripes or Mirrors) then it is up to the subclass to
  14. provide the proper synchronization.
  15. Revision History:
  16. --*/
  17. extern "C" {
  18. #include <ntddk.h>
  19. }
  20. #include <ftdisk.h>
  21. VOID
  22. SimpleFtCompletionRoutine(
  23. IN PVOID CompletionContext,
  24. IN NTSTATUS Status
  25. );
  26. #ifdef ALLOC_PRAGMA
  27. #pragma code_seg("PAGE")
  28. #endif
  29. NTSTATUS
  30. COMPOSITE_FT_VOLUME::Initialize(
  31. IN OUT PROOT_EXTENSION RootExtension,
  32. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  33. IN OUT PFT_VOLUME* VolumeArray,
  34. IN USHORT ArraySize,
  35. IN PVOID ConfigInfo,
  36. IN PVOID StateInfo
  37. )
  38. /*++
  39. Routine Description:
  40. Initialize routine for FT_VOLUME of type COMPOSITE_FT_VOLUME.
  41. Arguments:
  42. RootExtension - Supplies the root device extension.
  43. LogicalDiskId - Supplies the logical disk id for this volume.
  44. VolumeArray - Supplies the array of volumes for this volume set.
  45. ArraySize - Supplies the number of volumes in the volume array.
  46. ConfigInfo - Supplies the configuration information.
  47. StateInfo - Supplies the state information.
  48. Return Value:
  49. STATUS_SUCCESS
  50. --*/
  51. {
  52. ULONG i, secsize;
  53. FT_VOLUME::Initialize(RootExtension, LogicalDiskId);
  54. _volumeArray = VolumeArray;
  55. _arraySize = ArraySize;
  56. _sectorSize = 0;
  57. for (i = 0; i < _arraySize; i++) {
  58. if (_volumeArray[i]) {
  59. secsize = _volumeArray[i]->QuerySectorSize();
  60. if (_sectorSize < secsize) {
  61. _sectorSize = secsize;
  62. }
  63. }
  64. }
  65. return STATUS_SUCCESS;
  66. }
  67. NTSTATUS
  68. COMPOSITE_FT_VOLUME::OrphanMember(
  69. IN USHORT MemberNumber,
  70. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  71. IN PVOID Context
  72. )
  73. /*++
  74. Routine Description:
  75. This routine tries to orphan the given member of this logical disk.
  76. A completion routine will be called if and only if this attempt is successful.
  77. Arguments:
  78. MemberNumber - Supplies the member number to orphan.
  79. CompletionRoutine - Supplies the completion routine.
  80. Context - Supplies the completion routine context.
  81. Return Value:
  82. NTSTATUS
  83. --*/
  84. {
  85. return STATUS_INVALID_PARAMETER;
  86. }
  87. NTSTATUS
  88. COMPOSITE_FT_VOLUME::RegenerateMember(
  89. IN USHORT MemberNumber,
  90. IN OUT PFT_VOLUME NewMember,
  91. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  92. IN PVOID Context
  93. )
  94. /*++
  95. Routine Description:
  96. This routine regenerates the given member of this volume with
  97. the given volume.
  98. Arguments:
  99. MemberNumber - Supplies the member number to regenerate.
  100. NewMember - Supplies the new member to regenerate to.
  101. CompletionRoutine - Supplies the completion routine.
  102. Context - Supplies the completion routine context.
  103. Return Value:
  104. NTSTATUS
  105. --*/
  106. {
  107. return STATUS_INVALID_PARAMETER;
  108. }
  109. VOID
  110. COMPOSITE_FT_VOLUME::StopSyncOperations(
  111. )
  112. /*++
  113. Routine Description:
  114. This routine stops all sync operations.
  115. Arguments:
  116. None.
  117. Return Value:
  118. None.
  119. --*/
  120. {
  121. USHORT i;
  122. PFT_VOLUME vol;
  123. for (i = 0; i < _arraySize; i++) {
  124. if (vol = GetMember(i)) {
  125. vol->StopSyncOperations();
  126. }
  127. }
  128. }
  129. VOID
  130. COMPOSITE_FT_VOLUME::BroadcastIrp(
  131. IN PIRP Irp,
  132. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  133. IN PVOID Context
  134. )
  135. /*++
  136. Routine Description:
  137. This routine broadcasts a copy of the given IRP to every partition that
  138. is a member of the logical disk.
  139. Arguments:
  140. Irp - Supplies the I/O request packet.
  141. CompletionRoutine - Supplies the routine to be called when the operation
  142. completes.
  143. Context - Supplies the completion routine context.
  144. Return Value:
  145. None.
  146. --*/
  147. {
  148. PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
  149. USHORT i;
  150. PFT_VOLUME vol;
  151. completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT)
  152. ExAllocatePool(NonPagedPool,
  153. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  154. if (!completionContext) {
  155. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  156. return;
  157. }
  158. KeInitializeSpinLock(&completionContext->SpinLock);
  159. completionContext->Status = STATUS_SUCCESS;
  160. completionContext->RefCount = _arraySize;
  161. completionContext->CompletionRoutine = CompletionRoutine;
  162. completionContext->Context = Context;
  163. for (i = 0; i < _arraySize; i++) {
  164. if (vol = GetMember(i)) {
  165. vol->BroadcastIrp(Irp, SimpleFtCompletionRoutine,
  166. completionContext);
  167. } else {
  168. SimpleFtCompletionRoutine(completionContext, STATUS_SUCCESS);
  169. }
  170. }
  171. }
  172. PFT_VOLUME
  173. COMPOSITE_FT_VOLUME::GetParentLogicalDisk(
  174. IN PFT_VOLUME Volume
  175. )
  176. /*++
  177. Routine Description:
  178. This routine returns the parent of the given logical disk within
  179. this volume.
  180. Arguments:
  181. Volume - Supplies the sub-volume of which we are looking for the parent.
  182. Return Value:
  183. The parent volume or NULL;
  184. --*/
  185. {
  186. USHORT n, i;
  187. PFT_VOLUME vol;
  188. n = QueryNumMembers();
  189. for (i = 0; i < n; i++) {
  190. if (!(vol = GetMember(i))) {
  191. continue;
  192. }
  193. if (vol == Volume) {
  194. return this;
  195. }
  196. vol = vol->GetParentLogicalDisk(Volume);
  197. if (vol) {
  198. return vol;
  199. }
  200. }
  201. return NULL;
  202. }
  203. NTSTATUS
  204. COMPOSITE_FT_VOLUME::SetPartitionType(
  205. IN UCHAR PartitionType
  206. )
  207. /*++
  208. Routine Description:
  209. This routine sets the partition type on all the members of the
  210. FT set.
  211. Arguments:
  212. PartitionType - Supplies the partition type.
  213. Return Value:
  214. NTSTATUS
  215. --*/
  216. {
  217. NTSTATUS status, finalStatus;
  218. USHORT n, i;
  219. PFT_VOLUME vol;
  220. finalStatus = STATUS_SUCCESS;
  221. n = QueryNumMembers();
  222. for (i = 0; i < n; i++) {
  223. if (!(vol = GetMember(i))) {
  224. continue;
  225. }
  226. status = vol->SetPartitionType(PartitionType);
  227. if (!NT_SUCCESS(status)) {
  228. finalStatus = status;
  229. }
  230. }
  231. return finalStatus;
  232. }
  233. UCHAR
  234. COMPOSITE_FT_VOLUME::QueryPartitionType(
  235. )
  236. /*++
  237. Routine Description:
  238. This routine queries the partition type.
  239. Arguments:
  240. None.
  241. Return Value:
  242. The partition type.
  243. --*/
  244. {
  245. USHORT n, i;
  246. PFT_VOLUME vol;
  247. UCHAR type;
  248. n = QueryNumMembers();
  249. for (i = 0; i < n; i++) {
  250. if (!(vol = GetMember(i))) {
  251. continue;
  252. }
  253. type = vol->QueryPartitionType();
  254. if (type) {
  255. return type;
  256. }
  257. }
  258. return 0;
  259. }
  260. UCHAR
  261. COMPOSITE_FT_VOLUME::QueryStackSize(
  262. )
  263. /*++
  264. Routine Description:
  265. This routine queries IRP stack size.
  266. Arguments:
  267. None.
  268. Return Value:
  269. The IRP stack size.
  270. --*/
  271. {
  272. USHORT n, i;
  273. PFT_VOLUME vol;
  274. UCHAR stackSize, t;
  275. stackSize = 0;
  276. n = QueryNumMembers();
  277. for (i = 0; i < n; i++) {
  278. if (!(vol = GetMember(i))) {
  279. continue;
  280. }
  281. t = vol->QueryStackSize();
  282. if (t > stackSize) {
  283. stackSize = t;
  284. }
  285. }
  286. return stackSize;
  287. }
  288. VOID
  289. COMPOSITE_FT_VOLUME::CreateLegacyNameLinks(
  290. IN PUNICODE_STRING DeviceName
  291. )
  292. /*++
  293. Routine Description:
  294. This routine creates the \Device\HarddiskN\PartitionM links for
  295. this object to the given device name.
  296. Arguments:
  297. DeviceName - Supplies the device name.
  298. Return Value:
  299. None.
  300. --*/
  301. {
  302. USHORT n, i;
  303. PFT_VOLUME vol;
  304. n = QueryNumMembers();
  305. for (i = 0; i < n; i++) {
  306. if (!(vol = GetMember(i))) {
  307. continue;
  308. }
  309. vol->CreateLegacyNameLinks(DeviceName);
  310. }
  311. }
  312. #ifdef ALLOC_PRAGMA
  313. #pragma code_seg("PAGELK")
  314. #endif
  315. USHORT
  316. COMPOSITE_FT_VOLUME::QueryNumberOfMembers(
  317. )
  318. /*++
  319. Routine Description:
  320. This routine returns the number of members in this volume.
  321. Arguments:
  322. None.
  323. Return Value:
  324. The number of members in this volume.
  325. --*/
  326. {
  327. return _arraySize;
  328. }
  329. VOID
  330. COMPOSITE_FT_VOLUME::SetDirtyBit(
  331. IN BOOLEAN IsDirty,
  332. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  333. IN PVOID Context
  334. )
  335. /*++
  336. Routine Description:
  337. This routine sets the dirty bit on the volume. This bit is used at
  338. startup to determine whether or not there was a clean shutdown.
  339. Arguments:
  340. IsDirty - Supplies the value of the dirty bit.
  341. Return Value:
  342. None.
  343. --*/
  344. {
  345. USHORT n, i;
  346. PFT_VOLUME vol;
  347. PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
  348. if (!CompletionRoutine) {
  349. n = QueryNumMembers();
  350. for (i = 0; i < n; i++) {
  351. if (vol = GetMember(i)) {
  352. vol->SetDirtyBit(IsDirty, NULL, NULL);
  353. }
  354. }
  355. return;
  356. }
  357. completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT)
  358. ExAllocatePool(NonPagedPool,
  359. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  360. if (!completionContext) {
  361. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  362. return;
  363. }
  364. KeInitializeSpinLock(&completionContext->SpinLock);
  365. completionContext->Status = STATUS_SUCCESS;
  366. completionContext->RefCount = _arraySize;
  367. completionContext->CompletionRoutine = CompletionRoutine;
  368. completionContext->Context = Context;
  369. for (i = 0; i < _arraySize; i++) {
  370. if (vol = GetMember(i)) {
  371. vol->SetDirtyBit(IsDirty, SimpleFtCompletionRoutine,
  372. completionContext);
  373. } else {
  374. SimpleFtCompletionRoutine(completionContext, STATUS_SUCCESS);
  375. }
  376. }
  377. }
  378. PFT_VOLUME
  379. COMPOSITE_FT_VOLUME::GetMember(
  380. IN USHORT MemberNumber
  381. )
  382. /*++
  383. Routine Description:
  384. This routine returns the 'MemberNumber'th member of this volume.
  385. Arguments:
  386. MemberNumber - Supplies the zero based member number desired.
  387. Return Value:
  388. A pointer to the 'MemberNumber'th member or NULL if no such member.
  389. --*/
  390. {
  391. KIRQL irql;
  392. PFT_VOLUME r;
  393. ASSERT(MemberNumber < _arraySize);
  394. KeAcquireSpinLock(&_spinLock, &irql);
  395. r = _volumeArray[MemberNumber];
  396. KeReleaseSpinLock(&_spinLock, irql);
  397. return r;
  398. }
  399. VOID
  400. SimpleFtCompletionRoutine(
  401. IN PVOID CompletionContext,
  402. IN NTSTATUS Status
  403. )
  404. /*++
  405. Routine Description:
  406. This is a simple completion routine that expects the CompletionContext
  407. to be a FT_COMPLETION_ROUTINE_CONTEXT. It decrements the ref count and
  408. consolidates all of the status codes. When the ref count goes to zero it
  409. call the original completion routine with the result.
  410. Arguments:
  411. CompletionContext - Supplies the completion context.
  412. Status - Supplies the status of the request.
  413. Return Value:
  414. None.
  415. --*/
  416. {
  417. PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
  418. KIRQL oldIrql;
  419. LONG count;
  420. completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT) CompletionContext;
  421. KeAcquireSpinLock(&completionContext->SpinLock, &oldIrql);
  422. if (!NT_SUCCESS(Status) &&
  423. FtpIsWorseStatus(Status, completionContext->Status)) {
  424. completionContext->Status = Status;
  425. }
  426. count = --completionContext->RefCount;
  427. KeReleaseSpinLock(&completionContext->SpinLock, oldIrql);
  428. if (!count) {
  429. completionContext->CompletionRoutine(completionContext->Context,
  430. completionContext->Status);
  431. ExFreePool(completionContext);
  432. }
  433. }
  434. VOID
  435. COMPOSITE_FT_VOLUME::StartSyncOperations(
  436. IN BOOLEAN RegenerateOrphans,
  437. IN FT_COMPLETION_ROUTINE CompletionRoutine,
  438. IN PVOID Context
  439. )
  440. /*++
  441. Routine Description:
  442. This routine restarts any regenerate and initialize requests that were
  443. suspended because of a reboot. The volume examines the member state of
  444. all of its constituents and restarts any regenerations pending.
  445. Arguments:
  446. RegenerateOrphans - Supplies whether or not to try and regenerate
  447. orphaned members.
  448. CompletionRoutine - Supplies the completion routine.
  449. Context - Supplies the context for the completion routine.
  450. Return Value:
  451. None.
  452. --*/
  453. {
  454. PFT_COMPLETION_ROUTINE_CONTEXT completionContext;
  455. USHORT i;
  456. PFT_VOLUME vol;
  457. completionContext = (PFT_COMPLETION_ROUTINE_CONTEXT)
  458. ExAllocatePool(NonPagedPool,
  459. sizeof(FT_COMPLETION_ROUTINE_CONTEXT));
  460. if (!completionContext) {
  461. CompletionRoutine(Context, STATUS_INSUFFICIENT_RESOURCES);
  462. return;
  463. }
  464. KeInitializeSpinLock(&completionContext->SpinLock);
  465. completionContext->Status = STATUS_SUCCESS;
  466. completionContext->RefCount = _arraySize;
  467. completionContext->CompletionRoutine = CompletionRoutine;
  468. completionContext->Context = Context;
  469. for (i = 0; i < _arraySize; i++) {
  470. if (vol = GetMember(i)) {
  471. vol->StartSyncOperations(RegenerateOrphans,
  472. SimpleFtCompletionRoutine,
  473. completionContext);
  474. } else {
  475. SimpleFtCompletionRoutine(completionContext, STATUS_SUCCESS);
  476. }
  477. }
  478. }
  479. ULONG
  480. COMPOSITE_FT_VOLUME::QuerySectorSize(
  481. )
  482. /*++
  483. Routine Description:
  484. Returns the sector size for the volume.
  485. Arguments:
  486. None.
  487. Return Value:
  488. The volume sector size in bytes.
  489. --*/
  490. {
  491. return _sectorSize;
  492. }
  493. PFT_VOLUME
  494. COMPOSITE_FT_VOLUME::GetContainedLogicalDisk(
  495. IN FT_LOGICAL_DISK_ID LogicalDiskId
  496. )
  497. /*++
  498. Routine Description:
  499. This routine returns TRUE if the given logical disk id
  500. represents this logical disk or if this logical disk contains
  501. the given logical disk id either directly or indirectly.
  502. Arguments:
  503. LogicalDiskId - Supplies the logical disk id that we are searching for.
  504. Return Value:
  505. FALSE - The given logical disk id is not contained in this logical disk.
  506. TRUE - The given logical disk id is contained in this logical disk.
  507. --*/
  508. {
  509. USHORT n, i;
  510. PFT_VOLUME vol;
  511. if (LogicalDiskId == QueryLogicalDiskId()) {
  512. return this;
  513. }
  514. n = QueryNumMembers();
  515. for (i = 0; i < n; i++) {
  516. if ((vol = GetMember(i)) &&
  517. (vol = vol->GetContainedLogicalDisk(LogicalDiskId))) {
  518. return vol;
  519. }
  520. }
  521. return NULL;
  522. }
  523. PFT_VOLUME
  524. COMPOSITE_FT_VOLUME::GetContainedLogicalDisk(
  525. IN PDEVICE_OBJECT TargetObject
  526. )
  527. /*++
  528. Routine Description:
  529. This routine returns TRUE if the given logical disk id
  530. represents this logical disk or if this logical disk contains
  531. the given logical disk id either directly or indirectly.
  532. Arguments:
  533. TargetObject - Supplies the target object.
  534. Return Value:
  535. FALSE - The given logical disk id is not contained in this logical disk.
  536. TRUE - The given logical disk id is contained in this logical disk.
  537. --*/
  538. {
  539. USHORT n, i;
  540. PFT_VOLUME vol;
  541. n = QueryNumMembers();
  542. for (i = 0; i < n; i++) {
  543. if ((vol = GetMember(i)) &&
  544. (vol = vol->GetContainedLogicalDisk(TargetObject))) {
  545. return vol;
  546. }
  547. }
  548. return NULL;
  549. }
  550. PFT_VOLUME
  551. COMPOSITE_FT_VOLUME::GetContainedLogicalDisk(
  552. IN ULONG Signature,
  553. IN LONGLONG Offset
  554. )
  555. /*++
  556. Routine Description:
  557. This routine returns TRUE if the given logical disk id
  558. represents this logical disk or if this logical disk contains
  559. the given logical disk id either directly or indirectly.
  560. Arguments:
  561. TargetObject - Supplies the target object.
  562. Return Value:
  563. FALSE - The given logical disk id is not contained in this logical disk.
  564. TRUE - The given logical disk id is contained in this logical disk.
  565. --*/
  566. {
  567. USHORT n, i;
  568. PFT_VOLUME vol;
  569. n = QueryNumMembers();
  570. for (i = 0; i < n; i++) {
  571. vol = GetMember(i);
  572. if (!vol) {
  573. continue;
  574. }
  575. vol = vol->GetContainedLogicalDisk(Signature, Offset);
  576. if (vol) {
  577. return vol;
  578. }
  579. }
  580. return NULL;
  581. }
  582. VOID
  583. COMPOSITE_FT_VOLUME::SetMember(
  584. IN USHORT MemberNumber,
  585. IN PFT_VOLUME Member
  586. )
  587. /*++
  588. Routine Description:
  589. This routine sets the given member in this volume.
  590. Arguments:
  591. MemberNumber - Supplies the member number.
  592. Member - Supplies the member.
  593. Return Value:
  594. None.
  595. --*/
  596. {
  597. KIRQL irql;
  598. KeAcquireSpinLock(&_spinLock, &irql);
  599. SetMemberUnprotected(MemberNumber, Member);
  600. KeReleaseSpinLock(&_spinLock, irql);
  601. }
  602. BOOLEAN
  603. COMPOSITE_FT_VOLUME::IsComplete(
  604. IN BOOLEAN IoPending
  605. )
  606. /*++
  607. Routine Description:
  608. This routine computes whether or not this volume has either all
  609. (if IoPending is FALSE) of its members or enough (if IoPending is TRUE) of
  610. its members.
  611. Arguments:
  612. IoPending - Supplies whether or not there is IO pending.
  613. Return Value:
  614. None.
  615. --*/
  616. {
  617. USHORT n, i;
  618. PFT_VOLUME vol;
  619. ULONG secsize;
  620. n = QueryNumMembers();
  621. for (i = 0; i < n; i++) {
  622. vol = GetMember(i);
  623. if (!vol || !vol->IsComplete(IoPending)) {
  624. return FALSE;
  625. }
  626. }
  627. return TRUE;
  628. }
  629. VOID
  630. COMPOSITE_FT_VOLUME::CompleteNotification(
  631. IN BOOLEAN IoPending
  632. )
  633. /*++
  634. Routine Description:
  635. This routine is called to notify the volume that it is complete and
  636. to therefore prepare for incoming requests.
  637. Arguments:
  638. IoPending - Supplies whether or not there is IO pending.
  639. Return Value:
  640. None.
  641. --*/
  642. {
  643. USHORT n, i;
  644. PFT_VOLUME vol;
  645. ULONG secsize;
  646. n = QueryNumMembers();
  647. for (i = 0; i < n; i++) {
  648. vol = GetMember(i);
  649. if (!vol) {
  650. continue;
  651. }
  652. if (vol->IsComplete(IoPending)) {
  653. vol->CompleteNotification(IoPending);
  654. secsize = vol->QuerySectorSize();
  655. if (secsize > _sectorSize) {
  656. _sectorSize = secsize;
  657. }
  658. }
  659. }
  660. }
  661. ULONG
  662. COMPOSITE_FT_VOLUME::QueryNumberOfPartitions(
  663. )
  664. /*++
  665. Routine Description:
  666. This routine returns the number of partitions covered by this volume
  667. set.
  668. Arguments:
  669. None.
  670. Return Value:
  671. The number of partitions covered by this volume set.
  672. --*/
  673. {
  674. ULONG r;
  675. USHORT n, i;
  676. PFT_VOLUME vol;
  677. r = 0;
  678. n = QueryNumMembers();
  679. for (i = 0; i < n; i++) {
  680. if (!(vol = GetMember(i))) {
  681. continue;
  682. }
  683. r += vol->QueryNumberOfPartitions();
  684. }
  685. return r;
  686. }
  687. PDEVICE_OBJECT
  688. COMPOSITE_FT_VOLUME::GetLeftmostPartitionObject(
  689. )
  690. {
  691. USHORT n, i;
  692. PFT_VOLUME vol;
  693. n = QueryNumMembers();
  694. for (i = 0; i < n; i++) {
  695. vol = GetMember(i);
  696. if (vol) {
  697. return vol->GetLeftmostPartitionObject();
  698. }
  699. }
  700. return NULL;
  701. }
  702. NTSTATUS
  703. COMPOSITE_FT_VOLUME::QueryDiskExtents(
  704. OUT PDISK_EXTENT* DiskExtents,
  705. OUT PULONG NumberOfDiskExtents
  706. )
  707. /*++
  708. Routine Description:
  709. This routine returns an array of disk extents that describe the
  710. location of this volume.
  711. Arguments:
  712. DiskExtents - Returns the disk extents.
  713. NumberOfDiskExtents - Returns the number of disk extents.
  714. Return Value:
  715. NTSTATUS
  716. --*/
  717. {
  718. ULONG totalExtents, numExtents, newTotal;
  719. USHORT n, i;
  720. PFT_VOLUME vol;
  721. NTSTATUS status;
  722. PDISK_EXTENT extents, allExtents;
  723. Restart:
  724. totalExtents = 0;
  725. n = QueryNumMembers();
  726. for (i = 0; i < n; i++) {
  727. if (!(vol = GetMember(i))) {
  728. continue;
  729. }
  730. status = vol->QueryDiskExtents(&extents, &numExtents);
  731. if (!NT_SUCCESS(status)) {
  732. return status;
  733. }
  734. ExFreePool(extents);
  735. totalExtents += numExtents;
  736. }
  737. allExtents = (PDISK_EXTENT) ExAllocatePool(PagedPool, totalExtents*
  738. sizeof(DISK_EXTENT));
  739. if (!allExtents) {
  740. return STATUS_INSUFFICIENT_RESOURCES;
  741. }
  742. newTotal = 0;
  743. for (i = 0; i < n; i++) {
  744. if (!(vol = GetMember(i))) {
  745. continue;
  746. }
  747. status = vol->QueryDiskExtents(&extents, &numExtents);
  748. if (!NT_SUCCESS(status)) {
  749. ExFreePool(allExtents);
  750. return status;
  751. }
  752. if (newTotal + numExtents > totalExtents) {
  753. ExFreePool(extents);
  754. ExFreePool(allExtents);
  755. goto Restart;
  756. }
  757. RtlCopyMemory(&allExtents[newTotal], extents,
  758. numExtents*sizeof(DISK_EXTENT));
  759. ExFreePool(extents);
  760. newTotal += numExtents;
  761. }
  762. *DiskExtents = allExtents;
  763. *NumberOfDiskExtents = newTotal;
  764. return STATUS_SUCCESS;
  765. }
  766. BOOLEAN
  767. COMPOSITE_FT_VOLUME::QueryVolumeState(
  768. IN PFT_VOLUME Volume,
  769. OUT PFT_MEMBER_STATE State
  770. )
  771. /*++
  772. Routine Description:
  773. This routine returns the state of the given volume considered as a
  774. member of this volume.
  775. Arguments:
  776. Volume - Supplies the volume to query the state for.
  777. State - Returns the state.
  778. Return Value:
  779. FALSE - The given Volume is not a member of this volume.
  780. TRUE - The state was successfully computed.
  781. --*/
  782. {
  783. USHORT n, i;
  784. PFT_VOLUME vol;
  785. n = QueryNumMembers();
  786. for (i = 0; i < n; i++) {
  787. vol = GetMember(i);
  788. if (!vol) {
  789. continue;
  790. }
  791. if (vol->QueryVolumeState(Volume, State)) {
  792. return TRUE;
  793. }
  794. }
  795. return FALSE;
  796. }
  797. COMPOSITE_FT_VOLUME::~COMPOSITE_FT_VOLUME(
  798. )
  799. /*++
  800. Routine Description:
  801. Routine called to cleanup resources being used by the object.
  802. Arguments:
  803. None.
  804. Return Value:
  805. None.
  806. --*/
  807. {
  808. if (_volumeArray) {
  809. ExFreePool(_volumeArray);
  810. }
  811. }