sys: FspFsextProvider

This commit is contained in:
Bill Zissimopoulos 2019-06-18 16:11:38 -07:00
parent 2cd1bddafb
commit b637a72ec8
7 changed files with 129 additions and 21 deletions

View File

@ -65,6 +65,10 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
#define FSP_FSCTL_STOP \ #define FSP_FSCTL_STOP \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS) CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, FILE_ANY_ACCESS)
/* fsctl internal device codes (usable only in-kernel) */
#define FSP_FSCTL_TRANSACT_INTERNAL \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'I', METHOD_NEITHER, FILE_ANY_ACCESS)
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams=" #define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR)) #define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))
@ -83,7 +87,7 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024) #define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX #define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((T) & 0xffffffff)) #define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) ((HANDLE)((UINT_PTR)((T) & 0xffffffff)))
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff)) #define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff))
#define FSP_FSCTL_DEVICECONTROL_SIZEMAX (4 * 1024) /* must be < FSP_FSCTL_TRANSACT_{REQ,RSP}_SIZEMAX */ #define FSP_FSCTL_DEVICECONTROL_SIZEMAX (4 * 1024) /* must be < FSP_FSCTL_TRANSACT_{REQ,RSP}_SIZEMAX */
@ -185,7 +189,8 @@ enum
UINT32 SecurityTimeout; /* security info timeout (millis); overrides FileInfoTimeout */\ UINT32 SecurityTimeout; /* security info timeout (millis); overrides FileInfoTimeout */\
UINT32 StreamInfoTimeout; /* stream info timeout (millis); overrides FileInfoTimeout */\ UINT32 StreamInfoTimeout; /* stream info timeout (millis); overrides FileInfoTimeout */\
UINT32 EaTimeout; /* EA timeout (millis); overrides FileInfoTimeout */\ UINT32 EaTimeout; /* EA timeout (millis); overrides FileInfoTimeout */\
UINT32 Reserved32[2];\ UINT32 FsextControlCode;\
UINT32 Reserved32[1];\
UINT64 Reserved64[2]; UINT64 Reserved64[2];
typedef struct typedef struct
{ {

View File

@ -43,10 +43,10 @@ typedef struct
/* in */ /* in */
UINT32 DeviceTransactCode; UINT32 DeviceTransactCode;
UINT32 DeviceExtensionSize; UINT32 DeviceExtensionSize;
NTSTATUS (*DeviceInit)(PDEVICE_OBJECT DeviceObject); NTSTATUS (*DeviceInit)(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_PARAMS *VolumeParams);
VOID (*DeviceFini)(PDEVICE_OBJECT DeviceObject); VOID (*DeviceFini)(PDEVICE_OBJECT DeviceObject);
VOID (*DeviceExpirationRoutine)(PDEVICE_OBJECT DeviceObject, UINT64 ExpirationTime); VOID (*DeviceExpirationRoutine)(PDEVICE_OBJECT DeviceObject, UINT64 ExpirationTime);
NTSTATUS (*DeviceTransact)(PIRP Irp, PDEVICE_OBJECT DeviceObject); NTSTATUS (*DeviceTransact)(PDEVICE_OBJECT DeviceObject, PIRP Irp);
/* out */ /* out */
UINT32 DeviceExtensionOffset; UINT32 DeviceExtensionOffset;
} FSP_FSEXT_PROVIDER; } FSP_FSEXT_PROVIDER;

View File

@ -325,6 +325,20 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
* to track what has been initialized! * to track what has been initialized!
*/ */
/* initialize any fsext provider */
if (0 != FsvolDeviceExtension->VolumeParams.FsextControlCode)
{
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
FsvolDeviceExtension->VolumeParams.FsextControlCode);
if (0 != Provider)
{
Result = Provider->DeviceInit(DeviceObject, &FsvolDeviceExtension->VolumeParams);
if (!NT_SUCCESS(Result))
return Result;
FsvolDeviceExtension->InitDoneFsext = 1;
}
}
/* is there a virtual disk? */ /* is there a virtual disk? */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject) if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
{ {
@ -500,6 +514,15 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
if (0 != FsvolDeviceExtension->SwapVpb) if (0 != FsvolDeviceExtension->SwapVpb)
FspFreeExternal(FsvolDeviceExtension->SwapVpb); FspFreeExternal(FsvolDeviceExtension->SwapVpb);
} }
/* finalize any fsext provider */
if (FsvolDeviceExtension->InitDoneFsext)
{
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
FsvolDeviceExtension->VolumeParams.FsextControlCode);
if (0 != Provider)
Provider->DeviceFini(DeviceObject);
}
} }
static VOID FspFsvolDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context) static VOID FspFsvolDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context)
@ -546,6 +569,14 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime); FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime); FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime); FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime);
/* run any fsext provider expiration routine */
if (0 != FsvolDeviceExtension->VolumeParams.FsextControlCode)
{
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
FsvolDeviceExtension->VolumeParams.FsextControlCode);
if (0 != Provider)
Provider->DeviceExpirationRoutine(DeviceObject, InterruptTime);
}
FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime); FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime);
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql); KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);

View File

@ -1056,7 +1056,8 @@ typedef struct
{ {
FSP_DEVICE_EXTENSION Base; FSP_DEVICE_EXTENSION Base;
UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1, InitDoneEa:1, UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1, InitDoneEa:1,
InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1; InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1,
InitDoneFsext;
PDEVICE_OBJECT FsctlDeviceObject; PDEVICE_OBJECT FsctlDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject;
PDEVICE_OBJECT FsvolDeviceObject; PDEVICE_OBJECT FsvolDeviceObject;
@ -1179,7 +1180,7 @@ VOID FspDeviceGlobalUnlock(VOID)
// STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED) // STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED)
/* fsext */ /* fsext */
FSP_FSEXT_PROVIDER *FspFsextProvider(VOID); FSP_FSEXT_PROVIDER *FspFsextProvider(UINT32 ControlCode);
/* process buffers conditional usage */ /* process buffers conditional usage */
static inline static inline

View File

@ -86,6 +86,7 @@ static NTSTATUS FspFsctlFileSystemControl(
break; break;
case FSP_FSCTL_TRANSACT: case FSP_FSCTL_TRANSACT:
case FSP_FSCTL_TRANSACT_BATCH: case FSP_FSCTL_TRANSACT_BATCH:
case FSP_FSCTL_TRANSACT_INTERNAL:
if (0 != IrpSp->FileObject->FsContext2) if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp); Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp);
break; break;
@ -93,6 +94,33 @@ static NTSTATUS FspFsctlFileSystemControl(
if (0 != IrpSp->FileObject->FsContext2) if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp); Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp);
break; break;
case 0:
/* ensure that 0 != IrpSp->Parameters.FileSystemControl.FsControlCode in default: case */
break;
default:
if (0 != IrpSp->FileObject->FsContext2)
{
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->FileObject->FsContext2;
if (!FspDeviceReference(FsvolDeviceObject))
{
Result = STATUS_CANCELLED;
break;
}
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(
FsvolDeviceObject);
if (IrpSp->Parameters.FileSystemControl.FsControlCode ==
FsvolDeviceExtension->VolumeParams.FsextControlCode)
{
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
FsvolDeviceExtension->VolumeParams.FsextControlCode);
if (0 != Provider)
Result = Provider->DeviceTransact(FsvolDeviceObject, Irp);
}
FspDeviceDereference(FsvolDeviceObject);
}
break;
} }
break; break;
case IRP_MN_MOUNT_VOLUME: case IRP_MN_MOUNT_VOLUME:

View File

@ -25,7 +25,7 @@
static KSPIN_LOCK FsextSpinLock = 0; static KSPIN_LOCK FsextSpinLock = 0;
FSP_FSEXT_PROVIDER *FsextProvider; FSP_FSEXT_PROVIDER *FsextProvider;
FSP_FSEXT_PROVIDER *FspFsextProvider(VOID) FSP_FSEXT_PROVIDER *FspFsextProvider(UINT32 ControlCode)
{ {
FSP_FSEXT_PROVIDER *Provider; FSP_FSEXT_PROVIDER *Provider;
KIRQL Irql; KIRQL Irql;

View File

@ -652,7 +652,8 @@ NTSTATUS FspVolumeTransact(
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction); ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
ASSERT( ASSERT(
FSP_FSCTL_TRANSACT == IrpSp->Parameters.FileSystemControl.FsControlCode || FSP_FSCTL_TRANSACT == IrpSp->Parameters.FileSystemControl.FsControlCode ||
FSP_FSCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode); FSP_FSCTL_TRANSACT_BATCH == IrpSp->Parameters.FileSystemControl.FsControlCode ||
FSP_FSCTL_TRANSACT_INTERNAL == IrpSp->Parameters.FileSystemControl.FsControlCode);
ASSERT( ASSERT(
METHOD_BUFFERED == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3) || METHOD_BUFFERED == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3) ||
METHOD_OUT_DIRECT == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3)); METHOD_OUT_DIRECT == (IrpSp->Parameters.FileSystemControl.FsControlCode & 3));
@ -663,17 +664,31 @@ NTSTATUS FspVolumeTransact(
ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; ULONG ControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
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 = Irp->AssociatedIrp.SystemBuffer; PVOID InputBuffer = 0;
PVOID OutputBuffer = 0; PVOID OutputBuffer = 0;
if (0 != InputBufferLength && if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength) {
return STATUS_INVALID_PARAMETER; InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
if (0 != OutputBufferLength && if (KernelMode != Irp->RequestorMode)
((FSP_FSCTL_TRANSACT == ControlCode && return STATUS_INVALID_DEVICE_REQUEST;
FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) || ASSERT(0 == InputBufferLength ||
(FSP_FSCTL_TRANSACT_BATCH == ControlCode && FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) <= InputBufferLength);
FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength))) ASSERT(0 == OutputBufferLength ||
return STATUS_BUFFER_TOO_SMALL; sizeof(PVOID) <= OutputBufferLength);
}
else
{
InputBuffer = Irp->AssociatedIrp.SystemBuffer;
if (0 != InputBufferLength &&
FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength)
return STATUS_INVALID_PARAMETER;
if (0 != OutputBufferLength &&
((FSP_FSCTL_TRANSACT == ControlCode &&
FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN > OutputBufferLength) ||
(FSP_FSCTL_TRANSACT_BATCH == ControlCode &&
FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN > OutputBufferLength)))
return STATUS_BUFFER_TOO_SMALL;
}
if (!FspDeviceReference(FsvolDeviceObject)) if (!FspDeviceReference(FsvolDeviceObject))
return STATUS_CANCELLED; return STATUS_CANCELLED;
@ -683,6 +698,7 @@ NTSTATUS FspVolumeTransact(
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;
PVOID InternalBuffer = 0;
PIRP ProcessIrp, PendingIrp, RetriedIrp, RepostedIrp; PIRP ProcessIrp, PendingIrp, RetriedIrp, RepostedIrp;
ULONG LoopCount; ULONG LoopCount;
LARGE_INTEGER Timeout; LARGE_INTEGER Timeout;
@ -751,6 +767,9 @@ NTSTATUS FspVolumeTransact(
/* were we sent an output buffer? */ /* were we sent an output buffer? */
switch (ControlCode & 3) switch (ControlCode & 3)
{ {
case METHOD_NEITHER:
OutputBuffer = Irp->UserBuffer;
break;
case METHOD_OUT_DIRECT: case METHOD_OUT_DIRECT:
if (0 != Irp->MdlAddress) if (0 != Irp->MdlAddress)
OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); OutputBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
@ -795,7 +814,9 @@ NTSTATUS FspVolumeTransact(
RepostedIrp = 0; RepostedIrp = 0;
Request = OutputBuffer; Request = OutputBuffer;
BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength; BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength;
ASSERT(FspFsctlTransactCanProduceRequest(Request, BufferEnd)); ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode ?
TRUE :
FspFsctlTransactCanProduceRequest(Request, BufferEnd));
LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq); LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq);
for (;;) for (;;)
{ {
@ -816,8 +837,18 @@ NTSTATUS FspVolumeTransact(
FspIopCompleteIrp(PendingIrp, Result); FspIopCompleteIrp(PendingIrp, Result);
else else
{ {
RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size); if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size); {
InternalBuffer = FspAllocatePoolMustSucceed(
PagedPool, PendingIrpRequest->Size, FSP_ALLOC_EXTERNAL_TAG);
RtlCopyMemory(InternalBuffer, PendingIrpRequest, PendingIrpRequest->Size);
*(PVOID *)OutputBuffer = InternalBuffer;
}
else
{
RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size);
Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size);
}
if (!FspIoqStartProcessingIrp(FsvolDeviceExtension->Ioq, PendingIrp)) if (!FspIoqStartProcessingIrp(FsvolDeviceExtension->Ioq, PendingIrp))
{ {
@ -828,12 +859,24 @@ NTSTATUS FspVolumeTransact(
* also cancel the PendingIrp we have in our hands. * also cancel the PendingIrp we have in our hands.
*/ */
ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq)); ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq));
if (0 != InternalBuffer)
{
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode);
FspFree(InternalBuffer);
}
FspIopCompleteCanceledIrp(PendingIrp); FspIopCompleteCanceledIrp(PendingIrp);
Result = STATUS_CANCELLED; Result = STATUS_CANCELLED;
goto exit; goto exit;
} }
/* are we doing single request or batch mode? */ /* are we doing single request or batch mode? */
if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
{
Irp->IoStatus.Information = sizeof(PVOID);
Result = STATUS_SUCCESS;
goto exit;
}
else
if (FSP_FSCTL_TRANSACT == ControlCode) if (FSP_FSCTL_TRANSACT == ControlCode)
break; break;