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.

1276 lines
35 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. SCSI disk class driver
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "disk.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, DiskConvertExtendedToLayout)
  15. #pragma alloc_text(PAGE, DiskConvertPartitionToExtended)
  16. #pragma alloc_text(PAGE, DiskConvertLayoutToExtended)
  17. #pragma alloc_text(PAGE, DiskCreatePdo)
  18. #pragma alloc_text(PAGE, DiskEnumerateDevice)
  19. #pragma alloc_text(PAGE, DiskUpdateRemovablePartitions)
  20. #pragma alloc_text(PAGE, DiskUpdatePartitions)
  21. #pragma alloc_text(PAGE, DiskCreatePdo)
  22. #endif
  23. PDRIVE_LAYOUT_INFORMATION
  24. DiskConvertExtendedToLayout(
  25. IN CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx
  26. )
  27. {
  28. ULONG i;
  29. ULONG LayoutSize;
  30. PDRIVE_LAYOUT_INFORMATION Layout;
  31. PPARTITION_INFORMATION Partition;
  32. PPARTITION_INFORMATION_EX PartitionEx;
  33. PAGED_CODE ();
  34. ASSERT ( LayoutEx );
  35. //
  36. // The only valid conversion is from an MBR extended layout structure to
  37. // the old structure.
  38. //
  39. if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) {
  40. ASSERT ( FALSE );
  41. return NULL;
  42. }
  43. LayoutSize = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]) +
  44. LayoutEx->PartitionCount * sizeof (PARTITION_INFORMATION);
  45. Layout = ExAllocatePoolWithTag (
  46. NonPagedPool,
  47. LayoutSize,
  48. DISK_TAG_PART_LIST
  49. );
  50. if ( Layout == NULL ) {
  51. return NULL;
  52. }
  53. Layout->Signature = LayoutEx->Mbr.Signature;
  54. Layout->PartitionCount = LayoutEx->PartitionCount;
  55. for (i = 0; i < LayoutEx->PartitionCount; i++) {
  56. Partition = &Layout->PartitionEntry[i];
  57. PartitionEx = &LayoutEx->PartitionEntry[i];
  58. Partition->StartingOffset = PartitionEx->StartingOffset;
  59. Partition->PartitionLength = PartitionEx->PartitionLength;
  60. Partition->RewritePartition = PartitionEx->RewritePartition;
  61. Partition->PartitionNumber = PartitionEx->PartitionNumber;
  62. Partition->PartitionType = PartitionEx->Mbr.PartitionType;
  63. Partition->BootIndicator = PartitionEx->Mbr.BootIndicator;
  64. Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition;
  65. Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors;
  66. }
  67. return Layout;
  68. }
  69. VOID
  70. DiskConvertPartitionToExtended(
  71. IN PPARTITION_INFORMATION Partition,
  72. OUT PPARTITION_INFORMATION_EX PartitionEx
  73. )
  74. /*++
  75. Routine Description:
  76. Convert a PARTITION_INFORMATION structure to a PARTITION_INFORMATION_EX
  77. structure.
  78. Arguments:
  79. Partition - A pointer to the PARTITION_INFORMATION structure to convert.
  80. PartitionEx - A pointer to a buffer where the converted
  81. PARTITION_INFORMATION_EX structure is to be stored.
  82. Return Values:
  83. None.
  84. --*/
  85. {
  86. PAGED_CODE ();
  87. ASSERT ( PartitionEx != NULL );
  88. ASSERT ( Partition != NULL );
  89. PartitionEx->PartitionStyle = PARTITION_STYLE_MBR;
  90. PartitionEx->StartingOffset = Partition->StartingOffset;
  91. PartitionEx->PartitionLength = Partition->PartitionLength;
  92. PartitionEx->RewritePartition = Partition->RewritePartition;
  93. PartitionEx->PartitionNumber = Partition->PartitionNumber;
  94. PartitionEx->Mbr.PartitionType = Partition->PartitionType;
  95. PartitionEx->Mbr.BootIndicator = Partition->BootIndicator;
  96. PartitionEx->Mbr.RecognizedPartition = Partition->RecognizedPartition;
  97. PartitionEx->Mbr.HiddenSectors = Partition->HiddenSectors;
  98. }
  99. PDRIVE_LAYOUT_INFORMATION_EX
  100. DiskConvertLayoutToExtended(
  101. IN CONST PDRIVE_LAYOUT_INFORMATION Layout
  102. )
  103. /*++
  104. Routine Description:
  105. Convert a DRIVE_LAYOUT_INFORMATION structure into a
  106. DRIVE_LAYOUT_INFORMATION_EX structure.
  107. Arguments:
  108. Layout - The source DRIVE_LAYOUT_INFORMATION structure.
  109. Return Values:
  110. The resultant DRIVE_LAYOUT_INFORMATION_EX structure. This buffer must
  111. be freed by the callee using ExFreePool.
  112. --*/
  113. {
  114. ULONG i;
  115. ULONG size;
  116. PDRIVE_LAYOUT_INFORMATION_EX layoutEx;
  117. PAGED_CODE ();
  118. ASSERT ( Layout != NULL );
  119. //
  120. // Allocate enough space for a DRIVE_LAYOUT_INFORMATION_EX structure
  121. // plus as many PARTITION_INFORMATION_EX structures as are in the
  122. // source array.
  123. //
  124. size = FIELD_OFFSET (DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]) +
  125. Layout->PartitionCount * sizeof ( PARTITION_INFORMATION_EX );
  126. layoutEx = ExAllocatePoolWithTag(
  127. NonPagedPool,
  128. size,
  129. DISK_TAG_PART_LIST
  130. );
  131. if ( layoutEx == NULL ) {
  132. return NULL;
  133. }
  134. //
  135. // Convert the disk information.
  136. //
  137. layoutEx->PartitionStyle = PARTITION_STYLE_MBR;
  138. layoutEx->PartitionCount = Layout->PartitionCount;
  139. layoutEx->Mbr.Signature = Layout->Signature;
  140. for (i = 0; i < Layout->PartitionCount; i++) {
  141. //
  142. // Convert each entry.
  143. //
  144. DiskConvertPartitionToExtended (
  145. &Layout->PartitionEntry[i],
  146. &layoutEx->PartitionEntry[i]
  147. );
  148. }
  149. return layoutEx;
  150. }
  151. NTSTATUS
  152. DiskEnumerateDevice(
  153. IN PDEVICE_OBJECT Fdo
  154. )
  155. /*++
  156. Routine Description:
  157. This routine is called by the class driver to update the PDO list off
  158. of this FDO. The disk driver also calls it internally to re-create
  159. device objects.
  160. This routine will read the partition table and create new PDO objects as
  161. necessary. PDO's that no longer exist will be pulled out of the PDO list
  162. so that pnp will destroy them.
  163. Arguments:
  164. Fdo - a pointer to the FDO being re-enumerated
  165. Return Value:
  166. status
  167. --*/
  168. {
  169. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  170. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  171. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  172. PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData;
  173. PDEVICE_OBJECT pdo = NULL;
  174. PDRIVE_LAYOUT_INFORMATION_EX partitionList;
  175. NTSTATUS status;
  176. ASSERT(commonExtension->IsFdo);
  177. PAGED_CODE();
  178. //
  179. // If our cached partition table is valid, there is nothing to be done
  180. //
  181. if ( diskData->CachedPartitionTableValid == TRUE )
  182. {
  183. return STATUS_SUCCESS;
  184. }
  185. //
  186. // Update our image of the size of the drive. This may be necessary if
  187. // the drive size is extended or we just released a reservation to
  188. // ensure the kernel doesn't reject the partition table.
  189. //
  190. DiskReadDriveCapacity(Fdo);
  191. //
  192. // Lock out anyone else trying to repartition the disk.
  193. //
  194. DiskAcquirePartitioningLock(fdoExtension);
  195. //
  196. // Create objects for all the partitions on the device.
  197. //
  198. status = DiskReadPartitionTableEx(fdoExtension, FALSE, &partitionList);
  199. //
  200. // If the I/O read partition table failed and this is a removable device,
  201. // then fix up the partition list to make it look like there is one
  202. // zero length partition.
  203. //
  204. if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
  205. Fdo->Characteristics & FILE_REMOVABLE_MEDIA) {
  206. SIZE_T partitionListSize;
  207. //
  208. // Remember whether the drive is ready.
  209. //
  210. diskData->ReadyStatus = status;
  211. //
  212. // Allocate and zero a partition list.
  213. //
  214. partitionListSize =
  215. FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]);
  216. partitionList = ExAllocatePoolWithTag(NonPagedPool,
  217. partitionListSize,
  218. DISK_TAG_PART_LIST);
  219. if (partitionList != NULL) {
  220. RtlZeroMemory( partitionList, partitionListSize );
  221. //
  222. // Set the partition count to one and the status to success
  223. // so one device object will be created. Set the partition type
  224. // to a bogus value.
  225. //
  226. partitionList->PartitionStyle = PARTITION_STYLE_MBR;
  227. partitionList->PartitionCount = 1;
  228. status = STATUS_SUCCESS;
  229. } else {
  230. status = STATUS_INSUFFICIENT_RESOURCES;
  231. }
  232. }
  233. if (NT_SUCCESS(status)) {
  234. diskData->UpdatePartitionRoutine(Fdo, partitionList);
  235. }
  236. DiskReleasePartitioningLock(fdoExtension);
  237. return(STATUS_SUCCESS);
  238. } // end DiskEnumerateDevice()
  239. VOID
  240. DiskUpdateRemovablePartitions(
  241. IN PDEVICE_OBJECT Fdo,
  242. IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList
  243. )
  244. /*++
  245. Routine Description:
  246. This routine is called by the class DLL to update the PDO list off of this
  247. FDO. The disk driver also calls it internally to re-create device objects.
  248. This routine will read the partition table and update the size of the
  249. single partition device object which always exists for removable devices.
  250. Arguments:
  251. Fdo - a pointer to the FDO being reenumerated.
  252. Return Value:
  253. status
  254. --*/
  255. {
  256. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  257. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  258. ULONG partitionCount;
  259. ULONG partitionNumber;
  260. ULONG partitionOrdinal = 0;
  261. ULONG newPartitionNumber;
  262. PDISK_DATA pdoData;
  263. NTSTATUS status;
  264. PPARTITION_INFORMATION_EX partitionEntry;
  265. PARTITION_STYLE partitionStyle;
  266. PAGED_CODE();
  267. ASSERT(Fdo->Characteristics & FILE_REMOVABLE_MEDIA);
  268. partitionStyle = PartitionList->PartitionStyle;
  269. partitionCount = PartitionList->PartitionCount;
  270. for(partitionNumber = 0;
  271. partitionNumber < partitionCount;
  272. partitionNumber++) {
  273. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  274. partitionEntry->PartitionNumber = 0;
  275. }
  276. //
  277. // Get exclusive access to the child list while repartitioning.
  278. //
  279. ClassAcquireChildLock(fdoExtension);
  280. //
  281. // Removable media should never have more than one PDO.
  282. //
  283. pdoExtension = fdoExtension->CommonExtension.ChildList;
  284. if(pdoExtension == NULL) {
  285. PARTITION_INFORMATION_EX tmpPartitionEntry = { 0 };
  286. PDEVICE_OBJECT pdo;
  287. //
  288. // There is no PDO currently. Create one and pre-initialize it with
  289. // a zero length.
  290. //
  291. tmpPartitionEntry.PartitionNumber = 1;
  292. DebugPrint((1, "DiskUpdateRemovablePartitions: Creating RM partition\n"));
  293. status = DiskCreatePdo(Fdo,
  294. 0,
  295. &tmpPartitionEntry,
  296. partitionStyle,
  297. &pdo);
  298. if(!NT_SUCCESS(status)) {
  299. DebugPrint((1, "DiskUpdateRemovablePartitions: error %lx creating "
  300. "new PDO for RM partition\n",
  301. status));
  302. goto DiskUpdateRemovablePartitionsExit;
  303. }
  304. //
  305. // mark the new device as enumerated
  306. //
  307. pdoExtension = pdo->DeviceExtension;
  308. pdoExtension->IsMissing = FALSE;
  309. }
  310. pdoData = pdoExtension->CommonExtension.DriverData;
  311. //
  312. // Search the partition list for a valid entry. We're looking for a
  313. // primary partition since we only support the one.
  314. //
  315. for(partitionNumber = 0;
  316. partitionNumber < partitionCount;
  317. partitionNumber++) {
  318. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  319. //
  320. // Is this partition interesting?
  321. //
  322. if (partitionStyle == PARTITION_STYLE_MBR) {
  323. if(partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
  324. IsContainerPartition(partitionEntry->Mbr.PartitionType)) {
  325. continue;
  326. }
  327. }
  328. partitionOrdinal++;
  329. //
  330. // We have found the first and thus only partition allowed on
  331. // this disk. Update the information in the PDO to match the new
  332. // partition.
  333. //
  334. DebugPrint((1, "DiskUpdateRemovablePartitions: Matched %wZ to #%d, "
  335. "ordinal %d\n",
  336. &pdoExtension->CommonExtension.DeviceName,
  337. partitionEntry->PartitionNumber,
  338. partitionOrdinal));
  339. partitionEntry->PartitionNumber = 1;
  340. pdoData->PartitionStyle = partitionStyle;
  341. pdoData->PartitionOrdinal = partitionOrdinal;
  342. ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
  343. pdoExtension->CommonExtension.StartingOffset =
  344. partitionEntry->StartingOffset;
  345. pdoExtension->CommonExtension.PartitionLength =
  346. partitionEntry->PartitionLength;
  347. if (partitionStyle == PARTITION_STYLE_MBR) {
  348. pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors;
  349. pdoData->Mbr.BootIndicator = partitionEntry->Mbr.BootIndicator;
  350. //
  351. // If this partition is being re-written then update the type
  352. // information as well
  353. //
  354. if (partitionEntry->RewritePartition) {
  355. pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType;
  356. }
  357. } else {
  358. pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType;
  359. pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId;
  360. pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes;
  361. RtlCopyMemory(
  362. pdoData->Efi.PartitionName,
  363. partitionEntry->Gpt.Name,
  364. sizeof (pdoData->Efi.PartitionName)
  365. );
  366. }
  367. //
  368. // Mark this one as found
  369. //
  370. pdoExtension->IsMissing = FALSE;
  371. goto DiskUpdateRemovablePartitionsExit;
  372. }
  373. //
  374. // No interesting partition was found.
  375. //
  376. if (partitionStyle == PARTITION_STYLE_MBR) {
  377. pdoData->Mbr.HiddenSectors = 0;
  378. pdoData->Mbr.PartitionType = PARTITION_ENTRY_UNUSED;
  379. } else {
  380. RtlZeroMemory (&pdoData->Efi,
  381. sizeof (pdoData->Efi)
  382. );
  383. }
  384. pdoExtension->CommonExtension.StartingOffset.QuadPart = 0;
  385. pdoExtension->CommonExtension.PartitionLength.QuadPart = 0;
  386. DiskUpdateRemovablePartitionsExit:
  387. //
  388. // Update the parent device object
  389. //
  390. {
  391. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  392. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  393. if (partitionStyle == PARTITION_STYLE_MBR)
  394. {
  395. diskData->PartitionStyle = PARTITION_STYLE_MBR;
  396. diskData->Mbr.Signature = PartitionList->Mbr.Signature;
  397. }
  398. else
  399. {
  400. diskData->PartitionStyle = PARTITION_STYLE_GPT;
  401. diskData->Efi.DiskId = PartitionList->Gpt.DiskId;
  402. }
  403. }
  404. ClassReleaseChildLock(fdoExtension);
  405. return;
  406. }
  407. VOID
  408. DiskUpdatePartitions(
  409. IN PDEVICE_OBJECT Fdo,
  410. IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList
  411. )
  412. /*++
  413. Routine Description:
  414. This routine will synchronize the information held in the partition list
  415. with the device objects hanging off this Fdo. Any new partition objects
  416. will be created, any non-existant ones will be marked as un-enumerated.
  417. This will be done in several stages:
  418. * Clear state (partition number) from every entry in the partition
  419. list
  420. * Set IsMissing flag on every child of this FDO
  421. * For each child of the FDO:
  422. if a matching partition exists in the partition list,
  423. update the partition number in the table, update the
  424. ordinal in the object and mark the object as enumerated
  425. * For each un-enumerated device object
  426. zero out the partition information to invalidate the device
  427. delete the symbolic link if any
  428. * For each un-matched entry in the partition list:
  429. create a new partition object
  430. update the partition number in the list entry
  431. create a new symbolic link if necessary
  432. Arguments:
  433. Fdo - a pointer to the functional device object this partition list is for
  434. PartitionList - a pointer to the partition list being updated
  435. Return Value:
  436. none
  437. --*/
  438. {
  439. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  440. PPHYSICAL_DEVICE_EXTENSION oldChildList = NULL;
  441. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  442. ULONG partitionCount;
  443. ULONG partitionNumber;
  444. ULONG partitionOrdinal;
  445. ULONG newPartitionNumber;
  446. PPARTITION_INFORMATION_EX partitionEntry;
  447. PDISK_DATA pdoData;
  448. PARTITION_STYLE partitionStyle;
  449. NTSTATUS status;
  450. PAGED_CODE();
  451. //
  452. // Get exclusive access to the child list.
  453. //
  454. ClassAcquireChildLock(fdoExtension);
  455. partitionStyle = PartitionList->PartitionStyle;
  456. partitionCount = PartitionList->PartitionCount;
  457. //
  458. // Pull all the child device objects off the children list. We'll
  459. // add them back later.
  460. //
  461. oldChildList = fdoExtension->CommonExtension.ChildList;
  462. fdoExtension->CommonExtension.ChildList = NULL;
  463. //
  464. // Clear the partition numbers from the list entries
  465. //
  466. for(partitionNumber = 0;
  467. partitionNumber < partitionCount;
  468. partitionNumber++) {
  469. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  470. partitionEntry->PartitionNumber = 0;
  471. }
  472. //
  473. // Now match each child partition to it's entry (if any) in the partition
  474. // list.
  475. //
  476. while(oldChildList != NULL) {
  477. pdoExtension = oldChildList;
  478. pdoData = pdoExtension->CommonExtension.DriverData;
  479. //
  480. // Check all partition entries for a match on offset and length
  481. //
  482. partitionOrdinal = 0;
  483. for(partitionNumber = 0;
  484. partitionNumber < partitionCount;
  485. partitionNumber++) {
  486. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  487. //
  488. // Is this an interesting partition entry?
  489. //
  490. if (partitionStyle == PARTITION_STYLE_MBR) {
  491. if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) ||
  492. (IsContainerPartition(partitionEntry->Mbr.PartitionType))) {
  493. continue;
  494. }
  495. }
  496. partitionOrdinal++;
  497. if(partitionEntry->PartitionNumber) {
  498. //
  499. // This partition has already been found - skip it
  500. //
  501. continue;
  502. }
  503. //
  504. // Let's see if the partition information matches
  505. //
  506. if(partitionEntry->StartingOffset.QuadPart !=
  507. pdoExtension->CommonExtension.StartingOffset.QuadPart) {
  508. continue;
  509. }
  510. if(partitionEntry->PartitionLength.QuadPart !=
  511. pdoExtension->CommonExtension.PartitionLength.QuadPart) {
  512. continue;
  513. }
  514. //
  515. // Yep - it matches. Update the information in the entry
  516. //
  517. partitionEntry->PartitionNumber = pdoExtension->CommonExtension.PartitionNumber;
  518. if (partitionStyle == PARTITION_STYLE_MBR) {
  519. pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors;
  520. }
  521. break;
  522. }
  523. if(partitionNumber != partitionCount) {
  524. DebugPrint((1, "DiskUpdatePartitions: Matched %wZ to #%d, ordinal "
  525. "%d\n",
  526. &pdoExtension->CommonExtension.DeviceName,
  527. partitionEntry->PartitionNumber,
  528. partitionOrdinal));
  529. ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789);
  530. // ASSERT(pdoExtension->CommonExtension.PartitionLength.QuadPart != 0);
  531. pdoData->PartitionStyle = partitionStyle;
  532. //
  533. // we found a match - update the information in the device object
  534. // extension and driverdata
  535. //
  536. pdoData->PartitionOrdinal = partitionOrdinal;
  537. //
  538. // If this partition is being re-written then update the type
  539. // information as well
  540. //
  541. if (partitionStyle == PARTITION_STYLE_MBR) {
  542. if(partitionEntry->RewritePartition) {
  543. pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType;
  544. }
  545. } else {
  546. DebugPrint((1, "DiskUpdatePartitions: EFI Partition %ws\n",
  547. pdoData->Efi.PartitionName
  548. ));
  549. pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType;
  550. pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId;
  551. pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes;
  552. RtlCopyMemory(
  553. pdoData->Efi.PartitionName,
  554. partitionEntry->Gpt.Name,
  555. sizeof (pdoData->Efi.PartitionName)
  556. );
  557. }
  558. //
  559. // Mark this one as found.
  560. //
  561. pdoExtension->IsMissing = FALSE;
  562. //
  563. // Pull it out of the old child list and add it into the
  564. // real one.
  565. //
  566. oldChildList = pdoExtension->CommonExtension.ChildList;
  567. pdoExtension->CommonExtension.ChildList =
  568. fdoExtension->CommonExtension.ChildList;
  569. fdoExtension->CommonExtension.ChildList = pdoExtension;
  570. } else {
  571. PDEVICE_OBJECT nextPdo;
  572. DebugPrint ((1, "DiskUpdatePartitions: Deleting %wZ\n",
  573. &pdoExtension->CommonExtension.DeviceName));
  574. if (partitionStyle == PARTITION_STYLE_GPT) {
  575. DebugPrint ((1, "DiskUpdatePartitions: EFI Partition %ws\n",
  576. pdoData->Efi.PartitionName
  577. ));
  578. }
  579. //
  580. // no matching entry in the partition list - throw this partition
  581. // object away
  582. //
  583. pdoExtension->CommonExtension.PartitionLength.QuadPart = 0;
  584. //
  585. // grab a pointer to the next child before we mark this one as
  586. // missing since missing devices could vanish at any time.
  587. //
  588. oldChildList = pdoExtension->CommonExtension.ChildList;
  589. pdoExtension->CommonExtension.ChildList = (PVOID) -1;
  590. //
  591. // Now tell the class driver that this child is "missing" - this
  592. // will cause it to be deleted.
  593. //
  594. ClassMarkChildMissing(pdoExtension, FALSE);
  595. }
  596. }
  597. //
  598. // At this point the old child list had best be empty.
  599. //
  600. ASSERT(oldChildList == NULL);
  601. //
  602. // Iterate through the partition entries and create any partition
  603. // objects that don't already exist
  604. //
  605. partitionOrdinal = 0;
  606. newPartitionNumber = 0;
  607. for(partitionNumber = 0;
  608. partitionNumber < partitionCount;
  609. partitionNumber++) {
  610. PDEVICE_OBJECT pdo;
  611. partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]);
  612. //
  613. // Is this partition interesting
  614. //
  615. if (partitionStyle == PARTITION_STYLE_MBR) {
  616. if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) ||
  617. (IsContainerPartition(partitionEntry->Mbr.PartitionType))) {
  618. continue;
  619. }
  620. }
  621. //
  622. // Increment the count of interesting partitions
  623. //
  624. partitionOrdinal++;
  625. newPartitionNumber++;
  626. //
  627. // Has this already been matched
  628. //
  629. if(partitionEntry->PartitionNumber == 0) {
  630. LONG i;
  631. //
  632. // find the first safe partition number for this device
  633. //
  634. for(i = 0; i < (LONG) partitionCount; i++) {
  635. PPARTITION_INFORMATION_EX tmp = &(PartitionList->PartitionEntry[i]);
  636. if (partitionStyle == PARTITION_STYLE_MBR) {
  637. if (tmp->Mbr.PartitionType == PARTITION_ENTRY_UNUSED ||
  638. IsContainerPartition(tmp->Mbr.PartitionType)) {
  639. continue;
  640. }
  641. }
  642. if(tmp->PartitionNumber == newPartitionNumber) {
  643. //
  644. // Found a matching partition number - increment the count
  645. // and restart the scan.
  646. //
  647. newPartitionNumber++;
  648. i = -1;
  649. continue;
  650. }
  651. }
  652. //
  653. // Assign this partition a partition number
  654. //
  655. partitionEntry->PartitionNumber = newPartitionNumber;
  656. DebugPrint((1, "DiskUpdatePartitions: Found new partition #%d, ord %d "
  657. "starting at %#016I64x and running for %#016I64x\n",
  658. partitionEntry->PartitionNumber,
  659. partitionOrdinal,
  660. partitionEntry->StartingOffset.QuadPart,
  661. partitionEntry->PartitionLength.QuadPart));
  662. ClassReleaseChildLock(fdoExtension);
  663. status = DiskCreatePdo(Fdo,
  664. partitionOrdinal,
  665. partitionEntry,
  666. partitionStyle,
  667. &pdo);
  668. ClassAcquireChildLock(fdoExtension);
  669. if(!NT_SUCCESS(status)) {
  670. DebugPrint((1, "DiskUpdatePartitions: error %lx creating "
  671. "new PDO for partition ordinal %d, number %d\n",
  672. status,
  673. partitionOrdinal,
  674. partitionEntry->PartitionNumber));
  675. //
  676. // don't increment the partition number - we'll try to reuse
  677. // it for the next child.
  678. //
  679. partitionEntry->PartitionNumber = 0;
  680. newPartitionNumber--;
  681. continue;
  682. }
  683. //
  684. // mark the new device as enumerated
  685. //
  686. pdoExtension = pdo->DeviceExtension;
  687. pdoExtension->IsMissing = FALSE;
  688. //
  689. // This number's taken already - try to scanning the partition
  690. // table more than once for a new number.
  691. //
  692. }
  693. }
  694. //
  695. // Update the parent device object
  696. //
  697. {
  698. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  699. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  700. if (partitionStyle == PARTITION_STYLE_MBR)
  701. {
  702. diskData->PartitionStyle = PARTITION_STYLE_MBR;
  703. diskData->Mbr.Signature = PartitionList->Mbr.Signature;
  704. }
  705. else
  706. {
  707. diskData->PartitionStyle = PARTITION_STYLE_GPT;
  708. diskData->Efi.DiskId = PartitionList->Gpt.DiskId;
  709. }
  710. }
  711. ClassReleaseChildLock(fdoExtension);
  712. return;
  713. }
  714. NTSTATUS
  715. DiskCreatePdo(
  716. IN PDEVICE_OBJECT Fdo,
  717. IN ULONG PartitionOrdinal,
  718. IN PPARTITION_INFORMATION_EX PartitionEntry,
  719. IN PARTITION_STYLE PartitionStyle,
  720. OUT PDEVICE_OBJECT *Pdo
  721. )
  722. /*++
  723. Routine Description:
  724. This routine will create and initialize a new partition device object
  725. (PDO) and insert it into the FDO partition list.
  726. Arguments:
  727. Fdo - a pointer to the functional device object this PDO will be a child
  728. of
  729. PartitionOrdinal - the partition ordinal for this PDO
  730. PartitionEntry - the partition information for this device object
  731. PartitionStyle - what style of partition table entry PartitionEntry is;
  732. currently either MBR or EFI
  733. Pdo - a location to store the pdo pointer upon successful completion
  734. Return Value:
  735. status
  736. --*/
  737. {
  738. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  739. PDEVICE_OBJECT pdo = NULL;
  740. PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL;
  741. PUCHAR deviceName = NULL;
  742. PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData;
  743. ULONG numberListElements;
  744. NTSTATUS status = STATUS_SUCCESS;
  745. PAGED_CODE();
  746. //
  747. // Create partition object and set up partition parameters.
  748. //
  749. status = DiskGenerateDeviceName(FALSE,
  750. fdoExtension->DeviceNumber,
  751. PartitionEntry->PartitionNumber,
  752. &PartitionEntry->StartingOffset,
  753. &PartitionEntry->PartitionLength,
  754. &deviceName);
  755. if(!NT_SUCCESS(status)) {
  756. DebugPrint((1, "DiskCreatePdo - Can't generate name %lx\n", status));
  757. return status;
  758. }
  759. DebugPrint((2, "DiskCreatePdo: Create device object %s\n", deviceName));
  760. status = ClassCreateDeviceObject(Fdo->DriverObject,
  761. deviceName,
  762. Fdo,
  763. FALSE,
  764. &pdo);
  765. if (!NT_SUCCESS(status)) {
  766. DebugPrint((1, "DiskEnumerateDevice: Can't create device object for %s\n", deviceName));
  767. ExFreePool(deviceName);
  768. return status;
  769. }
  770. //
  771. // Set up device extension fields.
  772. //
  773. pdoExtension = pdo->DeviceExtension;
  774. //
  775. // Set up device object fields.
  776. //
  777. SET_FLAG(pdo->Flags, DO_DIRECT_IO);
  778. pdo->StackSize = (CCHAR)
  779. pdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1;
  780. //
  781. // Get pointer to new disk data.
  782. //
  783. diskData = (PDISK_DATA) pdoExtension->CommonExtension.DriverData;
  784. //
  785. // Set the alignment requirements for the device based on the
  786. // host adapter requirements
  787. //
  788. if (Fdo->AlignmentRequirement > pdo->AlignmentRequirement) {
  789. pdo->AlignmentRequirement = Fdo->AlignmentRequirement;
  790. }
  791. if (fdoExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
  792. numberListElements = 30;
  793. } else {
  794. numberListElements = 8;
  795. }
  796. //
  797. // Build the lookaside list for srb's for this partition based on
  798. // whether the adapter and disk can do tagged queueing. Don't bother to
  799. // check the status - this can't fail when called for a PDO.
  800. //
  801. ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) pdoExtension,
  802. numberListElements);
  803. //
  804. // Set the sense-data pointer in the device extension.
  805. //
  806. diskData->PartitionOrdinal = PartitionOrdinal;
  807. pdoExtension->CommonExtension.PartitionNumber = PartitionEntry->PartitionNumber;
  808. //
  809. // Initialize relevant data.
  810. //
  811. diskData->PartitionStyle = PartitionStyle;
  812. if (PartitionStyle == PARTITION_STYLE_MBR) {
  813. diskData->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType;
  814. diskData->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator;
  815. diskData->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors;
  816. } else {
  817. diskData->Efi.PartitionType = PartitionEntry->Gpt.PartitionType;
  818. diskData->Efi.PartitionId = PartitionEntry->Gpt.PartitionId;
  819. diskData->Efi.Attributes = PartitionEntry->Gpt.Attributes;
  820. RtlCopyMemory (diskData->Efi.PartitionName,
  821. PartitionEntry->Gpt.Name,
  822. sizeof (diskData->Efi.PartitionName)
  823. );
  824. }
  825. DebugPrint((2, "DiskEnumerateDevice: Partition type is %x\n",
  826. diskData->Mbr.PartitionType));
  827. pdoExtension->CommonExtension.StartingOffset =
  828. PartitionEntry->StartingOffset;
  829. pdoExtension->CommonExtension.PartitionLength =
  830. PartitionEntry->PartitionLength;
  831. DebugPrint((1, "DiskCreatePdo: hidden sectors value for pdo %#p set to %#x\n",
  832. pdo,
  833. diskData->Mbr.HiddenSectors));
  834. //
  835. // Check for removable media support.
  836. //
  837. if (fdoExtension->DeviceDescriptor->RemovableMedia) {
  838. SET_FLAG(pdo->Characteristics, FILE_REMOVABLE_MEDIA);
  839. }
  840. pdoExtension->CommonExtension.DeviceObject = pdo;
  841. CLEAR_FLAG(pdo->Flags, DO_DEVICE_INITIALIZING);
  842. *Pdo = pdo;
  843. return status;
  844. }
  845. /*
  846. * DiskAcquirePartitioningLock
  847. *
  848. * Acquire the PartitioningEvent.
  849. *
  850. * NOTE: This function is called by several ioctl handlers which run in user context.
  851. * Because we are acquiring an exclusion object in a user thread, we have to make sure
  852. * that the thread is not killed or suspended while we are holding the event.
  853. * So we call KeEnterCriticalRegion/KeLeaveCriticalRegion while holding the PartitioningEvent.
  854. * THEREFORE, it is VERY IMPORTANT that DiskAcquirePartitioningLock and DiskReleasePartitioningLock
  855. * are called on the SAME THREAD.
  856. */
  857. VOID
  858. DiskAcquirePartitioningLock(
  859. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  860. )
  861. {
  862. PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
  863. PAGED_CODE();
  864. ASSERT_FDO(FdoExtension->DeviceObject);
  865. /*
  866. * Don't let user-mode thread get suspended while we are holding the partitioning lock
  867. */
  868. KeEnterCriticalRegion();
  869. KeWaitForSingleObject(&(diskData->PartitioningEvent),
  870. UserRequest,
  871. KernelMode,
  872. FALSE,
  873. NULL);
  874. return;
  875. }
  876. VOID
  877. DiskReleasePartitioningLock(
  878. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  879. )
  880. {
  881. PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData;
  882. PAGED_CODE();
  883. ASSERT_FDO(FdoExtension->DeviceObject);
  884. KeSetEvent(&(diskData->PartitioningEvent), IO_NO_INCREMENT, FALSE);
  885. KeLeaveCriticalRegion();
  886. return;
  887. }