mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-25 01:42:24 -05:00
sys: oplocks: WIP
This commit is contained in:
parent
809505d8a3
commit
8395b22ddc
@ -514,6 +514,11 @@ NTSTATUS FspNotifyFullReportChange(
|
||||
ULONG FilterMatch,
|
||||
ULONG Action,
|
||||
PVOID TargetContext);
|
||||
NTSTATUS FspOplockFsctrlEx(
|
||||
POPLOCK Oplock,
|
||||
PIRP Irp,
|
||||
ULONG OpenCount,
|
||||
BOOLEAN Create);
|
||||
#define FspNotifyUninitializeSync(NS)\
|
||||
FsRtlNotifyUninitializeSync(NS)
|
||||
#define FspNotifyCleanupAll(NS, NL)\
|
||||
@ -526,6 +531,10 @@ NTSTATUS FspNotifyFullReportChange(
|
||||
FspNotifyFullChangeDirectory(NS, NL, FC, 0, 0, FALSE, 0, 0, 0, 0)
|
||||
#define FspNotifyReportChange(NS, NL, FN, FO, NP, F, A)\
|
||||
FspNotifyFullReportChange(NS, NL, (PSTRING)(FN), FO, 0, (PSTRING)(NP), F, A, 0)
|
||||
#define FspOplockFsctrlCreate(OL, I, OC)\
|
||||
FspOplockFsctrlEx(OL, I, OC, TRUE)
|
||||
#define FspOplockFsctrl(OL, I, OC)\
|
||||
FspOplockFsctrlEx(OL, I, OC, FALSE)
|
||||
|
||||
/* utility: synchronous work queue */
|
||||
typedef struct
|
||||
@ -983,6 +992,9 @@ typedef struct FSP_FILE_NODE
|
||||
ULONG StreamInfoChangeNumber;
|
||||
BOOLEAN TruncateOnClose;
|
||||
FILE_LOCK FileLock;
|
||||
#if (NTDDI_VERSION < NTDDI_WIN8)
|
||||
OPLOCK Oplock;
|
||||
#endif
|
||||
struct
|
||||
{
|
||||
PVOID LazyWriteThread;
|
||||
@ -1174,6 +1186,11 @@ BOOLEAN FspMainFileOpenCheck(PIRP Irp)
|
||||
#define FspFileNodeDereferenceDirInfo(P) FspMetaCacheDereferenceItemBuffer(P)
|
||||
#define FspFileNodeDereferenceStreamInfo(P) FspMetaCacheDereferenceItemBuffer(P)
|
||||
#define FspFileNodeUnlockAll(N,F,P) FsRtlFastUnlockAll(&(N)->FileLock, F, P, N)
|
||||
#if (NTDDI_VERSION < NTDDI_WIN8)
|
||||
#define FspFileNodeAddrOfOplock(N) (&(N)->Oplock)
|
||||
#else
|
||||
#define FspFileNodeAddrOfOplock(N) (&(N)->Header.Oplock)
|
||||
#endif
|
||||
|
||||
/* multiversion support */
|
||||
typedef
|
||||
|
@ -218,6 +218,7 @@ NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject,
|
||||
RtlInitEmptyUnicodeString(&FileNode->FileName, FileNode->FileNameBuf, (USHORT)ExtraSize);
|
||||
|
||||
FsRtlInitializeFileLock(&FileNode->FileLock, FspFileNodeCompleteLockIrp, 0);
|
||||
FsRtlInitializeOplock(FspFileNodeAddrOfOplock(FileNode));
|
||||
|
||||
*PFileNode = FileNode;
|
||||
|
||||
@ -231,6 +232,7 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode)
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||
|
||||
FsRtlUninitializeOplock(FspFileNodeAddrOfOplock(FileNode));
|
||||
FsRtlUninitializeFileLock(&FileNode->FileLock);
|
||||
|
||||
FsRtlTeardownPerStreamContexts(&FileNode->Header);
|
||||
|
214
src/sys/fsctl.c
214
src/sys/fsctl.c
@ -25,6 +25,10 @@ static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
||||
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||
BOOLEAN IsWrite);
|
||||
static NTSTATUS FspFsvolFileSystemControlOplock(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static IO_COMPLETION_ROUTINE FspFsvolFileSystemControlOplockCompletion;
|
||||
static WORKER_THREAD_ROUTINE FspFsvolFileSystemControlOplockCompletionWork;
|
||||
static NTSTATUS FspFsvolFileSystemControl(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
|
||||
@ -35,6 +39,9 @@ FSP_DRIVER_DISPATCH FspFileSystemControl;
|
||||
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePoint)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePointComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplock)
|
||||
// !#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletion)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletionWork)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlRequestFini)
|
||||
@ -296,6 +303,202 @@ static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PDEVICE_OBJECT FsvolDeviceObject;
|
||||
WORK_QUEUE_ITEM WorkItem;
|
||||
} FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT;
|
||||
|
||||
static NTSTATUS FspFsvolFileSystemControlOplock(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
|
||||
/* is this a valid FileObject? */
|
||||
if (!FspFileNodeIsValid(FileObject->FsContext))
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
||||
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||
ULONG OplockCount;
|
||||
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext;
|
||||
|
||||
if (FSCTL_REQUEST_OPLOCK == FsControlCode)
|
||||
{
|
||||
if (sizeof(REQUEST_OPLOCK_INPUT_BUFFER) > InputBufferLength ||
|
||||
sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER) > OutputBufferLength)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
if (FileNode->IsDirectory && !FsRtlOplockIsSharedRequest(Irp))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FileNode->IsDirectory)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/*
|
||||
* As per FastFat:
|
||||
*
|
||||
* We grab the Fcb exclusively for oplock requests, shared for oplock
|
||||
* break acknowledgement.
|
||||
*/
|
||||
|
||||
switch (FsControlCode)
|
||||
{
|
||||
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
||||
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
||||
case FSCTL_REQUEST_BATCH_OPLOCK:
|
||||
case FSCTL_REQUEST_FILTER_OPLOCK:
|
||||
exclusive:
|
||||
FspFileNodeAcquireExclusive(FileNode, Main);
|
||||
if (!FsRtlOplockIsSharedRequest(Irp))
|
||||
{
|
||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||
OplockCount = FileNode->HandleCount;
|
||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FileNode->IsDirectory)
|
||||
/* ???: Win8 and FsRtlCheckLockForOplockRequest? see FastFat */
|
||||
OplockCount = FsRtlAreThereCurrentOrInProgressFileLocks(&FileNode->FileLock);
|
||||
else
|
||||
OplockCount = 0;
|
||||
}
|
||||
if (FSCTL_REQUEST_FILTER_OPLOCK == FsControlCode ||
|
||||
FSCTL_REQUEST_BATCH_OPLOCK == FsControlCode ||
|
||||
(FSCTL_REQUEST_OPLOCK == FsControlCode &&
|
||||
FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->RequestedOplockLevel,
|
||||
OPLOCK_LEVEL_CACHE_HANDLE)))
|
||||
{
|
||||
BOOLEAN DeletePending;
|
||||
|
||||
DeletePending = 0 != FileNode->DeletePending;
|
||||
MemoryBarrier();
|
||||
if (DeletePending)
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
return STATUS_DELETE_PENDING;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
||||
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
||||
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
||||
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
||||
shared:
|
||||
FspFileNodeAcquireShared(FileNode, Main);
|
||||
OplockCount = 0;
|
||||
break;
|
||||
|
||||
case FSCTL_REQUEST_OPLOCK:
|
||||
if (FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->Flags,
|
||||
REQUEST_OPLOCK_INPUT_FLAG_REQUEST))
|
||||
goto exclusive;
|
||||
if (FlagOn(((PREQUEST_OPLOCK_INPUT_BUFFER)InputBuffer)->Flags,
|
||||
REQUEST_OPLOCK_INPUT_FLAG_ACK))
|
||||
goto shared;
|
||||
|
||||
/* one of REQUEST_OPLOCK_INPUT_FLAG_REQUEST or REQUEST_OPLOCK_INPUT_FLAG_ACK required */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
|
||||
/*
|
||||
* The FileNode is acquired exclusive or shared.
|
||||
* Make sure to release it before exiting!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This IRP will be completed by the FSRTL package and therefore
|
||||
* we will have no chance to do our normal IRP completion processing.
|
||||
* Hook the IRP completion and perform the IRP completion processing
|
||||
* there.
|
||||
*/
|
||||
|
||||
CompletionContext = FspAllocNonPaged(sizeof *CompletionContext);
|
||||
if (0 == CompletionContext)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto unlock_exit;
|
||||
}
|
||||
CompletionContext->FsvolDeviceObject = FsvolDeviceObject;
|
||||
ExInitializeWorkItem(&CompletionContext->WorkItem,
|
||||
FspFsvolFileSystemControlOplockCompletionWork, CompletionContext);
|
||||
|
||||
Result = FspIrpHook(Irp, FspFsvolFileSystemControlOplockCompletion, CompletionContext);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFree(CompletionContext);
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is possible for FspOplockFsctrl to complete the IRP immediately.
|
||||
* In this case trying to access the IRP (to get its IrpFlags) in FspFileNodeRelease
|
||||
* can lead to a bugcheck. For this reason we set the TopLevelIrp to NULL here.
|
||||
*
|
||||
* FspFsvolFileSystemControlOplock does not need the TopLevelIrp functionality,
|
||||
* because it cannot be used recursively (I believe -- famous last words).
|
||||
*/
|
||||
PIRP TopLevelIrp = IoGetTopLevelIrp();
|
||||
IoSetTopLevelIrp(0);
|
||||
|
||||
Result = FspOplockFsctrl(FspFileNodeAddrOfOplock(FileNode), Irp, OplockCount);
|
||||
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
/* set back the top level IRP just in case! */
|
||||
IoSetTopLevelIrp(TopLevelIrp);
|
||||
|
||||
FspIrpHookReset(Irp);
|
||||
FspFree(CompletionContext);
|
||||
return Result;
|
||||
}
|
||||
|
||||
return STATUS_PENDING;
|
||||
|
||||
unlock_exit:
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolFileSystemControlOplockCompletion(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
|
||||
{
|
||||
// !PAGED_CODE();
|
||||
|
||||
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext =
|
||||
FspIrpHookContext(Context);
|
||||
ExQueueWorkItem(&CompletionContext->WorkItem, DelayedWorkQueue);
|
||||
|
||||
return FspIrpHookNext(DeviceObject, Irp, Context);
|
||||
}
|
||||
|
||||
static VOID FspFsvolFileSystemControlOplockCompletionWork(PVOID Context)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FSVOL_FILESYSTEM_CONTROL_OPLOCK_COMPLETION_CONTEXT *CompletionContext = Context;
|
||||
FspDeviceDereference(CompletionContext->FsvolDeviceObject);
|
||||
FspFree(CompletionContext);
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolFileSystemControl(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
@ -318,6 +521,17 @@ static NTSTATUS FspFsvolFileSystemControl(
|
||||
case FSCTL_DELETE_REPARSE_POINT:
|
||||
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, TRUE);
|
||||
break;
|
||||
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
||||
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
||||
case FSCTL_REQUEST_BATCH_OPLOCK:
|
||||
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
||||
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
||||
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
||||
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
||||
case FSCTL_REQUEST_FILTER_OPLOCK:
|
||||
case FSCTL_REQUEST_OPLOCK:
|
||||
Result = FspFsvolFileSystemControlOplock(FsvolDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -67,6 +67,11 @@ NTSTATUS FspNotifyFullReportChange(
|
||||
ULONG FilterMatch,
|
||||
ULONG Action,
|
||||
PVOID TargetContext);
|
||||
NTSTATUS FspOplockFsctrlEx(
|
||||
POPLOCK Oplock,
|
||||
PIRP Irp,
|
||||
ULONG OpenCount,
|
||||
BOOLEAN Create);
|
||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
|
||||
VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem);
|
||||
@ -104,6 +109,7 @@ NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context);
|
||||
#pragma alloc_text(PAGE, FspNotifyInitializeSync)
|
||||
#pragma alloc_text(PAGE, FspNotifyFullChangeDirectory)
|
||||
#pragma alloc_text(PAGE, FspNotifyFullReportChange)
|
||||
#pragma alloc_text(PAGE, FspOplockFsctrlEx)
|
||||
#pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem)
|
||||
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem)
|
||||
#pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine)
|
||||
@ -640,6 +646,42 @@ NTSTATUS FspNotifyFullReportChange(
|
||||
return Result;
|
||||
}
|
||||
|
||||
NTSTATUS FspOplockFsctrlEx(
|
||||
POPLOCK Oplock,
|
||||
PIRP Irp,
|
||||
ULONG OpenCount,
|
||||
BOOLEAN Create)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS Result;
|
||||
|
||||
try
|
||||
{
|
||||
ASSERT(
|
||||
(Create && IRP_MJ_CREATE == IoGetCurrentIrpStackLocation(Irp)->MajorFunction) ||
|
||||
(!Create && IRP_MJ_FILE_SYSTEM_CONTROL == IoGetCurrentIrpStackLocation(Irp)->MajorFunction));
|
||||
|
||||
Result = FsRtlOplockFsctrl(
|
||||
Oplock,
|
||||
Irp,
|
||||
OpenCount);
|
||||
|
||||
/*
|
||||
* When the IRP is IRP_MJ_FILE_SYSTEM_CONTROL, FsRtlOplockFsctrl always completes the IRP
|
||||
* (unless it raises). So return STATUS_SUCCESS in that case.
|
||||
*/
|
||||
if (!Create)
|
||||
Result = STATUS_SUCCESS;
|
||||
}
|
||||
except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
Result = GetExceptionCode();
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem,
|
||||
PWORKER_THREAD_ROUTINE Routine, PVOID Context)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user