📄 vdiskmp.c
字号:
Status = ZwQueryValueKey(DiskKeyHandle, &Str, KeyValuePartialInformation,
u.valueKeyPartialInf, BufferSize, &Length);
if (NT_SUCCESS(Status) && (u.valueKeyPartialInf->Type == REG_DWORD))
// Retrieve the value (in megabytes)
*DiskSize = *(ULONG*)&(u.valueKeyPartialInf->Data);
else
// Use the default
*DiskSize = 10;
// Convert megabytes to sectors
*DiskSize *= 2048; // 2048 == (1024*1024/512)
KdPrint(("VdiskReadRegistryParameters: Filename is %ls. \r\n Size is %u sectors\r\n",
SzFileName, *DiskSize));
// Query the read only value
RtlInitUnicodeString(&Str, L"ReadOnly");
Status = ZwQueryValueKey(DiskKeyHandle, &Str, KeyValuePartialInformation,
u.valueKeyPartialInf, BufferSize, &Length);
if (NT_SUCCESS(Status) && (u.valueKeyPartialInf->Type == REG_DWORD))
// Retrieve the value (in megabytes)
*ReadOnly = *(ULONG*)&(u.valueKeyPartialInf->Data) ? TRUE : FALSE;
else
// Use the default
*ReadOnly = FALSE;
// Free buffer
ExFreePool(u.buffer);
// Close handle - it's not needed
ZwClose(DiskKeyHandle);
// Success
return STATUS_SUCCESS;
} // end VdiskReadRegistryParameters()
///////////////////////////////////////////////////////////////////////////////
// Remove the Lun's path from Registry
//
static NTSTATUS VdiskRemoveLunFromRegistry(UCHAR TargetId, UCHAR LunId)
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING Str;
HANDLE KeyHandle;
PVOID Buffer;
// Allocate buffer
Buffer = ExAllocatePoolWithTag(PagedPool, (wcslen(szVdiskLunPath)+1)*sizeof(WCHAR), 'Den3');
// Check status
if (Buffer == NULL)
{
KdPrint(("VdiskRemoveLunFromRegistry: Can't allocate buffer!\r\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
// Format Registry path
swprintf(Buffer, szVdiskLunPath, TargetId, LunId);
// Open the key
RtlInitUnicodeString(&Str, Buffer);
InitializeObjectAttributes(&ObjectAttributes, &Str, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
// Disk key is not exist
KdPrint(("VdiskRemoveLunFromRegistry: Can't open disk key %ls! 0x%X\r\n", Buffer, Status));
return Status;
}
// Delete the key
Status = ZwDeleteKey(KeyHandle);
if (!NT_SUCCESS(Status))
KdPrint(("VdiskRemoveLunFromRegistry: Can't delete disk key %ls! 0x%X\r\n", Buffer, Status));
else
KdPrint(("VdiskRemoveLunFromRegistry: %ls\r\n", Buffer));
ZwClose(KeyHandle);
ExFreePool(Buffer);
return Status;
}
///////////////////////////////////////////////////////////////////////////////
// Reads the file-disk parameters from the registry
// and start thread to process requests
//
static NTSTATUS VdiskInquiryLun(
PVDISK_DEVICE_EXTENSION DeviceExtension, UCHAR TargetId, UCHAR LunId)
{
NTSTATUS Status;
KIRQL Irql;
PVDISK_LUN_EXTENSION Lun = NULL;
KEVENT Event;
HANDLE ThreadHandle;
VDISK_LUN_REQUEST Request;
BOOLEAN ReadOnly = FALSE;
KdPrint(("VdiskReadRegistryParameters enter...\r\r\n"));
ASSERT(DeviceExtension);
// LUN_EXTENSION allocated by VSPORT
Lun = (PVDISK_LUN_EXTENSION)VsPortGetLogicalUnit(DeviceExtension, 0, TargetId, LunId);
if (Lun == NULL)
{
// The device have disappeared
KdPrint(("VdiskInquiryLun: the device has disappeared from under us\r\r\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
// If it isn't first inquiry - do not need next processing
if ((Lun->DeviceExtension == DeviceExtension) && (Lun->Sign == VDISK_LUN_SIGN))
{
// We must check Lun existence in the Registry
// and remove it if it is not found
WCHAR SzFileName[256];
ULONG DiskSize;
// If the worker thread isn't working then start it!
if(Lun->Flags & VDISK_LUN_SHUTDOWN)
{
// Lun shutdowned
KdPrint(("VdiskInquiryLun: LUN %X was shut down. Restart it.\r\n", Lun));
// Check for thread
ASSERT(Lun->Flags & VDISK_LUN_THREAD_FINISHED);
// Un-shutdown Lun and restart system thread;
Lun->Flags &= ~VDISK_LUN_SHUTDOWN;
// Parameters in the Registry may have been changed - read
// them again and start thread
goto LunInitialization;
}
// Read data from the Registry for the LUN
Status = VdiskReadRegistryParameters(TargetId, LunId, SzFileName, &DiskSize, &ReadOnly);
if (!NT_SUCCESS(Status))
{
// Error read Registry. LUN will be destroyed.
KdPrint(("VdiskInquiryLun: LUN %X will be destroyed\r\n", Lun));
VdiskRemoveLunFromRegistry(TargetId, LunId);
return Status;
}
// Compare the current values with the values in the LUN
// and remove the device if the values are not equal
if (
// Compare the file names
( (wcslen(SzFileName) !=0) && wcscmp(Lun->SzFileName, SzFileName) ) ||
// Compare the ReadOnly values (shutdown LUN if they are different)
( (BOOLEAN)(Lun->Flags & VDISK_LUN_READ_ONLY) ^ (BOOLEAN)ReadOnly )
)
{
// Values are not equal. LUN will be destroyed.
KdPrint(("VdiskInquiryLun: Registry was changed. Something goes wrong. LUN %X will be destroyed\r\n", Lun));
return STATUS_UNSUCCESSFUL;
}
KdPrint(("VdiskInquiryLun: LUN %X checked in Registry Ok.\r\n", Lun));
// Ok. Driver is quite satisfied with LUN state.
return STATUS_SUCCESS;
}
//
// From this point we create LUN
//
#if DBG
KdPrint(("VdiskInquiryLun: Begin inquiries. Lun %X DeviceExtension 0x%X\r\n",
Lun, DeviceExtension));
if (((PVDISK_DEVICE_EXTENSION)DeviceExtension)->Luns[VdiskLun2Index(TargetId, LunId)] != NULL)
{
KdPrint(("VdiskInquiryLun: *** Strange! Lun (%d,%d) marked as created.\r\n",
TargetId, LunId));
}
#endif
LunInitialization:
// Zero LUN's structure
RtlZeroMemory(Lun, sizeof (VDISK_LUN_EXTENSION));
// Save signature to check
Lun->Sign = VDISK_LUN_SIGN;
// Set this flag now. We must know thread state.
Lun->Flags = VDISK_LUN_THREAD_FINISHED;
// Save TargetId
Lun->TargetId = TargetId;
// Save LUN
Lun->LunId = LunId;
// Read data from the Registry for the LUN
Status = VdiskReadRegistryParameters(TargetId, LunId, (PWSTR)Lun->SzFileName,
&Lun->DiskSize, &ReadOnly);
if (!NT_SUCCESS(Status))
// Error read Registry. LUN will not be created.
return Status;
// Set flag if needed
if (ReadOnly)
Lun->Flags |= VDISK_LUN_READ_ONLY;
// Initialize the local event
KeInitializeEvent(&Event, NotificationEvent, FALSE);
// Initialize the queue
InitializeListHead(&Lun->RequestQueue);
// Initialize the lock
KeInitializeSpinLock(&Lun->RequestQueueLock);
// Lock acces to this LUN
KeInitializeSpinLock(&Lun->SpinLock);
// Initialize the event
KeInitializeEvent(&Lun->RequestQueueEvent, NotificationEvent, FALSE);
// Initialize the shutdown event
KeInitializeEvent(&Lun->ShutdownEvent, NotificationEvent, FALSE);
// Save pointer to the DeviceExtension (thread must know it to complete request)
Lun->DeviceExtension = DeviceExtension;
// Start the system thread to execute requests
Status = PsCreateSystemThread(&ThreadHandle, (ACCESS_MASK)0L, NULL, NULL, NULL,
VdiskRequestThread, (PVOID)Lun);
// Check status
if (!NT_SUCCESS(Status))
{
KdPrint(("VdiskInquiryLun: Can't create thread!\r\n"));
goto NotCreated;
}
// Save the thread's object pointer to wait for shutdown
// Don't need to save thread handle
Status = ObReferenceObjectByHandle(ThreadHandle, (ACCESS_MASK)0, NULL, KernelMode, &Lun->ThreadObject, NULL);
ZwClose(ThreadHandle);
// Check status
if (!NT_SUCCESS(Status))
{
KdPrint(("VdiskInquiryLun: Error in the ObReferenceObjectByHandle!\r\n"));
// Signal the completion
KeSetEvent((PKEVENT)(&Lun->ShutdownEvent), IO_NO_INCREMENT, FALSE);
goto NotCreated;
}
// Submit the initialization request
Request.RequestCode = VDISK_REQUEST_INIT;
Request.ParamInitEvent = (ULONG)(&Event);
(NTSTATUS)(Request.ParamInitStatus) = STATUS_SUCCESS;
VdiskRequestSubmit(&Request, Lun);
// Wait for completion of initializaton
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = Request.ParamInitStatus;
if (!NT_SUCCESS(Status))
{
KdPrint(("VdiskInquiryLun: Initialization of file is failed 0x%X\r\n", Status));
// Initialization failed
// Wait for the thread to terminate
KeWaitForSingleObject(Lun->ThreadObject, Executive, KernelMode, FALSE, NULL);
ObDereferenceObject(Lun->ThreadObject);
NotCreated:
// Mark it as not created
Lun->DeviceExtension = NULL;
return Status;
}
KdPrint(("VdiskInquiryLun: Lun (%u,%u) created\r\n", TargetId, LunId));
// Clear this flag now. It means thread is working.
Lun->Flags &= ~VDISK_LUN_THREAD_FINISHED;
// Save pointer to the array. We will check it in the VdiskMpDestroyLun()
DeviceExtension->Luns[VdiskLun2Index(TargetId, LunId)] = Lun;
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
// Process all SCSI disk operations
//
static VOID VdiskMpStartIo(PVOID DeviceExtension, PSCSI_REQUEST_BLOCK Srb)
{
PVDISK_LUN_EXTENSION Lun = NULL;
PVDISK_LUN_REQUEST Request;
ULONG Start;
ULONG MaxSector;
USHORT BlockCount;
UCHAR TargetId;
UCHAR LunId;
ASSERT(DeviceExtension);
ASSERT(Srb);
// Return selection timeout for is not existed devices
Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
TargetId = Srb->TargetId;
LunId = Srb->Lun;
if ((Srb->TargetId == INITIATOR_ID) || (Srb->PathId >= NUMBER_OF_BUSES))
{
// return selection timeout for is not existed devices
KdPrint(("VdiskMpStartIo : TargetId is wrong\r\n"));
goto Failed;
}
// Extract the LUN extension - it is guaranteed to exist
// Check if Lun is NULL - can be so if just removed by the DAD removal callback
// called by the protocol
Lun = (PVDISK_LUN_EXTENSION)VsPortGetLogicalUnit(DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun);
if (Lun == NULL)
{
// The device have disappeared
KdPrint(("VdiskMpStartIo : the device have disappeared from under us\r\n"));
goto Failed;
}
switch (Srb->Function)
{
#ifdef VSPORT_PNP
case SRB_FUNCTION_VSPORT_WMI:
// Process as a WMI SRB
VdiskMpWmiStartIo(DeviceExtension, (PSCSI_WMI_REQUEST_BLOCK)Srb);
return;
#endif
case SRB_FUNCTION_SHUTDOWN:
{
IF_SCSI(KdPrint(("VdiskMpStartIo : SRB_FUNCTION_SHUTDOWN Lun 0x%X\r\n", Lun));)
// Process shutdown
VdiskShutdownLun(Lun, FALSE);
// Clear pointer
((PVDISK_DEVICE_EXTENSION)DeviceExtension)->Luns[
VdiskLun2Index(Lun->TargetId, Lun->LunId) ] = NULL;
// Return SUCCESS
Srb->SrbStatus = SRB_STATUS_SUCCESS;
break;
}
case SRB_FUNCTION_RESET_BUS:
IF_SCSI(KdPrint(("VdiskMpStartIo : SRB_FUNCTION_RESET_BUS\r\n"));)
// Reset bus.
VdiskMpResetBus(DeviceExtension, 0);
// Return success.
Srb->SrbStatus = SRB_STATUS_SUCCESS;
break;
case SRB_FUNCTION_EXECUTE_SCSI:
switch (Srb->Cdb[0])
{
case SCSIOP_VERIFY:
IF_SCSI(KdPrint(("VdiskMpStartIo : SCSIOP_VERIFY\r\n"));)
case SCSIOP_TEST_UNIT_READY:
IF_SCSI(KdPrint(("VdiskMpStartIo : SCSIOP_TEST_UNIT_READY\r\n"));)
// Check Lun flags
if ( Lun->Flags & VDISK_LUN_SHUTDOWN)
{
IF_SCSI(KdPrint(("VdiskMpStartIo : Lun 0x%X shutdown.\r\n", Lun));)
// Return sense data
VdiskFillSenseData(&Lun->SenseData, Srb, SCSI_ADSENSE_NO_MEDIA_IN_DEVICE);
break;
}
else
// Return success.
Srb->SrbStatus = SRB_STATUS_SUCCESS;
break;
case SCSIOP_READ_CAPACITY:
{
// Device size in sectors
ULONG Size = Lun->DiskSize>0?Lun->DiskSize-1:0;
IF_SCSI(KdPrint(("VdiskMpStartIo : SCSIOP_READ_CAPACITY Disk size is 0x%X\r\n", Size));)
// Convert to big-endian
// 0x00020000 is 0x00000200 (512) big-endian
((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x00020000;
((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress = VdiskChangeBytes(Size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -