diff options
| author | Dave Wilson <[email protected]> | 2015-04-29 09:48:49 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-04-29 10:47:29 -0700 |
| commit | d40232638faaab19de557e70a3ee938da7a35295 (patch) | |
| tree | 14e61c973745949af186b7940e3a53d25322f5de /storage/class/disk/src/enum.c | |
| parent | 02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff) | |
samples update for //build
Diffstat (limited to 'storage/class/disk/src/enum.c')
| -rw-r--r-- | storage/class/disk/src/enum.c | 1313 |
1 files changed, 1313 insertions, 0 deletions
diff --git a/storage/class/disk/src/enum.c b/storage/class/disk/src/enum.c new file mode 100644 index 00000000..d5521caf --- /dev/null +++ b/storage/class/disk/src/enum.c @@ -0,0 +1,1313 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 1999 + +Module Name: + + pnp.c + +Abstract: + + SCSI disk class driver + +Environment: + + kernel mode only + +Notes: + +Revision History: + +--*/ + +#include "disk.h" +#include "ntintsafe.h" + +#ifdef DEBUG_USE_WPP +#include "enum.tmh" +#endif + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DiskConvertExtendedToLayout) +#pragma alloc_text(PAGE, DiskConvertPartitionToExtended) +#pragma alloc_text(PAGE, DiskConvertLayoutToExtended) +#pragma alloc_text(PAGE, DiskCreatePdo) +#pragma alloc_text(PAGE, DiskEnumerateDevice) +#pragma alloc_text(PAGE, DiskUpdateRemovablePartitions) +#pragma alloc_text(PAGE, DiskUpdatePartitions) +#pragma alloc_text(PAGE, DiskCreatePdo) + +#endif + + +PDRIVE_LAYOUT_INFORMATION +DiskConvertExtendedToLayout( + IN CONST PDRIVE_LAYOUT_INFORMATION_EX LayoutEx + ) +{ + ULONG i; + ULONG LayoutSize; + PDRIVE_LAYOUT_INFORMATION Layout; + PPARTITION_INFORMATION Partition; + PPARTITION_INFORMATION_EX PartitionEx; + NTSTATUS status; + + PAGED_CODE (); + + NT_ASSERT ( LayoutEx ); + + + // + // The only valid conversion is from an MBR extended layout structure to + // the old structure. + // + + if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR) { + NT_ASSERT ( FALSE ); + return NULL; + } + + // + // Use safe interger function + // + + status = RtlULongMult(LayoutEx->PartitionCount, sizeof(PARTITION_INFORMATION), &LayoutSize); + if (!NT_SUCCESS(status)) { + return NULL; + } + status = RtlULongAdd(LayoutSize, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[0]), + &LayoutSize); + if (!NT_SUCCESS(status)) { + return NULL; + } + + Layout = ExAllocatePoolWithTag ( + NonPagedPoolNx, + LayoutSize, + DISK_TAG_PART_LIST + ); + + if ( Layout == NULL ) { + return NULL; + } + + Layout->Signature = LayoutEx->Mbr.Signature; + Layout->PartitionCount = LayoutEx->PartitionCount; + + for (i = 0; i < LayoutEx->PartitionCount; i++) { + + Partition = &Layout->PartitionEntry[i]; + PartitionEx = &LayoutEx->PartitionEntry[i]; + + Partition->StartingOffset = PartitionEx->StartingOffset; + Partition->PartitionLength = PartitionEx->PartitionLength; + Partition->RewritePartition = PartitionEx->RewritePartition; + Partition->PartitionNumber = PartitionEx->PartitionNumber; + + Partition->PartitionType = PartitionEx->Mbr.PartitionType; + Partition->BootIndicator = PartitionEx->Mbr.BootIndicator; + Partition->RecognizedPartition = PartitionEx->Mbr.RecognizedPartition; + Partition->HiddenSectors = PartitionEx->Mbr.HiddenSectors; + } + + return Layout; +} + + +VOID +DiskConvertPartitionToExtended( + IN PPARTITION_INFORMATION Partition, + OUT PPARTITION_INFORMATION_EX PartitionEx + ) + +/*++ + +Routine Description: + + Convert a PARTITION_INFORMATION structure to a PARTITION_INFORMATION_EX + structure. + +Arguments: + + Partition - A pointer to the PARTITION_INFORMATION structure to convert. + + PartitionEx - A pointer to a buffer where the converted + PARTITION_INFORMATION_EX structure is to be stored. + +Return Values: + + None. + +--*/ + +{ + PAGED_CODE (); + + NT_ASSERT ( PartitionEx != NULL ); + NT_ASSERT ( Partition != NULL ); + + PartitionEx->PartitionStyle = PARTITION_STYLE_MBR; + PartitionEx->StartingOffset = Partition->StartingOffset; + PartitionEx->PartitionLength = Partition->PartitionLength; + PartitionEx->RewritePartition = Partition->RewritePartition; + PartitionEx->PartitionNumber = Partition->PartitionNumber; + + PartitionEx->Mbr.PartitionType = Partition->PartitionType; + PartitionEx->Mbr.BootIndicator = Partition->BootIndicator; + PartitionEx->Mbr.RecognizedPartition = Partition->RecognizedPartition; + PartitionEx->Mbr.HiddenSectors = Partition->HiddenSectors; +} + + +PDRIVE_LAYOUT_INFORMATION_EX +DiskConvertLayoutToExtended( + IN CONST PDRIVE_LAYOUT_INFORMATION Layout + ) + +/*++ + +Routine Description: + + Convert a DRIVE_LAYOUT_INFORMATION structure into a + DRIVE_LAYOUT_INFORMATION_EX structure. + +Arguments: + + Layout - The source DRIVE_LAYOUT_INFORMATION structure. + +Return Values: + + The resultant DRIVE_LAYOUT_INFORMATION_EX structure. This buffer must + be freed by the callee using ExFreePool. + +--*/ + +{ + ULONG i; + ULONG size; + PDRIVE_LAYOUT_INFORMATION_EX layoutEx; + NTSTATUS status; + + PAGED_CODE (); + + NT_ASSERT ( Layout != NULL ); + + + // + // Allocate enough space for a DRIVE_LAYOUT_INFORMATION_EX structure + // plus as many PARTITION_INFORMATION_EX structures as are in the + // source array. + // + + // + // Use safe interger function + // + + status = RtlULongMult(Layout->PartitionCount, sizeof(PARTITION_INFORMATION_EX), &size); + if (!NT_SUCCESS(status)) { + return NULL; + } + status = RtlULongAdd(size, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[0]), + &size); + if (!NT_SUCCESS(status)) { + return NULL; + } + + layoutEx = ExAllocatePoolWithTag( + NonPagedPoolNx, + size, + DISK_TAG_PART_LIST + ); + + if ( layoutEx == NULL ) { + return NULL; + } + + // + // Convert the disk information. + // + + layoutEx->PartitionStyle = PARTITION_STYLE_MBR; + layoutEx->PartitionCount = Layout->PartitionCount; + layoutEx->Mbr.Signature = Layout->Signature; + + for (i = 0; i < Layout->PartitionCount; i++) { + + // + // Convert each entry. + // + + DiskConvertPartitionToExtended ( + &Layout->PartitionEntry[i], + &layoutEx->PartitionEntry[i] + ); + } + + return layoutEx; +} + + +NTSTATUS +DiskEnumerateDevice( + IN PDEVICE_OBJECT Fdo + ) + +/*++ + +Routine Description: + + This routine is called by the class driver to update the PDO list off + of this FDO. The disk driver also calls it internally to re-create + device objects. + + This routine will read the partition table and create new PDO objects as + necessary. PDO's that no longer exist will be pulled out of the PDO list + so that pnp will destroy them. + +Arguments: + + Fdo - a pointer to the FDO being re-enumerated + +Return Value: + + status + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL; + PDISK_DATA diskData = (PDISK_DATA) commonExtension->DriverData; + PDEVICE_OBJECT pdo = NULL; + PDRIVE_LAYOUT_INFORMATION_EX partitionList; + NTSTATUS status; + BOOLEAN freePartitionList = FALSE; + + NT_ASSERT(commonExtension->IsFdo); + + PAGED_CODE(); + + // + // If our cached partition table is valid, there is nothing to be done + // + + if ( diskData->CachedPartitionTableValid == TRUE ) + { + return STATUS_SUCCESS; + } + + // + // Update our image of the size of the drive. This may be necessary if + // the drive size is extended or we just released a reservation to + // ensure the kernel doesn't reject the partition table. + // + + DiskReadDriveCapacity(Fdo); + + // + // Lock out anyone else trying to repartition the disk. + // + + DiskAcquirePartitioningLock(fdoExtension); + + // + // Create objects for all the partitions on the device. + // + + status = DiskReadPartitionTableEx(fdoExtension, FALSE, &partitionList); + + // + // If the I/O read partition table failed and this is a removable device, + // then fix up the partition list to make it look like there is one + // zero length partition. + // + + if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) && + Fdo->Characteristics & FILE_REMOVABLE_MEDIA) { + + SIZE_T partitionListSize; + + // + // Remember whether the drive is ready. + // + + diskData->ReadyStatus = status; + + // + // Allocate and zero a partition list. + // + + partitionListSize = + FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]); + + partitionList = ExAllocatePoolWithTag(NonPagedPoolNx, + partitionListSize, + DISK_TAG_PART_LIST); + + if (partitionList != NULL) { + + RtlZeroMemory( partitionList, partitionListSize ); + + // + // Set the partition count to one and the status to success + // so one device object will be created. Set the partition type + // to a bogus value. + // + + partitionList->PartitionStyle = PARTITION_STYLE_MBR; + partitionList->PartitionCount = 1; + + freePartitionList = TRUE; + + status = STATUS_SUCCESS; + } else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) { + + diskData->UpdatePartitionRoutine(Fdo, partitionList); + } + + DiskReleasePartitioningLock(fdoExtension); + + if (freePartitionList) { + FREE_POOL(partitionList); + } + + return(STATUS_SUCCESS); + +} // end DiskEnumerateDevice() + + +VOID +DiskUpdateRemovablePartitions( + IN PDEVICE_OBJECT Fdo, + IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList + ) + +/*++ + +Routine Description: + + This routine is called by the class DLL to update the PDO list off of this + FDO. The disk driver also calls it internally to re-create device objects. + + This routine will read the partition table and update the size of the + single partition device object which always exists for removable devices. + +Arguments: + + Fdo - a pointer to the FDO being reenumerated. + +Return Value: + + status + +--*/ + +{ + + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL; + + ULONG partitionCount; + + ULONG partitionNumber; + ULONG partitionOrdinal = 0; + ULONG newPartitionNumber; + + PDISK_DATA pdoData; + NTSTATUS status; + + PPARTITION_INFORMATION_EX partitionEntry; + PARTITION_STYLE partitionStyle; + + PAGED_CODE(); + + NT_ASSERT(Fdo->Characteristics & FILE_REMOVABLE_MEDIA); + + partitionStyle = PartitionList->PartitionStyle; + partitionCount = PartitionList->PartitionCount; + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + + partitionEntry->PartitionNumber = 0; + } + + // + // Get exclusive access to the child list while repartitioning. + // + + ClassAcquireChildLock(fdoExtension); + + // + // Removable media should never have more than one PDO. + // + + pdoExtension = fdoExtension->CommonExtension.ChildList; + + if(pdoExtension == NULL) { + + PARTITION_INFORMATION_EX tmpPartitionEntry = { 0 }; + PDEVICE_OBJECT pdo; + + // + // There is no PDO currently. Create one and pre-initialize it with + // a zero length. + // + + tmpPartitionEntry.PartitionNumber = 1; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: Creating RM partition\n")); + + status = DiskCreatePdo(Fdo, + 0, + &tmpPartitionEntry, + partitionStyle, + &pdo); + + if(!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: error %lx creating " + "new PDO for RM partition\n", + status)); + + goto DiskUpdateRemovablePartitionsExit; + } + + // + // mark the new device as enumerated + // + + pdoExtension = pdo->DeviceExtension; + pdoExtension->IsMissing = FALSE; + + } + + pdoData = pdoExtension->CommonExtension.DriverData; + + // + // Search the partition list for a valid entry. We're looking for a + // primary partition since we only support the one. + // + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + + + // + // Is this partition interesting? + // + + if (partitionStyle == PARTITION_STYLE_MBR) { + + if(partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED || + IsContainerPartition(partitionEntry->Mbr.PartitionType)) { + + continue; + } + } + + partitionOrdinal++; + + // + // We have found the first and thus only partition allowed on + // this disk. Update the information in the PDO to match the new + // partition. + // + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdateRemovablePartitions: Matched %wZ to #%d, " + "ordinal %d\n", + &pdoExtension->CommonExtension.DeviceName, + partitionEntry->PartitionNumber, + partitionOrdinal)); + + + partitionEntry->PartitionNumber = 1; + + pdoData->PartitionStyle = partitionStyle; + pdoData->PartitionOrdinal = partitionOrdinal; + NT_ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789); + + pdoExtension->CommonExtension.StartingOffset = + partitionEntry->StartingOffset; + + pdoExtension->CommonExtension.PartitionLength = + partitionEntry->PartitionLength; + + + if (partitionStyle == PARTITION_STYLE_MBR) { + + pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors; + pdoData->Mbr.BootIndicator = partitionEntry->Mbr.BootIndicator; + + + // + // If this partition is being re-written then update the type + // information as well + // + + if (partitionEntry->RewritePartition) { + pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType; + } + + } else { + + pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType; + pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId; + pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes; + + RtlCopyMemory( + pdoData->Efi.PartitionName, + partitionEntry->Gpt.Name, + sizeof (pdoData->Efi.PartitionName) + ); + } + + // + // Mark this one as found + // + + pdoExtension->IsMissing = FALSE; + goto DiskUpdateRemovablePartitionsExit; + } + + // + // No interesting partition was found. + // + + if (partitionStyle == PARTITION_STYLE_MBR) { + + pdoData->Mbr.HiddenSectors = 0; + pdoData->Mbr.PartitionType = PARTITION_ENTRY_UNUSED; + + } else { + + RtlZeroMemory (&pdoData->Efi, + sizeof (pdoData->Efi) + ); + } + + pdoExtension->CommonExtension.StartingOffset.QuadPart = 0; + pdoExtension->CommonExtension.PartitionLength.QuadPart = 0; + +DiskUpdateRemovablePartitionsExit: + + // + // Update the parent device object + // + + { + PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + + if (partitionStyle == PARTITION_STYLE_MBR) + { + diskData->PartitionStyle = PARTITION_STYLE_MBR; + diskData->Mbr.Signature = PartitionList->Mbr.Signature; + } + else + { + diskData->PartitionStyle = PARTITION_STYLE_GPT; + diskData->Efi.DiskId = PartitionList->Gpt.DiskId; + } + } + + ClassReleaseChildLock(fdoExtension); + return; +} + + +VOID +DiskUpdatePartitions( + IN PDEVICE_OBJECT Fdo, + IN OUT PDRIVE_LAYOUT_INFORMATION_EX PartitionList + ) + +/*++ + +Routine Description: + + This routine will synchronize the information held in the partition list + with the device objects hanging off this Fdo. Any new partition objects + will be created, any non-existant ones will be marked as un-enumerated. + + This will be done in several stages: + + * Clear state (partition number) from every entry in the partition + list + + * Set IsMissing flag on every child of this FDO + + * For each child of the FDO: + if a matching partition exists in the partition list, + update the partition number in the table, update the + ordinal in the object and mark the object as enumerated + + * For each un-enumerated device object + zero out the partition information to invalidate the device + delete the symbolic link if any + + * For each un-matched entry in the partition list: + create a new partition object + update the partition number in the list entry + create a new symbolic link if necessary + +Arguments: + + Fdo - a pointer to the functional device object this partition list is for + + PartitionList - a pointer to the partition list being updated + +Return Value: + + none + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + + PPHYSICAL_DEVICE_EXTENSION oldChildList = NULL; + PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL; + + ULONG partitionCount; + + ULONG partitionNumber; + ULONG partitionOrdinal; + ULONG newPartitionNumber; + + PPARTITION_INFORMATION_EX partitionEntry; + PDISK_DATA pdoData; + PARTITION_STYLE partitionStyle; + + NTSTATUS status; + + PAGED_CODE(); + + // + // Get exclusive access to the child list. + // + + ClassAcquireChildLock(fdoExtension); + + partitionStyle = PartitionList->PartitionStyle; + partitionCount = PartitionList->PartitionCount; + + // + // Pull all the child device objects off the children list. We'll + // add them back later. + // + + oldChildList = fdoExtension->CommonExtension.ChildList; + fdoExtension->CommonExtension.ChildList = NULL; + + // + // Clear the partition numbers from the list entries + // + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + partitionEntry->PartitionNumber = 0; + } + + // + // Now match each child partition to it's entry (if any) in the partition + // list. + // + + while(oldChildList != NULL) { + + pdoExtension = oldChildList; + pdoData = pdoExtension->CommonExtension.DriverData; + + // + // Check all partition entries for a match on offset and length + // + + partitionOrdinal = 0; + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + + // + // Is this an interesting partition entry? + // + + if (partitionStyle == PARTITION_STYLE_MBR) { + + if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) || + (IsContainerPartition(partitionEntry->Mbr.PartitionType))) { + + continue; + } + } + + partitionOrdinal++; + + if(partitionEntry->PartitionNumber) { + + // + // This partition has already been found - skip it + // + + continue; + } + + // + // Let's see if the partition information matches + // + + if(partitionEntry->StartingOffset.QuadPart != + pdoExtension->CommonExtension.StartingOffset.QuadPart) { + continue; + } + + if(partitionEntry->PartitionLength.QuadPart != + pdoExtension->CommonExtension.PartitionLength.QuadPart) { + continue; + } + + // + // Yep - it matches. Update the information in the entry + // + + partitionEntry->PartitionNumber = pdoExtension->CommonExtension.PartitionNumber; + + if (partitionStyle == PARTITION_STYLE_MBR) { + + pdoData->Mbr.HiddenSectors = partitionEntry->Mbr.HiddenSectors; + + } + + break; + } + + if(partitionNumber != partitionCount) { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: Matched %wZ to #%d, ordinal " + "%d\n", + &pdoExtension->CommonExtension.DeviceName, + partitionEntry->PartitionNumber, + partitionOrdinal)); + + NT_ASSERT(partitionEntry->PartitionLength.LowPart != 0x23456789); + // NT_ASSERT(pdoExtension->CommonExtension.PartitionLength.QuadPart != 0); + + pdoData->PartitionStyle = partitionStyle; + + // + // we found a match - update the information in the device object + // extension and driverdata + // + + pdoData->PartitionOrdinal = partitionOrdinal; + + // + // If this partition is being re-written then update the type + // information as well + // + + + if (partitionStyle == PARTITION_STYLE_MBR) { + + if(partitionEntry->RewritePartition) { + pdoData->Mbr.PartitionType = partitionEntry->Mbr.PartitionType; + } + + } else { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: EFI Partition %ws\n", + pdoData->Efi.PartitionName + )); + + pdoData->Efi.PartitionType = partitionEntry->Gpt.PartitionType; + pdoData->Efi.PartitionId = partitionEntry->Gpt.PartitionId; + pdoData->Efi.Attributes = partitionEntry->Gpt.Attributes; + + RtlCopyMemory( + pdoData->Efi.PartitionName, + partitionEntry->Gpt.Name, + sizeof (pdoData->Efi.PartitionName) + ); + } + + // + // Mark this one as found. + // + + pdoExtension->IsMissing = FALSE; + + // + // Pull it out of the old child list and add it into the + // real one. + // + + oldChildList = pdoExtension->CommonExtension.ChildList; + + pdoExtension->CommonExtension.ChildList = + fdoExtension->CommonExtension.ChildList; + + fdoExtension->CommonExtension.ChildList = pdoExtension; + + } else { + + PDEVICE_OBJECT nextPdo; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: Deleting %wZ\n", + &pdoExtension->CommonExtension.DeviceName)); + + if (partitionStyle == PARTITION_STYLE_GPT) { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: EFI Partition %ws\n", + pdoData->Efi.PartitionName + )); + } + // + // no matching entry in the partition list - throw this partition + // object away + // + + pdoExtension->CommonExtension.PartitionLength.QuadPart = 0; + + // + // grab a pointer to the next child before we mark this one as + // missing since missing devices could vanish at any time. + // + + oldChildList = pdoExtension->CommonExtension.ChildList; + pdoExtension->CommonExtension.ChildList = (PVOID) -1; + + // + // Now tell the class driver that this child is "missing" - this + // will cause it to be deleted. + // + + + ClassMarkChildMissing(pdoExtension, FALSE); + } + } + + // + // At this point the old child list had best be empty. + // + + NT_ASSERT(oldChildList == NULL); + + // + // Iterate through the partition entries and create any partition + // objects that don't already exist + // + + partitionOrdinal = 0; + newPartitionNumber = 0; + + for(partitionNumber = 0; + partitionNumber < partitionCount; + partitionNumber++) { + + PDEVICE_OBJECT pdo; + + partitionEntry = &(PartitionList->PartitionEntry[partitionNumber]); + + // + // Is this partition interesting + // + + if (partitionStyle == PARTITION_STYLE_MBR) { + + if((partitionEntry->Mbr.PartitionType == PARTITION_ENTRY_UNUSED) || + (IsContainerPartition(partitionEntry->Mbr.PartitionType))) { + + continue; + } + } + + // + // Increment the count of interesting partitions + // + + partitionOrdinal++; + newPartitionNumber++; + + // + // Has this already been matched + // + + if(partitionEntry->PartitionNumber == 0) { + + LONG i; + + // + // find the first safe partition number for this device + // + + for(i = 0; i < (LONG) partitionCount; i++) { + + + PPARTITION_INFORMATION_EX tmp = &(PartitionList->PartitionEntry[i]); + + if (partitionStyle == PARTITION_STYLE_MBR) { + if (tmp->Mbr.PartitionType == PARTITION_ENTRY_UNUSED || + IsContainerPartition(tmp->Mbr.PartitionType)) { + continue; + } + } + + if(tmp->PartitionNumber == newPartitionNumber) { + + // + // Found a matching partition number - increment the count + // and restart the scan. + // + + newPartitionNumber++; + i = -1; + continue; + } + } + + // + // Assign this partition a partition number + // + + partitionEntry->PartitionNumber = newPartitionNumber; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskUpdatePartitions: Found new partition #%d, ord %d " + "starting at %#016I64x and running for %#016I64x\n", + partitionEntry->PartitionNumber, + partitionOrdinal, + partitionEntry->StartingOffset.QuadPart, + partitionEntry->PartitionLength.QuadPart)); + + ClassReleaseChildLock(fdoExtension); + + status = DiskCreatePdo(Fdo, + partitionOrdinal, + partitionEntry, + partitionStyle, + &pdo); + + ClassAcquireChildLock(fdoExtension); + + if(!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskUpdatePartitions: error %lx creating " + "new PDO for partition ordinal %d, number %d\n", + status, + partitionOrdinal, + partitionEntry->PartitionNumber)); + + // + // don't increment the partition number - we'll try to reuse + // it for the next child. + // + + partitionEntry->PartitionNumber = 0; + newPartitionNumber--; + + continue; + } + + // + // mark the new device as enumerated + // + + pdoExtension = pdo->DeviceExtension; + pdoExtension->IsMissing = FALSE; + + // + // This number's taken already - try to scanning the partition + // table more than once for a new number. + // + + } + } + + // + // Update the parent device object + // + + { + PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; + PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData); + + if (partitionStyle == PARTITION_STYLE_MBR) + { + diskData->PartitionStyle = PARTITION_STYLE_MBR; + diskData->Mbr.Signature = PartitionList->Mbr.Signature; + } + else + { + diskData->PartitionStyle = PARTITION_STYLE_GPT; + diskData->Efi.DiskId = PartitionList->Gpt.DiskId; + } + } + + ClassReleaseChildLock(fdoExtension); + return; +} + + +NTSTATUS +DiskCreatePdo( + IN PDEVICE_OBJECT Fdo, + IN ULONG PartitionOrdinal, + IN PPARTITION_INFORMATION_EX PartitionEntry, + IN PARTITION_STYLE PartitionStyle, + OUT PDEVICE_OBJECT *Pdo + ) + +/*++ + +Routine Description: + + This routine will create and initialize a new partition device object + (PDO) and insert it into the FDO partition list. + +Arguments: + + Fdo - a pointer to the functional device object this PDO will be a child + of + + PartitionOrdinal - the partition ordinal for this PDO + + PartitionEntry - the partition information for this device object + + PartitionStyle - what style of partition table entry PartitionEntry is; + currently either MBR or EFI + + Pdo - a location to store the pdo pointer upon successful completion + +Return Value: + + status + +--*/ + +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; + PDEVICE_OBJECT pdo = NULL; + PPHYSICAL_DEVICE_EXTENSION pdoExtension = NULL; + + PUCHAR deviceName = NULL; + + PDISK_DATA diskData = fdoExtension->CommonExtension.DriverData; + + ULONG numberListElements; + + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Create partition object and set up partition parameters. + // + + status = DiskGenerateDeviceName(FALSE, + fdoExtension->DeviceNumber, + PartitionEntry->PartitionNumber, + &PartitionEntry->StartingOffset, + &PartitionEntry->PartitionLength, + &deviceName); + + if(!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskCreatePdo - Can't generate name %lx\n", status)); + return status; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskCreatePdo: Create device object %s\n", deviceName)); + + status = ClassCreateDeviceObject(Fdo->DriverObject, + deviceName, + Fdo, + FALSE, + &pdo); + + if (!NT_SUCCESS(status)) { + + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_ENUM, "DiskEnumerateDevice: Can't create device object for %s\n", deviceName)); + + FREE_POOL(deviceName); + return status; + } + + FREE_POOL(deviceName); + + // + // Set up device extension fields. + // + + pdoExtension = pdo->DeviceExtension; + + // + // Set up device object fields. + // + + SET_FLAG(pdo->Flags, DO_DIRECT_IO); + + pdo->StackSize = (CCHAR) + pdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1; + + // + // Get pointer to new disk data. + // + + diskData = (PDISK_DATA) pdoExtension->CommonExtension.DriverData; + + // + // Set the alignment requirements for the device based on the + // host adapter requirements + // + + if (Fdo->AlignmentRequirement > pdo->AlignmentRequirement) { + pdo->AlignmentRequirement = Fdo->AlignmentRequirement; + } + + if (fdoExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { + numberListElements = 30; + } else { + numberListElements = 8; + } + + // + // Build the lookaside list for srb's for this partition based on + // whether the adapter and disk can do tagged queueing. Don't bother to + // check the status - this can't fail when called for a PDO. + // + + ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION) pdoExtension, + numberListElements); + + // + // Set the sense-data pointer in the device extension. + // + + diskData->PartitionOrdinal = PartitionOrdinal; + pdoExtension->CommonExtension.PartitionNumber = PartitionEntry->PartitionNumber; + + // + // Initialize relevant data. + // + + diskData->PartitionStyle = PartitionStyle; + + if (PartitionStyle == PARTITION_STYLE_MBR) { + + diskData->Mbr.PartitionType = PartitionEntry->Mbr.PartitionType; + diskData->Mbr.BootIndicator = PartitionEntry->Mbr.BootIndicator; + diskData->Mbr.HiddenSectors = PartitionEntry->Mbr.HiddenSectors; + + } else { + + diskData->Efi.PartitionType = PartitionEntry->Gpt.PartitionType; + diskData->Efi.PartitionId = PartitionEntry->Gpt.PartitionId; + diskData->Efi.Attributes = PartitionEntry->Gpt.Attributes; + RtlCopyMemory (diskData->Efi.PartitionName, + PartitionEntry->Gpt.Name, + sizeof (diskData->Efi.PartitionName) + ); + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskEnumerateDevice: Partition type is %x\n", + diskData->Mbr.PartitionType)); + + pdoExtension->CommonExtension.StartingOffset = + PartitionEntry->StartingOffset; + + pdoExtension->CommonExtension.PartitionLength = + PartitionEntry->PartitionLength; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_ENUM, "DiskCreatePdo: hidden sectors value for pdo %#p set to %#x\n", + pdo, + diskData->Mbr.HiddenSectors)); + + // + // Check for removable media support. + // + + if (fdoExtension->DeviceDescriptor->RemovableMedia) { + SET_FLAG(pdo->Characteristics, FILE_REMOVABLE_MEDIA); + } + + pdoExtension->CommonExtension.DeviceObject = pdo; + + CLEAR_FLAG(pdo->Flags, DO_DEVICE_INITIALIZING); + + *Pdo = pdo; + + return status; +} + + +/* + * DiskAcquirePartitioningLock + * + * Acquire the PartitioningEvent. + * + * NOTE: This function is called by several ioctl handlers which run in user context. + * Because we are acquiring an exclusion object in a user thread, we have to make sure + * that the thread is not killed or suspended while we are holding the event. + * So we call KeEnterCriticalRegion/KeLeaveCriticalRegion while holding the PartitioningEvent. + * THEREFORE, it is VERY IMPORTANT that DiskAcquirePartitioningLock and DiskReleasePartitioningLock + * are called on the SAME THREAD. + */ +VOID +DiskAcquirePartitioningLock( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; + + PAGED_CODE(); + + ASSERT_FDO(FdoExtension->DeviceObject); + + /* + * Don't let user-mode thread get suspended while we are holding the partitioning lock + */ + KeEnterCriticalRegion(); + + KeWaitForSingleObject(&(diskData->PartitioningEvent), + UserRequest, + KernelMode, + FALSE, + NULL); + return; +} + + +VOID +DiskReleasePartitioningLock( + IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension + ) +{ + PDISK_DATA diskData = FdoExtension->CommonExtension.DriverData; + + PAGED_CODE(); + + ASSERT_FDO(FdoExtension->DeviceObject); + + KeSetEvent(&(diskData->PartitioningEvent), IO_NO_INCREMENT, FALSE); + + KeLeaveCriticalRegion(); + + return; +} |
