mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-29 19:18:39 -05:00 
			
		
		
		
	sys: oplock: misc fixes and improvements
This commit is contained in:
		
							
								
								
									
										105
									
								
								src/sys/create.c
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								src/sys/create.c
									
									
									
									
									
								
							| @@ -981,7 +981,7 @@ NTSTATUS FspFsvolCreateComplete( | ||||
|         /* SUCCESS! */ | ||||
|         FspIopRequestContext(Request, RequestFileDesc) = 0; | ||||
|         Irp->IoStatus.Information = Request->Req.Overwrite.Supersede ? FILE_SUPERSEDED : FILE_OVERWRITTEN; | ||||
|         Result = STATUS_SUCCESS; | ||||
|         Result = Irp->IoStatus.Status; /* get success value from oplock processing */ | ||||
|     } | ||||
|     else | ||||
|         ASSERT(0); | ||||
| @@ -1054,6 +1054,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re | ||||
|                 FspFileNodeClose(FileNode, FileObject, TRUE); | ||||
|             } | ||||
|  | ||||
|             Irp->IoStatus.Information = 0; | ||||
|             return DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; | ||||
|         } | ||||
|     } | ||||
| @@ -1068,7 +1069,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re | ||||
|     /* SUCCESS! */ | ||||
|     FspIopRequestContext(Request, RequestFileDesc) = 0; | ||||
|     Irp->IoStatus.Information = Response->IoStatus.Information; | ||||
|     return STATUS_SUCCESS; | ||||
|     return Irp->IoStatus.Status; /* get success value from oplock processing */ | ||||
| } | ||||
|  | ||||
| static VOID FspFsvolCreatePostClose(FSP_FILE_DESC *FileDesc) | ||||
| @@ -1241,8 +1242,8 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock( | ||||
|      * the CanWait parameter is TRUE. | ||||
|      * | ||||
|      * When CanWait is TRUE the routine is free to wait for any oplocks breaks. We | ||||
|      * try to break both batch and CACHE_HANDLE_LEVEL oplocks and return the | ||||
|      * appropriate status code. | ||||
|      * try to break both Batch and Handle oplocks and return the appropriate status | ||||
|      * code. | ||||
|      * | ||||
|      * We acquire the FileNode shared so allow oplock breaks to happen concurrently. | ||||
|      * See https://www.osronline.com/showthread.cfm?link=248984 | ||||
| @@ -1255,6 +1256,8 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock( | ||||
|     NTSTATUS Result; | ||||
|     BOOLEAN Success; | ||||
|  | ||||
|     ASSERT(FspFsctlTransactCreateKind == Request->Kind); | ||||
|  | ||||
|     Success = DEBUGTEST(90) && | ||||
|         FspFileNodeTryAcquireSharedF(ExtraFileNode, FspFileNodeAcquireMain, CanWait); | ||||
|     if (!Success) | ||||
| @@ -1264,13 +1267,13 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock( | ||||
|     if (!CanWait) | ||||
|     { | ||||
|         /* | ||||
|          * If there is no batch or CACHE_HANDLE_LEVEL oplock we are done; | ||||
|          * else retry in a worker thread to break the oplocks. | ||||
|          * If there is no Batch or Handle oplock we are done; else retry in a | ||||
|          * worker thread to break the oplocks. | ||||
|          */ | ||||
|         Success = DEBUGTEST(90) && | ||||
|             (!FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(ExtraFileNode)) && | ||||
|             (FlagOn(IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED) || | ||||
|                 !FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(ExtraFileNode)))); | ||||
|             !FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(ExtraFileNode)) && | ||||
|             !(!FlagOn(IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED) && | ||||
|                 FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(ExtraFileNode))); | ||||
|  | ||||
|         FspFileNodeRelease(ExtraFileNode, Main); | ||||
|  | ||||
| @@ -1283,44 +1286,36 @@ static NTSTATUS FspFsvolCreateSharingViolationOplock( | ||||
|     } | ||||
|     else | ||||
|     { | ||||
| #if 0 | ||||
|         /* ???: is this needed in this case? */ | ||||
|         Result = FspCheckOplockEx(FspFileNodeAddrOfOplock(ExtraFileNode), Irp, | ||||
|             OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 0, 0, 0); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|         { | ||||
|             Result = STATUS_SHARING_VIOLATION; | ||||
|             goto exit; | ||||
|         } | ||||
| #endif | ||||
|  | ||||
|         if (FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(ExtraFileNode))) | ||||
|         { | ||||
|             /* wait for batch oplock break to complete */ | ||||
|             /* wait for Batch oplock break to complete */ | ||||
|             Result = FspCheckOplock(FspFileNodeAddrOfOplock(ExtraFileNode), Irp, | ||||
|                 0, 0, 0); | ||||
|             if (STATUS_SUCCESS == Result) | ||||
|                 OpbatchBreakUnderway = TRUE; | ||||
|  | ||||
|             /* if a Batch oplock is broken, we still return STATUS_SHARING_VIOLATION */ | ||||
|             Result = STATUS_SHARING_VIOLATION; | ||||
|         } | ||||
|  | ||||
|         Result = STATUS_SHARING_VIOLATION; | ||||
|  | ||||
|         else | ||||
|         if (!FlagOn(IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED) && | ||||
|             FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(ExtraFileNode))) | ||||
|         { | ||||
|             /* wait for CACHE_HANDLE_LEVEL oplock break to complete */ | ||||
|             /* wait for Handle oplock break to complete */ | ||||
|             Result = FspOplockBreakH(FspFileNodeAddrOfOplock(ExtraFileNode), Irp, | ||||
|                 0, 0, 0, 0); | ||||
|         } | ||||
|             ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result); | ||||
|  | ||||
|             /* if a Handle oplock is broken, we can actually retry the sharing check */ | ||||
|         } | ||||
|         else | ||||
|             Result = STATUS_SHARING_VIOLATION; | ||||
|  | ||||
| #if 0 | ||||
|     exit: | ||||
| #endif | ||||
|         FspFileNodeRelease(ExtraFileNode, Main); | ||||
|  | ||||
|         Response = FspIopIrpResponse(Irp); | ||||
|  | ||||
|         if (NT_SUCCESS(Result)) | ||||
|         if (STATUS_SUCCESS == Result) | ||||
|         { | ||||
|             FspFileNodeClose(ExtraFileNode, 0, TRUE); | ||||
|             FspFileNodeDereference(ExtraFileNode); | ||||
| @@ -1348,10 +1343,14 @@ static BOOLEAN FspFsvolCreateOpenOrOverwriteOplock(PIRP Irp, const FSP_FSCTL_TRA | ||||
|     PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject; | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     BOOLEAN OpenRequiringOplock, CheckOplock; | ||||
|     ULONG OplockCount = 0; | ||||
|     NTSTATUS Result; | ||||
|  | ||||
|     ASSERT( | ||||
|         FspFsctlTransactReservedKind == FspIrpRequest(Irp)->Kind || | ||||
|         FspFsctlTransactOverwriteKind == FspIrpRequest(Irp)->Kind); | ||||
|  | ||||
|     /* add oplock key to the file object */ | ||||
|     Result = FspCheckOplockEx(FspFileNodeAddrOfOplock(FileNode), Irp, | ||||
|         OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 0, 0, 0); | ||||
|     if (!NT_SUCCESS(Result)) | ||||
| @@ -1360,22 +1359,13 @@ static BOOLEAN FspFsvolCreateOpenOrOverwriteOplock(PIRP Irp, const FSP_FSCTL_TRA | ||||
|         return FALSE; | ||||
|     } | ||||
|  | ||||
|     OpenRequiringOplock = BooleanFlagOn(IrpSp->Parameters.Create.Options, | ||||
|         FILE_OPEN_REQUIRING_OPLOCK); | ||||
|     CheckOplock = FALSE; | ||||
|     /* get current handle count */ | ||||
|     FspFsvolDeviceLockContextTable(FsvolDeviceObject); | ||||
|     OplockCount = FileNode->HandleCount; | ||||
|     FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); | ||||
|  | ||||
|     if (OpenRequiringOplock) | ||||
|     { | ||||
|         FspFsvolDeviceLockContextTable(FsvolDeviceObject); | ||||
|         OplockCount = FileNode->HandleCount; | ||||
|         FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); | ||||
|  | ||||
|         CheckOplock = 1 < OplockCount; | ||||
|     } | ||||
|  | ||||
|     CheckOplock = CheckOplock || FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(FileNode)); | ||||
|  | ||||
|     if (CheckOplock) | ||||
|     /* if there are more than one handles, perform oplock check */ | ||||
|     if (1 < OplockCount) | ||||
|     { | ||||
|         Result = FspCheckOplock(FspFileNodeAddrOfOplock(FileNode), Irp, | ||||
|             (PVOID)Response, | ||||
| @@ -1388,24 +1378,20 @@ static BOOLEAN FspFsvolCreateOpenOrOverwriteOplock(PIRP Irp, const FSP_FSCTL_TRA | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (OpenRequiringOplock && STATUS_SUCCESS == Result) | ||||
|     /* is an oplock requested during Create? */ | ||||
|     if (STATUS_SUCCESS == Result && | ||||
|         FlagOn(IrpSp->Parameters.Create.Options, FILE_OPEN_REQUIRING_OPLOCK)) | ||||
|     { | ||||
|         Result = FspOplockFsctrlCreate(FspFileNodeAddrOfOplock(FileNode), Irp, OplockCount); | ||||
|         ASSERT(STATUS_PENDING != Result); | ||||
|  | ||||
|         if (STATUS_SUCCESS == Result) | ||||
|             /* if we added an oplock, remember to remove it later in case of failure */ | ||||
|             FspIopRequestContext(FspIrpRequest(Irp), FspIopRequestExtraContext) = Irp; | ||||
|     } | ||||
|  | ||||
|     if (STATUS_SUCCESS != Result && | ||||
|         STATUS_OPLOCK_BREAK_IN_PROGRESS != Result) | ||||
|     { | ||||
|         *PResult = Result; | ||||
|         return FALSE; | ||||
|     } | ||||
|  | ||||
|     *PResult = STATUS_SUCCESS; | ||||
|     return TRUE; | ||||
|     *PResult = Irp->IoStatus.Status = Result; | ||||
|     return STATUS_SUCCESS == Result || STATUS_OPLOCK_BREAK_IN_PROGRESS == Result; | ||||
| } | ||||
|  | ||||
| static VOID FspFsvolCreateOpenOrOverwriteOplockPrepare( | ||||
| @@ -1425,10 +1411,13 @@ static VOID FspFsvolCreateOpenOrOverwriteOplockComplete( | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); | ||||
|     NTSTATUS Result; | ||||
|  | ||||
|     if (FspFsctlTransactReservedKind == Request->Kind) | ||||
|         FspIopRetryCompleteIrp(Irp, FspIopIrpResponse(Irp), &Result); | ||||
|     else | ||||
|     if (FspFsctlTransactOverwriteKind == Request->Kind) | ||||
|         FspIopRetryPrepareIrp(Irp, &Result); | ||||
|     else if (FspFsctlTransactReservedKind == Request->Kind) | ||||
|         FspIopRetryCompleteIrp(Irp, FspIopIrpResponse(Irp), &Result); | ||||
|     else | ||||
|         ASSERT(0); | ||||
| } | ||||
|  | ||||
| NTSTATUS FspCreate( | ||||
|   | ||||
| @@ -324,6 +324,7 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference) | ||||
|  | ||||
|     if (STATUS_SUCCESS != Result && | ||||
|         STATUS_REPARSE != Result && | ||||
|         STATUS_OPLOCK_BREAK_IN_PROGRESS != Result && | ||||
|         STATUS_BUFFER_OVERFLOW != Result && | ||||
|         STATUS_SHARING_VIOLATION != Result) | ||||
|         Irp->IoStatus.Information = 0; | ||||
|   | ||||
| @@ -779,8 +779,8 @@ NTSTATUS FspOplockFsctrlF( | ||||
|             OpenCount); | ||||
|  | ||||
|         /* | ||||
|          * When the IRP is IRP_MJ_FILE_SYSTEM_CONTROL, FsRtlOplockFsctrl always completes the IRP | ||||
|          * (unless it raises). So return STATUS_SUCCESS in that case. | ||||
|          * When the IRP is IRP_MJ_FILE_SYSTEM_CONTROL, FsRtlOplockFsctrl always takes ownership | ||||
|          * of the IRP (unless it raises). So return STATUS_SUCCESS in that case. | ||||
|          */ | ||||
|         if (!Create) | ||||
|             Result = STATUS_SUCCESS; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user