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

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