123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776 |
- /*++
- Copyright (c) 2014 Minoca Corp. All Rights Reserved
- Module Name:
- part.c
- Abstract:
- This module implements the partition manager driver.
- Author:
- Evan Green 30-Jan-2014
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/lib/partlib.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define PARTITION_ALLOCATION_TAG 0x74726150 // 'traP'
- #define PARTITION_STRING_SIZE sizeof("PartitionXXXXX")
- #define PARTITION_STRING_FORMAT "Partition%d"
- #define PARTITION_RAW_DISK_ID "RawDisk"
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef enum _PARTITION_OBJECT_TYPE {
- PartitionObjectInvalid,
- PartitionObjectParent,
- PartitionObjectChild
- } PARTITION_OBJECT_TYPE, *PPARTITION_OBJECT_TYPE;
- /*++
- Structure Description:
- This structure stores the common header for a partition manager object.
- Members:
- Type - Stores the partition object type.
- ReferenceCount - Stores the reference count on the object.
- --*/
- typedef struct _PARTITION_OBJECT {
- PARTITION_OBJECT_TYPE Type;
- ULONG ReferenceCount;
- } PARTITION_OBJECT, *PPARTITION_OBJECT;
- /*++
- Structure Description:
- This structure stores information about a partition parent context.
- Members:
- Header - Store the common partition object header.
- Device - Stores the OS device this device belongs to.
- IoHandle - Stores an open I/O handle to the disk, active when the partition
- manager is reading the device.
- PartitionContext - Stores the partition context for this disk.
- Children - Stores an array of pointers to devices representing the device
- partitions. The raw disk is not included here.
- RawDisk - Stores a pointer to the raw disk device.
- --*/
- typedef struct _PARTITION_PARENT {
- PARTITION_OBJECT Header;
- PDEVICE Device;
- PIO_HANDLE IoHandle;
- PARTITION_CONTEXT PartitionContext;
- PDEVICE *Children;
- PDEVICE RawDisk;
- } PARTITION_PARENT, *PPARTITION_PARENT;
- /*++
- Structure Description:
- This structure stores information about a particular partition.
- Members:
- Header - Stores the common partition object header.
- Parent - Stores a pointer to the parent structure.
- Index - Stores the index into the partition information for this partition.
- --*/
- typedef struct _PARTITION_CHILD {
- PARTITION_OBJECT Header;
- PPARTITION_PARENT Parent;
- ULONG Index;
- } PARTITION_CHILD, *PPARTITION_CHILD;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- PartAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- );
- VOID
- PartDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- PartDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- PartDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- PartDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- PartDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- KSTATUS
- PartpEnumerateChildren (
- PIRP Irp,
- PPARTITION_PARENT Parent
- );
- KSTATUS
- PartpReadPartitionStructures (
- PPARTITION_PARENT Parent
- );
- VOID
- PartpHandleDeviceInformationRequest (
- PIRP Irp,
- PPARTITION_CHILD Child
- );
- VOID
- PartpHandleBlockInformationRequest (
- PIRP Irp,
- PPARTITION_CHILD Child
- );
- PVOID
- PartpAllocate (
- UINTN Size
- );
- VOID
- PartpFree (
- PVOID Memory
- );
- KSTATUS
- PartpRead (
- PPARTITION_CONTEXT Context,
- ULONGLONG BlockAddress,
- PVOID Buffer
- );
- PPARTITION_CHILD
- PartpCreateChild (
- PPARTITION_PARENT Parent,
- ULONG Index
- );
- VOID
- PartpAddReference (
- PPARTITION_OBJECT Object
- );
- VOID
- PartpReleaseReference (
- PPARTITION_OBJECT Object
- );
- VOID
- PartpDestroyDevice (
- PPARTITION_OBJECT Object
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PDRIVER PartDriver;
- UUID PartPartitionDeviceInformationUuid = PARTITION_DEVICE_INFORMATION_UUID;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine implements the initial entry point of the networking core
- library, called when the library is first loaded.
- Arguments:
- Driver - Supplies a pointer to the driver object.
- Return Value:
- Status code.
- --*/
- {
- DRIVER_FUNCTION_TABLE FunctionTable;
- KSTATUS Status;
- PartDriver = Driver;
- RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
- FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
- FunctionTable.AddDevice = PartAddDevice;
- FunctionTable.DispatchStateChange = PartDispatchStateChange;
- FunctionTable.DispatchOpen = PartDispatchOpen;
- FunctionTable.DispatchClose = PartDispatchClose;
- FunctionTable.DispatchIo = PartDispatchIo;
- FunctionTable.DispatchSystemControl = PartDispatchSystemControl;
- Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
- return Status;
- }
- KSTATUS
- PartAddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- )
- /*++
- Routine Description:
- This routine is called when a disk is detected. The partition manager
- attaches to the disk.
- Arguments:
- Driver - Supplies a pointer to the driver being called.
- DeviceId - Supplies a pointer to a string with the device ID.
- ClassId - Supplies a pointer to a string containing the device's class ID.
- CompatibleIds - Supplies a pointer to a string containing device IDs
- that would be compatible with this device.
- DeviceToken - Supplies an opaque token that the driver can use to identify
- the device in the system. This token should be used when attaching to
- the stack.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code if the driver was unsuccessful in attaching itself.
- --*/
- {
- PPARTITION_PARENT Context;
- KSTATUS Status;
- Context = PartpAllocate(sizeof(PARTITION_PARENT));
- if (Context == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto AddDeviceEnd;
- }
- RtlZeroMemory(Context, sizeof(PARTITION_PARENT));
- Context->Header.Type = PartitionObjectParent;
- Context->Header.ReferenceCount = 1;
- Context->Device = DeviceToken;
- Status = IoAttachDriverToDevice(Driver, DeviceToken, Context);
- AddDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Context != NULL) {
- PartpFree(Context);
- Context = NULL;
- }
- }
- return Status;
- }
- VOID
- PartDispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PPARTITION_CHILD Child;
- PPARTITION_OBJECT Object;
- PPARTITION_PARENT Parent;
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorStateChange);
- Object = (PPARTITION_OBJECT)DeviceContext;
- switch (Object->Type) {
- //
- // If this is the functional driver for the disk itself, usurp the query
- // children IRP but don't alter any other IRP paths.
- //
- case PartitionObjectParent:
- Parent = PARENT_STRUCTURE(Object, PARTITION_PARENT, Header);
- switch (Irp->MinorCode) {
- case IrpMinorQueryChildren:
- Status = PartpEnumerateChildren(Irp, Parent);
- IoCompleteIrp(PartDriver, Irp, Status);
- break;
- case IrpMinorRemoveDevice:
- if (Irp->Direction == IrpUp) {
- PartpReleaseReference(Object);
- }
- break;
- //
- // For all other IRPs, do nothing.
- //
- default:
- break;
- }
- break;
- //
- // If this is a child, then this driver is being called as the bus driver.
- // Complete state change IRPs so they don't make it down to the disk.
- //
- case PartitionObjectChild:
- Child = PARENT_STRUCTURE(Object, PARTITION_CHILD, Header);
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- IoCompleteIrp(PartDriver, Irp, STATUS_SUCCESS);
- break;
- case IrpMinorStartDevice:
- //
- // Publish the partition information device type.
- //
- Status = IoRegisterDeviceInformation(
- Irp->Device,
- &PartPartitionDeviceInformationUuid,
- TRUE);
- IoCompleteIrp(PartDriver, Irp, Status);
- break;
- case IrpMinorQueryChildren:
- Status = STATUS_SUCCESS;
- //
- // If this is the raw disk coming up, then read off the partition
- // information.
- //
- if (Child->Index == -1) {
- Status = PartpReadPartitionStructures(Child->Parent);
- }
- IoCompleteIrp(PartDriver, Irp, Status);
- break;
- case IrpMinorRemoveDevice:
- IoRegisterDeviceInformation(Irp->Device,
- &PartPartitionDeviceInformationUuid,
- FALSE);
- PartpReleaseReference(Object);
- IoCompleteIrp(PartDriver, Irp, STATUS_SUCCESS);
- break;
- //
- // For all other IRPs, do nothing.
- //
- default:
- break;
- }
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- return;
- }
- VOID
- PartDispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Open IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- //
- // Let the IRP head down and be handled by the disk directly.
- //
- return;
- }
- VOID
- PartDispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Close IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- //
- // Let the IRP be handled by the disk.
- //
- return;
- }
- VOID
- PartDispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles I/O IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- ULONGLONG BlockAddress;
- ULONGLONG BlockCount;
- ULONG BlockShift;
- ULONG BlockSize;
- PPARTITION_CHILD Child;
- PPARTITION_OBJECT Object;
- ULONGLONG OriginalBlockCount;
- PPARTITION_INFORMATION Partition;
- PIRP_READ_WRITE ReadWrite;
- KSTATUS Status;
- Object = (PPARTITION_OBJECT)DeviceContext;
- //
- // Don't process I/O as the parent (bus driver), let that head down to the
- // disk.
- //
- if (Object->Type != PartitionObjectChild) {
- return;
- }
- ASSERT(Irp->MajorCode == IrpMajorIo);
- Child = PARENT_STRUCTURE(Object, PARTITION_CHILD, Header);
- //
- // If this is the raw disk partition, let the IRP continue down to the disk
- // unmolested.
- //
- if (Child->Index == -1) {
- return;
- }
- BlockShift = Child->Parent->PartitionContext.BlockShift;
- BlockSize = Child->Parent->PartitionContext.BlockSize;
- ASSERT(BlockSize != 0);
- ReadWrite = &(Irp->U.ReadWrite);
- Partition = &(Child->Parent->PartitionContext.Partitions[Child->Index]);
- if (Irp->Direction == IrpDown) {
- //
- // On the way down, convert the offset into a block address, translate
- // the partition-relative block address into a disk block address, and
- // then convert back into bytes.
- //
- ASSERT((IS_ALIGNED(ReadWrite->IoOffset, BlockSize)) &&
- (IS_ALIGNED(ReadWrite->IoSizeInBytes, BlockSize)));
- BlockAddress = ReadWrite->IoOffset >> BlockShift;
- BlockCount = ReadWrite->IoSizeInBytes >> BlockShift;
- OriginalBlockCount = BlockCount;
- Status = PartTranslateIo(Partition, &BlockAddress, &BlockCount);
- if (!KSUCCESS(Status)) {
- goto DispatchIoEnd;
- }
- ReadWrite->IoOffset = BlockAddress << BlockShift;
- ReadWrite->NewIoOffset += Partition->StartOffset << BlockShift;
- if (BlockCount != OriginalBlockCount) {
- ReadWrite->IoSizeInBytes = BlockCount << BlockShift;
- }
- //
- // On the way back up, re-adjust the I/O offset and new I/O offset.
- //
- } else {
- ASSERT(Irp->Direction == IrpUp);
- ASSERT(ReadWrite->IoOffset >= (Partition->StartOffset << BlockShift));
- ReadWrite->IoOffset -= Partition->StartOffset << BlockShift;
- ASSERT(ReadWrite->NewIoOffset >= Partition->StartOffset << BlockShift);
- ReadWrite->NewIoOffset -= Partition->StartOffset << BlockShift;
- }
- Status = STATUS_SUCCESS;
- DispatchIoEnd:
- //
- // If something bad happened, don't let this get down to the disk.
- // Otherwise, let it flow to the disk.
- //
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(PartDriver, Irp, Status);
- }
- return;
- }
- VOID
- PartDispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles System Control IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- ULONGLONG BlockCount;
- ULONG BlockSize;
- PPARTITION_CHILD Child;
- PVOID Context;
- PSYSTEM_CONTROL_FILE_OPERATION FileOperation;
- ULONGLONG FileSize;
- PSYSTEM_CONTROL_LOOKUP Lookup;
- PPARTITION_OBJECT Object;
- PPARTITION_PARENT Parent;
- PPARTITION_INFORMATION Partition;
- PPARTITION_CONTEXT PartitionContext;
- PFILE_PROPERTIES Properties;
- ULONGLONG PropertiesFileSize;
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorSystemControl);
- Object = (PPARTITION_OBJECT)DeviceContext;
- Context = Irp->U.SystemControl.SystemContext;
- if (Irp->Direction != IrpDown) {
- return;
- }
- if (Object->Type == PartitionObjectParent) {
- Parent = PARENT_STRUCTURE(Object, PARTITION_PARENT, Header);
- switch (Irp->MinorCode) {
- //
- // If the IRP is destined for the disk, then explicitly complete it as
- // "not supported" so the object manager will enumerate children. If
- // this is IRP was actually sent to the raw disk child, then let it
- // flow down to the disk.
- //
- case IrpMinorSystemControlLookup:
- if (Irp->Device != Parent->RawDisk) {
- IoCompleteIrp(PartDriver, Irp, STATUS_NOT_HANDLED);
- }
- break;
- default:
- break;
- }
- } else {
- ASSERT(Object->Type == PartitionObjectChild);
- Child = PARENT_STRUCTURE(Object, PARTITION_CHILD, Header);
- PartitionContext = &(Child->Parent->PartitionContext);
- BlockSize = PartitionContext->BlockSize;
- Partition = NULL;
- BlockCount = 0;
- if (Child->Index != -1) {
- Partition = &(PartitionContext->Partitions[Child->Index]);
- BlockCount = Partition->EndOffset - Partition->StartOffset;
- }
- FileSize = BlockCount << PartitionContext->BlockShift;
- switch (Irp->MinorCode) {
- case IrpMinorSystemControlLookup:
- //
- // Let the IRP pass down to the disk if this is the raw disk child.
- //
- if (Child->Index == -1) {
- break;
- }
- Lookup = (PSYSTEM_CONTROL_LOOKUP)Context;
- Status = STATUS_PATH_NOT_FOUND;
- if (Lookup->Root != FALSE) {
- //
- // Enable opening of the root as a single file.
- //
- Properties = &(Lookup->Properties);
- Properties->FileId = 0;
- Properties->Type = IoObjectBlockDevice;
- Properties->HardLinkCount = 1;
- Properties->BlockSize = BlockSize;
- Properties->BlockCount = BlockCount;
- WRITE_INT64_SYNC(&(Properties->FileSize), FileSize);
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(PartDriver, Irp, Status);
- break;
- //
- // Writes to the disk's properties are not allowed. Fail if the data
- // has changed.
- //
- case IrpMinorSystemControlWriteFileProperties:
- if (Child->Index == -1) {
- break;
- }
- FileOperation = (PSYSTEM_CONTROL_FILE_OPERATION)Context;
- Properties = FileOperation->FileProperties;
- READ_INT64_SYNC(&(Properties->FileSize), &PropertiesFileSize);
- if ((Properties->FileId != 0) ||
- (Properties->Type != IoObjectBlockDevice) ||
- (Properties->HardLinkCount != 1) ||
- (Properties->BlockSize != BlockSize) ||
- (Properties->BlockCount != BlockCount) ||
- (PropertiesFileSize != FileSize)) {
- Status = STATUS_NOT_SUPPORTED;
- } else {
- Status = STATUS_SUCCESS;
- }
- IoCompleteIrp(PartDriver, Irp, Status);
- break;
- //
- // Handle get/set device information requests.
- //
- case IrpMinorSystemControlDeviceInformation:
- PartpHandleDeviceInformationRequest(Irp, Child);
- break;
- case IrpMinorSystemControlGetBlockInformation:
- PartpHandleBlockInformationRequest(Irp, Child);
- break;
- //
- // Let synchronize requests go down to the disk.
- //
- case IrpMinorSystemControlSynchronize:
- break;
- //
- // Other operations are not supported.
- //
- default:
- IoCompleteIrp(PartDriver, Irp, STATUS_NOT_SUPPORTED);
- break;
- }
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- PartpEnumerateChildren (
- PIRP Irp,
- PPARTITION_PARENT Parent
- )
- /*++
- Routine Description:
- This routine is called to respond to enumeration requests of the parent.
- On the very first iteration, it enumerates only the raw disk. When the
- raw disk comes up, it reads the partition information and re-enumerates
- the parent. This routine is then called again an enumreates both the raw
- disk and all the partitions.
- Arguments:
- Irp - Supplies a pointer to the query children IRP.
- Parent - Supplies a pointer to the partition parent.
- Return Value:
- Status code.
- --*/
- {
- ULONG AllocationSize;
- PPARTITION_CHILD Child;
- CHAR DeviceId[PARTITION_STRING_SIZE];
- PPARTITION_INFORMATION Information;
- PPARTITION_CONTEXT PartitionContext;
- ULONG PartitionIndex;
- PARTITION_TYPE PartitionType;
- KSTATUS Status;
- Child = NULL;
- ASSERT(Irp->MinorCode == IrpMinorQueryChildren);
- //
- // If the raw disk has yet to be created, do that now.
- //
- if (Parent->RawDisk == NULL) {
- Child = PartpCreateChild(Parent, -1);
- if (Child == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto EnumerateChildrenEnd;
- }
- Status = IoCreateDevice(PartDriver,
- Child,
- Parent->Device,
- PARTITION_RAW_DISK_ID,
- PARTITION_CLASS_ID,
- NULL,
- &(Parent->RawDisk));
- if (!KSUCCESS(Status)) {
- goto EnumerateChildrenEnd;
- }
- Child = NULL;
- Status = IoSetTargetDevice(Parent->RawDisk, Parent->Device);
- if (!KSUCCESS(Status)) {
- goto EnumerateChildrenEnd;
- }
- }
- PartitionContext = &(Parent->PartitionContext);
- //
- // Allocate the array of children if needed.
- //
- if ((Parent->Children == NULL) && (PartitionContext->BlockSize != 0) &&
- (PartitionContext->PartitionCount != 0)) {
- AllocationSize = sizeof(PDEVICE) * PartitionContext->PartitionCount;
- Parent->Children = MmAllocatePagedPool(AllocationSize,
- PARTITION_ALLOCATION_TAG);
- if (Parent->Children == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto EnumerateChildrenEnd;
- }
- RtlZeroMemory(Parent->Children, AllocationSize);
- }
- //
- // Create a child device for every partition if needed.
- //
- for (PartitionIndex = 0;
- PartitionIndex < PartitionContext->PartitionCount;
- PartitionIndex += 1) {
- Information = &(PartitionContext->Partitions[PartitionIndex]);
- //
- // Skip empty and extended partitions.
- //
- PartitionType = Information->PartitionType;
- if ((PartitionType == PartitionTypeInvalid) ||
- (PartitionType == PartitionTypeEmpty) ||
- (PartitionType == PartitionTypeDosExtended) ||
- (PartitionType == PartitionTypeDosExtendedLba)) {
- continue;
- }
- if (Parent->Children[PartitionIndex] != NULL) {
- continue;
- }
- Child = PartpCreateChild(Parent, PartitionIndex);
- if (Child == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto EnumerateChildrenEnd;
- }
- RtlPrintToString(DeviceId,
- sizeof(DeviceId),
- CharacterEncodingDefault,
- PARTITION_STRING_FORMAT,
- Information->Number);
- Status = IoCreateDevice(PartDriver,
- Child,
- Parent->Device,
- DeviceId,
- PARTITION_CLASS_ID,
- NULL,
- &(Parent->Children[PartitionIndex]));
- if (!KSUCCESS(Status)) {
- goto EnumerateChildrenEnd;
- }
- IoSetDeviceMountable(Parent->Children[PartitionIndex]);
- Child = NULL;
- Status = IoSetTargetDevice(Parent->Children[PartitionIndex],
- Parent->Device);
- if (!KSUCCESS(Status)) {
- goto EnumerateChildrenEnd;
- }
- }
- if (PartitionContext->PartitionCount != 0) {
- Status = IoMergeChildArrays(Irp,
- Parent->Children,
- PartitionContext->PartitionCount,
- PARTITION_ALLOCATION_TAG);
- if (!KSUCCESS(Status)) {
- goto EnumerateChildrenEnd;
- }
- }
- ASSERT(Parent->RawDisk != NULL);
- Status = IoMergeChildArrays(Irp,
- &(Parent->RawDisk),
- 1,
- PARTITION_ALLOCATION_TAG);
- if (!KSUCCESS(Status)) {
- goto EnumerateChildrenEnd;
- }
- EnumerateChildrenEnd:
- if (Child != NULL) {
- PartpReleaseReference(&(Child->Header));
- }
- return Status;
- }
- KSTATUS
- PartpReadPartitionStructures (
- PPARTITION_PARENT Parent
- )
- /*++
- Routine Description:
- This routine is called to enumerate the partitions in a disk. This routine
- is called by a disk device upon starting.
- Arguments:
- Irp - Supplies a pointer to the query children IRP.
- Parent - Supplies a pointer to the partition parent.
- Return Value:
- Status code.
- --*/
- {
- ULONGLONG DiskCapacity;
- ULONG DiskOffsetAlignment;
- ULONG DiskSizeAlignment;
- PPARTITION_CONTEXT PartitionContext;
- KSTATUS Status;
- PartitionContext = &(Parent->PartitionContext);
- Status = STATUS_SUCCESS;
- //
- // Do nothing if the information has already been gathered.
- //
- if (PartitionContext->BlockSize != 0) {
- goto ReadPartitionStructuresEnd;
- }
- Status = IoOpenDevice(Parent->RawDisk,
- IO_ACCESS_READ,
- 0,
- &(Parent->IoHandle),
- &DiskOffsetAlignment,
- &DiskSizeAlignment,
- &DiskCapacity);
- if (!KSUCCESS(Status)) {
- goto ReadPartitionStructuresEnd;
- }
- PartitionContext->AllocateFunction = PartpAllocate;
- PartitionContext->FreeFunction = PartpFree;
- PartitionContext->ReadFunction = PartpRead;
- PartitionContext->BlockSize = DiskOffsetAlignment;
- PartitionContext->BlockCount = DiskCapacity / PartitionContext->BlockSize;
- PartitionContext->Alignment = MmGetIoBufferAlignment();
- Status = PartInitialize(PartitionContext);
- if (!KSUCCESS(Status)) {
- PartitionContext->BlockSize = 0;
- goto ReadPartitionStructuresEnd;
- }
- Status = PartEnumeratePartitions(PartitionContext);
- //
- // If the partition table isn't valid or no partitions enumreate, make the
- // entire disk mountable, maybe there's just a raw file system here.
- //
- if ((Status == STATUS_NO_ELIGIBLE_DEVICES) ||
- ((KSUCCESS(Status)) && (PartitionContext->PartitionCount == 0))) {
- IoSetDeviceMountable(Parent->RawDisk);
- Status = STATUS_SUCCESS;
- } else if (!KSUCCESS(Status)) {
- //
- // For other failures, clear the block size so it tries again next
- // time around.
- //
- PartitionContext->BlockSize = 0;
- goto ReadPartitionStructuresEnd;
- }
- //
- // Poke the system to re-enumerate the parent. Failure is not fatal.
- //
- IoNotifyDeviceTopologyChange(Parent->Device);
- ReadPartitionStructuresEnd:
- if (Parent->IoHandle != NULL) {
- IoClose(Parent->IoHandle);
- Parent->IoHandle = NULL;
- }
- return Status;
- }
- VOID
- PartpHandleDeviceInformationRequest (
- PIRP Irp,
- PPARTITION_CHILD Child
- )
- /*++
- Routine Description:
- This routine handles requests to get and set device information for the
- partition.
- Arguments:
- Irp - Supplies a pointer to the IRP making the request.
- Child - Supplies a pointer to the partition context.
- Return Value:
- None. Any completion status is set in the IRP.
- --*/
- {
- PPARTITION_DEVICE_INFORMATION Information;
- BOOL Match;
- PPARTITION_PARENT Parent;
- PPARTITION_CONTEXT PartitionContext;
- PPARTITION_INFORMATION PartitionInformation;
- PSYSTEM_CONTROL_DEVICE_INFORMATION Request;
- KSTATUS Status;
- Request = Irp->U.SystemControl.SystemContext;
- //
- // If this is not a request for the partition device information, ignore it.
- //
- Match = RtlAreUuidsEqual(&(Request->Uuid),
- &PartPartitionDeviceInformationUuid);
- if (Match == FALSE) {
- return;
- }
- //
- // Setting partition information is not supported.
- //
- if (Request->Set != FALSE) {
- Status = STATUS_ACCESS_DENIED;
- goto HandleDeviceInformationRequestEnd;
- }
- //
- // Make sure the size is large enough.
- //
- if (Request->DataSize < sizeof(PARTITION_DEVICE_INFORMATION)) {
- Request->DataSize = sizeof(PARTITION_DEVICE_INFORMATION);
- Status = STATUS_BUFFER_TOO_SMALL;
- goto HandleDeviceInformationRequestEnd;
- }
- ASSERT(Child->Header.Type == PartitionObjectChild);
- Parent = Child->Parent;
- PartitionContext = &(Parent->PartitionContext);
- Request->DataSize = sizeof(PARTITION_DEVICE_INFORMATION);
- Information = Request->Data;
- RtlZeroMemory(Information, sizeof(PARTITION_DEVICE_INFORMATION));
- Information->Version = PARTITION_DEVICE_INFORMATION_VERSION;
- Information->PartitionFormat = PartitionContext->Format;
- Information->BlockSize = PartitionContext->BlockSize;
- RtlCopyMemory(&(Information->DiskId),
- &(PartitionContext->DiskIdentifier),
- sizeof(Information->DiskId));
- //
- // If the index is -1, fill out the information for the parent disk itself.
- //
- if (Child->Index == -1) {
- Information->PartitionType = PartitionTypeNone;
- Information->Flags = PARTITION_FLAG_RAW_DISK;
- Information->FirstBlock = 0;
- Information->LastBlock = PartitionContext->BlockCount - 1;
- //
- // Fill out the information for the specific partition.
- //
- } else {
- ASSERT(Child->Index < PartitionContext->PartitionCount);
- PartitionInformation = &(PartitionContext->Partitions[Child->Index]);
- Information->PartitionType = PartitionInformation->PartitionType;
- Information->Flags = PartitionInformation->Flags;
- Information->FirstBlock = PartitionInformation->StartOffset;
- Information->LastBlock = PartitionInformation->EndOffset - 1;
- Information->Number = PartitionInformation->Number;
- Information->ParentNumber = PartitionInformation->ParentNumber;
- RtlCopyMemory(&(Information->PartitionId),
- &(PartitionInformation->Identifier),
- sizeof(Information->PartitionId));
- RtlCopyMemory(&(Information->PartitionTypeId),
- &(PartitionInformation->TypeIdentifier),
- sizeof(Information->PartitionTypeId));
- }
- Status = STATUS_SUCCESS;
- HandleDeviceInformationRequestEnd:
- IoCompleteIrp(PartDriver, Irp, Status);
- return;
- }
- VOID
- PartpHandleBlockInformationRequest (
- PIRP Irp,
- PPARTITION_CHILD Child
- )
- /*++
- Routine Description:
- This routine handles requests to get block information for the partition.
- Arguments:
- Irp - Supplies a pointer to the IRP making the request.
- Child - Supplies a pointer to the partition context.
- Return Value:
- None. Any completion status is set in the IRP.
- --*/
- {
- ULONGLONG BlockCount;
- PFILE_BLOCK_ENTRY BlockEntry;
- PFILE_BLOCK_INFORMATION BlockInformation;
- PLIST_ENTRY CurrentEntry;
- PPARTITION_PARENT Parent;
- PPARTITION_CONTEXT PartitionContext;
- PPARTITION_INFORMATION PartitionInformation;
- PPARTITION_INFORMATION Partitions;
- PSYSTEM_CONTROL_GET_BLOCK_INFORMATION Request;
- KSTATUS Status;
- ASSERT(Child->Header.Type == PartitionObjectChild);
- Request = Irp->U.SystemControl.SystemContext;
- BlockInformation = Request->FileBlockInformation;
- Parent = Child->Parent;
- PartitionContext = &(Parent->PartitionContext);
- //
- // If the request already contains non-empty file information, then the
- // partition is being requested to convert relative block offsets into
- // absolute block offsets.
- //
- if ((BlockInformation != NULL) &&
- (LIST_EMPTY(&(BlockInformation->BlockList)) == FALSE)) {
- //
- // If the index is -1, then the offsets are already accurate as there
- // are no partitions in the way.
- //
- if (Child->Index == -1) {
- Status = STATUS_SUCCESS;
- goto HandleBlockInformationRequestEnd;
- }
- ASSERT(Child->Index < PartitionContext->PartitionCount);
- Partitions = PartitionContext->Partitions;
- PartitionInformation = &(Partitions[Child->Index]);
- //
- // Otherwise, iterate over the list and convert the addresses.
- //
- CurrentEntry = BlockInformation->BlockList.Next;
- while (CurrentEntry != &(BlockInformation->BlockList)) {
- BlockEntry = LIST_VALUE(CurrentEntry, FILE_BLOCK_ENTRY, ListEntry);
- Status = PartTranslateIo(PartitionInformation,
- &(BlockEntry->Address),
- &(BlockEntry->Count));
- if (!KSUCCESS(Status)) {
- goto HandleBlockInformationRequestEnd;
- }
- CurrentEntry = CurrentEntry->Next;
- }
- //
- // Otherwise this is a request for the absolute block offsets and size of
- // the partition.
- //
- } else {
- if (BlockInformation == NULL) {
- BlockInformation = MmAllocateNonPagedPool(
- sizeof(FILE_BLOCK_INFORMATION),
- PARTITION_ALLOCATION_TAG);
- if (BlockInformation == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto HandleBlockInformationRequestEnd;
- }
- INITIALIZE_LIST_HEAD(&(BlockInformation->BlockList));
- }
- BlockEntry = MmAllocateNonPagedPool(sizeof(FILE_BLOCK_ENTRY),
- PARTITION_ALLOCATION_TAG);
- if (BlockEntry == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto HandleBlockInformationRequestEnd;
- }
- //
- // If the index is -1, then get the information for the whole parent
- // disk.
- //
- if (Child->Index == -1) {
- BlockEntry->Address = 0;
- BlockEntry->Count = PartitionContext->BlockCount;
- //
- // Otherwise return the information for the particular partition.
- //
- } else {
- ASSERT(Child->Index < PartitionContext->PartitionCount);
- Partitions = PartitionContext->Partitions;
- PartitionInformation = &(Partitions[Child->Index]);
- BlockEntry->Address = PartitionInformation->StartOffset;
- BlockCount = PartitionInformation->EndOffset -
- PartitionInformation->StartOffset;
- BlockEntry->Count = BlockCount;
- }
- INSERT_BEFORE(&(BlockEntry->ListEntry), &(BlockInformation->BlockList));
- //
- // Fill the block information back into the request, in case it was
- // allocated.
- //
- Request->FileBlockInformation = BlockInformation;
- }
- Status = STATUS_SUCCESS;
- HandleBlockInformationRequestEnd:
- if (!KSUCCESS(Status)) {
- if ((BlockInformation != NULL) &&
- (BlockInformation != Request->FileBlockInformation)) {
- while (LIST_EMPTY(&(BlockInformation->BlockList)) == FALSE) {
- BlockEntry = LIST_VALUE(BlockInformation->BlockList.Next,
- FILE_BLOCK_ENTRY,
- ListEntry);
- LIST_REMOVE(&(BlockEntry->ListEntry));
- MmFreeNonPagedPool(BlockEntry);
- }
- MmFreeNonPagedPool(BlockInformation);
- }
- }
- IoCompleteIrp(PartDriver, Irp, Status);
- return;
- }
- PVOID
- PartpAllocate (
- UINTN Size
- )
- /*++
- Routine Description:
- This routine allocates memory for the partition manager.
- Arguments:
- Size - Supplies the size of the allocation request, in bytes.
- Return Value:
- Returns a pointer to the allocation if successful, or NULL if the
- allocation failed.
- --*/
- {
- return MmAllocateNonPagedPool(Size, PARTITION_ALLOCATION_TAG);
- }
- VOID
- PartpFree (
- PVOID Memory
- )
- /*++
- Routine Description:
- This routine frees allocated memory for the partition manager.
- Arguments:
- Memory - Supplies the allocation returned by the allocation routine.
- Return Value:
- None.
- --*/
- {
- MmFreeNonPagedPool(Memory);
- return;
- }
- KSTATUS
- PartpRead (
- PPARTITION_CONTEXT Context,
- ULONGLONG BlockAddress,
- PVOID Buffer
- )
- /*++
- Routine Description:
- This routine reads from the underlying disk.
- Arguments:
- Context - Supplies the partition context identifying the disk.
- BlockAddress - Supplies the block address to read.
- Buffer - Supplies a pointer where the data will be returned on success.
- This buffer is expected to be one block in size (as specified in the
- partition context).
- Return Value:
- Status code.
- --*/
- {
- UINTN BytesCompleted;
- PIO_BUFFER IoBuffer;
- PPARTITION_PARENT Parent;
- KSTATUS Status;
- Parent = PARENT_STRUCTURE(Context, PARTITION_PARENT, PartitionContext);
- ASSERT((Parent->Header.Type == PartitionObjectParent) &&
- (Parent->IoHandle != NULL) &&
- (Context->BlockSize != 0));
- Status = MmCreateIoBuffer(Buffer,
- Context->BlockSize,
- IO_BUFFER_FLAG_KERNEL_MODE_DATA,
- &IoBuffer);
- if (!KSUCCESS(Status)) {
- goto ReadEnd;
- }
- Status = IoReadAtOffset(Parent->IoHandle,
- IoBuffer,
- BlockAddress << Context->BlockShift,
- Context->BlockSize,
- 0,
- WAIT_TIME_INDEFINITE,
- &BytesCompleted,
- NULL);
- if (!KSUCCESS(Status)) {
- goto ReadEnd;
- }
- ReadEnd:
- if (IoBuffer != NULL) {
- MmFreeIoBuffer(IoBuffer);
- }
- return Status;
- }
- PPARTITION_CHILD
- PartpCreateChild (
- PPARTITION_PARENT Parent,
- ULONG Index
- )
- /*++
- Routine Description:
- This routine creates a partition child structure.
- Arguments:
- Parent - Supplies a pointer to the parent structure.
- Index - Supplies the child index for this child.
- Return Value:
- Returns a pointer to the new child structure on success.
- NULL on allocation failure.
- --*/
- {
- PPARTITION_CHILD Child;
- Child = PartpAllocate(sizeof(PARTITION_CHILD));
- if (Child == NULL) {
- return NULL;
- }
- RtlZeroMemory(Child, sizeof(PARTITION_CHILD));
- Child->Header.Type = PartitionObjectChild;
- Child->Header.ReferenceCount = 1;
- Child->Parent = Parent;
- PartpAddReference(&(Parent->Header));
- Child->Index = Index;
- return Child;
- }
- VOID
- PartpAddReference (
- PPARTITION_OBJECT Object
- )
- /*++
- Routine Description:
- This routine adds a reference on the given partition manager context.
- Arguments:
- Object - Supplies a pointer to the partition manager object.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Object->ReferenceCount), 1);
- ASSERT(OldReferenceCount < 0x10000000);
- return;
- }
- VOID
- PartpReleaseReference (
- PPARTITION_OBJECT Object
- )
- /*++
- Routine Description:
- This routine releases a reference on a partition object.
- Arguments:
- Object - Supplies a pointer to the partition manager object.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Object->ReferenceCount), (ULONG)-1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x10000000));
- if (OldReferenceCount == 1) {
- PartpDestroyDevice(Object);
- }
- return;
- }
- VOID
- PartpDestroyDevice (
- PPARTITION_OBJECT Object
- )
- /*++
- Routine Description:
- This routine destroys a partition manager object.
- Arguments:
- Object - Supplies a pointer to the partition manager object.
- Return Value:
- None.
- --*/
- {
- PPARTITION_CHILD Child;
- PPARTITION_PARENT Parent;
- switch (Object->Type) {
- case PartitionObjectParent:
- Parent = PARENT_STRUCTURE(Object, PARTITION_PARENT, Header);
- if (Parent->PartitionContext.BlockSize != 0) {
- PartDestroy(&(Parent->PartitionContext));
- Parent->PartitionContext.BlockSize = 0;
- }
- if (Parent->Children != NULL) {
- MmFreePagedPool(Parent->Children);
- }
- ASSERT(Parent->IoHandle == NULL);
- Parent->Header.Type = PartitionObjectInvalid;
- PartpFree(Parent);
- break;
- case PartitionObjectChild:
- Child = PARENT_STRUCTURE(Object, PARTITION_CHILD, Header);
- PartpReleaseReference(&(Child->Parent->Header));
- Child->Header.Type = PartitionObjectInvalid;
- PartpFree(Child);
- break;
- default:
- ASSERT(FALSE);
- return;
- }
- return;
- }
|