mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 08:53:01 -05:00
sys: IRP_MJ_DIRECTORY_CONTROL: properly support asynchronous I/O
This commit is contained in:
parent
298cd73944
commit
a1c0c58dc2
@ -61,6 +61,9 @@ enum
|
|||||||
RequestAddress = 2,
|
RequestAddress = 2,
|
||||||
RequestProcess = 3,
|
RequestProcess = 3,
|
||||||
|
|
||||||
|
/* QueryDirectoryRetry */
|
||||||
|
RequestSystemBufferLength = 0,
|
||||||
|
|
||||||
/* DirectoryControlComplete retry */
|
/* DirectoryControlComplete retry */
|
||||||
RequestDirInfoChangeNumber = 0,
|
RequestDirInfoChangeNumber = 0,
|
||||||
};
|
};
|
||||||
@ -331,6 +334,31 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline NTSTATUS FspFsvolQueryDirectoryBufferUserBuffer(
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension, PIRP Irp, PULONG PLength)
|
||||||
|
{
|
||||||
|
if (0 != Irp->AssociatedIrp.SystemBuffer)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
ULONG Length = *PLength;
|
||||||
|
|
||||||
|
if (Length > FspFsvolDeviceDirInfoCacheItemSizeMax)
|
||||||
|
Length = FspFsvolDeviceDirInfoCacheItemSizeMax;
|
||||||
|
else if (Length < sizeof(FSP_FSCTL_DIR_INFO) +
|
||||||
|
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR))
|
||||||
|
Length = sizeof(FSP_FSCTL_DIR_INFO) +
|
||||||
|
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR);
|
||||||
|
|
||||||
|
Result = FspBufferUserBuffer(Irp, FSP_FSCTL_ALIGN_UP(Length, PAGE_SIZE), IoWriteAccess);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
*PLength = Length;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static NTSTATUS FspFsvolQueryDirectoryRetry(
|
static NTSTATUS FspFsvolQueryDirectoryRetry(
|
||||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||||
BOOLEAN CanWait)
|
BOOLEAN CanWait)
|
||||||
@ -354,16 +382,47 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
ULONG SystemBufferLength;
|
ULONG SystemBufferLength;
|
||||||
PVOID DirInfoBuffer;
|
PVOID DirInfoBuffer;
|
||||||
ULONG DirInfoSize;
|
ULONG DirInfoSize;
|
||||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||||
BOOLEAN Success;
|
BOOLEAN Success;
|
||||||
|
|
||||||
ASSERT(FileNode == FileDesc->FileNode);
|
ASSERT(FileNode == FileDesc->FileNode);
|
||||||
|
|
||||||
|
SystemBufferLength = 0 != Request ?
|
||||||
|
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestSystemBufferLength) : 0;
|
||||||
|
|
||||||
/* try to acquire the FileNode exclusive; Full because we may need to send a Request */
|
/* try to acquire the FileNode exclusive; Full because we may need to send a Request */
|
||||||
Success = DEBUGTEST(90, TRUE) &&
|
Success = DEBUGTEST(90, TRUE) &&
|
||||||
FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait);
|
FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait);
|
||||||
if (!Success)
|
if (!Success)
|
||||||
return FspWqRepostIrpWorkItem(Irp, FspFsvolQueryDirectoryRetry, 0);
|
{
|
||||||
|
if (0 == SystemBufferLength)
|
||||||
|
SystemBufferLength = 0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout ?
|
||||||
|
FspFsvolDeviceDirInfoCacheItemSizeMax : Length; /* best guess! */
|
||||||
|
|
||||||
|
Result = FspFsvolQueryDirectoryBufferUserBuffer(
|
||||||
|
FsvolDeviceExtension, Irp, &SystemBufferLength);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
Result = FspWqCreateIrpWorkItem(Irp, FspFsvolQueryDirectoryRetry, 0);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
Request = FspIrpRequest(Irp);
|
||||||
|
FspIopRequestContext(Request, RequestSystemBufferLength) =
|
||||||
|
(PVOID)(UINT_PTR)SystemBufferLength;
|
||||||
|
|
||||||
|
FspWqPostIrpWorkItem(Irp);
|
||||||
|
|
||||||
|
return STATUS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we have been retried reset our work item now! */
|
||||||
|
if (0 != Request)
|
||||||
|
{
|
||||||
|
FspWqDeleteIrpWorkItem(Irp);
|
||||||
|
Request = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* set the DirectoryPattern in the FileDesc */
|
/* set the DirectoryPattern in the FileDesc */
|
||||||
Result = FspFileDescResetDirectoryPattern(FileDesc, FileName, RestartScan);
|
Result = FspFileDescResetDirectoryPattern(FileDesc, FileName, RestartScan);
|
||||||
@ -388,7 +447,8 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
/* see if the required information is still in the cache and valid! */
|
/* see if the required information is still in the cache and valid! */
|
||||||
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
|
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
|
||||||
{
|
{
|
||||||
SystemBufferLength = Length;
|
if (0 == SystemBufferLength)
|
||||||
|
SystemBufferLength = Length;
|
||||||
|
|
||||||
Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
|
Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
|
||||||
IndexSpecified || RestartScan,
|
IndexSpecified || RestartScan,
|
||||||
@ -405,20 +465,17 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SystemBufferLength = 0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout ?
|
{
|
||||||
FspFsvolDeviceDirInfoCacheItemSizeMax : Length;
|
if (0 == SystemBufferLength)
|
||||||
|
SystemBufferLength = 0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout ?
|
||||||
|
FspFsvolDeviceDirInfoCacheItemSizeMax : Length;
|
||||||
|
}
|
||||||
|
|
||||||
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
||||||
|
|
||||||
/* buffer the user buffer! */
|
/* buffer the user buffer! */
|
||||||
if (SystemBufferLength > FspFsvolDeviceDirInfoCacheItemSizeMax)
|
Result = FspFsvolQueryDirectoryBufferUserBuffer(
|
||||||
SystemBufferLength = FspFsvolDeviceDirInfoCacheItemSizeMax;
|
FsvolDeviceExtension, Irp, &SystemBufferLength);
|
||||||
else if (SystemBufferLength < sizeof(FSP_FSCTL_DIR_INFO) +
|
|
||||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR))
|
|
||||||
SystemBufferLength = sizeof(FSP_FSCTL_DIR_INFO) +
|
|
||||||
FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR);
|
|
||||||
Result = FspBufferUserBuffer(Irp,
|
|
||||||
FSP_FSCTL_ALIGN_UP(SystemBufferLength, PAGE_SIZE), IoWriteAccess);
|
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
{
|
{
|
||||||
FspFileNodeRelease(FileNode, Full);
|
FspFileNodeRelease(FileNode, Full);
|
||||||
@ -462,6 +519,13 @@ static NTSTATUS FspFsvolQueryDirectory(
|
|||||||
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
|
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
|
||||||
ULONG BaseInfoLen;
|
ULONG BaseInfoLen;
|
||||||
|
|
||||||
|
/* SystemBuffer must be NULL as we are going to be using it! */
|
||||||
|
if (0 != Irp->AssociatedIrp.SystemBuffer)
|
||||||
|
{
|
||||||
|
ASSERT(0);
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
/* only directory files can be queried */
|
/* only directory files can be queried */
|
||||||
if (!FileNode->IsDirectory)
|
if (!FileNode->IsDirectory)
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
@ -613,6 +613,7 @@ typedef NTSTATUS FSP_WQ_REQUEST_WORK(
|
|||||||
NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
|
NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
|
||||||
FSP_WQ_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini,
|
FSP_WQ_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini,
|
||||||
BOOLEAN CreateAndPost);
|
BOOLEAN CreateAndPost);
|
||||||
|
VOID FspWqDeleteIrpWorkItem(PIRP Irp);
|
||||||
VOID FspWqPostIrpWorkItem(PIRP Irp);
|
VOID FspWqPostIrpWorkItem(PIRP Irp);
|
||||||
#define FspWqCreateIrpWorkItem(I, RW, RF)\
|
#define FspWqCreateIrpWorkItem(I, RW, RF)\
|
||||||
FspWqCreateAndPostIrpWorkItem(I, RW, RF, FALSE)
|
FspWqCreateAndPostIrpWorkItem(I, RW, RF, FALSE)
|
||||||
|
19
src/sys/wq.c
19
src/sys/wq.c
@ -30,13 +30,6 @@ NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
else if (IRP_MJ_DIRECTORY_CONTROL == IrpSp->MajorFunction &&
|
|
||||||
IRP_MN_QUERY_DIRECTORY == IrpSp->MinorFunction)
|
|
||||||
{
|
|
||||||
Result = FspBufferUserBuffer(Irp, IrpSp->Parameters.QueryDirectory.Length, IoWriteAccess);
|
|
||||||
if (!NT_SUCCESS(Result))
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result = FspIopCreateRequestWorkItem(Irp, sizeof(WORK_QUEUE_ITEM),
|
Result = FspIopCreateRequestWorkItem(Irp, sizeof(WORK_QUEUE_ITEM),
|
||||||
RequestFini, &RequestWorkItem);
|
RequestFini, &RequestWorkItem);
|
||||||
@ -57,6 +50,18 @@ NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
|
|||||||
return STATUS_PENDING;
|
return STATUS_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID FspWqDeleteIrpWorkItem(PIRP Irp)
|
||||||
|
{
|
||||||
|
FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp);
|
||||||
|
|
||||||
|
ASSERT(RequestWorkItem->Kind == FspFsctlTransactReservedKind);
|
||||||
|
ASSERT(RequestWorkItem->Size == sizeof *RequestWorkItem + sizeof(WORK_QUEUE_ITEM));
|
||||||
|
ASSERT(RequestWorkItem->Hint == (UINT_PTR)Irp);
|
||||||
|
|
||||||
|
FspIopDeleteRequest(RequestWorkItem);
|
||||||
|
FspIrpSetRequest(Irp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
VOID FspWqPostIrpWorkItem(PIRP Irp)
|
VOID FspWqPostIrpWorkItem(PIRP Irp)
|
||||||
{
|
{
|
||||||
FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp);
|
FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user