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 \
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_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_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_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 StreamInfoTimeout; /* stream info timeout (millis); overrides FileInfoTimeout */\
UINT32 EaTimeout; /* EA timeout (millis); overrides FileInfoTimeout */\
UINT32 Reserved32[2];\
UINT32 FsextControlCode;\
UINT32 Reserved32[1];\
UINT64 Reserved64[2];
typedef struct
{

View File

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

View File

@ -325,6 +325,20 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
* 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? */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
{
@ -500,6 +514,15 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
if (0 != 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)
@ -546,6 +569,14 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime);
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, 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);
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);

View File

@ -1056,7 +1056,8 @@ typedef struct
{
FSP_DEVICE_EXTENSION Base;
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 FsvrtDeviceObject;
PDEVICE_OBJECT FsvolDeviceObject;
@ -1179,7 +1180,7 @@ VOID FspDeviceGlobalUnlock(VOID)
// STATUS_VOLUME_DISMOUNTED : STATUS_DEVICE_NOT_CONNECTED)
/* fsext */
FSP_FSEXT_PROVIDER *FspFsextProvider(VOID);
FSP_FSEXT_PROVIDER *FspFsextProvider(UINT32 ControlCode);
/* process buffers conditional usage */
static inline

View File

@ -86,6 +86,7 @@ static NTSTATUS FspFsctlFileSystemControl(
break;
case FSP_FSCTL_TRANSACT:
case FSP_FSCTL_TRANSACT_BATCH:
case FSP_FSCTL_TRANSACT_INTERNAL:
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp);
break;
@ -93,6 +94,33 @@ static NTSTATUS FspFsctlFileSystemControl(
if (0 != IrpSp->FileObject->FsContext2)
Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp);
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;
case IRP_MN_MOUNT_VOLUME:

View File

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

View File

@ -652,7 +652,8 @@ NTSTATUS FspVolumeTransact(
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
ASSERT(
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(
METHOD_BUFFERED == (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 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
PVOID InputBuffer = 0;
PVOID OutputBuffer = 0;
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 (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
{
InputBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
if (KernelMode != Irp->RequestorMode)
return STATUS_INVALID_DEVICE_REQUEST;
ASSERT(0 == InputBufferLength ||
FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) <= InputBufferLength);
ASSERT(0 == OutputBufferLength ||
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))
return STATUS_CANCELLED;
@ -683,6 +698,7 @@ NTSTATUS FspVolumeTransact(
PUINT8 BufferEnd;
FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse;
FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest;
PVOID InternalBuffer = 0;
PIRP ProcessIrp, PendingIrp, RetriedIrp, RepostedIrp;
ULONG LoopCount;
LARGE_INTEGER Timeout;
@ -751,6 +767,9 @@ NTSTATUS FspVolumeTransact(
/* 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);
@ -795,7 +814,9 @@ NTSTATUS FspVolumeTransact(
RepostedIrp = 0;
Request = OutputBuffer;
BufferEnd = (PUINT8)OutputBuffer + OutputBufferLength;
ASSERT(FspFsctlTransactCanProduceRequest(Request, BufferEnd));
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode ?
TRUE :
FspFsctlTransactCanProduceRequest(Request, BufferEnd));
LoopCount = FspIoqPendingIrpCount(FsvolDeviceExtension->Ioq);
for (;;)
{
@ -816,8 +837,18 @@ NTSTATUS FspVolumeTransact(
FspIopCompleteIrp(PendingIrp, Result);
else
{
RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size);
Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size);
if (FSP_FSCTL_TRANSACT_INTERNAL == ControlCode)
{
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))
{
@ -828,12 +859,24 @@ NTSTATUS FspVolumeTransact(
* also cancel the PendingIrp we have in our hands.
*/
ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq));
if (0 != InternalBuffer)
{
ASSERT(FSP_FSCTL_TRANSACT_INTERNAL == ControlCode);
FspFree(InternalBuffer);
}
FspIopCompleteCanceledIrp(PendingIrp);
Result = STATUS_CANCELLED;
goto exit;
}
/* 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)
break;