mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 19:48: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, | ||||
|     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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user