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.

4203 lines
117 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. partmgr.c
  5. Abstract:
  6. This driver manages hides partitions from user mode, allowing access
  7. only from other device drivers. This driver implements a notification
  8. protocol for other drivers that want to be alerted of changes to the
  9. partitions in the system.
  10. Author:
  11. Norbert Kusters 18-Apr-1997
  12. Environment:
  13. kernel mode only
  14. Notes:
  15. Revision History:
  16. --*/
  17. #define RTL_USE_AVL_TABLES 0
  18. #include <ntosp.h>
  19. #include <stdio.h>
  20. #include <ntddvol.h>
  21. #include <ntdddisk.h>
  22. #include <initguid.h>
  23. #include <volmgr.h>
  24. #include <wmikm.h>
  25. #include <wmilib.h>
  26. #include <pmwmireg.h>
  27. #include <pmwmicnt.h>
  28. #include <partmgr.h>
  29. #include <ntiologc.h>
  30. #include <ioevent.h>
  31. NTSTATUS
  32. PmReadPartitionTableEx(
  33. IN PDEVICE_OBJECT DeviceObject,
  34. IN PDRIVE_LAYOUT_INFORMATION_EX* DriveLayout
  35. );
  36. NTSTATUS
  37. PmWritePartitionTableEx(
  38. IN PDEVICE_OBJECT DeviceObject,
  39. IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout
  40. );
  41. NTSTATUS
  42. DriverEntry(
  43. IN PDRIVER_OBJECT DriverObject,
  44. IN PUNICODE_STRING RegistryPath
  45. );
  46. VOID
  47. PmTakePartition(
  48. IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
  49. IN PDEVICE_OBJECT Partition,
  50. IN PDEVICE_OBJECT WholeDiskPdo
  51. );
  52. NTSTATUS
  53. PmGivePartition(
  54. IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
  55. IN PDEVICE_OBJECT Partition,
  56. IN PDEVICE_OBJECT WholeDiskPdo
  57. );
  58. NTSTATUS
  59. PmFindPartition(
  60. IN PDEVICE_EXTENSION Extension,
  61. IN ULONG PartitionNumber,
  62. OUT PPARTITION_LIST_ENTRY *PartitionEntry
  63. );
  64. NTSTATUS
  65. PmQueryDeviceRelations(
  66. IN PDEVICE_EXTENSION Extension,
  67. IN PIRP Irp
  68. );
  69. NTSTATUS
  70. PmRemoveDevice(
  71. IN PDEVICE_EXTENSION Extension,
  72. IN PIRP Irp
  73. );
  74. NTSTATUS
  75. PmCreateClose(
  76. IN PDEVICE_OBJECT DeviceObject,
  77. IN PIRP Irp
  78. );
  79. NTSTATUS
  80. PmPnp(
  81. IN PDEVICE_OBJECT DeviceObject,
  82. IN PIRP Irp
  83. );
  84. NTSTATUS
  85. PmPower(
  86. IN PDEVICE_OBJECT DeviceObject,
  87. IN PIRP Irp
  88. );
  89. VOID
  90. PmPowerNotify (
  91. IN PDEVICE_OBJECT DeviceObject,
  92. IN PVOID WorkItem
  93. );
  94. NTSTATUS
  95. PmAddDevice(
  96. IN PDRIVER_OBJECT DriverObject,
  97. IN PDEVICE_OBJECT PhysicalDeviceObject
  98. );
  99. NTSTATUS
  100. PmVolumeManagerNotification(
  101. IN PVOID NotificationStructure,
  102. IN PVOID DriverExtension
  103. );
  104. NTSTATUS
  105. PmNotifyPartitions(
  106. IN PDEVICE_EXTENSION DeviceObject,
  107. IN PIRP Irp
  108. );
  109. NTSTATUS
  110. PmBuildDependantVolumeRelations(
  111. IN PDEVICE_EXTENSION Extension,
  112. OUT PDEVICE_RELATIONS *Relations
  113. );
  114. NTSTATUS
  115. PmQueryDependantVolumeList(
  116. IN PDEVICE_OBJECT VolumeManager,
  117. IN PDEVICE_OBJECT Partition,
  118. IN PDEVICE_OBJECT WholeDiskPdo,
  119. OUT PDEVICE_RELATIONS *DependantVolumes
  120. );
  121. NTSTATUS
  122. PmQueryRemovalRelations(
  123. IN PDEVICE_EXTENSION Extension,
  124. IN PIRP Irp
  125. );
  126. NTSTATUS
  127. PmStartPartition(
  128. IN PDEVICE_OBJECT Partition
  129. );
  130. NTSTATUS
  131. PmRemovePartition(
  132. IN PPARTITION_LIST_ENTRY Partition
  133. );
  134. NTSTATUS
  135. PmDeviceControl(
  136. IN PDEVICE_OBJECT DeviceObject,
  137. IN PIRP Irp
  138. );
  139. NTSTATUS
  140. PmGetPartitionInformation(
  141. IN PDEVICE_OBJECT Partition,
  142. IN PFILE_OBJECT FileObject,
  143. OUT PLONGLONG PartitionOffset,
  144. OUT PLONGLONG PartitionLength
  145. );
  146. NTSTATUS
  147. PmDiskGrowPartition(
  148. IN PDEVICE_OBJECT DeviceObject,
  149. IN PIRP Irp
  150. );
  151. NTSTATUS
  152. PmCheckForUnclaimedPartitions(
  153. IN PDEVICE_OBJECT DeviceObject
  154. );
  155. NTSTATUS
  156. PmChangePartitionIoctl(
  157. IN PDEVICE_EXTENSION Extension,
  158. IN PPARTITION_LIST_ENTRY Partition,
  159. IN ULONG IoctlCode
  160. );
  161. NTSTATUS
  162. PmEjectVolumeManagers(
  163. IN PDEVICE_OBJECT DeviceObject
  164. );
  165. VOID
  166. PmAddSignatures(
  167. IN PDEVICE_EXTENSION Extension,
  168. IN PDRIVE_LAYOUT_INFORMATION_EX Layout
  169. );
  170. RTL_GENERIC_COMPARE_RESULTS
  171. PmTableSignatureCompareRoutine(
  172. IN PRTL_GENERIC_TABLE Table,
  173. IN PVOID First,
  174. IN PVOID Second
  175. );
  176. RTL_GENERIC_COMPARE_RESULTS
  177. PmTableGuidCompareRoutine(
  178. IN PRTL_GENERIC_TABLE Table,
  179. IN PVOID First,
  180. IN PVOID Second
  181. );
  182. PVOID
  183. PmTableAllocateRoutine(
  184. IN PRTL_GENERIC_TABLE Table,
  185. IN CLONG Size
  186. );
  187. VOID
  188. PmTableFreeRoutine(
  189. IN PRTL_GENERIC_TABLE Table,
  190. IN PVOID Buffer
  191. );
  192. NTSTATUS
  193. PmQueryDiskSignature(
  194. IN PDEVICE_OBJECT DeviceObject,
  195. IN PIRP Irp
  196. );
  197. NTSTATUS
  198. PmReadWrite(
  199. IN PDEVICE_OBJECT DeviceObject,
  200. IN PIRP Irp
  201. );
  202. NTSTATUS
  203. PmIoCompletion(
  204. IN PDEVICE_OBJECT DeviceObject,
  205. IN PIRP Irp,
  206. IN PVOID Context
  207. );
  208. NTSTATUS PmWmi(
  209. IN PDEVICE_OBJECT DeviceObject,
  210. IN PIRP Irp
  211. );
  212. NTSTATUS
  213. PmWmiFunctionControl(
  214. IN PDEVICE_OBJECT DeviceObject,
  215. IN PIRP Irp,
  216. IN ULONG GuidIndex,
  217. IN WMIENABLEDISABLECONTROL Function,
  218. IN BOOLEAN Enable
  219. );
  220. VOID
  221. PmDriverReinit(
  222. IN PDRIVER_OBJECT DriverObject,
  223. IN PVOID DriverExtension,
  224. IN ULONG Count
  225. );
  226. BOOLEAN
  227. PmIsRedundantPath(
  228. IN PDEVICE_EXTENSION Extension,
  229. IN PDEVICE_EXTENSION WinningExtension,
  230. IN ULONG Signature,
  231. IN GUID* Guid
  232. );
  233. VOID
  234. PmLogError(
  235. IN PDEVICE_EXTENSION Extension,
  236. IN PDEVICE_EXTENSION WinningExtension,
  237. IN NTSTATUS SpecificIoStatus
  238. );
  239. ULONG
  240. PmQueryRegistrySignature(
  241. );
  242. #ifdef ALLOC_PRAGMA
  243. #pragma alloc_text(INIT, DriverEntry)
  244. #pragma alloc_text(PAGE, PmTakePartition)
  245. #pragma alloc_text(PAGE, PmGivePartition)
  246. #pragma alloc_text(PAGE, PmFindPartition)
  247. #pragma alloc_text(PAGE, PmQueryDeviceRelations)
  248. #pragma alloc_text(PAGE, PmRemoveDevice)
  249. #pragma alloc_text(PAGE, PmCreateClose)
  250. #pragma alloc_text(PAGE, PmPnp)
  251. #pragma alloc_text(PAGE, PmAddDevice)
  252. #pragma alloc_text(PAGE, PmVolumeManagerNotification)
  253. #pragma alloc_text(PAGE, PmNotifyPartitions)
  254. #pragma alloc_text(PAGE, PmBuildDependantVolumeRelations)
  255. #pragma alloc_text(PAGE, PmQueryDependantVolumeList)
  256. #pragma alloc_text(PAGE, PmQueryRemovalRelations)
  257. #pragma alloc_text(PAGE, PmStartPartition)
  258. #pragma alloc_text(PAGE, PmDeviceControl)
  259. #pragma alloc_text(PAGE, PmGetPartitionInformation)
  260. #pragma alloc_text(PAGE, PmDiskGrowPartition)
  261. #pragma alloc_text(PAGE, PmCheckForUnclaimedPartitions)
  262. #pragma alloc_text(PAGE, PmChangePartitionIoctl)
  263. #pragma alloc_text(PAGE, PmEjectVolumeManagers)
  264. #pragma alloc_text(PAGE, PmAddSignatures)
  265. #pragma alloc_text(PAGE, PmTableSignatureCompareRoutine)
  266. #pragma alloc_text(PAGE, PmTableGuidCompareRoutine)
  267. #pragma alloc_text(PAGE, PmTableAllocateRoutine)
  268. #pragma alloc_text(PAGE, PmTableFreeRoutine)
  269. #pragma alloc_text(PAGE, PmQueryDiskSignature)
  270. #pragma alloc_text(PAGE, PmWmi)
  271. #pragma alloc_text(PAGE, PmWmiFunctionControl)
  272. #pragma alloc_text(PAGE, PmReadPartitionTableEx)
  273. #pragma alloc_text(PAGE, PmWritePartitionTableEx)
  274. #pragma alloc_text(PAGE, PmDriverReinit)
  275. #pragma alloc_text(PAGE, PmIsRedundantPath)
  276. #pragma alloc_text(PAGE, PmLogError)
  277. #pragma alloc_text(PAGE, PmQueryRegistrySignature)
  278. #endif
  279. NTSTATUS
  280. PmPassThrough(
  281. IN PDEVICE_OBJECT DeviceObject,
  282. IN PIRP Irp
  283. )
  284. /*++
  285. Routine Description:
  286. This routine is the dispatch for IRP_MJ_PNP_POWER.
  287. Arguments:
  288. DeviceObject - Supplies the device object.
  289. Irp - Supplies the IO request packet.
  290. Return Value:
  291. NTSTATUS
  292. --*/
  293. {
  294. PDEVICE_EXTENSION extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  295. IoSkipCurrentIrpStackLocation(Irp);
  296. return IoCallDriver(extension->TargetObject, Irp);
  297. }
  298. NTSTATUS
  299. PmSignalCompletion(
  300. IN PDEVICE_OBJECT DeviceObject,
  301. IN PIRP Irp,
  302. IN PVOID Event
  303. )
  304. /*++
  305. Routine Description:
  306. This routine will signal the event given as context.
  307. Arguments:
  308. DeviceObject - Supplies the device object.
  309. Irp - Supplies the IO request packet.
  310. Event - Supplies the event to signal.
  311. Return Value:
  312. NTSTATUS
  313. --*/
  314. {
  315. KeSetEvent((PKEVENT) Event, IO_NO_INCREMENT, FALSE);
  316. return STATUS_MORE_PROCESSING_REQUIRED;
  317. }
  318. VOID
  319. PmTakePartition(
  320. IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
  321. IN PDEVICE_OBJECT Partition,
  322. IN PDEVICE_OBJECT WholeDiskPdo
  323. )
  324. /*++
  325. Routine Description:
  326. This routine passes the given partition to the given volume manager
  327. and waits to see if the volume manager accepts the partition. A success
  328. status indicates that the volume manager has accepted the partition.
  329. Arguments:
  330. VolumeManager - Supplies a volume manager.
  331. Partition - Supplies a partition.
  332. WholeDiskPdo - Supplies the whole disk PDO.
  333. Return Value:
  334. NTSTATUS
  335. --*/
  336. {
  337. KEVENT event;
  338. VOLMGR_PARTITION_INFORMATION input;
  339. PIRP irp;
  340. IO_STATUS_BLOCK ioStatus;
  341. NTSTATUS status;
  342. if (!VolumeManagerEntry) {
  343. return;
  344. }
  345. KeInitializeEvent(&event, NotificationEvent, FALSE);
  346. input.PartitionDeviceObject = Partition;
  347. input.WholeDiskPdo = WholeDiskPdo;
  348. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_VOLMGR_PARTITION_REMOVED,
  349. VolumeManagerEntry->VolumeManager,
  350. &input, sizeof(input), NULL, 0, TRUE,
  351. &event, &ioStatus);
  352. if (!irp) {
  353. return;
  354. }
  355. status = IoCallDriver(VolumeManagerEntry->VolumeManager, irp);
  356. if (status == STATUS_PENDING) {
  357. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  358. }
  359. VolumeManagerEntry->RefCount--;
  360. if (!VolumeManagerEntry->RefCount) {
  361. VolumeManagerEntry->VolumeManager = NULL;
  362. ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
  363. VolumeManagerEntry->VolumeManagerFileObject = NULL;
  364. }
  365. }
  366. NTSTATUS
  367. PmGivePartition(
  368. IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
  369. IN PDEVICE_OBJECT Partition,
  370. IN PDEVICE_OBJECT WholeDiskPdo
  371. )
  372. /*++
  373. Routine Description:
  374. This routine passes the given partition to the given volume manager
  375. and waits to see if the volume manager accepts the partition. A success
  376. status indicates that the volume manager has accepted the partition.
  377. Arguments:
  378. VolumeManager - Supplies a volume manager.
  379. Partition - Supplies a partition.
  380. WholeDiskPdo - Supplies the whole disk PDO.
  381. Return Value:
  382. NTSTATUS
  383. --*/
  384. {
  385. NTSTATUS status;
  386. KEVENT event;
  387. VOLMGR_PARTITION_INFORMATION input;
  388. PIRP irp;
  389. IO_STATUS_BLOCK ioStatus;
  390. if (!VolumeManagerEntry->RefCount) {
  391. status = IoGetDeviceObjectPointer(
  392. &VolumeManagerEntry->VolumeManagerName, FILE_READ_DATA,
  393. &VolumeManagerEntry->VolumeManagerFileObject,
  394. &VolumeManagerEntry->VolumeManager);
  395. if (!NT_SUCCESS(status)) {
  396. return status;
  397. }
  398. }
  399. KeInitializeEvent(&event, NotificationEvent, FALSE);
  400. input.PartitionDeviceObject = Partition;
  401. input.WholeDiskPdo = WholeDiskPdo;
  402. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_VOLMGR_PARTITION_ARRIVED,
  403. VolumeManagerEntry->VolumeManager,
  404. &input, sizeof(input),
  405. NULL, 0, TRUE, &event, &ioStatus);
  406. if (!irp) {
  407. if (!VolumeManagerEntry->RefCount) {
  408. VolumeManagerEntry->VolumeManager = NULL;
  409. ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
  410. VolumeManagerEntry->VolumeManagerFileObject = NULL;
  411. }
  412. return STATUS_INSUFFICIENT_RESOURCES;
  413. }
  414. status = IoCallDriver(VolumeManagerEntry->VolumeManager, irp);
  415. if (status == STATUS_PENDING) {
  416. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  417. status = ioStatus.Status;
  418. }
  419. if (NT_SUCCESS(status)) {
  420. VolumeManagerEntry->RefCount++;
  421. } else {
  422. if (!VolumeManagerEntry->RefCount) {
  423. VolumeManagerEntry->VolumeManager = NULL;
  424. ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
  425. VolumeManagerEntry->VolumeManagerFileObject = NULL;
  426. }
  427. }
  428. return status;
  429. }
  430. NTSTATUS
  431. PmFindPartition(
  432. IN PDEVICE_EXTENSION Extension,
  433. IN ULONG PartitionNumber,
  434. OUT PPARTITION_LIST_ENTRY* Partition
  435. )
  436. {
  437. PLIST_ENTRY l;
  438. PPARTITION_LIST_ENTRY partition;
  439. KEVENT event;
  440. PIRP irp;
  441. STORAGE_DEVICE_NUMBER deviceNumber;
  442. IO_STATUS_BLOCK ioStatus;
  443. NTSTATUS status;
  444. ASSERT(Partition);
  445. *Partition = NULL;
  446. for (l = Extension->PartitionList.Flink; l != &Extension->PartitionList;
  447. l = l->Flink) {
  448. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  449. KeInitializeEvent(&event, NotificationEvent, FALSE);
  450. irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
  451. partition->TargetObject, NULL, 0,
  452. &deviceNumber,
  453. sizeof(deviceNumber), FALSE,
  454. &event, &ioStatus);
  455. if (!irp) {
  456. return STATUS_INSUFFICIENT_RESOURCES;
  457. }
  458. status = IoCallDriver(partition->TargetObject, irp);
  459. if (status == STATUS_PENDING) {
  460. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  461. status = ioStatus.Status;
  462. }
  463. if (NT_SUCCESS(status) &&
  464. PartitionNumber == deviceNumber.PartitionNumber) {
  465. *Partition = partition;
  466. return status;
  467. }
  468. }
  469. return STATUS_NOT_FOUND;
  470. }
  471. NTSTATUS
  472. PmChangePartitionIoctl(
  473. IN PDEVICE_EXTENSION Extension,
  474. IN PPARTITION_LIST_ENTRY Partition,
  475. IN ULONG IoctlCode
  476. )
  477. {
  478. PVOLMGR_LIST_ENTRY volumeEntry;
  479. KEVENT event;
  480. VOLMGR_PARTITION_INFORMATION input;
  481. PIRP irp;
  482. IO_STATUS_BLOCK ioStatus;
  483. NTSTATUS status;
  484. volumeEntry = Partition->VolumeManagerEntry;
  485. if (!volumeEntry) {
  486. return STATUS_SUCCESS;
  487. }
  488. KeInitializeEvent(&event, NotificationEvent, FALSE);
  489. input.PartitionDeviceObject = Partition->TargetObject;
  490. input.WholeDiskPdo = Partition->WholeDiskPdo;
  491. irp = IoBuildDeviceIoControlRequest(
  492. IoctlCode, volumeEntry->VolumeManager, &input, sizeof(input),
  493. NULL, 0, TRUE, &event, &ioStatus);
  494. if (!irp) {
  495. return STATUS_INSUFFICIENT_RESOURCES;
  496. }
  497. status = IoCallDriver(volumeEntry->VolumeManager, irp);
  498. if (status == STATUS_PENDING) {
  499. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  500. status = ioStatus.Status;
  501. }
  502. return status;
  503. }
  504. NTSTATUS
  505. PmStartPartition(
  506. IN PDEVICE_OBJECT Partition
  507. )
  508. {
  509. PIRP irp;
  510. KEVENT event;
  511. PIO_STACK_LOCATION irpSp;
  512. NTSTATUS status;
  513. irp = IoAllocateIrp(Partition->StackSize, FALSE);
  514. if (!irp) {
  515. return STATUS_INSUFFICIENT_RESOURCES;
  516. }
  517. KeInitializeEvent(&event, NotificationEvent, FALSE);
  518. irpSp = IoGetNextIrpStackLocation(irp);
  519. irpSp->MajorFunction = IRP_MJ_PNP;
  520. irpSp->MinorFunction = IRP_MN_START_DEVICE;
  521. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  522. IoSetCompletionRoutine(irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
  523. IoCallDriver(Partition, irp);
  524. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  525. status = irp->IoStatus.Status;
  526. IoFreeIrp(irp);
  527. return status;
  528. }
  529. NTSTATUS
  530. PmQueryDeviceRelations(
  531. IN PDEVICE_EXTENSION Extension,
  532. IN PIRP Irp
  533. )
  534. /*++
  535. Routine Description:
  536. This routine processes the query device relations request.
  537. Arguments:
  538. Extension - Supplies the device extension.
  539. Irp - Supplies the IO request packet.
  540. Return Value:
  541. NTSTATUS
  542. --*/
  543. {
  544. NTSTATUS status;
  545. PDRIVE_LAYOUT_INFORMATION_EX newLayout;
  546. KEVENT event;
  547. PDEVICE_RELATIONS deviceRelations;
  548. PLIST_ENTRY l, b;
  549. PPARTITION_LIST_ENTRY partition;
  550. ULONG i;
  551. PDO_EXTENSION driverExtension;
  552. PVOLMGR_LIST_ENTRY volmgrEntry;
  553. KeInitializeEvent(&event, NotificationEvent, FALSE);
  554. IoCopyCurrentIrpStackLocationToNext(Irp);
  555. IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
  556. IoCallDriver(Extension->TargetObject, Irp);
  557. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  558. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  559. return Irp->IoStatus.Status;
  560. }
  561. deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  562. if (Extension->SignaturesNotChecked) {
  563. status = PmReadPartitionTableEx(Extension->TargetObject,
  564. &newLayout);
  565. if (NT_SUCCESS(status)) {
  566. KeWaitForSingleObject(&Extension->DriverExtension->Mutex,
  567. Executive, KernelMode, FALSE, NULL);
  568. PmAddSignatures(Extension, newLayout);
  569. Extension->SignaturesNotChecked = FALSE;
  570. KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
  571. ExFreePool(newLayout);
  572. }
  573. }
  574. //
  575. // First notify clients of partitions that have gone away.
  576. //
  577. driverExtension = Extension->DriverExtension;
  578. KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
  579. FALSE, NULL);
  580. for (l = Extension->PartitionList.Flink; l != &Extension->PartitionList;
  581. l = l->Flink) {
  582. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  583. for (i = 0; i < deviceRelations->Count; i++) {
  584. if (partition->TargetObject == deviceRelations->Objects[i]) {
  585. break;
  586. }
  587. }
  588. if (i < deviceRelations->Count) {
  589. continue;
  590. }
  591. PmTakePartition(partition->VolumeManagerEntry,
  592. partition->TargetObject, partition->WholeDiskPdo);
  593. //
  594. // We're pretending to be pnp. Send a remove to the partition
  595. // object so it can delete it.
  596. //
  597. PmRemovePartition(partition);
  598. b = l->Blink;
  599. RemoveEntryList(l);
  600. l = b;
  601. ExFreePool(partition);
  602. }
  603. //
  604. // Then notify clients of new partitions.
  605. //
  606. for (i = 0; i < deviceRelations->Count; i++) {
  607. for (l = Extension->PartitionList.Flink;
  608. l != &Extension->PartitionList; l = l->Flink) {
  609. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  610. if (deviceRelations->Objects[i] == partition->TargetObject) {
  611. break;
  612. }
  613. }
  614. if (l != &Extension->PartitionList) {
  615. //
  616. // Must attempt to start the partition even if it is in our list
  617. // because it may be stopped and need restarting.
  618. //
  619. PmStartPartition(deviceRelations->Objects[i]);
  620. continue;
  621. }
  622. if (Extension->DriverExtension->PastReinit) {
  623. //
  624. // Now that this partition is owned by the partition manager
  625. // make sure that nobody can open it another way.
  626. //
  627. deviceRelations->Objects[i]->Flags |= DO_DEVICE_INITIALIZING;
  628. }
  629. status = PmStartPartition(deviceRelations->Objects[i]);
  630. if (!NT_SUCCESS(status)) {
  631. continue;
  632. }
  633. partition = ExAllocatePoolWithTag(NonPagedPool,
  634. sizeof(PARTITION_LIST_ENTRY),
  635. PARTMGR_TAG_PARTITION_ENTRY);
  636. if (!partition) {
  637. continue;
  638. }
  639. partition->TargetObject = deviceRelations->Objects[i];
  640. partition->WholeDiskPdo = Extension->Pdo;
  641. partition->VolumeManagerEntry = NULL;
  642. InsertHeadList(&Extension->PartitionList, &partition->ListEntry);
  643. if (Extension->IsRedundantPath) {
  644. continue;
  645. }
  646. for (l = driverExtension->VolumeManagerList.Flink;
  647. l != &driverExtension->VolumeManagerList; l = l->Flink) {
  648. volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
  649. status = PmGivePartition(volmgrEntry,
  650. partition->TargetObject,
  651. partition->WholeDiskPdo);
  652. if (NT_SUCCESS(status)) {
  653. partition->VolumeManagerEntry = volmgrEntry;
  654. break;
  655. }
  656. }
  657. }
  658. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  659. deviceRelations->Count = 0;
  660. return Irp->IoStatus.Status;
  661. }
  662. VOID
  663. PmTakeWholeDisk(
  664. IN PVOLMGR_LIST_ENTRY VolumeManagerEntry,
  665. IN PDEVICE_OBJECT WholeDiskPdo
  666. )
  667. /*++
  668. Routine Description:
  669. This routine alerts the volume manager that the given PDO is going away.
  670. Arguments:
  671. VolumeManager - Supplies a volume manager.
  672. WholeDiskPdo - Supplies the whole disk PDO.
  673. Return Value:
  674. NTSTATUS
  675. --*/
  676. {
  677. NTSTATUS status;
  678. KEVENT event;
  679. VOLMGR_WHOLE_DISK_INFORMATION input;
  680. PIRP irp;
  681. IO_STATUS_BLOCK ioStatus;
  682. if (!VolumeManagerEntry) {
  683. return;
  684. }
  685. if (!VolumeManagerEntry->RefCount) {
  686. status = IoGetDeviceObjectPointer(
  687. &VolumeManagerEntry->VolumeManagerName, FILE_READ_DATA,
  688. &VolumeManagerEntry->VolumeManagerFileObject,
  689. &VolumeManagerEntry->VolumeManager);
  690. if (!NT_SUCCESS(status)) {
  691. return;
  692. }
  693. }
  694. KeInitializeEvent(&event, NotificationEvent, FALSE);
  695. input.WholeDiskPdo = WholeDiskPdo;
  696. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_VOLMGR_WHOLE_DISK_REMOVED,
  697. VolumeManagerEntry->VolumeManager,
  698. &input, sizeof(input), NULL, 0, TRUE,
  699. &event, &ioStatus);
  700. if (!irp) {
  701. if (!VolumeManagerEntry->RefCount) {
  702. VolumeManagerEntry->VolumeManager = NULL;
  703. ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
  704. VolumeManagerEntry->VolumeManagerFileObject = NULL;
  705. }
  706. return;
  707. }
  708. status = IoCallDriver(VolumeManagerEntry->VolumeManager, irp);
  709. if (status == STATUS_PENDING) {
  710. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  711. }
  712. if (!VolumeManagerEntry->RefCount) {
  713. VolumeManagerEntry->VolumeManager = NULL;
  714. ObDereferenceObject(VolumeManagerEntry->VolumeManagerFileObject);
  715. VolumeManagerEntry->VolumeManagerFileObject = NULL;
  716. }
  717. }
  718. NTSTATUS
  719. PmNotifyPartitions(
  720. IN PDEVICE_EXTENSION Extension,
  721. IN PIRP Irp
  722. )
  723. /*++
  724. Routine Description:
  725. This routine notifies each partition stolen by the partmgr that it is
  726. about to be removed.
  727. Arguments:
  728. Extension - Supplies the device extension.
  729. Irp - Supplies the IO request packet.
  730. Return Value:
  731. NTSTATUS
  732. --*/
  733. {
  734. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  735. PLIST_ENTRY l;
  736. PPARTITION_LIST_ENTRY partition;
  737. NTSTATUS status = STATUS_SUCCESS;
  738. KEVENT event;
  739. PAGED_CODE();
  740. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  741. KeWaitForSingleObject(&Extension->DriverExtension->Mutex, Executive,
  742. KernelMode, FALSE, NULL);
  743. for(l = Extension->PartitionList.Flink;
  744. l != &(Extension->PartitionList);
  745. l = l->Flink) {
  746. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  747. IoCopyCurrentIrpStackLocationToNext(Irp);
  748. IoSetCompletionRoutine(Irp,
  749. PmSignalCompletion,
  750. &event,
  751. TRUE,
  752. TRUE,
  753. TRUE);
  754. status = IoCallDriver(partition->TargetObject, Irp);
  755. if(status == STATUS_PENDING) {
  756. KeWaitForSingleObject(&event,
  757. Executive,
  758. KernelMode,
  759. FALSE,
  760. NULL);
  761. status = Irp->IoStatus.Status;
  762. }
  763. if(!NT_SUCCESS(status)) {
  764. break;
  765. }
  766. }
  767. KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
  768. return status;
  769. }
  770. NTSTATUS
  771. PmRemoveDevice(
  772. IN PDEVICE_EXTENSION Extension,
  773. IN PIRP Irp
  774. )
  775. /*++
  776. Routine Description:
  777. This routine processes the query device relations request.
  778. Arguments:
  779. Extension - Supplies the device extension.
  780. Irp - Supplies the I/O request packet.
  781. Return Value:
  782. NTSTATUS
  783. --*/
  784. {
  785. PDO_EXTENSION driverExtension = Extension->DriverExtension;
  786. NTSTATUS status;
  787. PDRIVE_LAYOUT_INFORMATION_EX layout;
  788. PLIST_ENTRY l;
  789. PPARTITION_LIST_ENTRY partition;
  790. PVOLMGR_LIST_ENTRY volmgrEntry;
  791. KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
  792. FALSE, NULL);
  793. if (Extension->RemoveProcessed) {
  794. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  795. return STATUS_SUCCESS;
  796. }
  797. Extension->RemoveProcessed = TRUE;
  798. Extension->IsStarted = FALSE;
  799. PmAddSignatures(Extension, NULL);
  800. for (l = Extension->PartitionList.Flink;
  801. l != &Extension->PartitionList; l = l->Flink) {
  802. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  803. PmTakePartition(partition->VolumeManagerEntry,
  804. partition->TargetObject, NULL);
  805. }
  806. status = PmNotifyPartitions(Extension, Irp);
  807. ASSERT(NT_SUCCESS(status));
  808. while (!IsListEmpty(&Extension->PartitionList)) {
  809. l = RemoveHeadList(&Extension->PartitionList);
  810. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  811. ExFreePool(partition);
  812. }
  813. for (l = driverExtension->VolumeManagerList.Flink;
  814. l != &driverExtension->VolumeManagerList; l = l->Flink) {
  815. volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
  816. PmTakeWholeDisk(volmgrEntry, Extension->Pdo);
  817. }
  818. RemoveEntryList(&Extension->ListEntry);
  819. if (Extension->WmilibContext != NULL) { // just to be safe
  820. IoWMIRegistrationControl(Extension->DeviceObject,
  821. WMIREG_ACTION_DEREGISTER);
  822. ExFreePool(Extension->WmilibContext);
  823. Extension->WmilibContext = NULL;
  824. PmWmiCounterDisable(&Extension->PmWmiCounterContext,
  825. TRUE, TRUE);
  826. Extension->CountersEnabled = FALSE;
  827. }
  828. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  829. return status;
  830. }
  831. VOID
  832. PmPowerNotify (
  833. IN PDEVICE_OBJECT DeviceObject,
  834. IN PVOID PublicWorkItem
  835. )
  836. /*++
  837. Routine Description:
  838. This routine notifies volume managers about changes in
  839. the power state of the given disk.
  840. Arguments:
  841. DeviceObject - Supplies the device object.
  842. PublicWorkItem - Supplies the public work item
  843. Return Value:
  844. None
  845. --*/
  846. {
  847. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  848. PDO_EXTENSION driverExtension = deviceExtension->DriverExtension;
  849. KEVENT event;
  850. KIRQL irql;
  851. LIST_ENTRY q;
  852. PLIST_ENTRY l;
  853. BOOLEAN empty;
  854. PPM_POWER_WORK_ITEM privateWorkItem;
  855. PPARTITION_LIST_ENTRY partition;
  856. VOLMGR_POWER_STATE input;
  857. PIRP irp;
  858. IO_STATUS_BLOCK ioStatus;
  859. NTSTATUS status;
  860. KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
  861. FALSE, NULL);
  862. KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
  863. if (IsListEmpty(&deviceExtension->PowerQueue)) {
  864. empty = TRUE;
  865. } else {
  866. empty = FALSE;
  867. q = deviceExtension->PowerQueue;
  868. InitializeListHead(&deviceExtension->PowerQueue);
  869. }
  870. KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
  871. if (empty) {
  872. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  873. IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
  874. IoFreeWorkItem((PIO_WORKITEM) PublicWorkItem);
  875. return;
  876. }
  877. q.Flink->Blink = &q;
  878. q.Blink->Flink = &q;
  879. KeInitializeEvent(&event, NotificationEvent, FALSE);
  880. while (!IsListEmpty(&q)) {
  881. l = RemoveHeadList(&q);
  882. privateWorkItem = CONTAINING_RECORD(l, PM_POWER_WORK_ITEM, ListEntry);
  883. for (l = deviceExtension->PartitionList.Flink;
  884. l != &deviceExtension->PartitionList; l = l->Flink) {
  885. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  886. if (!partition->VolumeManagerEntry) {
  887. continue;
  888. }
  889. input.PartitionDeviceObject = partition->TargetObject;
  890. input.WholeDiskPdo = partition->WholeDiskPdo;
  891. input.PowerState = privateWorkItem->DevicePowerState;
  892. irp = IoBuildDeviceIoControlRequest(
  893. IOCTL_INTERNAL_VOLMGR_SET_POWER_STATE,
  894. partition->VolumeManagerEntry->VolumeManager,
  895. &input, sizeof(input), NULL, 0, TRUE,
  896. &event, &ioStatus);
  897. if (!irp) {
  898. continue;
  899. }
  900. status = IoCallDriver(partition->VolumeManagerEntry->VolumeManager,
  901. irp);
  902. if (status == STATUS_PENDING) {
  903. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  904. }
  905. KeClearEvent(&event);
  906. }
  907. ExFreePool(privateWorkItem);
  908. }
  909. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  910. IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
  911. IoFreeWorkItem((PIO_WORKITEM) PublicWorkItem);
  912. }
  913. NTSTATUS
  914. PmPowerCompletion(
  915. IN PDEVICE_OBJECT DeviceObject,
  916. IN PIRP Irp,
  917. IN PVOID Context
  918. )
  919. /*++
  920. Routine Description:
  921. This routine handles completion of an IRP_MN_SET_POWER irp.
  922. Arguments:
  923. DeviceObject - Supplies the device object.
  924. Irp - Supplies the IO request packet.
  925. Context - Not used.
  926. Return Value:
  927. NTSTATUS
  928. --*/
  929. {
  930. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  931. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  932. PIO_WORKITEM publicWorkItem;
  933. PPM_POWER_WORK_ITEM privateWorkItem;
  934. KIRQL irql;
  935. ASSERT(irpStack->MajorFunction == IRP_MJ_POWER &&
  936. irpStack->MinorFunction == IRP_MN_SET_POWER);
  937. ASSERT(irpStack->Parameters.Power.Type == DevicePowerState);
  938. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  939. PoStartNextPowerIrp(Irp);
  940. IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
  941. return STATUS_SUCCESS;
  942. }
  943. publicWorkItem = IoAllocateWorkItem(DeviceObject);
  944. if (!publicWorkItem) {
  945. PoStartNextPowerIrp(Irp);
  946. IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
  947. return STATUS_SUCCESS;
  948. }
  949. privateWorkItem = (PPM_POWER_WORK_ITEM) ExAllocatePoolWithTag(NonPagedPool,
  950. sizeof(PM_POWER_WORK_ITEM),
  951. PARTMGR_TAG_POWER_WORK_ITEM);
  952. if (!privateWorkItem) {
  953. PoStartNextPowerIrp(Irp);
  954. IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
  955. IoFreeWorkItem(publicWorkItem);
  956. return STATUS_SUCCESS;
  957. }
  958. privateWorkItem->DevicePowerState =
  959. irpStack->Parameters.Power.State.DeviceState;
  960. KeAcquireSpinLock(&deviceExtension->SpinLock, &irql);
  961. InsertTailList(&deviceExtension->PowerQueue, &privateWorkItem->ListEntry);
  962. KeReleaseSpinLock(&deviceExtension->SpinLock, irql);
  963. IoQueueWorkItem(publicWorkItem, PmPowerNotify, DelayedWorkQueue,
  964. publicWorkItem);
  965. PoStartNextPowerIrp(Irp);
  966. return STATUS_SUCCESS;
  967. }
  968. NTSTATUS
  969. PmPower(
  970. IN PDEVICE_OBJECT DeviceObject,
  971. IN PIRP Irp
  972. )
  973. /*++
  974. Routine Description:
  975. This routine is the dispatch for IRP_MJ_POWER.
  976. Arguments:
  977. DeviceObject - Supplies the device object.
  978. Irp - Supplies the IO request packet.
  979. Return Value:
  980. NTSTATUS
  981. --*/
  982. {
  983. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  984. PDEVICE_EXTENSION deviceExtension =
  985. (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  986. NTSTATUS status;
  987. status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
  988. if (!NT_SUCCESS (status)) {
  989. PoStartNextPowerIrp (Irp);
  990. Irp->IoStatus.Information = 0;
  991. Irp->IoStatus.Status = status;
  992. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  993. return status;
  994. }
  995. if (irpSp->MinorFunction == IRP_MN_SET_POWER &&
  996. irpSp->Parameters.Power.Type == DevicePowerState) {
  997. IoCopyCurrentIrpStackLocationToNext(Irp);
  998. IoSetCompletionRoutine(Irp, PmPowerCompletion, NULL, TRUE,
  999. TRUE, TRUE);
  1000. IoMarkIrpPending(Irp);
  1001. PoCallDriver(deviceExtension->TargetObject, Irp);
  1002. return STATUS_PENDING;
  1003. }
  1004. PoStartNextPowerIrp(Irp);
  1005. IoSkipCurrentIrpStackLocation(Irp);
  1006. status = PoCallDriver(deviceExtension->TargetObject, Irp);
  1007. IoReleaseRemoveLock(&deviceExtension->RemoveLock, NULL);
  1008. return status;
  1009. }
  1010. NTSTATUS
  1011. PmQueryRemovalRelations(
  1012. IN PDEVICE_EXTENSION Extension,
  1013. IN PIRP Irp
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. This routine processes the query removal relations request.
  1018. Arguments:
  1019. Extension - Supplies the device extension.
  1020. Irp - Supplies the IO request packet.
  1021. Return Value:
  1022. NTSTATUS
  1023. --*/
  1024. {
  1025. NTSTATUS status;
  1026. KEVENT event;
  1027. PDEVICE_RELATIONS deviceRelations;
  1028. PLIST_ENTRY l, b;
  1029. PPARTITION_LIST_ENTRY partition;
  1030. ULONG i;
  1031. PDO_EXTENSION driverExtension;
  1032. PVOLMGR_LIST_ENTRY volmgrEntry;
  1033. status = Irp->IoStatus.Status;
  1034. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1035. IoCopyCurrentIrpStackLocationToNext(Irp);
  1036. IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
  1037. IoCallDriver(Extension->TargetObject, Irp);
  1038. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1039. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  1040. Irp->IoStatus.Information = 0;
  1041. if (status != Irp->IoStatus.Status) {
  1042. return Irp->IoStatus.Status;
  1043. }
  1044. }
  1045. return PmBuildDependantVolumeRelations(Extension,
  1046. &((PDEVICE_RELATIONS) Irp->IoStatus.Information));
  1047. }
  1048. BOOLEAN
  1049. PmIsRedundantPath(
  1050. IN PDEVICE_EXTENSION Extension,
  1051. IN PDEVICE_EXTENSION WinningExtension,
  1052. IN ULONG Signature,
  1053. IN GUID* Guid
  1054. )
  1055. {
  1056. PDO_EXTENSION driverExtension = Extension->DriverExtension;
  1057. PDEVICE_EXTENSION extension = WinningExtension;
  1058. PGUID_TABLE_ENTRY guidEntry;
  1059. PSIGNATURE_TABLE_ENTRY sigEntry;
  1060. KEVENT event;
  1061. PIRP irp;
  1062. DISK_GEOMETRY geometry, geometry2;
  1063. IO_STATUS_BLOCK ioStatus;
  1064. NTSTATUS status;
  1065. ULONG bufferSize;
  1066. ULONG readSize;
  1067. PVOID buffer;
  1068. LARGE_INTEGER byteOffset;
  1069. PULONG signature;
  1070. BOOLEAN isRedundant;
  1071. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1072. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
  1073. Extension->TargetObject, NULL, 0,
  1074. &geometry, sizeof(geometry), FALSE,
  1075. &event, &ioStatus);
  1076. if (!irp) {
  1077. return FALSE;
  1078. }
  1079. status = IoCallDriver(Extension->TargetObject, irp);
  1080. if (status == STATUS_PENDING) {
  1081. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1082. status = ioStatus.Status;
  1083. }
  1084. if (!NT_SUCCESS(status)) {
  1085. return FALSE;
  1086. }
  1087. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1088. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
  1089. extension->TargetObject, NULL, 0,
  1090. &geometry2, sizeof(geometry2), FALSE,
  1091. &event, &ioStatus);
  1092. if (!irp) {
  1093. return FALSE;
  1094. }
  1095. status = IoCallDriver(extension->TargetObject, irp);
  1096. if (status == STATUS_PENDING) {
  1097. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1098. status = ioStatus.Status;
  1099. }
  1100. if (!NT_SUCCESS(status)) {
  1101. return FALSE;
  1102. }
  1103. if (geometry2.BytesPerSector > geometry.BytesPerSector) {
  1104. geometry.BytesPerSector = geometry2.BytesPerSector;
  1105. }
  1106. byteOffset.QuadPart = 0;
  1107. readSize = 512;
  1108. if (readSize < geometry.BytesPerSector) {
  1109. readSize = geometry.BytesPerSector;
  1110. }
  1111. bufferSize = 2*readSize;
  1112. buffer = ExAllocatePoolWithTag(NonPagedPool, bufferSize < PAGE_SIZE ?
  1113. PAGE_SIZE : bufferSize,
  1114. PARTMGR_TAG_IOCTL_BUFFER);
  1115. if (!buffer) {
  1116. return FALSE;
  1117. }
  1118. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1119. irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, Extension->TargetObject,
  1120. buffer, readSize, &byteOffset, &event,
  1121. &ioStatus);
  1122. if (!irp) {
  1123. ExFreePool(buffer);
  1124. return FALSE;
  1125. }
  1126. status = IoCallDriver(Extension->TargetObject, irp);
  1127. if (status == STATUS_PENDING) {
  1128. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1129. status = ioStatus.Status;
  1130. }
  1131. if (!NT_SUCCESS(status)) {
  1132. ExFreePool(buffer);
  1133. return FALSE;
  1134. }
  1135. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1136. irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, extension->TargetObject,
  1137. (PCHAR) buffer + readSize, readSize,
  1138. &byteOffset, &event, &ioStatus);
  1139. if (!irp) {
  1140. ExFreePool(buffer);
  1141. return FALSE;
  1142. }
  1143. status = IoCallDriver(extension->TargetObject, irp);
  1144. if (status == STATUS_PENDING) {
  1145. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1146. status = ioStatus.Status;
  1147. }
  1148. if (!NT_SUCCESS(status)) {
  1149. ExFreePool(buffer);
  1150. return FALSE;
  1151. }
  1152. if (RtlCompareMemory(buffer, (PCHAR) buffer + readSize, readSize) !=
  1153. readSize) {
  1154. ExFreePool(buffer);
  1155. return FALSE;
  1156. }
  1157. signature = (PULONG) ((PCHAR) buffer + 0x1B8);
  1158. (*signature)++;
  1159. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1160. irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, Extension->TargetObject,
  1161. buffer, readSize, &byteOffset, &event,
  1162. &ioStatus);
  1163. if (!irp) {
  1164. ExFreePool(buffer);
  1165. return FALSE;
  1166. }
  1167. status = IoCallDriver(Extension->TargetObject, irp);
  1168. if (status == STATUS_PENDING) {
  1169. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1170. status = ioStatus.Status;
  1171. }
  1172. if (!NT_SUCCESS(status)) {
  1173. ExFreePool(buffer);
  1174. return FALSE;
  1175. }
  1176. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1177. irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, extension->TargetObject,
  1178. (PCHAR) buffer + readSize, readSize,
  1179. &byteOffset, &event, &ioStatus);
  1180. if (!irp) {
  1181. ExFreePool(buffer);
  1182. return FALSE;
  1183. }
  1184. status = IoCallDriver(extension->TargetObject, irp);
  1185. if (status == STATUS_PENDING) {
  1186. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1187. status = ioStatus.Status;
  1188. }
  1189. if (!NT_SUCCESS(status)) {
  1190. ExFreePool(buffer);
  1191. return FALSE;
  1192. }
  1193. if (RtlCompareMemory(buffer, (PCHAR) buffer + readSize, readSize) !=
  1194. readSize) {
  1195. ExFreePool(buffer);
  1196. return FALSE;
  1197. }
  1198. (*signature)--;
  1199. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1200. irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, Extension->TargetObject,
  1201. buffer, readSize, &byteOffset, &event,
  1202. &ioStatus);
  1203. if (!irp) {
  1204. ExFreePool(buffer);
  1205. return TRUE;
  1206. }
  1207. status = IoCallDriver(Extension->TargetObject, irp);
  1208. if (status == STATUS_PENDING) {
  1209. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1210. status = ioStatus.Status;
  1211. }
  1212. if (!NT_SUCCESS(status)) {
  1213. ExFreePool(buffer);
  1214. return TRUE;
  1215. }
  1216. ExFreePool(buffer);
  1217. return TRUE;
  1218. }
  1219. VOID
  1220. PmLogError(
  1221. IN PDEVICE_EXTENSION Extension,
  1222. IN PDEVICE_EXTENSION WinningExtension,
  1223. IN NTSTATUS SpecificIoStatus
  1224. )
  1225. {
  1226. KEVENT event;
  1227. PIRP irp;
  1228. STORAGE_DEVICE_NUMBER deviceNumber, winningDeviceNumber;
  1229. IO_STATUS_BLOCK ioStatus;
  1230. NTSTATUS status;
  1231. WCHAR buffer1[30], buffer2[30];
  1232. UNICODE_STRING number, winningNumber;
  1233. ULONG extraSpace;
  1234. PIO_ERROR_LOG_PACKET errorLogPacket;
  1235. PWCHAR p;
  1236. GUID_IO_DISK_CLONE_ARRIVAL_INFORMATION diskCloneArrivalInfo;
  1237. UCHAR notificationBuffer[sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) + sizeof(GUID_IO_DISK_CLONE_ARRIVAL_INFORMATION)];
  1238. PTARGET_DEVICE_CUSTOM_NOTIFICATION notification = (PTARGET_DEVICE_CUSTOM_NOTIFICATION) notificationBuffer;
  1239. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1240. irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
  1241. Extension->TargetObject, NULL, 0,
  1242. &deviceNumber, sizeof(deviceNumber),
  1243. FALSE, &event, &ioStatus);
  1244. if (!irp) {
  1245. return;
  1246. }
  1247. status = IoCallDriver(Extension->TargetObject, irp);
  1248. if (status == STATUS_PENDING) {
  1249. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1250. status = ioStatus.Status;
  1251. }
  1252. if (!NT_SUCCESS(status)) {
  1253. return;
  1254. }
  1255. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1256. irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
  1257. WinningExtension->TargetObject, NULL,
  1258. 0, &winningDeviceNumber,
  1259. sizeof(winningDeviceNumber),
  1260. FALSE, &event, &ioStatus);
  1261. if (!irp) {
  1262. return;
  1263. }
  1264. status = IoCallDriver(WinningExtension->TargetObject, irp);
  1265. if (status == STATUS_PENDING) {
  1266. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1267. status = ioStatus.Status;
  1268. }
  1269. if (!NT_SUCCESS(status)) {
  1270. return;
  1271. }
  1272. swprintf(buffer1, L"%d", deviceNumber.DeviceNumber);
  1273. RtlInitUnicodeString(&number, buffer1);
  1274. swprintf(buffer2, L"%d", winningDeviceNumber.DeviceNumber);
  1275. RtlInitUnicodeString(&winningNumber, buffer2);
  1276. extraSpace = number.Length + winningNumber.Length + 2*sizeof(WCHAR);
  1277. extraSpace += sizeof(IO_ERROR_LOG_PACKET);
  1278. if (extraSpace > 0xFF) {
  1279. return;
  1280. }
  1281. errorLogPacket = (PIO_ERROR_LOG_PACKET)
  1282. IoAllocateErrorLogEntry(Extension->DeviceObject,
  1283. (UCHAR) extraSpace);
  1284. if (!errorLogPacket) {
  1285. return;
  1286. }
  1287. errorLogPacket->ErrorCode = SpecificIoStatus;
  1288. errorLogPacket->SequenceNumber = 0;
  1289. errorLogPacket->FinalStatus = 0;
  1290. errorLogPacket->UniqueErrorValue = 0;
  1291. errorLogPacket->DumpDataSize = 0;
  1292. errorLogPacket->RetryCount = 0;
  1293. errorLogPacket->NumberOfStrings = 2;
  1294. errorLogPacket->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
  1295. p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET));
  1296. RtlCopyMemory(p, number.Buffer, number.Length);
  1297. p[number.Length/sizeof(WCHAR)] = 0;
  1298. p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET) +
  1299. number.Length + sizeof(WCHAR));
  1300. RtlCopyMemory(p, winningNumber.Buffer, winningNumber.Length);
  1301. p[winningNumber.Length/sizeof(WCHAR)] = 0;
  1302. IoWriteErrorLogEntry(errorLogPacket);
  1303. if (SpecificIoStatus == IO_WARNING_DUPLICATE_SIGNATURE) {
  1304. diskCloneArrivalInfo.DiskNumber = deviceNumber.DeviceNumber;
  1305. notification->Version = 1;
  1306. notification->Size = (USHORT)
  1307. (FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION,
  1308. CustomDataBuffer) +
  1309. sizeof(diskCloneArrivalInfo));
  1310. RtlCopyMemory(&notification->Event, &GUID_IO_DISK_CLONE_ARRIVAL,
  1311. sizeof(GUID_IO_DISK_CLONE_ARRIVAL));
  1312. notification->FileObject = NULL;
  1313. notification->NameBufferOffset = -1;
  1314. RtlCopyMemory(notification->CustomDataBuffer, &diskCloneArrivalInfo,
  1315. sizeof(diskCloneArrivalInfo));
  1316. IoReportTargetDeviceChangeAsynchronous(WinningExtension->Pdo,
  1317. notification, NULL, NULL);
  1318. }
  1319. }
  1320. ULONG
  1321. PmQueryRegistrySignature(
  1322. )
  1323. /*++
  1324. Routine Description:
  1325. This routine checks a registry value for an MBR signature to be used
  1326. for the bad signature case. This is to facilitate OEM pre-install.
  1327. Arguments:
  1328. None.
  1329. Return Value:
  1330. A valid signature or 0.
  1331. --*/
  1332. {
  1333. ULONG zero, signature;
  1334. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  1335. NTSTATUS status;
  1336. zero = 0;
  1337. signature = 0;
  1338. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  1339. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1340. queryTable[0].Name = L"BootDiskSig";
  1341. queryTable[0].EntryContext = &signature;
  1342. queryTable[0].DefaultType = REG_DWORD;
  1343. queryTable[0].DefaultData = &zero;
  1344. queryTable[0].DefaultLength = sizeof(ULONG);
  1345. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  1346. L"\\Registry\\Machine\\System\\Setup",
  1347. queryTable, NULL, NULL);
  1348. if (!NT_SUCCESS(status)) {
  1349. signature = zero;
  1350. }
  1351. RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  1352. L"\\Registry\\Machine\\System\\Setup",
  1353. L"BootDiskSig");
  1354. return signature;
  1355. }
  1356. VOID
  1357. PmAddSignatures(
  1358. IN PDEVICE_EXTENSION Extension,
  1359. IN PDRIVE_LAYOUT_INFORMATION_EX Layout
  1360. )
  1361. /*++
  1362. Routine Description:
  1363. This routine adds the disk and partition signature to their
  1364. respective tables. If a collision is detected, the signatures are
  1365. changed and written back out.
  1366. Arguments:
  1367. Extension - Supplies the device extension.
  1368. Return Value:
  1369. NTSTATUS
  1370. --*/
  1371. {
  1372. PDO_EXTENSION driverExtension = Extension->DriverExtension;
  1373. PLIST_ENTRY l;
  1374. PSIGNATURE_TABLE_ENTRY s;
  1375. PGUID_TABLE_ENTRY g;
  1376. SIGNATURE_TABLE_ENTRY sigEntry;
  1377. GUID_TABLE_ENTRY guidEntry;
  1378. NTSTATUS status;
  1379. PVOID nodeOrParent, nodeOrParent2;
  1380. TABLE_SEARCH_RESULT searchResult, searchResult2;
  1381. UUID uuid;
  1382. PULONG p;
  1383. ULONG i;
  1384. while (!IsListEmpty(&Extension->SignatureList)) {
  1385. l = RemoveHeadList(&Extension->SignatureList);
  1386. s = CONTAINING_RECORD(l, SIGNATURE_TABLE_ENTRY, ListEntry);
  1387. RtlDeleteElementGenericTable(&driverExtension->SignatureTable, s);
  1388. }
  1389. while (!IsListEmpty(&Extension->GuidList)) {
  1390. l = RemoveHeadList(&Extension->GuidList);
  1391. g = CONTAINING_RECORD(l, GUID_TABLE_ENTRY, ListEntry);
  1392. RtlDeleteElementGenericTable(&driverExtension->GuidTable, g);
  1393. }
  1394. if (!Layout) {
  1395. return;
  1396. }
  1397. if (Layout->PartitionStyle == PARTITION_STYLE_MBR) {
  1398. if (!Layout->PartitionCount && !Layout->Mbr.Signature) {
  1399. // RAW disk. No signature to validate.
  1400. return;
  1401. }
  1402. if (Layout->PartitionCount > 0 &&
  1403. Layout->PartitionEntry[0].PartitionLength.QuadPart > 0 &&
  1404. Layout->PartitionEntry[0].StartingOffset.QuadPart == 0) {
  1405. // Super floppy. No signature to validate.
  1406. return;
  1407. }
  1408. sigEntry.Signature = Layout->Mbr.Signature;
  1409. s = RtlLookupElementGenericTableFull(
  1410. &driverExtension->SignatureTable, &sigEntry,
  1411. &nodeOrParent, &searchResult);
  1412. if (s || !sigEntry.Signature ||
  1413. Extension->DriverExtension->BootDiskSig) {
  1414. if (s) {
  1415. if (PmIsRedundantPath(Extension, s->Extension,
  1416. sigEntry.Signature, NULL)) {
  1417. PmLogError(Extension, s->Extension,
  1418. IO_WARNING_DUPLICATE_PATH);
  1419. Extension->IsRedundantPath = TRUE;
  1420. return;
  1421. }
  1422. PmLogError(Extension, s->Extension,
  1423. IO_WARNING_DUPLICATE_SIGNATURE);
  1424. }
  1425. if (Extension->DriverExtension->BootDiskSig) {
  1426. Layout->Mbr.Signature =
  1427. Extension->DriverExtension->BootDiskSig;
  1428. Extension->DriverExtension->BootDiskSig = 0;
  1429. } else {
  1430. status = ExUuidCreate(&uuid);
  1431. if (!NT_SUCCESS(status)) {
  1432. return;
  1433. }
  1434. p = (PULONG) &uuid;
  1435. Layout->Mbr.Signature = p[0] ^ p[1] ^ p[2] ^ p[3];
  1436. }
  1437. sigEntry.Signature = Layout->Mbr.Signature;
  1438. if (driverExtension->PastReinit) {
  1439. status = PmWritePartitionTableEx(Extension->TargetObject,
  1440. Layout);
  1441. if (!NT_SUCCESS(status)) {
  1442. return;
  1443. }
  1444. } else {
  1445. Extension->DiskSignature = Layout->Mbr.Signature;
  1446. }
  1447. RtlLookupElementGenericTableFull(
  1448. &driverExtension->SignatureTable, &sigEntry,
  1449. &nodeOrParent, &searchResult);
  1450. }
  1451. s = RtlInsertElementGenericTableFull(&driverExtension->SignatureTable,
  1452. &sigEntry, sizeof(sigEntry), NULL,
  1453. nodeOrParent, searchResult);
  1454. if (!s) {
  1455. return;
  1456. }
  1457. InsertTailList(&Extension->SignatureList, &s->ListEntry);
  1458. s->Extension = Extension;
  1459. return;
  1460. }
  1461. ASSERT(Layout->PartitionStyle == PARTITION_STYLE_GPT);
  1462. if (Layout->PartitionStyle != PARTITION_STYLE_GPT) {
  1463. return;
  1464. }
  1465. if (Extension->DriverExtension->PastReinit) {
  1466. p = (PULONG) &Layout->Gpt.DiskId;
  1467. sigEntry.Signature = p[0] ^ p[1] ^ p[2] ^ p[3];
  1468. guidEntry.Guid = Layout->Gpt.DiskId;
  1469. s = RtlLookupElementGenericTableFull(
  1470. &driverExtension->SignatureTable, &sigEntry,
  1471. &nodeOrParent, &searchResult);
  1472. g = RtlLookupElementGenericTableFull(
  1473. &driverExtension->GuidTable, &guidEntry,
  1474. &nodeOrParent2, &searchResult2);
  1475. if (s || g || !sigEntry.Signature) {
  1476. if (g) {
  1477. if (PmIsRedundantPath(Extension, g->Extension, 0,
  1478. &guidEntry.Guid)) {
  1479. PmLogError(Extension, g->Extension,
  1480. IO_WARNING_DUPLICATE_PATH);
  1481. Extension->IsRedundantPath = TRUE;
  1482. return;
  1483. }
  1484. PmLogError(Extension, g->Extension,
  1485. IO_WARNING_DUPLICATE_SIGNATURE);
  1486. }
  1487. status = ExUuidCreate(&uuid);
  1488. if (!NT_SUCCESS(status)) {
  1489. return;
  1490. }
  1491. Layout->Gpt.DiskId = uuid;
  1492. status = PmWritePartitionTableEx(Extension->TargetObject, Layout);
  1493. if (!NT_SUCCESS(status)) {
  1494. return;
  1495. }
  1496. p = (PULONG) &Layout->Gpt.DiskId;
  1497. sigEntry.Signature = p[0] ^ p[1] ^ p[2] ^ p[3];
  1498. guidEntry.Guid = Layout->Gpt.DiskId;
  1499. RtlLookupElementGenericTableFull(
  1500. &driverExtension->SignatureTable, &sigEntry,
  1501. &nodeOrParent, &searchResult);
  1502. RtlLookupElementGenericTableFull(
  1503. &driverExtension->GuidTable, &guidEntry,
  1504. &nodeOrParent2, &searchResult2);
  1505. }
  1506. s = RtlInsertElementGenericTableFull(
  1507. &driverExtension->SignatureTable, &sigEntry,
  1508. sizeof(sigEntry), NULL, nodeOrParent, searchResult);
  1509. if (!s) {
  1510. return;
  1511. }
  1512. InsertTailList(&Extension->SignatureList, &s->ListEntry);
  1513. s->Extension = Extension;
  1514. g = RtlInsertElementGenericTableFull(
  1515. &driverExtension->GuidTable, &guidEntry,
  1516. sizeof(guidEntry), NULL, nodeOrParent2, searchResult2);
  1517. if (!g) {
  1518. return;
  1519. }
  1520. InsertTailList(&Extension->GuidList, &g->ListEntry);
  1521. g->Extension = Extension;
  1522. }
  1523. for (i = 0; i < Layout->PartitionCount; i++) {
  1524. p = (PULONG) &Layout->PartitionEntry[i].Gpt.PartitionId;
  1525. sigEntry.Signature = p[0] | p[1] | p[2] | p[3];
  1526. guidEntry.Guid = Layout->PartitionEntry[i].Gpt.PartitionId;
  1527. g = RtlLookupElementGenericTableFull(
  1528. &driverExtension->GuidTable, &guidEntry,
  1529. &nodeOrParent, &searchResult);
  1530. if (g || !sigEntry.Signature) {
  1531. status = ExUuidCreate(&uuid);
  1532. if (!NT_SUCCESS(status)) {
  1533. return;
  1534. }
  1535. Layout->PartitionEntry[i].Gpt.PartitionId = uuid;
  1536. status = PmWritePartitionTableEx(Extension->TargetObject, Layout);
  1537. if (!NT_SUCCESS(status)) {
  1538. return;
  1539. }
  1540. guidEntry.Guid = Layout->PartitionEntry[i].Gpt.PartitionId;
  1541. RtlLookupElementGenericTableFull(
  1542. &driverExtension->GuidTable, &guidEntry,
  1543. &nodeOrParent, &searchResult);
  1544. }
  1545. g = RtlInsertElementGenericTableFull(
  1546. &driverExtension->GuidTable, &guidEntry,
  1547. sizeof(guidEntry), NULL, nodeOrParent, searchResult);
  1548. if (!g) {
  1549. return;
  1550. }
  1551. InsertTailList(&Extension->GuidList, &g->ListEntry);
  1552. g->Extension = Extension;
  1553. }
  1554. }
  1555. NTSTATUS
  1556. PmPnp(
  1557. IN PDEVICE_OBJECT DeviceObject,
  1558. IN PIRP Irp
  1559. )
  1560. /*++
  1561. Routine Description:
  1562. This routine is the dispatch for IRP_MJ_PNP.
  1563. Arguments:
  1564. DeviceObject - Supplies the device object.
  1565. Irp - Supplies the IO request packet.
  1566. Return Value:
  1567. NTSTATUS
  1568. --*/
  1569. {
  1570. PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  1571. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1572. KEVENT event;
  1573. NTSTATUS status, status2;
  1574. PDEVICE_OBJECT targetObject;
  1575. PDRIVE_LAYOUT_INFORMATION_EX layout;
  1576. if (irpSp->MinorFunction == IRP_MN_DEVICE_USAGE_NOTIFICATION &&
  1577. irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging) {
  1578. ULONG count;
  1579. BOOLEAN setPagable;
  1580. //
  1581. // synchronize these irps.
  1582. //
  1583. KeWaitForSingleObject(&extension->PagingPathCountEvent,
  1584. Executive, KernelMode, FALSE, NULL);
  1585. //
  1586. // if removing last paging device, need to set DO_POWER_PAGABLE
  1587. // bit here, and possible re-set it below on failure.
  1588. //
  1589. setPagable = FALSE;
  1590. if (!irpSp->Parameters.UsageNotification.InPath &&
  1591. extension->PagingPathCount == 0 ) {
  1592. //
  1593. // removing a paging file. if last removal,
  1594. // must have DO_POWER_PAGABLE bits set
  1595. //
  1596. if (extension->PagingPathCount == 0) {
  1597. if (!(DeviceObject->Flags & DO_POWER_INRUSH)) {
  1598. DeviceObject->Flags |= DO_POWER_PAGABLE;
  1599. setPagable = TRUE;
  1600. }
  1601. }
  1602. }
  1603. //
  1604. // send the irp synchronously
  1605. //
  1606. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1607. IoCopyCurrentIrpStackLocationToNext(Irp);
  1608. IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
  1609. status = IoCallDriver(extension->TargetObject, Irp);
  1610. if (status == STATUS_PENDING) {
  1611. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1612. status = Irp->IoStatus.Status;
  1613. }
  1614. //
  1615. // now deal with the failure and success cases.
  1616. // note that we are not allowed to fail the irp
  1617. // once it is sent to the lower drivers.
  1618. //
  1619. if (NT_SUCCESS(status)) {
  1620. IoAdjustPagingPathCount(
  1621. &extension->PagingPathCount,
  1622. irpSp->Parameters.UsageNotification.InPath);
  1623. if (irpSp->Parameters.UsageNotification.InPath) {
  1624. if (extension->PagingPathCount == 1) {
  1625. DeviceObject->Flags &= ~DO_POWER_PAGABLE;
  1626. }
  1627. }
  1628. } else {
  1629. //
  1630. // cleanup the changes done above
  1631. //
  1632. if (setPagable == TRUE) {
  1633. DeviceObject->Flags &= ~DO_POWER_PAGABLE;
  1634. setPagable = FALSE;
  1635. }
  1636. }
  1637. //
  1638. // set the event so the next one can occur.
  1639. //
  1640. KeSetEvent(&extension->PagingPathCountEvent,
  1641. IO_NO_INCREMENT, FALSE);
  1642. //
  1643. // and complete the irp
  1644. //
  1645. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1646. return status;
  1647. }
  1648. if (extension->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  1649. IoSkipCurrentIrpStackLocation(Irp);
  1650. return IoCallDriver(extension->TargetObject, Irp);
  1651. }
  1652. switch (irpSp->MinorFunction) {
  1653. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1654. switch (irpSp->Parameters.QueryDeviceRelations.Type) {
  1655. case BusRelations:
  1656. status = PmQueryDeviceRelations(extension, Irp);
  1657. break;
  1658. case RemovalRelations:
  1659. status = PmQueryRemovalRelations(extension, Irp);
  1660. break;
  1661. default:
  1662. IoSkipCurrentIrpStackLocation(Irp);
  1663. return IoCallDriver(extension->TargetObject, Irp);
  1664. }
  1665. break;
  1666. case IRP_MN_START_DEVICE:
  1667. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1668. IoCopyCurrentIrpStackLocationToNext(Irp);
  1669. IoSetCompletionRoutine(Irp, PmSignalCompletion, &event,
  1670. TRUE, TRUE, TRUE);
  1671. IoCallDriver(extension->TargetObject, Irp);
  1672. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1673. status = Irp->IoStatus.Status;
  1674. if (!NT_SUCCESS(status)) {
  1675. break;
  1676. }
  1677. if (extension->TargetObject->Characteristics&
  1678. FILE_REMOVABLE_MEDIA) {
  1679. break;
  1680. }
  1681. status2 = PmReadPartitionTableEx(extension->TargetObject,
  1682. &layout);
  1683. KeWaitForSingleObject(&extension->DriverExtension->Mutex,
  1684. Executive, KernelMode, FALSE, NULL);
  1685. extension->IsStarted = TRUE;
  1686. if (NT_SUCCESS(status2)) {
  1687. PmAddSignatures(extension, layout);
  1688. ExFreePool(layout);
  1689. } else {
  1690. extension->SignaturesNotChecked = TRUE;
  1691. }
  1692. KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
  1693. //
  1694. // Register its existence with WMI
  1695. //
  1696. PmRegisterDevice(DeviceObject);
  1697. break;
  1698. case IRP_MN_QUERY_STOP_DEVICE:
  1699. case IRP_MN_CANCEL_STOP_DEVICE:
  1700. case IRP_MN_STOP_DEVICE:
  1701. case IRP_MN_QUERY_REMOVE_DEVICE:
  1702. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1703. status = PmNotifyPartitions(extension, Irp);
  1704. if (!NT_SUCCESS(status)) {
  1705. break;
  1706. }
  1707. IoSkipCurrentIrpStackLocation(Irp);
  1708. return IoCallDriver(extension->TargetObject, Irp);
  1709. case IRP_MN_SURPRISE_REMOVAL:
  1710. case IRP_MN_REMOVE_DEVICE:
  1711. //
  1712. // Notify all the children of their imminent removal.
  1713. //
  1714. PmRemoveDevice(extension, Irp);
  1715. targetObject = extension->TargetObject;
  1716. if (irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
  1717. status = IoAcquireRemoveLock (&extension->RemoveLock, Irp);
  1718. ASSERT(NT_SUCCESS(status));
  1719. IoReleaseRemoveLockAndWait(&extension->RemoveLock, Irp);
  1720. IoDetachDevice(targetObject);
  1721. IoDeleteDevice(extension->DeviceObject);
  1722. }
  1723. IoSkipCurrentIrpStackLocation(Irp);
  1724. return IoCallDriver(targetObject, Irp);
  1725. default:
  1726. IoSkipCurrentIrpStackLocation(Irp);
  1727. return IoCallDriver(extension->TargetObject, Irp);
  1728. }
  1729. Irp->IoStatus.Status = status;
  1730. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1731. return status;
  1732. }
  1733. NTSTATUS
  1734. PmAddDevice(
  1735. IN PDRIVER_OBJECT DriverObject,
  1736. IN PDEVICE_OBJECT PhysicalDeviceObject
  1737. )
  1738. /*++
  1739. Routine Description:
  1740. This routine creates and initializes a new FDO for the corresponding
  1741. PDO.
  1742. Arguments:
  1743. DriverObject - Supplies the FTDISK driver object.
  1744. PhysicalDeviceObject - Supplies the physical device object.
  1745. Return Value:
  1746. NTSTATUS
  1747. --*/
  1748. {
  1749. PDEVICE_OBJECT attachedDevice;
  1750. NTSTATUS status;
  1751. PDEVICE_OBJECT deviceObject;
  1752. PDEVICE_EXTENSION extension;
  1753. attachedDevice = IoGetAttachedDeviceReference(PhysicalDeviceObject);
  1754. if (attachedDevice) {
  1755. if (attachedDevice->Characteristics&FILE_REMOVABLE_MEDIA) {
  1756. ObDereferenceObject(attachedDevice);
  1757. return STATUS_SUCCESS;
  1758. }
  1759. ObDereferenceObject(attachedDevice);
  1760. }
  1761. status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
  1762. NULL, FILE_DEVICE_DISK, 0, FALSE, &deviceObject);
  1763. if (!NT_SUCCESS(status)) {
  1764. return status;
  1765. }
  1766. deviceObject->Flags |= DO_DIRECT_IO;
  1767. //
  1768. // the storage stack explicitly requires DO_POWER_PAGABLE to be
  1769. // set in all filter drivers *unless* DO_POWER_INRUSH is set.
  1770. // this is true even if the attached device doesn't set DO_POWER_PAGABLE
  1771. //
  1772. if (attachedDevice->Flags & DO_POWER_INRUSH) {
  1773. deviceObject->Flags |= DO_POWER_INRUSH;
  1774. } else {
  1775. deviceObject->Flags |= DO_POWER_PAGABLE;
  1776. }
  1777. extension = deviceObject->DeviceExtension;
  1778. RtlZeroMemory(extension, sizeof(DEVICE_EXTENSION));
  1779. extension->DeviceObject = deviceObject;
  1780. extension->DriverExtension = IoGetDriverObjectExtension(DriverObject,
  1781. PmAddDevice);
  1782. extension->TargetObject =
  1783. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  1784. if (!extension->TargetObject) {
  1785. IoDeleteDevice(deviceObject);
  1786. return STATUS_NO_SUCH_DEVICE;
  1787. }
  1788. extension->Pdo = PhysicalDeviceObject;
  1789. InitializeListHead(&extension->PartitionList);
  1790. KeInitializeEvent(&extension->PagingPathCountEvent,
  1791. SynchronizationEvent, TRUE);
  1792. InitializeListHead(&extension->SignatureList);
  1793. InitializeListHead(&extension->GuidList);
  1794. KeWaitForSingleObject(&extension->DriverExtension->Mutex, Executive,
  1795. KernelMode, FALSE, NULL);
  1796. InsertTailList(&extension->DriverExtension->DeviceExtensionList,
  1797. &extension->ListEntry);
  1798. KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
  1799. deviceObject->AlignmentRequirement =
  1800. extension->TargetObject->AlignmentRequirement;
  1801. extension->PhysicalDeviceName.Buffer
  1802. = extension->PhysicalDeviceNameBuffer;
  1803. // Allocate WMI library context
  1804. extension->WmilibContext =
  1805. ExAllocatePoolWithTag(PagedPool, sizeof(WMILIB_CONTEXT),
  1806. PARTMGR_TAG_PARTITION_ENTRY);
  1807. if (extension->WmilibContext != NULL)
  1808. {
  1809. RtlZeroMemory(extension->WmilibContext, sizeof(WMILIB_CONTEXT));
  1810. extension->WmilibContext->GuidCount = DiskperfGuidCount;
  1811. extension->WmilibContext->GuidList = DiskperfGuidList;
  1812. extension->WmilibContext->QueryWmiRegInfo = PmQueryWmiRegInfo;
  1813. extension->WmilibContext->QueryWmiDataBlock = PmQueryWmiDataBlock;
  1814. extension->WmilibContext->WmiFunctionControl = PmWmiFunctionControl;
  1815. }
  1816. KeInitializeSpinLock(&extension->SpinLock);
  1817. InitializeListHead(&extension->PowerQueue);
  1818. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  1819. IoInitializeRemoveLock (&extension->RemoveLock, PARTMGR_TAG_REMOVE_LOCK,
  1820. 2, 5);
  1821. return STATUS_SUCCESS;
  1822. }
  1823. VOID
  1824. PmUnload(
  1825. IN PDRIVER_OBJECT DriverObject
  1826. )
  1827. /*++
  1828. Routine Description:
  1829. This routine unloads.
  1830. Arguments:
  1831. DriverObject - Supplies the driver object.
  1832. Return Value:
  1833. None.
  1834. --*/
  1835. {
  1836. PDO_EXTENSION driverExtension;
  1837. PDEVICE_OBJECT deviceObject;
  1838. while (deviceObject = DriverObject->DeviceObject) {
  1839. IoDeleteDevice(deviceObject);
  1840. }
  1841. driverExtension = IoGetDriverObjectExtension(DriverObject, PmAddDevice);
  1842. if (driverExtension) {
  1843. IoUnregisterPlugPlayNotification(driverExtension->NotificationEntry);
  1844. }
  1845. }
  1846. NTSTATUS
  1847. PmVolumeManagerNotification(
  1848. IN PVOID NotificationStructure,
  1849. IN PVOID DriverExtension
  1850. )
  1851. /*++
  1852. Routine Description:
  1853. This routine is called whenever a volume comes or goes.
  1854. Arguments:
  1855. NotificationStructure - Supplies the notification structure.
  1856. RootExtension - Supplies the root extension.
  1857. Return Value:
  1858. NTSTATUS
  1859. --*/
  1860. {
  1861. PDEVICE_INTERFACE_CHANGE_NOTIFICATION notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) NotificationStructure;
  1862. PDO_EXTENSION driverExtension = (PDO_EXTENSION) DriverExtension;
  1863. PVOLMGR_LIST_ENTRY volmgrEntry;
  1864. NTSTATUS status;
  1865. PLIST_ENTRY l, ll;
  1866. PDEVICE_EXTENSION extension;
  1867. PPARTITION_LIST_ENTRY partition;
  1868. PMWMICOUNTERLIB_CONTEXT input;
  1869. PIRP irp;
  1870. KEVENT event;
  1871. IO_STATUS_BLOCK ioStatus;
  1872. PFILE_OBJECT fileObject;
  1873. PDEVICE_OBJECT deviceObject;
  1874. KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
  1875. FALSE, NULL);
  1876. if (IsEqualGUID(&notification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
  1877. for (l = driverExtension->VolumeManagerList.Flink;
  1878. l != &driverExtension->VolumeManagerList; l = l->Flink) {
  1879. volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
  1880. if (RtlEqualUnicodeString(notification->SymbolicLinkName,
  1881. &volmgrEntry->VolumeManagerName,
  1882. TRUE)) {
  1883. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  1884. return STATUS_SUCCESS;
  1885. }
  1886. }
  1887. volmgrEntry = (PVOLMGR_LIST_ENTRY)
  1888. ExAllocatePoolWithTag(NonPagedPool,
  1889. sizeof(VOLMGR_LIST_ENTRY),
  1890. PARTMGR_TAG_VOLUME_ENTRY
  1891. );
  1892. if (!volmgrEntry) {
  1893. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  1894. return STATUS_SUCCESS;
  1895. }
  1896. volmgrEntry->VolumeManagerName.Length =
  1897. notification->SymbolicLinkName->Length;
  1898. volmgrEntry->VolumeManagerName.MaximumLength =
  1899. volmgrEntry->VolumeManagerName.Length + sizeof(WCHAR);
  1900. volmgrEntry->VolumeManagerName.Buffer = ExAllocatePoolWithTag(
  1901. PagedPool, volmgrEntry->VolumeManagerName.MaximumLength,
  1902. PARTMGR_TAG_VOLUME_ENTRY);
  1903. if (!volmgrEntry->VolumeManagerName.Buffer) {
  1904. ExFreePool(volmgrEntry);
  1905. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  1906. return STATUS_SUCCESS;
  1907. }
  1908. RtlCopyMemory(volmgrEntry->VolumeManagerName.Buffer,
  1909. notification->SymbolicLinkName->Buffer,
  1910. volmgrEntry->VolumeManagerName.Length);
  1911. volmgrEntry->VolumeManagerName.Buffer[
  1912. volmgrEntry->VolumeManagerName.Length/sizeof(WCHAR)] = 0;
  1913. volmgrEntry->RefCount = 0;
  1914. InsertTailList(&driverExtension->VolumeManagerList,
  1915. &volmgrEntry->ListEntry);
  1916. volmgrEntry->VolumeManager = NULL;
  1917. volmgrEntry->VolumeManagerFileObject = NULL;
  1918. status = IoGetDeviceObjectPointer(&volmgrEntry->VolumeManagerName,
  1919. FILE_READ_DATA, &fileObject,
  1920. &deviceObject);
  1921. if (NT_SUCCESS(status)) {
  1922. input.PmWmiCounterEnable = PmWmiCounterEnable;
  1923. input.PmWmiCounterDisable = PmWmiCounterDisable;
  1924. input.PmWmiCounterIoStart = PmWmiCounterIoStart;
  1925. input.PmWmiCounterIoComplete = PmWmiCounterIoComplete;
  1926. input.PmWmiCounterQuery = PmWmiCounterQuery;
  1927. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1928. irp = IoBuildDeviceIoControlRequest(
  1929. IOCTL_INTERNAL_VOLMGR_PMWMICOUNTERLIB_CONTEXT,
  1930. deviceObject, &input, sizeof(input), NULL, 0, TRUE,
  1931. &event, &ioStatus);
  1932. if (irp) {
  1933. status = IoCallDriver(deviceObject, irp);
  1934. if (status == STATUS_PENDING) {
  1935. KeWaitForSingleObject(&event, Executive, KernelMode,
  1936. FALSE, NULL);
  1937. }
  1938. }
  1939. ObDereferenceObject(fileObject);
  1940. }
  1941. for (l = driverExtension->DeviceExtensionList.Flink;
  1942. l != &driverExtension->DeviceExtensionList; l = l->Flink) {
  1943. extension = CONTAINING_RECORD(l, DEVICE_EXTENSION, ListEntry);
  1944. if (extension->IsRedundantPath) {
  1945. continue;
  1946. }
  1947. for (ll = extension->PartitionList.Flink;
  1948. ll != &extension->PartitionList; ll = ll->Flink) {
  1949. partition = CONTAINING_RECORD(ll, PARTITION_LIST_ENTRY,
  1950. ListEntry);
  1951. if (!partition->VolumeManagerEntry) {
  1952. status = PmGivePartition(volmgrEntry,
  1953. partition->TargetObject,
  1954. partition->WholeDiskPdo);
  1955. if (NT_SUCCESS(status)) {
  1956. partition->VolumeManagerEntry = volmgrEntry;
  1957. }
  1958. }
  1959. }
  1960. }
  1961. status = STATUS_SUCCESS;
  1962. } else if (IsEqualGUID(&notification->Event,
  1963. &GUID_DEVICE_INTERFACE_REMOVAL)) {
  1964. for (l = driverExtension->VolumeManagerList.Flink;
  1965. l != &driverExtension->VolumeManagerList; l = l->Flink) {
  1966. volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
  1967. if (RtlEqualUnicodeString(&volmgrEntry->VolumeManagerName,
  1968. notification->SymbolicLinkName, TRUE)) {
  1969. if (!volmgrEntry->RefCount) {
  1970. RemoveEntryList(l);
  1971. ExFreePool(volmgrEntry->VolumeManagerName.Buffer);
  1972. ExFreePool(volmgrEntry);
  1973. }
  1974. break;
  1975. }
  1976. }
  1977. status = STATUS_SUCCESS;
  1978. } else {
  1979. status = STATUS_INVALID_PARAMETER;
  1980. }
  1981. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  1982. return STATUS_SUCCESS;
  1983. }
  1984. NTSTATUS
  1985. PmGetPartitionInformation(
  1986. IN PDEVICE_OBJECT Partition,
  1987. IN PFILE_OBJECT FileObject,
  1988. OUT PLONGLONG PartitionOffset,
  1989. OUT PLONGLONG PartitionLength
  1990. )
  1991. {
  1992. KEVENT event;
  1993. PIRP irp;
  1994. PIO_STACK_LOCATION irpSp;
  1995. PARTITION_INFORMATION partInfo;
  1996. IO_STATUS_BLOCK ioStatus;
  1997. NTSTATUS status;
  1998. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1999. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
  2000. Partition, NULL, 0, &partInfo,
  2001. sizeof(partInfo), FALSE, &event,
  2002. &ioStatus);
  2003. if (!irp) {
  2004. return STATUS_INSUFFICIENT_RESOURCES;
  2005. }
  2006. irpSp = IoGetNextIrpStackLocation(irp);
  2007. irpSp->FileObject = FileObject;
  2008. status = IoCallDriver(Partition, irp);
  2009. if (status == STATUS_PENDING) {
  2010. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2011. status = ioStatus.Status;
  2012. }
  2013. if (!NT_SUCCESS(status)) {
  2014. return status;
  2015. }
  2016. *PartitionOffset = partInfo.StartingOffset.QuadPart;
  2017. *PartitionLength = partInfo.PartitionLength.QuadPart;
  2018. return status;
  2019. }
  2020. VOID
  2021. PmDriverReinit(
  2022. IN PDRIVER_OBJECT DriverObject,
  2023. IN PVOID DriverExtension,
  2024. IN ULONG Count
  2025. )
  2026. {
  2027. PDO_EXTENSION driverExtension = DriverExtension;
  2028. PLIST_ENTRY l, ll;
  2029. PDEVICE_EXTENSION extension;
  2030. PPARTITION_LIST_ENTRY partition;
  2031. NTSTATUS status;
  2032. PDRIVE_LAYOUT_INFORMATION_EX layout;
  2033. KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
  2034. FALSE, NULL);
  2035. InterlockedExchange(&driverExtension->PastReinit, TRUE);
  2036. for (l = driverExtension->DeviceExtensionList.Flink;
  2037. l != &driverExtension->DeviceExtensionList; l = l->Flink) {
  2038. extension = CONTAINING_RECORD(l, DEVICE_EXTENSION, ListEntry);
  2039. if (extension->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  2040. continue;
  2041. }
  2042. if (!extension->IsStarted) {
  2043. continue;
  2044. }
  2045. for (ll = extension->PartitionList.Flink;
  2046. ll != &extension->PartitionList; ll = ll->Flink) {
  2047. partition = CONTAINING_RECORD(ll, PARTITION_LIST_ENTRY,
  2048. ListEntry);
  2049. partition->TargetObject->Flags |= DO_DEVICE_INITIALIZING;
  2050. }
  2051. status = PmReadPartitionTableEx(extension->TargetObject, &layout);
  2052. if (!NT_SUCCESS(status)) {
  2053. continue;
  2054. }
  2055. if (extension->DiskSignature) {
  2056. if (layout->PartitionStyle == PARTITION_STYLE_MBR) {
  2057. layout->Mbr.Signature = extension->DiskSignature;
  2058. PmWritePartitionTableEx(extension->TargetObject, layout);
  2059. }
  2060. extension->DiskSignature = 0;
  2061. }
  2062. if (layout->PartitionStyle == PARTITION_STYLE_GPT) {
  2063. PmAddSignatures(extension, layout);
  2064. }
  2065. ExFreePool(layout);
  2066. }
  2067. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  2068. }
  2069. VOID
  2070. PmBootDriverReinit(
  2071. IN PDRIVER_OBJECT DriverObject,
  2072. IN PVOID DriverExtension,
  2073. IN ULONG Count
  2074. )
  2075. {
  2076. IoRegisterDriverReinitialization(DriverObject, PmDriverReinit,
  2077. DriverExtension);
  2078. }
  2079. NTSTATUS
  2080. PmCheckForUnclaimedPartitions(
  2081. IN PDEVICE_OBJECT DeviceObject
  2082. )
  2083. {
  2084. PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  2085. PDO_EXTENSION driverExtension = extension->DriverExtension;
  2086. NTSTATUS status = STATUS_SUCCESS;
  2087. PLIST_ENTRY l, ll;
  2088. PPARTITION_LIST_ENTRY partition;
  2089. PVOLMGR_LIST_ENTRY volmgrEntry;
  2090. KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
  2091. FALSE, NULL);
  2092. if (extension->IsRedundantPath) {
  2093. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  2094. return STATUS_SUCCESS;
  2095. }
  2096. for (l = extension->PartitionList.Flink; l != &extension->PartitionList;
  2097. l = l->Flink) {
  2098. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  2099. if (partition->VolumeManagerEntry) {
  2100. continue;
  2101. }
  2102. for (ll = driverExtension->VolumeManagerList.Flink;
  2103. ll != &driverExtension->VolumeManagerList; ll = ll->Flink) {
  2104. volmgrEntry = CONTAINING_RECORD(ll, VOLMGR_LIST_ENTRY, ListEntry);
  2105. status = PmGivePartition(volmgrEntry,
  2106. partition->TargetObject,
  2107. partition->WholeDiskPdo);
  2108. if (NT_SUCCESS(status)) {
  2109. partition->VolumeManagerEntry = volmgrEntry;
  2110. break;
  2111. }
  2112. }
  2113. if (ll == &driverExtension->VolumeManagerList) {
  2114. status = STATUS_UNSUCCESSFUL;
  2115. }
  2116. }
  2117. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  2118. return status;
  2119. }
  2120. NTSTATUS
  2121. PmDiskGrowPartition(
  2122. IN PDEVICE_OBJECT DeviceObject,
  2123. IN PIRP Irp
  2124. )
  2125. {
  2126. PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  2127. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2128. PDISK_GROW_PARTITION input;
  2129. NTSTATUS status;
  2130. PPARTITION_LIST_ENTRY partition;
  2131. KEVENT event;
  2132. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2133. sizeof(DISK_GROW_PARTITION)) {
  2134. return STATUS_INVALID_PARAMETER;
  2135. }
  2136. KeWaitForSingleObject(&extension->DriverExtension->Mutex, Executive,
  2137. KernelMode, FALSE, NULL);
  2138. input = (PDISK_GROW_PARTITION) Irp->AssociatedIrp.SystemBuffer;
  2139. status = PmFindPartition(extension, input->PartitionNumber, &partition);
  2140. if (!NT_SUCCESS(status)) {
  2141. KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
  2142. return status;
  2143. }
  2144. status = PmChangePartitionIoctl(extension, partition,
  2145. IOCTL_INTERNAL_VOLMGR_QUERY_CHANGE_PARTITION);
  2146. if (!NT_SUCCESS(status)) {
  2147. KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
  2148. return status;
  2149. }
  2150. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2151. IoCopyCurrentIrpStackLocationToNext(Irp);
  2152. IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE, TRUE, TRUE);
  2153. IoCallDriver(extension->TargetObject, Irp);
  2154. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2155. status = Irp->IoStatus.Status;
  2156. if (NT_SUCCESS(status)) {
  2157. PmChangePartitionIoctl(extension, partition,
  2158. IOCTL_INTERNAL_VOLMGR_PARTITION_CHANGED);
  2159. } else {
  2160. PmChangePartitionIoctl(extension, partition,
  2161. IOCTL_INTERNAL_VOLMGR_CANCEL_CHANGE_PARTITION);
  2162. }
  2163. KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
  2164. return status;
  2165. }
  2166. NTSTATUS
  2167. PmEjectVolumeManagers(
  2168. IN PDEVICE_OBJECT DeviceObject
  2169. )
  2170. /*++
  2171. Routine Description:
  2172. This routine goes through the list of partitions for the given disk
  2173. and takes the partition away from the owning volume managers. It then
  2174. goes through initial arbitration for each partition on the volume.
  2175. This has the effect that each volume manager forgets any cached disk
  2176. information and then start fresh on the disk as it may have been changed
  2177. by another cluster member.
  2178. Arguments:
  2179. DeviceObject - Supplies the device object.
  2180. Return Value:
  2181. NTSTATUS
  2182. --*/
  2183. {
  2184. PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  2185. PDO_EXTENSION driverExtension = extension->DriverExtension;
  2186. PPARTITION_LIST_ENTRY partition;
  2187. PLIST_ENTRY l;
  2188. PVOLMGR_LIST_ENTRY volmgrEntry;
  2189. KeWaitForSingleObject(&driverExtension->Mutex, Executive, KernelMode,
  2190. FALSE, NULL);
  2191. for (l = extension->PartitionList.Flink; l != &extension->PartitionList;
  2192. l = l->Flink) {
  2193. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  2194. if (!partition->VolumeManagerEntry) {
  2195. continue;
  2196. }
  2197. PmTakePartition(partition->VolumeManagerEntry,
  2198. partition->TargetObject, NULL);
  2199. partition->VolumeManagerEntry = NULL;
  2200. }
  2201. for (l = driverExtension->VolumeManagerList.Flink;
  2202. l != &driverExtension->VolumeManagerList; l = l->Flink) {
  2203. volmgrEntry = CONTAINING_RECORD(l, VOLMGR_LIST_ENTRY, ListEntry);
  2204. PmTakeWholeDisk(volmgrEntry, extension->Pdo);
  2205. }
  2206. KeReleaseMutex(&driverExtension->Mutex, FALSE);
  2207. return STATUS_SUCCESS;
  2208. }
  2209. NTSTATUS
  2210. PmQueryDiskSignature(
  2211. IN PDEVICE_OBJECT DeviceObject,
  2212. IN PIRP Irp
  2213. )
  2214. /*++
  2215. Routine Description:
  2216. This routine returns the disk signature for the disk. If the
  2217. volume is not an MBR disk then this call will fail.
  2218. Arguments:
  2219. DeviceObject - Supplies the device object.
  2220. Irp - Supplies the IO request packet.
  2221. Return Value:
  2222. NTSTATUS
  2223. --*/
  2224. {
  2225. PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  2226. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2227. PPARTMGR_DISK_SIGNATURE partSig = Irp->AssociatedIrp.SystemBuffer;
  2228. NTSTATUS status;
  2229. PDRIVE_LAYOUT_INFORMATION_EX layout;
  2230. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2231. sizeof(PARTMGR_DISK_SIGNATURE)) {
  2232. return STATUS_INVALID_PARAMETER;
  2233. }
  2234. Irp->IoStatus.Information = sizeof(PARTMGR_DISK_SIGNATURE);
  2235. if (extension->DiskSignature) {
  2236. partSig->Signature = extension->DiskSignature;
  2237. return STATUS_SUCCESS;
  2238. }
  2239. status = PmReadPartitionTableEx(extension->TargetObject, &layout);
  2240. if (!NT_SUCCESS(status)) {
  2241. Irp->IoStatus.Information = 0;
  2242. return status;
  2243. }
  2244. if (layout->PartitionStyle != PARTITION_STYLE_MBR) {
  2245. ExFreePool(layout);
  2246. Irp->IoStatus.Information = 0;
  2247. return STATUS_INVALID_PARAMETER;
  2248. }
  2249. partSig->Signature = layout->Mbr.Signature;
  2250. ExFreePool(layout);
  2251. return status;
  2252. }
  2253. NTSTATUS
  2254. PmDeviceControl(
  2255. IN PDEVICE_OBJECT DeviceObject,
  2256. IN PIRP Irp
  2257. )
  2258. /*++
  2259. Routine Description:
  2260. This routine is the dispatch for IRP_MJ_PNP.
  2261. Arguments:
  2262. DeviceObject - Supplies the device object.
  2263. Irp - Supplies the IO request packet.
  2264. Return Value:
  2265. NTSTATUS
  2266. --*/
  2267. {
  2268. PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  2269. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2270. KEVENT event;
  2271. NTSTATUS status;
  2272. PDRIVE_LAYOUT_INFORMATION layout;
  2273. PDRIVE_LAYOUT_INFORMATION_EX newLayout;
  2274. if (extension->TargetObject->Characteristics&FILE_REMOVABLE_MEDIA) {
  2275. IoSkipCurrentIrpStackLocation(Irp);
  2276. return IoCallDriver(extension->TargetObject, Irp);
  2277. }
  2278. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  2279. case IOCTL_DISK_SET_DRIVE_LAYOUT:
  2280. case IOCTL_DISK_SET_DRIVE_LAYOUT_EX:
  2281. case IOCTL_DISK_CREATE_DISK:
  2282. case IOCTL_DISK_DELETE_DRIVE_LAYOUT:
  2283. KeWaitForSingleObject(&extension->DriverExtension->Mutex,
  2284. Executive, KernelMode, FALSE, NULL);
  2285. extension->SignaturesNotChecked = TRUE;
  2286. KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
  2287. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2288. IoCopyCurrentIrpStackLocationToNext(Irp);
  2289. IoSetCompletionRoutine(Irp, PmSignalCompletion, &event, TRUE,
  2290. TRUE, TRUE);
  2291. IoCallDriver(extension->TargetObject, Irp);
  2292. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  2293. NULL);
  2294. status = Irp->IoStatus.Status;
  2295. if (!NT_SUCCESS(status)) {
  2296. break;
  2297. }
  2298. status = PmReadPartitionTableEx(extension->TargetObject,
  2299. &newLayout);
  2300. if (!NT_SUCCESS(status)) {
  2301. break;
  2302. }
  2303. KeWaitForSingleObject(&extension->DriverExtension->Mutex,
  2304. Executive, KernelMode, FALSE, NULL);
  2305. PmAddSignatures(extension, newLayout);
  2306. extension->SignaturesNotChecked = FALSE;
  2307. KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
  2308. ExFreePool(newLayout);
  2309. break;
  2310. case IOCTL_PARTMGR_CHECK_UNCLAIMED_PARTITIONS:
  2311. status = PmCheckForUnclaimedPartitions(DeviceObject);
  2312. Irp->IoStatus.Information = 0;
  2313. break;
  2314. case IOCTL_DISK_GROW_PARTITION:
  2315. status = PmDiskGrowPartition(DeviceObject, Irp);
  2316. break;
  2317. case IOCTL_PARTMGR_EJECT_VOLUME_MANAGERS:
  2318. status = PmEjectVolumeManagers(DeviceObject);
  2319. break;
  2320. case IOCTL_DISK_PERFORMANCE:
  2321. //
  2322. // Verify user buffer is large enough for the performance data.
  2323. //
  2324. status = STATUS_SUCCESS;
  2325. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2326. sizeof(DISK_PERFORMANCE)) {
  2327. //
  2328. // Indicate unsuccessful status and no data transferred.
  2329. //
  2330. status = STATUS_BUFFER_TOO_SMALL;
  2331. Irp->IoStatus.Information = 0;
  2332. }
  2333. else if (!(extension->CountersEnabled)) {
  2334. if (!PmQueryEnableAlways(DeviceObject)) {
  2335. status = STATUS_UNSUCCESSFUL;
  2336. Irp->IoStatus.Information = 0;
  2337. }
  2338. }
  2339. if (status == STATUS_SUCCESS) {
  2340. PmWmiCounterQuery(extension->PmWmiCounterContext,
  2341. (PDISK_PERFORMANCE) Irp->AssociatedIrp.SystemBuffer,
  2342. L"Partmgr ",
  2343. extension->DiskNumber);
  2344. Irp->IoStatus.Information = sizeof(DISK_PERFORMANCE);
  2345. }
  2346. break;
  2347. case IOCTL_DISK_PERFORMANCE_OFF:
  2348. //
  2349. // Turns off counting
  2350. //
  2351. if (extension->CountersEnabled) {
  2352. if (InterlockedCompareExchange(&extension->EnableAlways, 0, 1) == 1) {
  2353. if (!PmWmiCounterDisable(&extension->PmWmiCounterContext, FALSE, FALSE)) {
  2354. extension->CountersEnabled = FALSE;
  2355. }
  2356. }
  2357. }
  2358. Irp->IoStatus.Information = 0;
  2359. status = STATUS_SUCCESS;
  2360. break;
  2361. case IOCTL_PARTMGR_QUERY_DISK_SIGNATURE:
  2362. case IOCTL_DISK_GET_DRIVE_LAYOUT:
  2363. case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
  2364. if (extension->SignaturesNotChecked) {
  2365. status = PmReadPartitionTableEx(extension->TargetObject,
  2366. &newLayout);
  2367. if (NT_SUCCESS(status)) {
  2368. KeWaitForSingleObject(&extension->DriverExtension->Mutex,
  2369. Executive, KernelMode, FALSE, NULL);
  2370. PmAddSignatures(extension, newLayout);
  2371. extension->SignaturesNotChecked = FALSE;
  2372. KeReleaseMutex(&extension->DriverExtension->Mutex, FALSE);
  2373. ExFreePool(newLayout);
  2374. }
  2375. }
  2376. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  2377. IOCTL_PARTMGR_QUERY_DISK_SIGNATURE) {
  2378. status = PmQueryDiskSignature(DeviceObject, Irp);
  2379. break;
  2380. }
  2381. // Fall through.
  2382. default:
  2383. IoSkipCurrentIrpStackLocation(Irp);
  2384. return IoCallDriver(extension->TargetObject, Irp);
  2385. }
  2386. Irp->IoStatus.Status = status;
  2387. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2388. return status;
  2389. }
  2390. RTL_GENERIC_COMPARE_RESULTS
  2391. PmTableSignatureCompareRoutine(
  2392. IN PRTL_GENERIC_TABLE Table,
  2393. IN PVOID First,
  2394. IN PVOID Second
  2395. )
  2396. {
  2397. PSIGNATURE_TABLE_ENTRY f = First;
  2398. PSIGNATURE_TABLE_ENTRY s = Second;
  2399. if (f->Signature < s->Signature) {
  2400. return GenericLessThan;
  2401. }
  2402. if (f->Signature > s->Signature) {
  2403. return GenericGreaterThan;
  2404. }
  2405. return GenericEqual;
  2406. }
  2407. RTL_GENERIC_COMPARE_RESULTS
  2408. PmTableGuidCompareRoutine(
  2409. IN PRTL_GENERIC_TABLE Table,
  2410. IN PVOID First,
  2411. IN PVOID Second
  2412. )
  2413. {
  2414. PGUID_TABLE_ENTRY f = First;
  2415. PGUID_TABLE_ENTRY s = Second;
  2416. PULONGLONG p1, p2;
  2417. p1 = (PULONGLONG) &f->Guid;
  2418. p2 = (PULONGLONG) &s->Guid;
  2419. if (p1[0] < p2[0]) {
  2420. return GenericLessThan;
  2421. }
  2422. if (p1[0] > p2[0]) {
  2423. return GenericGreaterThan;
  2424. }
  2425. if (p1[1] < p2[1]) {
  2426. return GenericLessThan;
  2427. }
  2428. if (p1[1] > p2[1]) {
  2429. return GenericGreaterThan;
  2430. }
  2431. return GenericEqual;
  2432. }
  2433. PVOID
  2434. PmTableAllocateRoutine(
  2435. IN PRTL_GENERIC_TABLE Table,
  2436. IN CLONG Size
  2437. )
  2438. {
  2439. return ExAllocatePoolWithTag(PagedPool, Size, PARTMGR_TAG_TABLE_ENTRY);
  2440. }
  2441. VOID
  2442. PmTableFreeRoutine(
  2443. IN PRTL_GENERIC_TABLE Table,
  2444. IN PVOID Buffer
  2445. )
  2446. {
  2447. ExFreePool(Buffer);
  2448. }
  2449. NTSTATUS
  2450. DriverEntry(
  2451. IN PDRIVER_OBJECT DriverObject,
  2452. IN PUNICODE_STRING RegistryPath
  2453. )
  2454. /*++
  2455. Routine Description:
  2456. This routine is the entry point for the driver.
  2457. Arguments:
  2458. DriverObject - Supplies the driver object.
  2459. RegistryPath - Supplies the registry path for this driver.
  2460. Return Value:
  2461. NTSTATUS
  2462. --*/
  2463. {
  2464. ULONG i;
  2465. NTSTATUS status;
  2466. PDO_EXTENSION driverExtension;
  2467. PDEVICE_OBJECT deviceObject;
  2468. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  2469. DriverObject->MajorFunction[i] = PmPassThrough;
  2470. }
  2471. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PmDeviceControl;
  2472. DriverObject->MajorFunction[IRP_MJ_PNP] = PmPnp;
  2473. DriverObject->MajorFunction[IRP_MJ_POWER] = PmPower;
  2474. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PmWmi;
  2475. DriverObject->MajorFunction[IRP_MJ_READ] = PmReadWrite;
  2476. DriverObject->MajorFunction[IRP_MJ_WRITE] = PmReadWrite;
  2477. DriverObject->DriverExtension->AddDevice = PmAddDevice;
  2478. DriverObject->DriverUnload = PmUnload;
  2479. status = IoAllocateDriverObjectExtension(DriverObject, PmAddDevice,
  2480. sizeof(DO_EXTENSION),
  2481. &driverExtension);
  2482. if (!NT_SUCCESS(status)) {
  2483. return status;
  2484. }
  2485. driverExtension->DiskPerfRegistryPath.MaximumLength =
  2486. RegistryPath->Length + sizeof(UNICODE_NULL);
  2487. driverExtension->DiskPerfRegistryPath.Buffer =
  2488. ExAllocatePoolWithTag(
  2489. PagedPool,
  2490. driverExtension->DiskPerfRegistryPath.MaximumLength,
  2491. PARTMGR_TAG_PARTITION_ENTRY);
  2492. if (driverExtension->DiskPerfRegistryPath.Buffer != NULL)
  2493. {
  2494. RtlCopyUnicodeString(&driverExtension->DiskPerfRegistryPath,
  2495. RegistryPath);
  2496. } else {
  2497. driverExtension->DiskPerfRegistryPath.Length = 0;
  2498. driverExtension->DiskPerfRegistryPath.MaximumLength = 0;
  2499. }
  2500. driverExtension->DriverObject = DriverObject;
  2501. InitializeListHead(&driverExtension->VolumeManagerList);
  2502. InitializeListHead(&driverExtension->DeviceExtensionList);
  2503. KeInitializeMutex(&driverExtension->Mutex, 0);
  2504. driverExtension->PastReinit = FALSE;
  2505. RtlInitializeGenericTable(&driverExtension->SignatureTable,
  2506. PmTableSignatureCompareRoutine,
  2507. PmTableAllocateRoutine,
  2508. PmTableFreeRoutine, driverExtension);
  2509. RtlInitializeGenericTable(&driverExtension->GuidTable,
  2510. PmTableGuidCompareRoutine,
  2511. PmTableAllocateRoutine,
  2512. PmTableFreeRoutine, driverExtension);
  2513. IoRegisterBootDriverReinitialization(DriverObject, PmBootDriverReinit,
  2514. driverExtension);
  2515. status = IoRegisterPlugPlayNotification(
  2516. EventCategoryDeviceInterfaceChange,
  2517. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  2518. (PVOID) &VOLMGR_VOLUME_MANAGER_GUID, DriverObject,
  2519. PmVolumeManagerNotification, driverExtension,
  2520. &driverExtension->NotificationEntry);
  2521. if (!NT_SUCCESS(status)) {
  2522. return status;
  2523. }
  2524. driverExtension->BootDiskSig = PmQueryRegistrySignature();
  2525. return STATUS_SUCCESS;
  2526. }
  2527. NTSTATUS
  2528. PmBuildDependantVolumeRelations(
  2529. IN PDEVICE_EXTENSION Extension,
  2530. OUT PDEVICE_RELATIONS *Relations
  2531. )
  2532. /*++
  2533. Routine Description:
  2534. This routine builds a list of volumes which are dependant on a given
  2535. physical disk. This list can be used for reporting removal relations
  2536. to the pnp system.
  2537. Arguments:
  2538. Extension - Supplies the device extension for the pm filter.
  2539. Relations - Supplies a location to store the relations list.
  2540. Return Value:
  2541. NTSTATUS
  2542. --*/
  2543. {
  2544. ULONG partitionCount;
  2545. PIRP irp;
  2546. PDEVICE_RELATIONS relationsList;
  2547. PDEVICE_RELATIONS combinedList;
  2548. ULONG dependantVolumeCount = 0;
  2549. PLIST_ENTRY l;
  2550. PPARTITION_LIST_ENTRY partition;
  2551. NTSTATUS status = STATUS_SUCCESS;
  2552. ULONG i;
  2553. KEVENT event;
  2554. PAGED_CODE();
  2555. KeWaitForSingleObject(&Extension->DriverExtension->Mutex, Executive,
  2556. KernelMode, FALSE, NULL);
  2557. //
  2558. // Count the number of partitions we know about. If there aren't any then
  2559. // there aren't any relations either.
  2560. //
  2561. for(l = Extension->PartitionList.Flink, partitionCount = 0;
  2562. l != &(Extension->PartitionList);
  2563. l = l->Flink, partitionCount++);
  2564. //
  2565. // Allocate the relations list.
  2566. //
  2567. relationsList = ExAllocatePoolWithTag(
  2568. PagedPool,
  2569. (sizeof(DEVICE_RELATIONS) +
  2570. (sizeof(PDEVICE_RELATIONS) * partitionCount)),
  2571. PARTMGR_TAG_DEPENDANT_VOLUME_LIST);
  2572. if(relationsList== NULL) {
  2573. KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
  2574. return STATUS_INSUFFICIENT_RESOURCES;
  2575. }
  2576. RtlZeroMemory(relationsList, (sizeof(DEVICE_RELATIONS) +
  2577. sizeof(PDEVICE_OBJECT) * partitionCount));
  2578. if(partitionCount == 0) {
  2579. *Relations = relationsList;
  2580. KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
  2581. return STATUS_SUCCESS;
  2582. }
  2583. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  2584. for(l = Extension->PartitionList.Flink, i = 0, dependantVolumeCount = 0;
  2585. l != &(Extension->PartitionList);
  2586. l = l->Flink, i++) {
  2587. PDEVICE_RELATIONS dependantVolumes;
  2588. partition = CONTAINING_RECORD(l, PARTITION_LIST_ENTRY, ListEntry);
  2589. //
  2590. // Check to make sure the volume has a volume manager. If it doesn't
  2591. // then just skip to the next one.
  2592. //
  2593. if(partition->VolumeManagerEntry == NULL) {
  2594. continue;
  2595. }
  2596. status = PmQueryDependantVolumeList(
  2597. partition->VolumeManagerEntry->VolumeManager,
  2598. partition->TargetObject,
  2599. partition->WholeDiskPdo,
  2600. &dependantVolumes);
  2601. if(!NT_SUCCESS(status)) {
  2602. //
  2603. // Error getting this list. We'll need to release the lists from
  2604. // the other partitions.
  2605. //
  2606. break;
  2607. }
  2608. dependantVolumeCount += dependantVolumes->Count;
  2609. relationsList->Objects[i] = (PDEVICE_OBJECT) dependantVolumes;
  2610. }
  2611. KeReleaseMutex(&Extension->DriverExtension->Mutex, FALSE);
  2612. relationsList->Count = i;
  2613. if(NT_SUCCESS(status)) {
  2614. //
  2615. // Allocate a new device relations list which can hold all the dependant
  2616. // volumes for all the partitions.
  2617. //
  2618. combinedList = ExAllocatePoolWithTag(
  2619. PagedPool,
  2620. (sizeof(DEVICE_RELATIONS) +
  2621. (sizeof(PDEVICE_OBJECT) * dependantVolumeCount)),
  2622. PARTMGR_TAG_DEPENDANT_VOLUME_LIST);
  2623. } else {
  2624. combinedList = NULL;
  2625. }
  2626. if(combinedList != NULL) {
  2627. RtlZeroMemory(combinedList,
  2628. (sizeof(DEVICE_RELATIONS) +
  2629. (sizeof(PDEVICE_OBJECT) * dependantVolumeCount)));
  2630. //
  2631. // For each partition list ...
  2632. //
  2633. for(i = 0; i < relationsList->Count; i++) {
  2634. PDEVICE_RELATIONS volumeList;
  2635. ULONG j;
  2636. volumeList = (PDEVICE_RELATIONS) relationsList->Objects[i];
  2637. //
  2638. // We might have skipped this volume above. If we did the object
  2639. // list should be NULL;
  2640. //
  2641. if(volumeList == NULL) {
  2642. continue;
  2643. }
  2644. //
  2645. // For each dependant volume in that list ...
  2646. //
  2647. for(j = 0; j < volumeList->Count; j++) {
  2648. PDEVICE_OBJECT volume;
  2649. ULONG k;
  2650. volume = volumeList->Objects[j];
  2651. //
  2652. // Check to see if there's a duplicate in our combined list.
  2653. //
  2654. for(k = 0; k < combinedList->Count; k++) {
  2655. if(combinedList->Objects[k] == volume) {
  2656. break;
  2657. }
  2658. }
  2659. if(k == combinedList->Count) {
  2660. //
  2661. // We found no match - shove this object onto the end of
  2662. // the set.
  2663. //
  2664. combinedList->Objects[k] = volume;
  2665. combinedList->Count++;
  2666. } else {
  2667. //
  2668. // We've got a spare reference to this device object.
  2669. // release it.
  2670. //
  2671. ObDereferenceObject(volume);
  2672. }
  2673. }
  2674. //
  2675. // Free the list.
  2676. //
  2677. ExFreePool(volumeList);
  2678. relationsList->Objects[i] = NULL;
  2679. }
  2680. status = STATUS_SUCCESS;
  2681. } else {
  2682. //
  2683. // For each partition list ...
  2684. //
  2685. for(i = 0; i < relationsList->Count; i++) {
  2686. PDEVICE_RELATIONS volumeList;
  2687. ULONG j;
  2688. volumeList = (PDEVICE_RELATIONS) relationsList->Objects[i];
  2689. //
  2690. // For each dependant volume in that list ...
  2691. //
  2692. for(j = 0; j < volumeList->Count; j++) {
  2693. PDEVICE_OBJECT volume;
  2694. volume = volumeList->Objects[j];
  2695. //
  2696. // Dereference the volume.
  2697. //
  2698. ObDereferenceObject(volume);
  2699. }
  2700. //
  2701. // Free the list.
  2702. //
  2703. ExFreePool(volumeList);
  2704. relationsList->Objects[i] = NULL;
  2705. }
  2706. status = STATUS_INSUFFICIENT_RESOURCES;
  2707. }
  2708. //
  2709. // Free the list of lists.
  2710. //
  2711. ExFreePool(relationsList);
  2712. *Relations = combinedList;
  2713. return status;
  2714. }
  2715. NTSTATUS
  2716. PmQueryDependantVolumeList(
  2717. IN PDEVICE_OBJECT VolumeManager,
  2718. IN PDEVICE_OBJECT Partition,
  2719. IN PDEVICE_OBJECT WholeDiskPdo,
  2720. OUT PDEVICE_RELATIONS *DependantVolumes
  2721. )
  2722. {
  2723. KEVENT event;
  2724. PIRP irp;
  2725. IO_STATUS_BLOCK ioStatus;
  2726. NTSTATUS status;
  2727. VOLMGR_PARTITION_INFORMATION input;
  2728. VOLMGR_DEPENDANT_VOLUMES_INFORMATION output;
  2729. PAGED_CODE();
  2730. ASSERT(DependantVolumes != NULL);
  2731. if (!VolumeManager) {
  2732. *DependantVolumes = ExAllocatePoolWithTag(PagedPool,
  2733. sizeof(DEVICE_RELATIONS),
  2734. PARTMGR_TAG_DEPENDANT_VOLUME_LIST);
  2735. if (*DependantVolumes == NULL) {
  2736. return STATUS_INSUFFICIENT_RESOURCES;
  2737. }
  2738. (*DependantVolumes)->Count = 0;
  2739. return STATUS_SUCCESS;
  2740. }
  2741. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2742. input.PartitionDeviceObject = Partition;
  2743. input.WholeDiskPdo = WholeDiskPdo;
  2744. irp = IoBuildDeviceIoControlRequest(
  2745. IOCTL_INTERNAL_VOLMGR_REFERENCE_DEPENDANT_VOLUMES, VolumeManager,
  2746. &input, sizeof(input), &output, sizeof(output), TRUE, &event,
  2747. &ioStatus);
  2748. if (!irp) {
  2749. *DependantVolumes = NULL;
  2750. return STATUS_INSUFFICIENT_RESOURCES;
  2751. }
  2752. status = IoCallDriver(VolumeManager, irp);
  2753. if (status == STATUS_PENDING) {
  2754. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2755. status = ioStatus.Status;
  2756. }
  2757. if (NT_SUCCESS(status)) {
  2758. *DependantVolumes = output.DependantVolumeReferences;
  2759. }
  2760. return status;
  2761. }
  2762. NTSTATUS
  2763. PmRemovePartition(
  2764. IN PPARTITION_LIST_ENTRY Partition
  2765. )
  2766. {
  2767. PIRP irp;
  2768. KEVENT event;
  2769. PIO_STACK_LOCATION nextStack;
  2770. NTSTATUS status;
  2771. PAGED_CODE();
  2772. irp = IoAllocateIrp(Partition->TargetObject->StackSize, FALSE);
  2773. if(irp == NULL) {
  2774. return STATUS_INSUFFICIENT_RESOURCES;
  2775. }
  2776. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  2777. nextStack = IoGetNextIrpStackLocation(irp);
  2778. nextStack->MajorFunction = IRP_MJ_PNP;
  2779. nextStack->MinorFunction = IRP_MN_REMOVE_DEVICE;
  2780. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  2781. IoSetCompletionRoutine(irp,
  2782. PmSignalCompletion,
  2783. &event,
  2784. TRUE,
  2785. TRUE,
  2786. TRUE);
  2787. IoCallDriver(Partition->TargetObject, irp);
  2788. KeWaitForSingleObject(&event,
  2789. KernelMode,
  2790. Executive,
  2791. FALSE,
  2792. NULL);
  2793. status = irp->IoStatus.Status;
  2794. IoFreeIrp(irp);
  2795. return status;
  2796. }
  2797. NTSTATUS
  2798. PmReadWrite(
  2799. IN PDEVICE_OBJECT DeviceObject,
  2800. IN PIRP Irp
  2801. )
  2802. /*++
  2803. Routine Description:
  2804. This routine is the dispatch for IRP_MJ_READ & _WRITE.
  2805. Arguments:
  2806. DeviceObject - Supplies the device object.
  2807. Irp - Supplies the IO request packet.
  2808. Return Value:
  2809. NTSTATUS
  2810. --*/
  2811. {
  2812. PDEVICE_EXTENSION extension =
  2813. (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2814. if (extension->CountersEnabled || extension->PhysicalDiskIoNotifyRoutine) {
  2815. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  2816. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  2817. *nextIrpStack = *currentIrpStack;
  2818. if (extension->CountersEnabled) {
  2819. PmWmiCounterIoStart(extension->PmWmiCounterContext,
  2820. (PLARGE_INTEGER) &currentIrpStack->Parameters.Read);
  2821. }
  2822. else { // need to calculate response time for tracing
  2823. PmWmiGetClock(
  2824. *((PLARGE_INTEGER)&currentIrpStack->Parameters.Read), NULL);
  2825. }
  2826. IoMarkIrpPending(Irp);
  2827. IoSetCompletionRoutine(Irp, PmIoCompletion, DeviceObject,
  2828. TRUE, TRUE, TRUE);
  2829. IoCallDriver(extension->TargetObject, Irp);
  2830. return STATUS_PENDING;
  2831. }
  2832. IoSkipCurrentIrpStackLocation(Irp);
  2833. return IoCallDriver(extension->TargetObject, Irp);
  2834. }
  2835. NTSTATUS
  2836. PmIoCompletion(
  2837. IN PDEVICE_OBJECT DeviceObject,
  2838. IN PIRP Irp,
  2839. IN PVOID Context
  2840. )
  2841. /*++
  2842. Routine Description:
  2843. This routine will get control from the system at the completion of an IRP.
  2844. Arguments:
  2845. DeviceObject - for the IRP.
  2846. Irp - The I/O request that just completed.
  2847. Context - Not used.
  2848. Return Value:
  2849. The IRP status.
  2850. --*/
  2851. {
  2852. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  2853. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  2854. PPHYSICAL_DISK_IO_NOTIFY_ROUTINE notifyRoutine;
  2855. UNREFERENCED_PARAMETER(Context);
  2856. if (deviceExtension->CountersEnabled) {
  2857. PmWmiCounterIoComplete(deviceExtension->PmWmiCounterContext, Irp,
  2858. (PLARGE_INTEGER) &irpStack->Parameters.Read);
  2859. }
  2860. notifyRoutine = deviceExtension->PhysicalDiskIoNotifyRoutine;
  2861. if (notifyRoutine) {
  2862. #ifdef NTPERF
  2863. //
  2864. // For now, only NTPERF needs this for tracing. Remove ifdef if it
  2865. // is required for tracing in retail build
  2866. //
  2867. if (deviceExtension->CountersEnabled) {
  2868. DISK_PERFORMANCE PerfCounters;
  2869. PmWmiCounterQuery(deviceExtension->PmWmiCounterContext,
  2870. &PerfCounters,
  2871. L"Partmgr ",
  2872. deviceExtension->DiskNumber);
  2873. (*notifyRoutine) (deviceExtension->DiskNumber, Irp, &PerfCounters);
  2874. } else {
  2875. (*notifyRoutine) (deviceExtension->DiskNumber, Irp, NULL);
  2876. }
  2877. #else
  2878. if (!deviceExtension->CountersEnabled) {
  2879. LARGE_INTEGER completeTime;
  2880. PLARGE_INTEGER response;
  2881. response = (PLARGE_INTEGER) &irpStack->Parameters.Read;
  2882. PmWmiGetClock(completeTime, NULL);
  2883. response->QuadPart = completeTime.QuadPart - response->QuadPart;
  2884. }
  2885. (*notifyRoutine) (deviceExtension->DiskNumber, Irp, NULL);
  2886. #endif
  2887. }
  2888. return STATUS_SUCCESS;
  2889. }
  2890. NTSTATUS
  2891. PmWmi(
  2892. IN PDEVICE_OBJECT DeviceObject,
  2893. IN PIRP Irp
  2894. )
  2895. /*++
  2896. Routine Description:
  2897. This routine handles any WMI requests for information.
  2898. Arguments:
  2899. DeviceObject - Context for the activity.
  2900. Irp - The device control argument block.
  2901. Return Value:
  2902. Status is returned.
  2903. --*/
  2904. {
  2905. PIO_STACK_LOCATION irpSp;
  2906. NTSTATUS status;
  2907. SYSCTL_IRP_DISPOSITION disposition;
  2908. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  2909. PAGED_CODE();
  2910. irpSp = IoGetCurrentIrpStackLocation(Irp);
  2911. if (irpSp->MinorFunction == IRP_MN_SET_TRACE_NOTIFY)
  2912. {
  2913. PVOID buffer = irpSp->Parameters.WMI.Buffer;
  2914. ULONG bufferSize = irpSp->Parameters.WMI.BufferSize;
  2915. if (bufferSize < sizeof(PPHYSICAL_DISK_IO_NOTIFY_ROUTINE))
  2916. {
  2917. status = STATUS_BUFFER_TOO_SMALL;
  2918. } else {
  2919. #ifdef NTPERF
  2920. //
  2921. // For NTPERF Build, automatically turn on counters for tracing
  2922. //
  2923. if ((deviceExtension->PhysicalDiskIoNotifyRoutine == NULL) &&
  2924. (*((PVOID *)buffer) != NULL)) {
  2925. PmWmiCounterEnable(&deviceExtension->PmWmiCounterContext);
  2926. deviceExtension->CountersEnabled = TRUE;
  2927. } else
  2928. if ((deviceExtension->PhysicalDiskIoNotifyRoutine != NULL) &&
  2929. (*((PVOID *)buffer) == NULL)) {
  2930. deviceExtension->CountersEnabled =
  2931. PmWmiCounterDisable(&deviceExtension->PmWmiCounterContext,
  2932. FALSE, FALSE);
  2933. }
  2934. #endif
  2935. deviceExtension->PhysicalDiskIoNotifyRoutine
  2936. = (PPHYSICAL_DISK_IO_NOTIFY_ROUTINE)
  2937. *((PVOID *)buffer);
  2938. status = STATUS_SUCCESS;
  2939. }
  2940. Irp->IoStatus.Status = status;
  2941. Irp->IoStatus.Information = 0;
  2942. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  2943. } else {
  2944. if (deviceExtension->WmilibContext == NULL) {
  2945. disposition = IrpForward;
  2946. status = STATUS_SUCCESS;
  2947. }
  2948. else {
  2949. status = WmiSystemControl(deviceExtension->WmilibContext,
  2950. DeviceObject,
  2951. Irp,
  2952. &disposition);
  2953. }
  2954. switch (disposition)
  2955. {
  2956. case IrpProcessed:
  2957. {
  2958. break;
  2959. }
  2960. case IrpNotCompleted:
  2961. {
  2962. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2963. break;
  2964. }
  2965. default:
  2966. {
  2967. IoSkipCurrentIrpStackLocation(Irp);
  2968. status = IoCallDriver(deviceExtension->TargetObject, Irp);
  2969. break;
  2970. }
  2971. }
  2972. }
  2973. return(status);
  2974. }
  2975. NTSTATUS
  2976. PmWmiFunctionControl(
  2977. IN PDEVICE_OBJECT DeviceObject,
  2978. IN PIRP Irp,
  2979. IN ULONG GuidIndex,
  2980. IN WMIENABLEDISABLECONTROL Function,
  2981. IN BOOLEAN Enable
  2982. )
  2983. /*++
  2984. Routine Description:
  2985. This routine is a callback into the driver to query for enabling or
  2986. disabling events and data collection. When the driver has finished it
  2987. must call WmiCompleteRequest to complete the irp. The driver can return
  2988. STATUS_PENDING if the irp cannot be completed immediately.
  2989. Arguments:
  2990. DeviceObject is the device whose events or data collection are being
  2991. enabled or disabled
  2992. Irp is the Irp that makes this request
  2993. GuidIndex is the index into the list of guids provided when the
  2994. device registered
  2995. Function differentiates between event and data collection operations
  2996. Enable indicates whether to enable or disable
  2997. Return Value:
  2998. status
  2999. --*/
  3000. {
  3001. NTSTATUS status;
  3002. PDEVICE_EXTENSION deviceExtension;
  3003. PAGED_CODE();
  3004. deviceExtension = DeviceObject->DeviceExtension;
  3005. if (GuidIndex == 0)
  3006. {
  3007. status = STATUS_SUCCESS;
  3008. if (Function == WmiDataBlockControl) {
  3009. if (!Enable) {
  3010. deviceExtension->CountersEnabled =
  3011. PmWmiCounterDisable(&deviceExtension->PmWmiCounterContext,
  3012. FALSE, FALSE);
  3013. } else
  3014. if (NT_SUCCESS(status =
  3015. PmWmiCounterEnable(&deviceExtension->PmWmiCounterContext))) {
  3016. deviceExtension->CountersEnabled = TRUE;
  3017. }
  3018. }
  3019. } else {
  3020. status = STATUS_WMI_GUID_NOT_FOUND;
  3021. }
  3022. status = WmiCompleteRequest(
  3023. DeviceObject,
  3024. Irp,
  3025. status,
  3026. 0,
  3027. IO_NO_INCREMENT);
  3028. return(status);
  3029. }
  3030. NTSTATUS
  3031. PmReadPartitionTableEx(
  3032. IN PDEVICE_OBJECT DeviceObject,
  3033. IN PDRIVE_LAYOUT_INFORMATION_EX* DriveLayout
  3034. )
  3035. /*++
  3036. Routine Description:
  3037. This routine reads the partition table for the disk.
  3038. The partition list is built in nonpaged pool that is allocated by this
  3039. routine. It is the caller's responsability to free this memory when it
  3040. is finished with the data.
  3041. Arguments:
  3042. DeviceObject - Pointer for device object for this disk.
  3043. DriveLayout - Pointer to the pointer that will return the patition list.
  3044. This buffer is allocated in nonpaged pool by this routine. It is
  3045. the responsability of the caller to free this memory if this
  3046. routine is successful.
  3047. Return Values:
  3048. Status.
  3049. --*/
  3050. {
  3051. NTSTATUS Status;
  3052. IO_STATUS_BLOCK IoStatus;
  3053. PIRP Irp;
  3054. KEVENT Event;
  3055. PVOID IoCtlBuffer;
  3056. ULONG IoCtlBufferSize;
  3057. ULONG NewAllocationSize;
  3058. ULONG NumTries;
  3059. //
  3060. // Initialize locals.
  3061. //
  3062. NumTries = 0;
  3063. IoCtlBuffer = NULL;
  3064. IoCtlBufferSize = 0;
  3065. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  3066. //
  3067. // Initialize the IOCTL buffer.
  3068. //
  3069. IoCtlBuffer = ExAllocatePoolWithTag(NonPagedPool,
  3070. PAGE_SIZE,
  3071. PARTMGR_TAG_IOCTL_BUFFER);
  3072. if (!IoCtlBuffer) {
  3073. Status = STATUS_INSUFFICIENT_RESOURCES;
  3074. goto cleanup;
  3075. }
  3076. IoCtlBufferSize = PAGE_SIZE;
  3077. //
  3078. // First try to get the partition table by issuing an IOCTL.
  3079. //
  3080. do {
  3081. //
  3082. // Make sure the event is reset.
  3083. //
  3084. KeClearEvent(&Event);
  3085. //
  3086. // Build an IOCTL Irp.
  3087. //
  3088. Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  3089. DeviceObject,
  3090. NULL,
  3091. 0,
  3092. IoCtlBuffer,
  3093. IoCtlBufferSize,
  3094. FALSE,
  3095. &Event,
  3096. &IoStatus);
  3097. if (!Irp) {
  3098. Status = STATUS_INSUFFICIENT_RESOURCES;
  3099. goto cleanup;
  3100. }
  3101. //
  3102. // Call the driver.
  3103. //
  3104. Status = IoCallDriver(DeviceObject, Irp);
  3105. if (Status == STATUS_PENDING) {
  3106. KeWaitForSingleObject(&Event,
  3107. Executive,
  3108. KernelMode,
  3109. FALSE,
  3110. NULL);
  3111. //
  3112. // Update status.
  3113. //
  3114. Status = IoStatus.Status;
  3115. }
  3116. if (NT_SUCCESS(Status)) {
  3117. //
  3118. // We got it!
  3119. //
  3120. break;
  3121. }
  3122. if (Status != STATUS_BUFFER_TOO_SMALL) {
  3123. //
  3124. // It is a real error.
  3125. //
  3126. goto cleanup;
  3127. }
  3128. //
  3129. // Resize IOCTL buffer. We should not enter the loop with a
  3130. // NULL buffer.
  3131. //
  3132. ASSERT(IoCtlBuffer && IoCtlBufferSize);
  3133. NewAllocationSize = IoCtlBufferSize * 2;
  3134. ExFreePool(IoCtlBuffer);
  3135. IoCtlBufferSize = 0;
  3136. IoCtlBuffer = ExAllocatePoolWithTag(NonPagedPool,
  3137. NewAllocationSize,
  3138. PARTMGR_TAG_IOCTL_BUFFER);
  3139. if (!IoCtlBuffer) {
  3140. Status = STATUS_INSUFFICIENT_RESOURCES;
  3141. goto cleanup;
  3142. }
  3143. IoCtlBufferSize = NewAllocationSize;
  3144. //
  3145. // Try again with the new buffer but do not loop forever.
  3146. //
  3147. NumTries++;
  3148. if (NumTries > 32) {
  3149. Status = STATUS_UNSUCCESSFUL;
  3150. goto cleanup;
  3151. }
  3152. } while (TRUE);
  3153. //
  3154. // If we came here we should have acquired the partition tables in
  3155. // IoCtlBuffer.
  3156. //
  3157. ASSERT(NT_SUCCESS(Status));
  3158. ASSERT(IoCtlBuffer && IoCtlBufferSize);
  3159. //
  3160. // Set the output parameter and clear IoCtlBuffer so we don't free
  3161. // it when we are cleaning up.
  3162. //
  3163. (*DriveLayout) = (PDRIVE_LAYOUT_INFORMATION_EX) IoCtlBuffer;
  3164. IoCtlBuffer = NULL;
  3165. IoCtlBufferSize = 0;
  3166. Status = STATUS_SUCCESS;
  3167. cleanup:
  3168. if (IoCtlBuffer) {
  3169. ASSERT(IoCtlBufferSize);
  3170. ExFreePool(IoCtlBuffer);
  3171. }
  3172. //
  3173. // If we were not successful with the IOCTL, pass the request off
  3174. // to IoReadPartitionTableEx.
  3175. //
  3176. if (!NT_SUCCESS(Status)) {
  3177. Status = IoReadPartitionTableEx(DeviceObject,
  3178. DriveLayout);
  3179. }
  3180. return Status;
  3181. }
  3182. NTSTATUS
  3183. PmWritePartitionTableEx(
  3184. IN PDEVICE_OBJECT DeviceObject,
  3185. IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout
  3186. )
  3187. {
  3188. ULONG layoutSize;
  3189. KEVENT event;
  3190. PIRP irp;
  3191. IO_STATUS_BLOCK ioStatus;
  3192. NTSTATUS status;
  3193. layoutSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
  3194. DriveLayout->PartitionCount*sizeof(PARTITION_INFORMATION_EX);
  3195. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3196. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
  3197. DeviceObject, DriveLayout,
  3198. layoutSize, NULL, 0, FALSE, &event,
  3199. &ioStatus);
  3200. if (!irp) {
  3201. return STATUS_INSUFFICIENT_RESOURCES;
  3202. }
  3203. status = IoCallDriver(DeviceObject, irp);
  3204. if (status == STATUS_PENDING) {
  3205. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  3206. status = ioStatus.Status;
  3207. }
  3208. return status;
  3209. }