mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
sys: IRP_MJ_CREATE: oplock support
This commit is contained in:
parent
7adbd7a56c
commit
fb70eccc9c
@ -74,7 +74,7 @@ static NTSTATUS FspFsvolClose(
|
||||
Request->Req.Close.UserContext = FileNode->UserContext;
|
||||
Request->Req.Close.UserContext2 = FileDesc->UserContext2;
|
||||
|
||||
FspFileNodeClose(FileNode, FileObject, FALSE);
|
||||
FspFileNodeClose(FileNode, FileObject, FALSE, FALSE);
|
||||
|
||||
/* delete the FileDesc and deref the FileNode; order is important (FileDesc has FileNode ref) */
|
||||
FspFileDescDelete(FileDesc); /* this will also close the MainFileObject if any */
|
||||
|
148
src/sys/create.c
148
src/sys/create.c
@ -28,6 +28,13 @@ static NTSTATUS FspFsvolCreateNoLock(
|
||||
BOOLEAN MainFileOpen);
|
||||
FSP_IOPREP_DISPATCH FspFsvolCreatePrepare;
|
||||
FSP_IOCMPL_DISPATCH FspFsvolCreateComplete;
|
||||
static NTSTATUS FspFsvolCreateSharingViolation(
|
||||
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, FSP_FILE_NODE *FileNode);
|
||||
static NTSTATUS FspFsvolCreateSharingViolationWork(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
BOOLEAN CanWait);
|
||||
static VOID FspFsvolCreateSharingViolationOplockComplete(
|
||||
PVOID Context, PIRP Irp);
|
||||
static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||
FSP_FILE_NODE *FileNode, FSP_FILE_DESC *FileDesc, PFILE_OBJECT FileObject,
|
||||
BOOLEAN FlushImage);
|
||||
@ -45,6 +52,9 @@ FSP_DRIVER_DISPATCH FspCreate;
|
||||
#pragma alloc_text(PAGE, FspFsvolCreatePrepare)
|
||||
#pragma alloc_text(PAGE, FspFsvolCreateComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolCreateTryOpen)
|
||||
#pragma alloc_text(PAGE, FspFsvolCreateSharingViolation)
|
||||
#pragma alloc_text(PAGE, FspFsvolCreateSharingViolationWork)
|
||||
#pragma alloc_text(PAGE, FspFsvolCreateSharingViolationOplockComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolCreatePostClose)
|
||||
#pragma alloc_text(PAGE, FspFsvolCreateRequestFini)
|
||||
#pragma alloc_text(PAGE, FspFsvolCreateTryOpenRequestFini)
|
||||
@ -813,11 +823,25 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
FileDesc->DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE);
|
||||
|
||||
/* open the FileNode */
|
||||
OpenedFileNode = FspFileNodeOpen(FileNode, FileObject,
|
||||
Result = FspFileNodeOpen(FileNode, FileObject,
|
||||
Response->Rsp.Create.Opened.GrantedAccess, IrpSp->Parameters.Create.ShareAccess,
|
||||
&Result);
|
||||
if (0 == OpenedFileNode)
|
||||
&OpenedFileNode);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
if (STATUS_SHARING_VIOLATION == Result)
|
||||
{
|
||||
Result = FspFsvolCreateSharingViolation(Irp, Response, OpenedFileNode);
|
||||
if (STATUS_PENDING != Result)
|
||||
{
|
||||
FspFileNodeClose(OpenedFileNode, FileObject, FALSE, TRUE);
|
||||
FspFileNodeDereference(OpenedFileNode);
|
||||
Result = STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
FSP_RETURN();
|
||||
}
|
||||
|
||||
/* unable to open the FileNode; post a Close request */
|
||||
FspFsvolCreatePostClose(FileDesc);
|
||||
|
||||
@ -955,6 +979,118 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName);
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolCreateSharingViolation(
|
||||
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, FSP_FILE_NODE *FileNode)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||
|
||||
FspIopSetIrpResponse(Irp, Response);
|
||||
FspIopRequestContext(Request, FspIopRequestExtraContext) = FileNode;
|
||||
|
||||
Result = FspWqRepostIrpWorkItem(Irp,
|
||||
FspFsvolCreateSharingViolationWork, FspFsvolCreateRequestFini);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
|
||||
return STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolCreateSharingViolationWork(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
BOOLEAN CanWait)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/*
|
||||
* Perform oplock checks in the case that we received STATUS_SHARING_VIOLATION.
|
||||
* The logic below is quite tortured, because it tries to mimic what FastFat
|
||||
* does in Win7. Here is an explanation.
|
||||
*
|
||||
* First notice that this is run in a work thread. So it is assumed that we can
|
||||
* block here. We cannot block in the completion thread, because it belongs to
|
||||
* the user mode file system that may have a limited number of threads to service
|
||||
* file system requests.
|
||||
*
|
||||
* Second we want a way to differentiate the case between an oplock break being
|
||||
* underway and no oplock needed. Unfortunately this only seems possible when a
|
||||
* completion routine is set in FsRtlCheckOplock and FsRtlOplockBreakH. In this
|
||||
* case we get STATUS_PENDING when there is an oplock to be broken and
|
||||
* STATUS_SUCCESS where there is not one.
|
||||
*
|
||||
* Third notice that by default we must return STATUS_SHARING_VIOLATION, because
|
||||
* the share access check failed. The only case that we will completely retry is
|
||||
* when FspRtlOplockBreakH returns STATUS_PENDING.
|
||||
*
|
||||
* So in a nutshell, this routine emulates what happens with FastFat during
|
||||
* STATUS_SHARING_VIOLATION processing. However FastFat tries to break batch
|
||||
* oplocks before the share access check. Unfortunately this is hard to do in
|
||||
* this FSD, so we have to emulate this behavior.
|
||||
*/
|
||||
|
||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||
FSP_FSCTL_TRANSACT_RSP *Response = FspIopIrpResponse(Irp);
|
||||
FSP_FILE_NODE *FileNode = FspIopRequestContext(Request, FspIopRequestExtraContext);
|
||||
BOOLEAN StatusSharingViolation = TRUE, OpbatchBreakUnderway = FALSE;
|
||||
KEVENT Event;
|
||||
NTSTATUS Result;
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
FspFileNodeAcquireShared(FileNode, Main);
|
||||
|
||||
if (FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(FileNode)))
|
||||
{
|
||||
Result = FspCheckOplock(FspFileNodeAddrOfOplock(FileNode), Irp,
|
||||
&Event, FspFsvolCreateSharingViolationOplockComplete, 0);
|
||||
if (STATUS_PENDING == Result)
|
||||
{
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);
|
||||
if (STATUS_SUCCESS == Irp->IoStatus.Status)
|
||||
OpbatchBreakUnderway = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
KeResetEvent(&Event);
|
||||
Result = FspOplockBreakH(FspFileNodeAddrOfOplock(FileNode), Irp, 0,
|
||||
&Event, FspFsvolCreateSharingViolationOplockComplete, 0);
|
||||
if (STATUS_PENDING == Result)
|
||||
{
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);
|
||||
if (STATUS_SUCCESS == Irp->IoStatus.Status)
|
||||
StatusSharingViolation = FALSE;
|
||||
}
|
||||
|
||||
FspFileNodeRelease(FileNode, Main);
|
||||
|
||||
FspFileNodeClose(FileNode, IrpSp->FileObject, FALSE, TRUE);
|
||||
FspFileNodeDereference(FileNode);
|
||||
FspIopRequestContext(Request, FspIopRequestExtraContext) = 0;
|
||||
|
||||
if (StatusSharingViolation)
|
||||
{
|
||||
Response->IoStatus.Status = (UINT32)STATUS_SHARING_VIOLATION;
|
||||
Response->IoStatus.Information = OpbatchBreakUnderway ? FILE_OPBATCH_BREAK_UNDERWAY : 0;
|
||||
}
|
||||
|
||||
FspIopRetryCompleteIrp(Irp, Response, &Result);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static VOID FspFsvolCreateSharingViolationOplockComplete(
|
||||
PVOID Context, PIRP Irp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
KeSetEvent((PKEVENT)Context, FSP_IO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||
FSP_FILE_NODE *FileNode, FSP_FILE_DESC *FileDesc, PFILE_OBJECT FileObject,
|
||||
BOOLEAN FlushImage)
|
||||
@ -1009,7 +1145,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re
|
||||
if (0 == Request)
|
||||
{
|
||||
FspFsvolCreatePostClose(FileDesc);
|
||||
FspFileNodeClose(FileNode, FileObject, TRUE);
|
||||
FspFileNodeClose(FileNode, FileObject, TRUE, TRUE);
|
||||
}
|
||||
|
||||
return DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION;
|
||||
@ -1115,7 +1251,7 @@ static VOID FspFsvolCreateTryOpenRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PV
|
||||
ASSERT(0 != FileObject);
|
||||
|
||||
FspFsvolCreatePostClose(FileDesc);
|
||||
FspFileNodeClose(FileDesc->FileNode, FileObject, TRUE);
|
||||
FspFileNodeClose(FileDesc->FileNode, FileObject, TRUE, TRUE);
|
||||
FspFileNodeDereference(FileDesc->FileNode);
|
||||
FspFileDescDelete(FileDesc);
|
||||
}
|
||||
@ -1142,7 +1278,7 @@ static VOID FspFsvolCreateOverwriteRequestFini(FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
else if (RequestProcessing == State)
|
||||
FspFileNodeReleaseOwner(FileDesc->FileNode, Full, Request);
|
||||
|
||||
FspFileNodeClose(FileDesc->FileNode, FileObject, TRUE);
|
||||
FspFileNodeClose(FileDesc->FileNode, FileObject, TRUE, TRUE);
|
||||
FspFileNodeDereference(FileDesc->FileNode);
|
||||
FspFileDescDelete(FileDesc);
|
||||
}
|
||||
|
@ -712,6 +712,10 @@ enum
|
||||
FspIopCreateRequestNonPagedFlag = 0x02,
|
||||
FspIopCreateRequestWorkItemFlag = 0x04,
|
||||
};
|
||||
enum
|
||||
{
|
||||
FspIopRequestExtraContext = 4,
|
||||
};
|
||||
typedef VOID FSP_IOP_REQUEST_FINI(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]);
|
||||
typedef NTSTATUS FSP_IOP_REQUEST_WORK(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
@ -724,7 +728,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
FSP_IOP_REQUEST_FINI *RequestFini;
|
||||
PVOID Context[4];
|
||||
PVOID Context[4 + 1/*FspIopRequestExtraContext*/];
|
||||
FSP_FSCTL_TRANSACT_RSP *Response;
|
||||
FSP_FSCTL_TRANSACT_REQ_WORK_ITEM *WorkItem;
|
||||
__declspec(align(FSP_FSCTL_TRANSACT_REQ_ALIGNMENT)) UINT8 RequestBuf[];
|
||||
@ -1098,13 +1102,13 @@ VOID FspFileNodeReleaseForeign(FSP_FILE_NODE *FileNode)
|
||||
FileNode = FileNode->MainFileNode;
|
||||
ExReleaseResourceLite(FileNode->Header.Resource);
|
||||
}
|
||||
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult);
|
||||
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
UINT32 GrantedAccess, UINT32 ShareAccess, FSP_FILE_NODE **POpenedFileNode);
|
||||
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
PBOOLEAN PDeletePending);
|
||||
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
|
||||
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
BOOLEAN AlsoCleanup);
|
||||
BOOLEAN RemoveShareAccess, BOOLEAN HandleCleanup);
|
||||
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
|
||||
UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge);
|
||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
||||
|
@ -31,13 +31,13 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags);
|
||||
VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
||||
VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags);
|
||||
VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner);
|
||||
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult);
|
||||
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
UINT32 GrantedAccess, UINT32 ShareAccess, FSP_FILE_NODE **POpenedFileNode);
|
||||
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
PBOOLEAN PDeletePending);
|
||||
VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject);
|
||||
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
BOOLEAN AlsoCleanup);
|
||||
BOOLEAN RemoveShareAccess, BOOLEAN HandleCleanup);
|
||||
NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
|
||||
UINT64 FlushOffset64, ULONG FlushLength, BOOLEAN FlushAndPurge);
|
||||
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
|
||||
@ -447,8 +447,8 @@ VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner)
|
||||
FSP_FILE_NODE_CLR_FLAGS();
|
||||
}
|
||||
|
||||
FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult)
|
||||
NTSTATUS FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
UINT32 GrantedAccess, UINT32 ShareAccess, FSP_FILE_NODE **POpenedFileNode)
|
||||
{
|
||||
/*
|
||||
* Attempt to insert our FileNode into the volume device's generic table.
|
||||
@ -596,13 +596,8 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
if (0 != PResult)
|
||||
*PResult = Result;
|
||||
|
||||
if (!NT_SUCCESS(Result) && STATUS_SHARING_VIOLATION != Result)
|
||||
OpenedFileNode = 0;
|
||||
}
|
||||
|
||||
if (0 != OpenedFileNode)
|
||||
{
|
||||
@ -613,7 +608,9 @@ exit:
|
||||
|
||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||
|
||||
return OpenedFileNode;
|
||||
*POpenedFileNode = OpenedFileNode;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
@ -724,7 +721,7 @@ VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject
|
||||
}
|
||||
|
||||
VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
BOOLEAN AlsoCleanup)
|
||||
BOOLEAN RemoveShareAccess, BOOLEAN HandleCleanup)
|
||||
{
|
||||
/*
|
||||
* Close the FileNode. If the OpenCount becomes zero remove it
|
||||
@ -740,7 +737,7 @@ VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
|
||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||
|
||||
if (AlsoCleanup)
|
||||
if (RemoveShareAccess)
|
||||
{
|
||||
/*
|
||||
* Sharing violations between main file and streams were determined
|
||||
@ -759,10 +756,11 @@ VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject,
|
||||
}
|
||||
|
||||
IoRemoveShareAccess(FileObject, &FileNode->ShareAccess);
|
||||
|
||||
FileNode->HandleCount--;
|
||||
}
|
||||
|
||||
if (HandleCleanup)
|
||||
FileNode->HandleCount--;
|
||||
|
||||
if (0 < FileNode->OpenCount && 0 == --FileNode->OpenCount)
|
||||
{
|
||||
FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName,
|
||||
|
@ -321,7 +321,10 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference)
|
||||
ClearFlag(Irp->Flags, IRP_INPUT_OPERATION | IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
|
||||
}
|
||||
|
||||
if (STATUS_SUCCESS != Result && STATUS_REPARSE != Result && STATUS_BUFFER_OVERFLOW != Result)
|
||||
if (STATUS_SUCCESS != Result &&
|
||||
STATUS_REPARSE != Result &&
|
||||
STATUS_BUFFER_OVERFLOW != Result &&
|
||||
STATUS_SHARING_VIOLATION != Result)
|
||||
Irp->IoStatus.Information = 0;
|
||||
Irp->IoStatus.Status = Result;
|
||||
IoCompleteRequest(Irp, FSP_IO_INCREMENT);
|
||||
|
Loading…
x
Reference in New Issue
Block a user