mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-31 03:58:38 -05:00 
			
		
		
		
	sys: IRP_MJ_DIRECTORY_CONTROL: properly support asynchronous I/O
This commit is contained in:
		| @@ -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); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user