From ba78fbb95630c61f1875d01af233865ce221cb6f Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 22 Nov 2016 14:18:10 -0800 Subject: [PATCH] sys: rename: oplock refactoring --- src/sys/driver.h | 5 +- src/sys/file.c | 161 ++++++++++++++++++++++++++++----------- src/sys/fileinfo.c | 186 +++++++++++++++++++++++---------------------- 3 files changed, 214 insertions(+), 138 deletions(-) mode change 100644 => 100755 src/sys/file.c diff --git a/src/sys/driver.h b/src/sys/driver.h index 9f4a4e92..adc6a82e 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -1123,8 +1123,9 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams( FSP_FILE_NODE *FileNode, ULONG AcquireFlags, PUNICODE_STRING StreamFileName); -BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, - FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName); +NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, + FSP_FILE_NODE *FileNode, ULONG AcquireFlags, + PUNICODE_STRING FileName, BOOLEAN CheckingOldName); VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName); VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); diff --git a/src/sys/file.c b/src/sys/file.c old mode 100644 new mode 100755 index 2e25f650..fd39b67f --- a/src/sys/file.c +++ b/src/sys/file.c @@ -48,8 +48,9 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams( FSP_FILE_NODE *FileNode, ULONG AcquireFlags, PUNICODE_STRING StreamFileName); -BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, - FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName); +NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, + FSP_FILE_NODE *FileNode, ULONG AcquireFlags, + PUNICODE_STRING FileName, BOOLEAN CheckingOldName); VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName); VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); @@ -851,7 +852,7 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode, return IoStatus.Status; } -#define GATHER_DESCENDANTS(FILENAME, SUBPATHONLY, REFERENCE, ...)\ +#define GATHER_DESCENDANTS(FILENAME, REFERENCE, ...)\ FSP_FILE_NODE *DescendantFileNode;\ FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\ ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\ @@ -862,7 +863,7 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode, for (;;) \ { \ DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\ - FILENAME, SUBPATHONLY, &RestartKey);\ + FILENAME, FALSE, &RestartKey);\ if (0 == DescendantFileNode) \ break; \ ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\ @@ -882,7 +883,7 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode, for (;;) \ { \ DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\ - FILENAME, SUBPATHONLY, &RestartKey);\ + FILENAME, FALSE, &RestartKey);\ if (0 == DescendantFileNode)\ break; \ ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\ @@ -934,7 +935,7 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams( FspFsvolDeviceLockContextTable(FsvolDeviceObject); - GATHER_DESCENDANTS(&FileNode->FileName, FALSE, TRUE, + GATHER_DESCENDANTS(&FileNode->FileName, TRUE, if (DescendantFileNode->FileName.Length > FileNameLength && L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)]) break; @@ -1028,42 +1029,36 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams( return Result; } -BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, - FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName) +NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, + FSP_FILE_NODE *FileNode, ULONG AcquireFlags, + PUNICODE_STRING FileName, BOOLEAN CheckingOldName) { PAGED_CODE(); - BOOLEAN CheckingOldName = 0 != FileNode; - BOOLEAN HasOpenHandles; - BOOLEAN Success = TRUE; + NTSTATUS Result; + ULONG HasHandles, IsBatchOplock, IsHandleOplock; FspFsvolDeviceLockContextTable(FsvolDeviceObject); - /* if we are checking the existing file name, do a quick check here */ - if (CheckingOldName) + if (CheckingOldName && !FileNode->IsDirectory && 1 == FileNode->HandleCount) { - /* if file has single open handle (also means no streams open) and not a directory, exit now */ - if (1 == FileNode->HandleCount && !FileNode->IsDirectory) - { - FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); - return TRUE; - } - - /* Note: when CheckingOldName==TRUE, the old FileNode is not included in enumerations below */ + /* quick exit */ + FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); + return STATUS_SUCCESS; } - GATHER_DESCENDANTS(FileName, CheckingOldName, TRUE, + GATHER_DESCENDANTS(FileName, TRUE, DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode | (0 < DescendantFileNode->HandleCount))); + FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); + if (0 == DescendantFileNodeCount) { - ASSERT(Success); - goto unlock_exit; + Result = STATUS_SUCCESS; + goto exit; } - FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); - /* * At this point all descendant FileNode's are enumerated and referenced. * There can be no new FileNode's because Rename has acquired the device's @@ -1079,29 +1074,103 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, DescendantFileNodeIndex++) { DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex]; - DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~1); + DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7); - Success = MmFlushImageSection(&DescendantFileNode->NonPaged->SectionObjectPointers, - MmFlushForDelete); - if (!Success) - goto unlock_exit; + if (!MmFlushImageSection(&DescendantFileNode->NonPaged->SectionObjectPointers, + MmFlushForDelete)) + { + /* release the FileNode in case of failure! */ + FspFileNodeReleaseF(FileNode, AcquireFlags); + + Result = STATUS_ACCESS_DENIED; + goto exit; + } } } /* break any Batch or Handle oplocks on descendants */ + Result = STATUS_SUCCESS; for ( DescendantFileNodeIndex = 0; DescendantFileNodeCount > DescendantFileNodeIndex; DescendantFileNodeIndex++) { DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex]; - HasOpenHandles = (UINT_PTR)DescendantFileNode & 1; - DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~1); + HasHandles = (UINT_PTR)DescendantFileNode & 1; + DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7); - if (HasOpenHandles) - if (FspFileNodeOplockIsBatch(DescendantFileNode) || - FspFileNodeOplockIsHandle(DescendantFileNode)) - FspFileNodeOplockCheck(DescendantFileNode, OplockIrp); + if (!HasHandles) + continue; + + if (FspFileNodeOplockIsBatch(DescendantFileNode)) + { + NTSTATUS Result0 = FspFileNodeOplockCheckEx(DescendantFileNode, OplockIrp, + OPLOCK_FLAG_COMPLETE_IF_OPLOCKED); + if (STATUS_SUCCESS == Result0) + Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result; + else + if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0) + { + Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result; + DescendantFileNodes[DescendantFileNodeIndex] = + (PVOID)((UINT_PTR)DescendantFileNode | 2); + } + else + Result = STATUS_ACCESS_DENIED; + } + else + if (FspFileNodeOplockIsHandle(DescendantFileNode)) + { + NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp, + OPLOCK_FLAG_COMPLETE_IF_OPLOCKED); + if (STATUS_SUCCESS == Result0) + Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result; + else + if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0) + { + Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result; + DescendantFileNodes[DescendantFileNodeIndex] = + (PVOID)((UINT_PTR)DescendantFileNode | 2); + } + else + Result = STATUS_ACCESS_DENIED; + } + } + + if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result || !NT_SUCCESS(Result)) + { + /* release the FileNode so that we can safely wait without deadlocks */ + FspFileNodeReleaseF(FileNode, AcquireFlags); + + /* wait for oplock breaks to finish */ + for ( + DescendantFileNodeIndex = 0; + DescendantFileNodeCount > DescendantFileNodeIndex; + DescendantFileNodeIndex++) + { + DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex]; + IsBatchOplock = (UINT_PTR)DescendantFileNode & 2; + IsHandleOplock = (UINT_PTR)DescendantFileNode & 4; + DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7); + + if (IsBatchOplock) + { + NTSTATUS Result0 = FspFileNodeOplockCheck(DescendantFileNode, OplockIrp); + ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0); + if (STATUS_SUCCESS != Result0) + Result = STATUS_ACCESS_DENIED; + } + else + if (IsHandleOplock) + { + NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp, 0); + ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0); + if (STATUS_SUCCESS != Result0) + Result = STATUS_ACCESS_DENIED; + } + } + + goto exit; } FspFsvolDeviceLockContextTable(FsvolDeviceObject); @@ -1111,23 +1180,27 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, for (;;) { DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, - FileName, CheckingOldName, &RestartKey); + FileName, FALSE, &RestartKey); if (0 == DescendantFileNode) break; - if (0 < DescendantFileNode->HandleCount) + /* if this is the FileNode being renamed then HandleCount must be 1, else 0 */ + if ((DescendantFileNode == FileNode) < DescendantFileNode->HandleCount) { - Success = FALSE; - goto unlock_exit; + /* release the FileNode in case of failure! */ + FspFileNodeReleaseF(FileNode, AcquireFlags); + + Result = STATUS_ACCESS_DENIED; + break; } } -unlock_exit: FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); +exit: SCATTER_DESCENDANTS(TRUE); - return Success; + return Result; } VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) @@ -1160,7 +1233,7 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) FspFsvolDeviceLockContextTable(FsvolDeviceObject); - GATHER_DESCENDANTS(&FileNode->FileName, FALSE, FALSE, {}); + GATHER_DESCENDANTS(&FileNode->FileName, FALSE, {}); FileNameLength = FileNode->FileName.Length; for ( diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index c997a975..e2eb5ed8 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -1159,7 +1159,7 @@ static NTSTATUS FspFsvolSetRenameInformation( FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ? TargetFileObject->FsContext : 0; - FSP_FSCTL_TRANSACT_REQ *Request; + FSP_FSCTL_TRANSACT_REQ *Request = 0; UNICODE_STRING Remain, Suffix; UNICODE_STRING NewFileName; PUINT8 NewFileNameBuffer; @@ -1186,91 +1186,62 @@ static NTSTATUS FspFsvolSetRenameInformation( ASSERT(TargetFileNode->IsDirectory); } -retry: FspFsvolDeviceFileRenameAcquireExclusive(FsvolDeviceObject); +retry: FspFileNodeAcquireExclusive(FileNode, Full); - /* - * Perform oplock check. - * - * It is ok to block our thread during receipt of the SetInformation IRP. - * However we cannot acquire the FileNode exclusive and wait for oplock - * breaks to complete, because oplock break processing acquires the FileNode - * shared. - * - * Instead we initiate the oplock breaks and then check if any are in progress. - * If that is the case we release the FileNode and wait for the oplock breaks - * to complete. Once they are complete we retry the whole thing. - */ - Result = FspFileNodeOplockCheckEx(FileNode, Irp, - OPLOCK_FLAG_COMPLETE_IF_OPLOCKED); - if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result || - DEBUGTEST_EX(NT_SUCCESS(Result), 10, FALSE)) + if (0 == Request) { - FspFileNodeRelease(FileNode, Full); - FspFsvolDeviceFileRenameRelease(FsvolDeviceObject); - Result = FspFileNodeOplockCheck(FileNode, Irp); - if (!NT_SUCCESS(Result)) - return Result; - goto retry; - } - if (!NT_SUCCESS(Result)) - goto unlock_exit; + if (0 != TargetFileNode) + Remain = TargetFileNode->FileName; + else + FspFileNameSuffix(&FileNode->FileName, &Remain, &Suffix); - if (0 != TargetFileNode) - Remain = TargetFileNode->FileName; - else - FspFileNameSuffix(&FileNode->FileName, &Remain, &Suffix); + Suffix.Length = (USHORT)Info->FileNameLength; + Suffix.Buffer = Info->FileName; + /* if there is a backslash anywhere in the NewFileName get its suffix */ + for (PWSTR P = Suffix.Buffer, EndP = P + Suffix.Length / sizeof(WCHAR); EndP > P; P++) + if (L'\\' == *P) + { + Suffix.Length = (USHORT)((EndP - P - 1) * sizeof(WCHAR)); + Suffix.Buffer = P + 1; + } + Suffix.MaximumLength = Suffix.Length; - Suffix.Length = (USHORT)Info->FileNameLength; - Suffix.Buffer = Info->FileName; - /* if there is a backslash anywhere in the NewFileName get its suffix */ - for (PWSTR P = Suffix.Buffer, EndP = P + Suffix.Length / sizeof(WCHAR); EndP > P; P++) - if (L'\\' == *P) + if (!FspFileNameIsValid(&Remain, 0, 0) || !FspFileNameIsValid(&Suffix, 0, 0)) { - Suffix.Length = (USHORT)((EndP - P - 1) * sizeof(WCHAR)); - Suffix.Buffer = P + 1; + /* cannot rename streams (WinFsp limitation) */ + Result = STATUS_INVALID_PARAMETER; + goto unlock_exit; } - Suffix.MaximumLength = Suffix.Length; - if (!FspFileNameIsValid(&Remain, 0, 0) || !FspFileNameIsValid(&Suffix, 0, 0)) - { - /* cannot rename streams (WinFsp limitation) */ - Result = STATUS_INVALID_PARAMETER; - goto unlock_exit; + AppendBackslash = sizeof(WCHAR) < Remain.Length; + NewFileName.Length = NewFileName.MaximumLength = + Remain.Length + AppendBackslash * sizeof(WCHAR) + Suffix.Length; + + Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, + NewFileName.Length + sizeof(WCHAR), + FspFsvolSetInformationRequestFini, &Request); + if (!NT_SUCCESS(Result)) + goto unlock_exit; + + NewFileNameBuffer = Request->Buffer + Request->FileName.Size; + NewFileName.Buffer = (PVOID)NewFileNameBuffer; + + RtlCopyMemory(NewFileNameBuffer, Remain.Buffer, Remain.Length); + *(PWSTR)(NewFileNameBuffer + Remain.Length) = L'\\'; + RtlCopyMemory(NewFileNameBuffer + Remain.Length + AppendBackslash * sizeof(WCHAR), + Suffix.Buffer, Suffix.Length); + *(PWSTR)(NewFileNameBuffer + NewFileName.Length) = L'\0'; + + Request->Kind = FspFsctlTransactSetInformationKind; + Request->Req.SetInformation.UserContext = FileNode->UserContext; + Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2; + Request->Req.SetInformation.FileInformationClass = FileRenameInformation; + Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size; + Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR); } - AppendBackslash = sizeof(WCHAR) < Remain.Length; - NewFileName.Length = NewFileName.MaximumLength = - Remain.Length + AppendBackslash * sizeof(WCHAR) + Suffix.Length; - - Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, - NewFileName.Length + sizeof(WCHAR), - FspFsvolSetInformationRequestFini, &Request); - if (!NT_SUCCESS(Result)) - goto unlock_exit; - - NewFileNameBuffer = Request->Buffer + Request->FileName.Size; - NewFileName.Buffer = (PVOID)NewFileNameBuffer; - - RtlCopyMemory(NewFileNameBuffer, Remain.Buffer, Remain.Length); - *(PWSTR)(NewFileNameBuffer + Remain.Length) = L'\\'; - RtlCopyMemory(NewFileNameBuffer + Remain.Length + AppendBackslash * sizeof(WCHAR), - Suffix.Buffer, Suffix.Length); - *(PWSTR)(NewFileNameBuffer + NewFileName.Length) = L'\0'; - - Request->Kind = FspFsctlTransactSetInformationKind; - Request->Req.SetInformation.UserContext = FileNode->UserContext; - Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2; - Request->Req.SetInformation.FileInformationClass = FileRenameInformation; - Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size; - Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR); - - FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request); - FspFileNodeSetOwner(FileNode, Full, Request); - FspIopRequestContext(Request, RequestFileNode) = FileNode; - FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject; - /* * Special rules for renaming open files: * - A file cannot be renamed if it has any open handles, @@ -1281,29 +1252,60 @@ retry: * - A directory cannot be renamed if it or any of its subdirectories contains a file * that has open handles (except in the batch-oplock case described earlier). */ - Result = STATUS_SUCCESS; - if (!FspFileNodeRenameCheck(FsvolDeviceObject, Irp, FileNode, &FileNode->FileName) || - (0 != FspFileNameCompare(&FileNode->FileName, &NewFileName, !FileDesc->CaseSensitive, 0) && - !FspFileNodeRenameCheck(FsvolDeviceObject, Irp, 0, &NewFileName))) - Result = STATUS_ACCESS_DENIED; - if (!NT_SUCCESS(Result)) - return Result; - /* - * If the new file name is *exactly* the same (including case) as the old one, - * there is no need to go to the user mode file system. Just return STATUS_SUCCESS. - * Our RequestFini will do any cleanup necessary. - * - * This check needs to be done *after* the open handle test above. This is what FASTFAT - * and NTFS do. - */ - if (0 == FspFileNameCompare(&FileNode->FileName, &NewFileName, FALSE, 0)) - return STATUS_SUCCESS; + Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp, + FileNode, FspFileNodeAcquireFull, + &FileNode->FileName, TRUE); + /* FspFileNodeRenameCheck releases FileNode with STATUS_OPLOCK_BREAK_IN_PROGRESS or failure */ + if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result) + goto retry; + if (!NT_SUCCESS(Result)) + { + Result = STATUS_ACCESS_DENIED; + goto rename_unlock_exit; + } + + if (0 != FspFileNameCompare(&FileNode->FileName, &NewFileName, !FileDesc->CaseSensitive, 0)) + { + Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp, + FileNode, FspFileNodeAcquireFull, + &NewFileName, FALSE); + /* FspFileNodeRenameCheck releases FileNode with STATUS_OPLOCK_BREAK_IN_PROGRESS or failure */ + if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result) + goto retry; + if (!NT_SUCCESS(Result)) + { + Result = STATUS_ACCESS_DENIED; + goto rename_unlock_exit; + } + } + else + { + /* + * If the new file name is *exactly* the same (including case) as the old one, + * there is no need to go to the user mode file system. Just return STATUS_SUCCESS. + * Our RequestFini will do any cleanup necessary. + * + * This check needs to be done *after* the open handle test above. This is what FASTFAT + * and NTFS do. + */ + if (0 == FspFileNameCompare(&FileNode->FileName, &NewFileName, FALSE, 0)) + { + Result = STATUS_SUCCESS; + goto unlock_exit; + } + } + + FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request); + FspFileNodeSetOwner(FileNode, Full, Request); + FspIopRequestContext(Request, RequestFileNode) = FileNode; + FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject; return FSP_STATUS_IOQ_POST; unlock_exit: FspFileNodeRelease(FileNode, Full); +rename_unlock_exit: FspFsvolDeviceFileRenameRelease(FsvolDeviceObject); return Result;