sys: oplocks: WIP

This commit is contained in:
Bill Zissimopoulos 2016-11-07 20:42:32 -08:00
parent 809505d8a3
commit 8395b22ddc
4 changed files with 275 additions and 0 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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)
{