diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /storage/class/classpnp/src/create.c | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'storage/class/classpnp/src/create.c')
| -rw-r--r-- | storage/class/classpnp/src/create.c | 1018 |
1 files changed, 1018 insertions, 0 deletions
diff --git a/storage/class/classpnp/src/create.c b/storage/class/classpnp/src/create.c new file mode 100644 index 00000000..f871ab26 --- /dev/null +++ b/storage/class/classpnp/src/create.c @@ -0,0 +1,1018 @@ +/*++ + +Copyright (C) Microsoft Corporation, 1991 - 2010 + +Module Name: + + class.c + +Abstract: + + SCSI class driver routines + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#define CLASS_INIT_GUID 0 +#include "classp.h" +#include "debug.h" + +#ifdef DEBUG_USE_WPP +#include "create.tmh" +#endif + +ULONG BreakOnClose = 0; + +const PCSZ LockTypeStrings[] = { + "Simple", + "Secure", + "Internal" +}; + + +VOID +ClasspCleanupDisableMcn( + IN PFILE_OBJECT_EXTENSION FsContext + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, ClassCreateClose) +#pragma alloc_text(PAGE, ClasspCreateClose) +#pragma alloc_text(PAGE, ClasspCleanupProtectedLocks) +#pragma alloc_text(PAGE, ClasspEjectionControl) +#pragma alloc_text(PAGE, ClasspCleanupDisableMcn) +#pragma alloc_text(PAGE, ClassGetFsContext) +#endif + +NTSTATUS +ClassCreateClose( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) + +/*++ + +Routine Description: + + SCSI class driver create and close routine. This is called by the I/O system + when the device is opened or closed. + +Arguments: + + DriverObject - Pointer to driver object created by system. + + Irp - IRP involved. + +Return Value: + + Device-specific drivers return value or STATUS_SUCCESS. + +--*/ + +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + ULONG removeState; + NTSTATUS status; + + PAGED_CODE(); + + // + // If we're getting a close request then we know the device object hasn't + // been completely destroyed. Let the driver cleanup if necessary. + // + + removeState = ClassAcquireRemoveLock(DeviceObject, Irp); + + // + // Invoke the device-specific routine, if one exists. Otherwise complete + // with SUCCESS + // + + if((removeState == NO_REMOVE) || + IS_CLEANUP_REQUEST(IoGetCurrentIrpStackLocation(Irp)->MajorFunction)) { + + status = ClasspCreateClose(DeviceObject, Irp); + + if((NT_SUCCESS(status)) && + (commonExtension->DevInfo->ClassCreateClose)) { + + return commonExtension->DevInfo->ClassCreateClose(DeviceObject, Irp); + } + + } else { + status = STATUS_DEVICE_DOES_NOT_EXIST; + } + + Irp->IoStatus.Status = status; + ClassReleaseRemoveLock(DeviceObject, Irp); + ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); + return status; +} + + +NTSTATUS +ClasspCreateClose( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +/*++ + +Routine Description: + + This routine will handle create/close operations for a given classpnp + device if the class driver doesn't supply it's own handler. If there + is a file object supplied for our driver (if it's a FO_DIRECT_DEVICE_OPEN + file object) then it will initialize a file extension on create or destroy + the extension on a close. + +Arguments: + + DeviceObject - the device object being opened or closed. + + Irp - the create/close irp + +Return Value: + + status + +--*/ +{ + PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); + + PFILE_OBJECT fileObject = irpStack->FileObject; + + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + + // + // ISSUE-2000/3/28-henrygab - if lower stack fails create/close, we end up + // in an inconsistent state. re-write to verify all args and allocate all + // required resources, then pass the irp down, then complete the + // transaction. this is because we also cannot forward the irp, then fail + // it after it has succeeded a lower-level driver. + // + + if(irpStack->MajorFunction == IRP_MJ_CREATE) { + + PIO_SECURITY_CONTEXT securityContext = + irpStack->Parameters.Create.SecurityContext; + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCREATEClose: create received for device %p\n", + DeviceObject)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCREATEClose: desired access %lx\n", + securityContext->DesiredAccess)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCREATEClose: file object %p\n", + irpStack->FileObject)); + + NT_ASSERT(BreakOnClose == FALSE); + + if(irpStack->FileObject != NULL) { + + PFILE_OBJECT_EXTENSION fsContext; + + // + // Allocate our own file object extension for this device object. + // + + status = AllocateDictionaryEntry( + &commonExtension->FileObjectDictionary, + (ULONGLONG) irpStack->FileObject, + sizeof(FILE_OBJECT_EXTENSION), + CLASS_TAG_FILE_OBJECT_EXTENSION, + &fsContext); + + if(NT_SUCCESS(status)) { + + RtlZeroMemory(fsContext, + sizeof(FILE_OBJECT_EXTENSION)); + + fsContext->FileObject = irpStack->FileObject; + fsContext->DeviceObject = DeviceObject; + } else if (status == STATUS_OBJECT_NAME_COLLISION) { + status = STATUS_SUCCESS; + } + } + + } else { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCreateCLOSE: close received for device %p\n", + DeviceObject)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCreateCLOSE: file object %p\n", + fileObject)); + + if(irpStack->FileObject != NULL) { + + PFILE_OBJECT_EXTENSION fsContext = + ClassGetFsContext(commonExtension, irpStack->FileObject); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCreateCLOSE: file extension %p\n", + fsContext)); + + if(fsContext != NULL) { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCreateCLOSE: extension is ours - " + "freeing\n")); + NT_ASSERT(BreakOnClose == FALSE); + + ClasspCleanupProtectedLocks(fsContext); + + ClasspCleanupDisableMcn(fsContext); + + FreeDictionaryEntry(&(commonExtension->FileObjectDictionary), + fsContext); + } + } + } + + // + // Notify the lower levels about the create or close operation - give them + // a chance to cleanup too. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCreateClose: %s for devobj %p\n", + (NT_SUCCESS(status) ? "Success" : "FAILED"), + DeviceObject)); + + + if(NT_SUCCESS(status)) { + + KEVENT event; + + // + // Set up the event to wait on + // + + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + + IoCopyCurrentIrpStackLocationToNext(Irp); + IoSetCompletionRoutine( Irp, ClassSignalCompletion, &event, + TRUE, TRUE, TRUE); + + status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); + + if(status == STATUS_PENDING) { + (VOID)KeWaitForSingleObject(&event, + Executive, + KernelMode, + FALSE, + NULL); + status = Irp->IoStatus.Status; + } + + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_INIT, + "ClasspCreateClose: Lower driver failed, but we " + "succeeded. This is a problem, lock counts will be " + "out of sync between levels.\n")); + } + + } + + + return status; +} + + +VOID +ClasspCleanupProtectedLocks( + IN PFILE_OBJECT_EXTENSION FsContext + ) +{ + PCOMMON_DEVICE_EXTENSION commonExtension = + FsContext->DeviceObject->DeviceExtension; + + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = + commonExtension->PartitionZeroExtension; + + ULONG newDeviceLockCount = 1; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCleanupProtectedLocks called for %p\n", + FsContext->DeviceObject)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCleanupProtectedLocks - FsContext %p is locked " + "%d times\n", FsContext, FsContext->LockCount)); + + NT_ASSERT(BreakOnClose == FALSE); + + // + // Synchronize with ejection and ejection control requests. + // + + KeEnterCriticalRegion(); + (VOID)KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent), + UserRequest, + KernelMode, + FALSE, + NULL); + + // + // For each secure lock on this handle decrement the secured lock count + // for the FDO. Keep track of the new value. + // + + if (FsContext->LockCount != 0) { + + do { + + InterlockedDecrement((volatile LONG *)&FsContext->LockCount); + + newDeviceLockCount = + InterlockedDecrement(&fdoExtension->ProtectedLockCount); + + } while (FsContext->LockCount > 0); + + // + // If the new lock count has been dropped to zero then issue a lock + // command to the device. + // + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCleanupProtectedLocks: FDO secured lock count = %d " + "lock count = %d\n", + fdoExtension->ProtectedLockCount, + fdoExtension->LockCount)); + + if ((newDeviceLockCount == 0) && (fdoExtension->LockCount == 0)) { + + SCSI_REQUEST_BLOCK srb = {0}; + UCHAR srbExBuffer[CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE] = {0}; + PSTORAGE_REQUEST_BLOCK srbEx = (PSTORAGE_REQUEST_BLOCK)srbExBuffer; + PCDB cdb = NULL; + NTSTATUS status; + PSCSI_REQUEST_BLOCK srbPtr; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCleanupProtectedLocks: FDO lock count dropped " + "to zero\n")); + + if (fdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + #pragma prefast(suppress:26015, "InitializeStorageRequestBlock ensures buffer access is bounded") + status = InitializeStorageRequestBlock(srbEx, + STORAGE_ADDRESS_TYPE_BTL8, + sizeof(srbExBuffer), + 1, + SrbExDataTypeScsiCdb16); + if (NT_SUCCESS(status)) { + srbEx->TimeOutValue = fdoExtension->TimeOutValue; + SrbSetCdbLength(srbEx, 6); + cdb = SrbGetCdb(srbEx); + srbPtr = (PSCSI_REQUEST_BLOCK)srbEx; + } else { + // + // Should not happen. Revert to legacy SRB. + // + NT_ASSERT(FALSE); + srb.TimeOutValue = fdoExtension->TimeOutValue; + srb.CdbLength = 6; + cdb = (PCDB) &(srb.Cdb); + srbPtr = &srb; + } + + } else { + + srb.TimeOutValue = fdoExtension->TimeOutValue; + srb.CdbLength = 6; + cdb = (PCDB) &(srb.Cdb); + srbPtr = &srb; + + } + + cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; + + // + // TRUE - prevent media removal. + // FALSE - allow media removal. + // + + cdb->MEDIA_REMOVAL.Prevent = FALSE; + + status = ClassSendSrbSynchronous(fdoExtension->DeviceObject, + srbPtr, + NULL, + 0, + FALSE); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, + "ClasspCleanupProtectedLocks: unlock request to drive " + "returned status %lx\n", status)); + } + } + + KeSetEvent(&fdoExtension->EjectSynchronizationEvent, + IO_NO_INCREMENT, + FALSE); + KeLeaveCriticalRegion(); + return; +} + + +VOID +ClasspCleanupDisableMcn( + IN PFILE_OBJECT_EXTENSION FsContext + ) +{ + PCOMMON_DEVICE_EXTENSION commonExtension = + FsContext->DeviceObject->DeviceExtension; + + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = + commonExtension->PartitionZeroExtension; + + PAGED_CODE(); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "ClasspCleanupDisableMcn called for %p\n", + FsContext->DeviceObject)); + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, + "ClasspCleanupDisableMcn - FsContext %p is disabled " + "%d times\n", FsContext, FsContext->McnDisableCount)); + + // + // For each secure lock on this handle decrement the secured lock count + // for the FDO. Keep track of the new value. + // + + while(FsContext->McnDisableCount != 0) { + FsContext->McnDisableCount--; + ClassEnableMediaChangeDetection(fdoExtension); + } + + return; +} + + +#if 1 +/* + * ISSUE: REMOVE this old function implementation as soon as the + * boottime pagefile problems with the new one (below) + * are resolved. + */ +NTSTATUS +ClasspEjectionControl( + IN PDEVICE_OBJECT Fdo, + IN PIRP Irp, + IN MEDIA_LOCK_TYPE LockType, + IN BOOLEAN Lock + ) +{ + PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension; + PCOMMON_DEVICE_EXTENSION commonExtension = + (PCOMMON_DEVICE_EXTENSION) FdoExtension; + + PFILE_OBJECT_EXTENSION fsContext = NULL; + NTSTATUS status; + PSCSI_REQUEST_BLOCK srb = NULL; + BOOLEAN countChanged = FALSE; + + PAGED_CODE(); + + /* + * Ensure that the user thread is not suspended while we are holding EjectSynchronizationEvent. + */ + KeEnterCriticalRegion(); + + status = KeWaitForSingleObject( + &(FdoExtension->EjectSynchronizationEvent), + UserRequest, + KernelMode, + FALSE, + NULL); + + NT_ASSERT(status == STATUS_SUCCESS); + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "ClasspEjectionControl: " + "Received request for %s lock type\n", + LockTypeStrings[LockType] + )); + + try { + PCDB cdb = NULL; + + // + // Determine if this is a "secured" request. + // + + if (LockType == SecureMediaLock) { + + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); + PFILE_OBJECT fileObject = irpStack->FileObject; + + // + // Make sure that the file object we are supplied has a + // proper FsContext before we try doing a secured lock. + // + + if (fileObject != NULL) { + fsContext = ClassGetFsContext(commonExtension, fileObject); + } + + if (fsContext == NULL) { + + // + // This handle isn't setup correctly. We can't let the + // operation go. + // + + status = STATUS_INVALID_PARAMETER; + leave; + } + } + + if (Lock) { + + // + // This is a lock command. Reissue the command in case bus or + // device was reset and the lock was cleared. + // note: may need to decrement count if actual lock operation + // failed.... + // + + switch (LockType) { + + case SimpleMediaLock: { + FdoExtension->LockCount++; + countChanged = TRUE; + break; + } + + case SecureMediaLock: { + fsContext->LockCount++; + FdoExtension->ProtectedLockCount++; + countChanged = TRUE; + break; + } + + case InternalMediaLock: { + FdoExtension->InternalLockCount++; + countChanged = TRUE; + break; + } + } + + } else { + + // + // This is an unlock command. If it's a secured one then make sure + // the caller has a lock outstanding or return an error. + // note: may need to re-increment the count if actual unlock + // operation fails.... + // + + switch (LockType) { + + case SimpleMediaLock: { + if(FdoExtension->LockCount != 0) { + FdoExtension->LockCount--; + countChanged = TRUE; + } + break; + } + + case SecureMediaLock: { + if(fsContext->LockCount == 0) { + status = STATUS_INVALID_DEVICE_STATE; + leave; + } + fsContext->LockCount--; + FdoExtension->ProtectedLockCount--; + countChanged = TRUE; + break; + } + + case InternalMediaLock: { + NT_ASSERT(FdoExtension->InternalLockCount != 0); + FdoExtension->InternalLockCount--; + countChanged = TRUE; + break; + } + } + + // + // We only send an unlock command to the drive if both the + // secured and unsecured lock counts have dropped to zero. + // + + if ((FdoExtension->ProtectedLockCount != 0) || + (FdoExtension->InternalLockCount != 0) || + (FdoExtension->LockCount != 0)) { + + status = STATUS_SUCCESS; + leave; + } + } + + status = STATUS_SUCCESS; + if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { + + srb = (PSCSI_REQUEST_BLOCK)ClasspAllocateSrb(FdoExtension); + + if (srb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + leave; + } + + if (FdoExtension->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) { + + // + // NOTE - this is based on size used in ClasspAllocateSrb + // + + status = InitializeStorageRequestBlock((PSTORAGE_REQUEST_BLOCK)srb, + STORAGE_ADDRESS_TYPE_BTL8, + CLASS_SRBEX_SCSI_CDB16_BUFFER_SIZE, + 1, + SrbExDataTypeScsiCdb16); + if (!NT_SUCCESS(status)) { + NT_ASSERT(FALSE); + leave; + } + + } else { + RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); + } + + SrbSetCdbLength(srb, 6); + cdb = SrbGetCdb(srb); + NT_ASSERT(cdb != NULL); + + cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; + + // + // TRUE - prevent media removal. + // FALSE - allow media removal. + // + + cdb->MEDIA_REMOVAL.Prevent = Lock; + + // + // Set timeout value. + // + + SrbSetTimeOutValue(srb, FdoExtension->TimeOutValue); + + // + // The actual lock operation on the device isn't so important + // as the internal lock counts. Ignore failures. + // + + status = ClassSendSrbSynchronous(FdoExtension->DeviceObject, + srb, + NULL, + 0, + FALSE); + } + + } finally { + + if (!NT_SUCCESS(status)) { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "ClasspEjectionControl: FAILED status %x -- " + "reverting lock counts\n", status)); + + if (countChanged) { + + // + // have to revert to previous counts if the + // lock/unlock operation actually failed. + // + + if (Lock) { + + switch (LockType) { + + case SimpleMediaLock: { + FdoExtension->LockCount--; + break; + } + + case SecureMediaLock: { + fsContext->LockCount--; + FdoExtension->ProtectedLockCount--; + break; + } + + case InternalMediaLock: { + FdoExtension->InternalLockCount--; + break; + } + } + + } else { + + switch (LockType) { + + case SimpleMediaLock: { + FdoExtension->LockCount++; + break; + } + + case SecureMediaLock: { + fsContext->LockCount++; + FdoExtension->ProtectedLockCount++; + break; + } + + case InternalMediaLock: { + FdoExtension->InternalLockCount++; + break; + } + } + } + + } + + } else { + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "ClasspEjectionControl: Succeeded\n")); + + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, + "ClasspEjectionControl: " + "Current Counts: Internal: %x Secure: %x Simple: %x\n", + FdoExtension->InternalLockCount, + FdoExtension->ProtectedLockCount, + FdoExtension->LockCount + )); + + KeSetEvent(&(FdoExtension->EjectSynchronizationEvent), + IO_NO_INCREMENT, + FALSE); + KeLeaveCriticalRegion(); + + if (srb) { + ClassFreeOrReuseSrb(FdoExtension, srb); + } + + } + return status; +} + +#else + +/* + * ISSUE: RESTORE this (see above) + * This is a new implementation of the function that doesn't thrash memory + * or depend on the srbLookasideList. + * HOWEVER, it seems to cause pagefile initialization to fail during boot + * for some reason. Need to resolve this before switching to this function. + */ +NTSTATUS +ClasspEjectionControl( + IN PDEVICE_OBJECT Fdo, + IN PIRP Irp, + IN MEDIA_LOCK_TYPE LockType, + IN BOOLEAN Lock + ) +{ + PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; + PFILE_OBJECT_EXTENSION fsContext; + BOOLEAN fileHandleOk = TRUE; + BOOLEAN countChanged = FALSE; + NTSTATUS status; + + PAGED_CODE(); + + status = KeWaitForSingleObject( + &fdoExt->EjectSynchronizationEvent, + UserRequest, + KernelMode, + FALSE, + NULL); + NT_ASSERT(status == STATUS_SUCCESS); + + /* + * If this is a "secured" request, we have to make sure + * that the file handle is valid. + */ + if (LockType == SecureMediaLock){ + PIO_STACK_LOCATION thisSp = IoGetCurrentIrpStackLocation(Irp); + + /* + * Make sure that the file object we are supplied has a + * proper FsContext before we try doing a secured lock. + */ + if (thisSp->FileObject){ + PCOMMON_DEVICE_EXTENSION commonExt = (PCOMMON_DEVICE_EXTENSION)fdoExt; + fsContext = ClassGetFsContext(commonExt, thisSp->FileObject); + } + else { + fsContext = NULL; + } + + if (!fsContext){ + NT_ASSERT(fsContext); + fileHandleOk = FALSE; + } + } + + if (fileHandleOk){ + + /* + * Adjust the lock counts and make sure they make sense. + */ + status = STATUS_SUCCESS; + if (Lock){ + switch(LockType) { + case SimpleMediaLock: + fdoExt->LockCount++; + countChanged = TRUE; + break; + case SecureMediaLock: + fsContext->LockCount++; + fdoExt->ProtectedLockCount++; + countChanged = TRUE; + break; + case InternalMediaLock: + fdoExt->InternalLockCount++; + countChanged = TRUE; + break; + } + } + else { + /* + * This is an unlock command. If it's a secured one then make sure + * the caller has a lock outstanding or return an error. + */ + switch (LockType){ + case SimpleMediaLock: + if (fdoExt->LockCount > 0){ + fdoExt->LockCount--; + countChanged = TRUE; + } + else { + NT_ASSERT(fdoExt->LockCount > 0); + status = STATUS_INTERNAL_ERROR; + } + break; + case SecureMediaLock: + if (fsContext->LockCount > 0){ + NT_ASSERT(fdoExt->ProtectedLockCount > 0); + fsContext->LockCount--; + fdoExt->ProtectedLockCount--; + countChanged = TRUE; + } + else { + NT_ASSERT(fsContext->LockCount > 0); + status = STATUS_INVALID_DEVICE_STATE; + } + break; + case InternalMediaLock: + NT_ASSERT(fdoExt->InternalLockCount > 0); + fdoExt->InternalLockCount--; + countChanged = TRUE; + break; + } + } + + if (NT_SUCCESS(status)){ + /* + * We only send an unlock command to the drive if + * all the lock counts have dropped to zero. + */ + if (!Lock && + (fdoExt->ProtectedLockCount || + fdoExt->InternalLockCount || + fdoExt->LockCount)){ + + /* + * The lock count is still positive, so don't unlock yet. + */ + status = STATUS_SUCCESS; + } + else if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { + /* + * The device isn't removable media. don't send a cmd. + */ + status = STATUS_SUCCESS; + } + else { + TRANSFER_PACKET *pkt; + + pkt = DequeueFreeTransferPacket(Fdo, TRUE); + if (pkt){ + KEVENT event; + + /* + * Store the number of packets servicing the irp (one) + * inside the original IRP. It will be used to counted down + * to zero when the packet completes. + * Initialize the original IRP's status to success. + * If the packet fails, we will set it to the error status. + */ + Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1); + Irp->IoStatus.Status = STATUS_SUCCESS; + + /* + * Set this up as a SYNCHRONOUS transfer, submit it, + * and wait for the packet to complete. The result + * status will be written to the original irp. + */ + KeInitializeEvent(&event, SynchronizationEvent, FALSE); + SetupEjectionTransferPacket(pkt, Lock, &event, Irp); + SubmitTransferPacket(pkt); + (VOID)KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + status = Irp->IoStatus.Status; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + } + } + else { + status = STATUS_INVALID_PARAMETER; + } + + if (!NT_SUCCESS(status) && countChanged) { + + // + // have to revert to previous counts if the + // lock/unlock operation actually failed. + // + + if(Lock) { + + switch(LockType) { + + case SimpleMediaLock: { + FdoExtension->LockCount--; + break; + } + + case SecureMediaLock: { + fsContext->LockCount--; + FdoExtension->ProtectedLockCount--; + break; + } + + case InternalMediaLock: { + FdoExtension->InternalLockCount--; + break; + } + } + + } else { + + switch(LockType) { + + case SimpleMediaLock: { + FdoExtension->LockCount++; + break; + } + + case SecureMediaLock: { + fsContext->LockCount++; + FdoExtension->ProtectedLockCount++; + break; + } + + case InternalMediaLock: { + FdoExtension->InternalLockCount++; + break; + } + } + } + } + + + + KeSetEvent(&fdoExt->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE); + + return status; +} +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +PFILE_OBJECT_EXTENSION +ClassGetFsContext( + _In_ PCOMMON_DEVICE_EXTENSION CommonExtension, + _In_ PFILE_OBJECT FileObject + ) +{ + PAGED_CODE(); + return GetDictionaryEntry(&(CommonExtension->FileObjectDictionary), + (ULONGLONG) FileObject); +} |
