sys: FspVolumeFastTransact

This commit is contained in:
Bill Zissimopoulos 2022-05-17 17:25:18 +01:00
parent 43af829d46
commit c0fa5696d7
5 changed files with 139 additions and 30 deletions

View File

@ -21,6 +21,7 @@
#include <sys/driver.h> #include <sys/driver.h>
FAST_IO_DEVICE_CONTROL FspFastIoDeviceControl;
static NTSTATUS FspFsctlDeviceControl( static NTSTATUS FspFsctlDeviceControl(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvrtDeviceControl( static NTSTATUS FspFsvrtDeviceControl(
@ -35,6 +36,7 @@ static FSP_IOP_REQUEST_FINI FspFsvolDeviceControlRequestFini;
FSP_DRIVER_DISPATCH FspDeviceControl; FSP_DRIVER_DISPATCH FspDeviceControl;
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspFastIoDeviceControl)
#pragma alloc_text(PAGE, FspFsctlDeviceControl) #pragma alloc_text(PAGE, FspFsctlDeviceControl)
#pragma alloc_text(PAGE, FspFsvrtDeviceControl) #pragma alloc_text(PAGE, FspFsvrtDeviceControl)
#pragma alloc_text(PAGE, FspFsvrtDeviceControlStorageQuery) #pragma alloc_text(PAGE, FspFsvrtDeviceControlStorageQuery)
@ -49,6 +51,62 @@ enum
RequestFileNode = 0, RequestFileNode = 0,
}; };
BOOLEAN FspFastIoDeviceControl(
PFILE_OBJECT FileObject,
BOOLEAN CanWait,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
ULONG IoControlCode,
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
FSP_ENTER_BOOL(PAGED_CODE());
/* cannot use FSP_ENTER_FIO() because it only supports fsvol devices */
Result = DEBUGTEST(50) &&
CanWait &&
FSP_IOCTL_TRANSACT == IoControlCode &&
FspFsctlDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind;
if (!Result)
FSP_RETURN();
#if 0
PDEVICE_OBJECT FsctlDeviceObject = DeviceObject;
if (!FspDeviceReference(FsctlDeviceObject))
{
IoStatus->Status = STATUS_CANCELLED;
IoStatus->Information = 0;
FSP_RETURN();
}
#endif
ASSERT(0 == IoGetTopLevelIrp());
IoSetTopLevelIrp((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP);
IoStatus->Status = FspVolumeFastTransact(
FileObject->FsContext2,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
IoStatus,
(PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP);
IoSetTopLevelIrp(0);
#if 0
FspDeviceDereference(FsctlDeviceObject);
#endif
FSP_LEAVE_BOOL(
"%s, FileObject=%p",
IoctlCodeSym(IoControlCode),
FileObject);
}
static NTSTATUS FspFsctlDeviceControl( static NTSTATUS FspFsctlDeviceControl(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {

View File

@ -97,7 +97,7 @@ NTSTATUS DriverEntry(
//FspFastIoDispatch.FastIoUnlockSingle = 0; //FspFastIoDispatch.FastIoUnlockSingle = 0;
//FspFastIoDispatch.FastIoUnlockAll = 0; //FspFastIoDispatch.FastIoUnlockAll = 0;
//FspFastIoDispatch.FastIoUnlockAllByKey = 0; //FspFastIoDispatch.FastIoUnlockAllByKey = 0;
//FspFastIoDispatch.FastIoDeviceControl = 0; FspFastIoDispatch.FastIoDeviceControl = FspFastIoDeviceControl;
FspFastIoDispatch.AcquireFileForNtCreateSection = FspAcquireFileForNtCreateSection; FspFastIoDispatch.AcquireFileForNtCreateSection = FspAcquireFileForNtCreateSection;
FspFastIoDispatch.ReleaseFileForNtCreateSection = FspReleaseFileForNtCreateSection; FspFastIoDispatch.ReleaseFileForNtCreateSection = FspReleaseFileForNtCreateSection;
//FspFastIoDispatch.FastIoDetachDevice = 0; //FspFastIoDispatch.FastIoDetachDevice = 0;

View File

@ -425,6 +425,7 @@ FSP_IOPREP_DISPATCH FspFsvolWritePrepare;
FSP_IOCMPL_DISPATCH FspFsvolWriteComplete; FSP_IOCMPL_DISPATCH FspFsvolWriteComplete;
/* fast I/O and resource acquisition callbacks */ /* fast I/O and resource acquisition callbacks */
FAST_IO_DEVICE_CONTROL FspFastIoDeviceControl;
FAST_IO_READ FspFastIoRead; FAST_IO_READ FspFastIoRead;
FAST_IO_WRITE FspFastIoWrite; FAST_IO_WRITE FspFastIoWrite;
FAST_IO_QUERY_BASIC_INFO FspFastIoQueryBasicInfo; FAST_IO_QUERY_BASIC_INFO FspFastIoQueryBasicInfo;
@ -687,6 +688,8 @@ NTSTATUS FspOplockFsctrl(
FspNotifyFullReportChange(NS, NL, (PSTRING)(FN), FO, 0, (PSTRING)(NP), F, A, 0) FspNotifyFullReportChange(NS, NL, (PSTRING)(FN), FO, 0, (PSTRING)(NP), F, A, 0)
#define FSP_NEXT_EA(Ea, EaEnd) \ #define FSP_NEXT_EA(Ea, EaEnd) \
(0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd)) (0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd))
#define FSP_FUNCTION_FROM_CTL_CODE(ControlCode)\
(((ControlCode) >> 2) & 0xfff)
/* utility: synchronous work queue */ /* utility: synchronous work queue */
typedef struct typedef struct
@ -926,7 +929,7 @@ retry:
{ {
if (PsIsThreadTerminating(PsGetCurrentThread())) if (PsIsThreadTerminating(PsGetCurrentThread()))
return STATUS_THREAD_IS_TERMINATING; return STATUS_THREAD_IS_TERMINATING;
if (0 != Irp && Irp->Cancel) if (0 != Irp && ((PIRP)FSRTL_MAX_TOP_LEVEL_IRP_FLAG >= Irp || Irp->Cancel))
return STATUS_CANCELLED; return STATUS_CANCELLED;
if (0 != ExpirationTime) if (0 != ExpirationTime)
{ {
@ -1424,6 +1427,15 @@ NTSTATUS FspVolumeGetNameList(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeTransact( NTSTATUS FspVolumeTransact(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeFastTransact(
PDEVICE_OBJECT FsvolDeviceObject,
ULONG ControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PIO_STATUS_BLOCK IoStatus,
PIRP Irp);
NTSTATUS FspVolumeTransactFsext( NTSTATUS FspVolumeTransactFsext(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeStop( NTSTATUS FspVolumeStop(

View File

@ -152,6 +152,7 @@
#define FspIoqEventSet(E) KeSetEvent(E, 1, FALSE) #define FspIoqEventSet(E) KeSetEvent(E, 1, FALSE)
#define FspIoqEventCancellableWait(E,T,I) FsRtlCancellableWaitForSingleObject(E,T,I) #define FspIoqEventCancellableWait(E,T,I) FsRtlCancellableWaitForSingleObject(E,T,I)
#define FspIoqEventClear(E) KeClearEvent(E) #define FspIoqEventClear(E) KeClearEvent(E)
#error FsRtlCancellableWaitForSingleObject needs to support FSRTL_FAST_IO_TOP_LEVEL_IRP cancellation
#endif #endif
/* /*

View File

@ -46,6 +46,15 @@ static NTSTATUS FspVolumeGetNameListNoLock(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeTransact( NTSTATUS FspVolumeTransact(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeFastTransact(
PDEVICE_OBJECT FsvolDeviceObject,
ULONG ControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PIO_STATUS_BLOCK IoStatus,
PIRP Irp);
NTSTATUS FspVolumeTransactFsext( NTSTATUS FspVolumeTransactFsext(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
NTSTATUS FspVolumeStop( NTSTATUS FspVolumeStop(
@ -71,6 +80,7 @@ NTSTATUS FspVolumeWork(
#pragma alloc_text(PAGE, FspVolumeGetNameList) #pragma alloc_text(PAGE, FspVolumeGetNameList)
#pragma alloc_text(PAGE, FspVolumeGetNameListNoLock) #pragma alloc_text(PAGE, FspVolumeGetNameListNoLock)
#pragma alloc_text(PAGE, FspVolumeTransact) #pragma alloc_text(PAGE, FspVolumeTransact)
#pragma alloc_text(PAGE, FspVolumeFastTransact)
#pragma alloc_text(PAGE, FspVolumeTransactFsext) #pragma alloc_text(PAGE, FspVolumeTransactFsext)
#pragma alloc_text(PAGE, FspVolumeStop) #pragma alloc_text(PAGE, FspVolumeStop)
#pragma alloc_text(PAGE, FspVolumeNotify) #pragma alloc_text(PAGE, FspVolumeNotify)
@ -787,11 +797,12 @@ NTSTATUS FspVolumeTransact(
/* check parameters */ /* check parameters */
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2; PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
ULONG ControlFunction = FSP_FUNCTION_FROM_CTL_CODE(ControlCode);
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
PVOID InputBuffer = 0; PVOID InputBuffer = 0;
PVOID OutputBuffer = 0; PVOID OutputBuffer = 0;
if (0x800 + 'I' /*FSP_xxCTL_TRANSACT_INTERNAL*/ == ((ControlCode >> 2) & 0xfff)) if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction)
{ {
InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer; InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
if (KernelMode != Irp->RequestorMode) if (KernelMode != Irp->RequestorMode)
@ -808,13 +819,36 @@ NTSTATUS FspVolumeTransact(
FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength) FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
if (0 != OutputBufferLength && if (0 != OutputBufferLength &&
((0x800 + 'T' /*FSP_xxCTL_TRANSACT*/ == ((ControlCode >> 2) & 0xfff) && ((FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT) == ControlFunction &&
FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) || FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) ||
(0x800 + 't' /*FSP_xxCTL_TRANSACT_BATCH*/ == ((ControlCode >> 2) & 0xfff) && (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_BATCH) == ControlFunction &&
FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength))) FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength)))
return STATUS_BUFFER_TOO_SMALL; return STATUS_BUFFER_TOO_SMALL;
} }
return FspVolumeFastTransact(
FsvolDeviceObject,
ControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength,
&Irp->IoStatus,
Irp);
}
NTSTATUS FspVolumeFastTransact(
PDEVICE_OBJECT FsvolDeviceObject,
ULONG ControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength,
PIO_STATUS_BLOCK IoStatus,
PIRP Irp)
{
PAGED_CODE();
if (!FspDeviceReference(FsvolDeviceObject)) if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED; return STATUS_CANCELLED;
@ -825,6 +859,7 @@ NTSTATUS FspVolumeTransact(
NTSTATUS Result; NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
ULONG ControlFunction = FSP_FUNCTION_FROM_CTL_CODE(ControlCode);
PUINT8 BufferEnd; PUINT8 BufferEnd;
FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse; FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse;
FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest; FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest;
@ -894,27 +929,30 @@ NTSTATUS FspVolumeTransact(
} }
} }
/* were we sent an output buffer? */ if ((PIRP)FSRTL_MAX_TOP_LEVEL_IRP_FLAG < Irp)
switch (ControlCode & 3)
{ {
case METHOD_NEITHER: /* were we sent an output buffer? */
OutputBuffer = Irp->UserBuffer; switch (ControlCode & 3)
break; {
case METHOD_OUT_DIRECT: case METHOD_NEITHER:
if (0 != Irp->MdlAddress) OutputBuffer = Irp->UserBuffer;
OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); break;
break; case METHOD_OUT_DIRECT:
case METHOD_BUFFERED: if (0 != Irp->MdlAddress)
if (0 != OutputBufferLength) OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
OutputBuffer = Irp->AssociatedIrp.SystemBuffer; break;
break; case METHOD_BUFFERED:
default: if (0 != OutputBufferLength)
ASSERT(0); OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
break; break;
default:
ASSERT(0);
break;
}
} }
if (0 == OutputBuffer) if (0 == OutputBuffer)
{ {
Irp->IoStatus.Information = 0; IoStatus->Information = 0;
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
goto exit; goto exit;
} }
@ -935,7 +973,7 @@ NTSTATUS FspVolumeTransact(
} }
if (FspIoqTimeout == PendingIrp || FspIoqCancelled == PendingIrp) if (FspIoqTimeout == PendingIrp || FspIoqCancelled == PendingIrp)
{ {
Irp->IoStatus.Information = 0; IoStatus->Information = 0;
Result = FspIoqTimeout == PendingIrp ? STATUS_SUCCESS : STATUS_CANCELLED; Result = FspIoqTimeout == PendingIrp ? STATUS_SUCCESS : STATUS_CANCELLED;
goto exit; goto exit;
} }
@ -944,7 +982,7 @@ NTSTATUS FspVolumeTransact(
RepostedIrp = 0; RepostedIrp = 0;
Request = OutputBuffer; Request = OutputBuffer;
BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength; BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength;
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode ? ASSERT(FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction ?
TRUE : TRUE :
FspFsctlTransactCanProduceRequest(Request, BufferEnd)); FspFsctlTransactCanProduceRequest(Request, BufferEnd));
LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq); LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq);
@ -967,7 +1005,7 @@ NTSTATUS FspVolumeTransact(
FspIopCompleteIrp(PendingIrp, Result); FspIopCompleteIrp(PendingIrp, Result);
else else
{ {
if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode) if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction)
{ {
InternalBuffer = FspAllocatePoolMustSucceed( InternalBuffer = FspAllocatePoolMustSucceed(
PagedPool, PendingIrpRequest->Size, FSP_ALLOC_EXTERNAL_TAG); PagedPool, PendingIrpRequest->Size, FSP_ALLOC_EXTERNAL_TAG);
@ -991,7 +1029,7 @@ NTSTATUS FspVolumeTransact(
ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq)); ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq));
if (0 != InternalBuffer) if (0 != InternalBuffer)
{ {
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode); ASSERT(FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction);
*(PVOID *)OutputBuffer = 0; *(PVOID *)OutputBuffer = 0;
FspFree(InternalBuffer); FspFree(InternalBuffer);
} }
@ -1001,14 +1039,14 @@ NTSTATUS FspVolumeTransact(
} }
/* are we doing single request or batch mode? */ /* are we doing single request or batch mode? */
if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode) if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction)
{ {
Irp->IoStatus.Information = sizeof(PVOID); IoStatus->Information = sizeof(PVOID);
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
goto exit; goto exit;
} }
else else
if (FSP_FSCTL_TRANSACT == ControlCode) if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT) == ControlFunction)
break; break;
/* check that we have enough space before pulling the next pending IRP off the queue */ /* check that we have enough space before pulling the next pending IRP off the queue */
@ -1025,7 +1063,7 @@ NTSTATUS FspVolumeTransact(
break; break;
} }
Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)OutputBuffer; IoStatus->Information = (PUINT8)Request - (PUINT8)OutputBuffer;
Result = STATUS_SUCCESS; Result = STATUS_SUCCESS;
exit: exit: