mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 00:43:00 -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,
|
||||
RequestProcess = 3,
|
||||
|
||||
/* QueryDirectoryRetry */
|
||||
RequestSystemBufferLength = 0,
|
||||
|
||||
/* DirectoryControlComplete retry */
|
||||
RequestDirInfoChangeNumber = 0,
|
||||
};
|
||||
@ -331,6 +334,31 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
|
||||
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(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
BOOLEAN CanWait)
|
||||
@ -354,16 +382,47 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
||||
ULONG SystemBufferLength;
|
||||
PVOID DirInfoBuffer;
|
||||
ULONG DirInfoSize;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||
BOOLEAN Success;
|
||||
|
||||
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 */
|
||||
Success = DEBUGTEST(90, TRUE) &&
|
||||
FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait);
|
||||
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 */
|
||||
Result = FspFileDescResetDirectoryPattern(FileDesc, FileName, RestartScan);
|
||||
@ -388,7 +447,8 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
||||
/* see if the required information is still in the cache and valid! */
|
||||
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
|
||||
{
|
||||
SystemBufferLength = Length;
|
||||
if (0 == SystemBufferLength)
|
||||
SystemBufferLength = Length;
|
||||
|
||||
Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
|
||||
IndexSpecified || RestartScan,
|
||||
@ -405,20 +465,17 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
|
||||
}
|
||||
}
|
||||
else
|
||||
SystemBufferLength = 0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout ?
|
||||
FspFsvolDeviceDirInfoCacheItemSizeMax : Length;
|
||||
{
|
||||
if (0 == SystemBufferLength)
|
||||
SystemBufferLength = 0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout ?
|
||||
FspFsvolDeviceDirInfoCacheItemSizeMax : Length;
|
||||
}
|
||||
|
||||
FspFileNodeConvertExclusiveToShared(FileNode, Full);
|
||||
|
||||
/* buffer the user buffer! */
|
||||
if (SystemBufferLength > FspFsvolDeviceDirInfoCacheItemSizeMax)
|
||||
SystemBufferLength = FspFsvolDeviceDirInfoCacheItemSizeMax;
|
||||
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);
|
||||
Result = FspFsvolQueryDirectoryBufferUserBuffer(
|
||||
FsvolDeviceExtension, Irp, &SystemBufferLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
@ -462,6 +519,13 @@ static NTSTATUS FspFsvolQueryDirectory(
|
||||
ULONG Length = IrpSp->Parameters.QueryDirectory.Length;
|
||||
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 */
|
||||
if (!FileNode->IsDirectory)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
@ -613,6 +613,7 @@ typedef NTSTATUS FSP_WQ_REQUEST_WORK(
|
||||
NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
|
||||
FSP_WQ_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini,
|
||||
BOOLEAN CreateAndPost);
|
||||
VOID FspWqDeleteIrpWorkItem(PIRP Irp);
|
||||
VOID FspWqPostIrpWorkItem(PIRP Irp);
|
||||
#define FspWqCreateIrpWorkItem(I, RW, RF)\
|
||||
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))
|
||||
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),
|
||||
RequestFini, &RequestWorkItem);
|
||||
@ -57,6 +50,18 @@ NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp,
|
||||
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)
|
||||
{
|
||||
FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp);
|
||||
|
Loading…
x
Reference in New Issue
Block a user