sys: IRP_MJ_DIRECTORY_CONTROL: properly support asynchronous I/O

This commit is contained in:
Bill Zissimopoulos 2016-03-30 15:43:26 -07:00
parent 298cd73944
commit a1c0c58dc2
3 changed files with 90 additions and 20 deletions

View File

@ -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,6 +447,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
/* see if the required information is still in the cache and valid! */
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
{
if (0 == SystemBufferLength)
SystemBufferLength = Length;
Result = FspFsvolQueryDirectoryCopyCache(FileDesc,
@ -405,20 +465,17 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
}
}
else
{
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;

View File

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

View File

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