From c0fa5696d78fa1b793a3ce867b4fa35a284a7566 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 17 May 2022 17:25:18 +0100 Subject: [PATCH] sys: FspVolumeFastTransact --- src/sys/devctl.c | 58 ++++++++++++++++++++++++++++++ src/sys/driver.c | 2 +- src/sys/driver.h | 14 +++++++- src/sys/ioq.c | 1 + src/sys/volume.c | 94 +++++++++++++++++++++++++++++++++--------------- 5 files changed, 139 insertions(+), 30 deletions(-) diff --git a/src/sys/devctl.c b/src/sys/devctl.c index fc9e6b9d..5910d35f 100644 --- a/src/sys/devctl.c +++ b/src/sys/devctl.c @@ -21,6 +21,7 @@ #include +FAST_IO_DEVICE_CONTROL FspFastIoDeviceControl; static NTSTATUS FspFsctlDeviceControl( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspFsvrtDeviceControl( @@ -35,6 +36,7 @@ static FSP_IOP_REQUEST_FINI FspFsvolDeviceControlRequestFini; FSP_DRIVER_DISPATCH FspDeviceControl; #ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspFastIoDeviceControl) #pragma alloc_text(PAGE, FspFsctlDeviceControl) #pragma alloc_text(PAGE, FspFsvrtDeviceControl) #pragma alloc_text(PAGE, FspFsvrtDeviceControlStorageQuery) @@ -49,6 +51,62 @@ enum 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( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { diff --git a/src/sys/driver.c b/src/sys/driver.c index cb7d2bfd..b0e5a036 100644 --- a/src/sys/driver.c +++ b/src/sys/driver.c @@ -97,7 +97,7 @@ NTSTATUS DriverEntry( //FspFastIoDispatch.FastIoUnlockSingle = 0; //FspFastIoDispatch.FastIoUnlockAll = 0; //FspFastIoDispatch.FastIoUnlockAllByKey = 0; - //FspFastIoDispatch.FastIoDeviceControl = 0; + FspFastIoDispatch.FastIoDeviceControl = FspFastIoDeviceControl; FspFastIoDispatch.AcquireFileForNtCreateSection = FspAcquireFileForNtCreateSection; FspFastIoDispatch.ReleaseFileForNtCreateSection = FspReleaseFileForNtCreateSection; //FspFastIoDispatch.FastIoDetachDevice = 0; diff --git a/src/sys/driver.h b/src/sys/driver.h index e1c9447f..1322b269 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -425,6 +425,7 @@ FSP_IOPREP_DISPATCH FspFsvolWritePrepare; FSP_IOCMPL_DISPATCH FspFsvolWriteComplete; /* fast I/O and resource acquisition callbacks */ +FAST_IO_DEVICE_CONTROL FspFastIoDeviceControl; FAST_IO_READ FspFastIoRead; FAST_IO_WRITE FspFastIoWrite; FAST_IO_QUERY_BASIC_INFO FspFastIoQueryBasicInfo; @@ -687,6 +688,8 @@ NTSTATUS FspOplockFsctrl( FspNotifyFullReportChange(NS, NL, (PSTRING)(FN), FO, 0, (PSTRING)(NP), F, A, 0) #define FSP_NEXT_EA(Ea, EaEnd) \ (0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd)) +#define FSP_FUNCTION_FROM_CTL_CODE(ControlCode)\ + (((ControlCode) >> 2) & 0xfff) /* utility: synchronous work queue */ typedef struct @@ -926,7 +929,7 @@ retry: { if (PsIsThreadTerminating(PsGetCurrentThread())) 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; if (0 != ExpirationTime) { @@ -1424,6 +1427,15 @@ NTSTATUS FspVolumeGetNameList( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeTransact( 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( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeStop( diff --git a/src/sys/ioq.c b/src/sys/ioq.c index ac8f3c94..78b0b165 100644 --- a/src/sys/ioq.c +++ b/src/sys/ioq.c @@ -152,6 +152,7 @@ #define FspIoqEventSet(E) KeSetEvent(E, 1, FALSE) #define FspIoqEventCancellableWait(E,T,I) FsRtlCancellableWaitForSingleObject(E,T,I) #define FspIoqEventClear(E) KeClearEvent(E) +#error FsRtlCancellableWaitForSingleObject needs to support FSRTL_FAST_IO_TOP_LEVEL_IRP cancellation #endif /* diff --git a/src/sys/volume.c b/src/sys/volume.c index 5f4045d3..7cd87654 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -46,6 +46,15 @@ static NTSTATUS FspVolumeGetNameListNoLock( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeTransact( 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( PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); NTSTATUS FspVolumeStop( @@ -71,6 +80,7 @@ NTSTATUS FspVolumeWork( #pragma alloc_text(PAGE, FspVolumeGetNameList) #pragma alloc_text(PAGE, FspVolumeGetNameListNoLock) #pragma alloc_text(PAGE, FspVolumeTransact) +#pragma alloc_text(PAGE, FspVolumeFastTransact) #pragma alloc_text(PAGE, FspVolumeTransactFsext) #pragma alloc_text(PAGE, FspVolumeStop) #pragma alloc_text(PAGE, FspVolumeNotify) @@ -787,11 +797,12 @@ NTSTATUS FspVolumeTransact( /* check parameters */ PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2; ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; + ULONG ControlFunction = FSP_FUNCTION_FROM_CTL_CODE(ControlCode); ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; PVOID InputBuffer = 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; if (KernelMode != Irp->RequestorMode) @@ -808,13 +819,36 @@ NTSTATUS FspVolumeTransact( FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength) return STATUS_INVALID_PARAMETER; 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) || - (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))) 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)) return STATUS_CANCELLED; @@ -825,6 +859,7 @@ NTSTATUS FspVolumeTransact( NTSTATUS Result; FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + ULONG ControlFunction = FSP_FUNCTION_FROM_CTL_CODE(ControlCode); PUINT8 BufferEnd; FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse; FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest; @@ -894,27 +929,30 @@ NTSTATUS FspVolumeTransact( } } - /* were we sent an output buffer? */ - switch (ControlCode & 3) + if ((PIRP)FSRTL_MAX_TOP_LEVEL_IRP_FLAG < Irp) { - case METHOD_NEITHER: - OutputBuffer = Irp->UserBuffer; - break; - case METHOD_OUT_DIRECT: - if (0 != Irp->MdlAddress) - OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); - break; - case METHOD_BUFFERED: - if (0 != OutputBufferLength) - OutputBuffer = Irp->AssociatedIrp.SystemBuffer; - break; - default: - ASSERT(0); - break; + /* were we sent an output buffer? */ + switch (ControlCode & 3) + { + case METHOD_NEITHER: + OutputBuffer = Irp->UserBuffer; + break; + case METHOD_OUT_DIRECT: + if (0 != Irp->MdlAddress) + OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); + break; + case METHOD_BUFFERED: + if (0 != OutputBufferLength) + OutputBuffer = Irp->AssociatedIrp.SystemBuffer; + break; + default: + ASSERT(0); + break; + } } if (0 == OutputBuffer) { - Irp->IoStatus.Information = 0; + IoStatus->Information = 0; Result = STATUS_SUCCESS; goto exit; } @@ -935,7 +973,7 @@ NTSTATUS FspVolumeTransact( } if (FspIoqTimeout == PendingIrp || FspIoqCancelled == PendingIrp) { - Irp->IoStatus.Information = 0; + IoStatus->Information = 0; Result = FspIoqTimeout == PendingIrp ? STATUS_SUCCESS : STATUS_CANCELLED; goto exit; } @@ -944,7 +982,7 @@ NTSTATUS FspVolumeTransact( RepostedIrp = 0; Request = OutputBuffer; BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength; - ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode ? + ASSERT(FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction ? TRUE : FspFsctlTransactCanProduceRequest(Request, BufferEnd)); LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq); @@ -967,7 +1005,7 @@ NTSTATUS FspVolumeTransact( FspIopCompleteIrp(PendingIrp, Result); else { - if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode) + if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction) { InternalBuffer = FspAllocatePoolMustSucceed( PagedPool, PendingIrpRequest->Size, FSP_ALLOC_EXTERNAL_TAG); @@ -991,7 +1029,7 @@ NTSTATUS FspVolumeTransact( ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq)); if (0 != InternalBuffer) { - ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode); + ASSERT(FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT_INTERNAL) == ControlFunction); *(PVOID *)OutputBuffer = 0; FspFree(InternalBuffer); } @@ -1001,14 +1039,14 @@ NTSTATUS FspVolumeTransact( } /* 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; goto exit; } else - if (FSP_FSCTL_TRANSACT == ControlCode) + if (FSP_FUNCTION_FROM_CTL_CODE(FSP_FSCTL_TRANSACT) == ControlFunction) break; /* check that we have enough space before pulling the next pending IRP off the queue */ @@ -1025,7 +1063,7 @@ NTSTATUS FspVolumeTransact( break; } - Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)OutputBuffer; + IoStatus->Information = (PUINT8)Request - (PUINT8)OutputBuffer; Result = STATUS_SUCCESS; exit: