From ae1901b2c37db8cc4e1f91bb0358acb0e3dcad5f Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Sat, 8 Jul 2017 17:12:33 +0000 Subject: [PATCH] [RXCE] - Define RxShouldPostCompletion() and use it - Define RxIsResourceOwnershipStateExclusive() and use it - Define some magic values [RDBSS] - Implement CheckForLoudOperations(), RxAdjustFileTimesAndSize(), RxIsOkToPurgeFcb() - Continue implementation of RxCommonCleanup() - Fix bugs in the RxCommonCleanup() implementation and make it more explicit when in the delete on close path - Stub RxCleanupPipeQueues(), RxLowIoLockControlShell() - Silent a few DPRINTs CORE-8204 CORE-11327 svn path=/trunk/; revision=75307 --- reactos/sdk/include/ddk/fcb.h | 4 + reactos/sdk/include/ddk/mrx.h | 3 + reactos/sdk/include/ddk/ntrxdef.h | 4 + reactos/sdk/include/ddk/rxprocs.h | 15 ++ reactos/sdk/lib/drivers/rdbsslib/rdbss.c | 282 +++++++++++++++++++++-- reactos/sdk/lib/drivers/rxce/rxce.c | 15 +- 6 files changed, 292 insertions(+), 31 deletions(-) diff --git a/reactos/sdk/include/ddk/fcb.h b/reactos/sdk/include/ddk/fcb.h index 2b53c19438f..a32d0c7f3c2 100644 --- a/reactos/sdk/include/ddk/fcb.h +++ b/reactos/sdk/include/ddk/fcb.h @@ -200,6 +200,7 @@ typedef struct _FCB } FCB, *PFCB; #define FCB_STATE_DELETE_ON_CLOSE 0x00000001 +#define FCB_STATE_TRUNCATE_ON_CLOSE 0x00000002 #define FCB_STATE_PAGING_FILE 0x00000004 #define FCB_STATE_DISABLE_LOCAL_BUFFERING 0x00000010 #define FCB_STATE_TEMPORARY 0x00000020 @@ -287,6 +288,9 @@ typedef struct _SRV_OPEN #define FOBX_FLAG_MATCH_ALL 0x10000 #define FOBX_FLAG_FREE_UNICODE 0x20000 +#define FOBX_FLAG_USER_SET_LAST_WRITE 0x40000 +#define FOBX_FLAG_USER_SET_LAST_ACCESS 0x80000 +#define FOBX_FLAG_USER_SET_LAST_CHANGE 0x200000 #define FOBX_FLAG_DELETE_ON_CLOSE 0x800000 #define FOBX_FLAG_SRVOPEN_CLOSED 0x1000000 #define FOBX_FLAG_UNC_NAME 0x2000000 diff --git a/reactos/sdk/include/ddk/mrx.h b/reactos/sdk/include/ddk/mrx.h index e6bb83ecd38..21156463858 100644 --- a/reactos/sdk/include/ddk/mrx.h +++ b/reactos/sdk/include/ddk/mrx.h @@ -1,6 +1,8 @@ #ifndef _RXMINIRDR_ #define _RXMINIRDR_ +#define RxShouldPostCompletion() ((KeGetCurrentIrql() >= DISPATCH_LEVEL)) + #define RX_REGISTERMINI_FLAG_DONT_PROVIDE_UNCS 0x00000001 #define RX_REGISTERMINI_FLAG_DONT_PROVIDE_MAILSLOTS 0x00000002 #define RX_REGISTERMINI_FLAG_DONT_INIT_DRIVER_DISPATCH 0x00000004 @@ -313,6 +315,7 @@ typedef struct _LOWIO_CONTEXT } LOWIO_CONTEXT; #define LOWIO_CONTEXT_FLAG_SYNCCALL 0x01 +#define LOWIO_CONTEXT_FLAG_SAVEUNLOCKS 0x2 #define LOWIO_CONTEXT_FLAG_LOUDOPS 0x04 #define LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL 0x08 diff --git a/reactos/sdk/include/ddk/ntrxdef.h b/reactos/sdk/include/ddk/ntrxdef.h index 424bdf8af60..da3a9ac75fa 100644 --- a/reactos/sdk/include/ddk/ntrxdef.h +++ b/reactos/sdk/include/ddk/ntrxdef.h @@ -9,9 +9,13 @@ #define RxAllocatePoolWithTag ExAllocatePoolWithTag #define RxFreePool ExFreePool +#define RxIsResourceOwnershipStateExclusive(Resource) (FlagOn((Resource)->Flag, ResourceOwnedExclusive)) + #define RxMdlIsLocked(Mdl) ((Mdl)->MdlFlags & MDL_PAGES_LOCKED) #define RxMdlSourceIsNonPaged(Mdl) ((Mdl)->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) +#define RxGetRequestorProcess(RxContext) IoGetRequestorProcess(RxContext->CurrentIrp) + #define RxAdjustAllocationSizeforCC(Fcb) \ { \ if ((Fcb)->Header.FileSize.QuadPart > (Fcb)->Header.AllocationSize.QuadPart) \ diff --git a/reactos/sdk/include/ddk/rxprocs.h b/reactos/sdk/include/ddk/rxprocs.h index 68c5f1df774..63080ce35dc 100644 --- a/reactos/sdk/include/ddk/rxprocs.h +++ b/reactos/sdk/include/ddk/rxprocs.h @@ -116,6 +116,9 @@ RxMapSystemBuffer( #define FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE 3 #define FCB_MODE_SHARED_STARVE_EXCLUSIVE 4 +#define CHANGE_BUFFERING_STATE_CONTEXT ((PRX_CONTEXT)IntToPtr(0xffffffff)) +#define CHANGE_BUFFERING_STATE_CONTEXT_WAIT ((PRX_CONTEXT)IntToPtr(0xfffffffe)) + NTSTATUS __RxAcquireFcb( _Inout_ PFCB Fcb, @@ -374,6 +377,18 @@ RxFindOrConstructVirtualNetRoot( _In_ PUNICODE_STRING RemainingName); #endif +#if (_WIN32_WINNT >= 0x0600) +NTSTATUS +RxLowIoLockControlShell( + _In_ PRX_CONTEXT RxContext, + _In_ PIRP Irp, + _In_ PFCB Fcb); +#else +NTSTATUS +RxLowIoLockControlShell( + _In_ PRX_CONTEXT RxContext); +#endif + NTSTATUS NTAPI RxChangeBufferingState( diff --git a/reactos/sdk/lib/drivers/rdbsslib/rdbss.c b/reactos/sdk/lib/drivers/rdbsslib/rdbss.c index e1f30e60381..d297a466524 100644 --- a/reactos/sdk/lib/drivers/rdbsslib/rdbss.c +++ b/reactos/sdk/lib/drivers/rdbsslib/rdbss.c @@ -491,6 +491,7 @@ NPAGED_LOOKASIDE_LIST RxContextLookasideList; FAST_MUTEX RxContextPerFileSerializationMutex; RDBSS_DATA RxData; FCB RxDeviceFCB; +BOOLEAN RxLoudLowIoOpsEnabled = FALSE; RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] = { { RxCommonDispatchProblem }, @@ -593,11 +594,31 @@ DECLARE_CONST_UNICODE_STRING(unknownId, L"???"); /* FUNCTIONS ****************************************************************/ +/* + * @implemented + */ VOID CheckForLoudOperations( PRX_CONTEXT RxContext) { - UNIMPLEMENTED; + PAGED_CODE(); + +#define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL)) + + /* Are loud operations enabled? */ + if (RxLoudLowIoOpsEnabled) + { + PFCB Fcb; + + /* If so, the operation will be loud only if filename ends with all.scr */ + Fcb = (PFCB)RxContext->pFcb; + if (RtlCompareMemory(Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, (Fcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)), + L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH) + { + SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS); + } + } +#undef ALLSCR_LENGTH } /* @@ -746,6 +767,106 @@ RxAddToWorkque( ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue); } +/* + * @implemented + */ +VOID +RxAdjustFileTimesAndSize( + PRX_CONTEXT Context) +{ + PFCB Fcb; + PFOBX Fobx; + NTSTATUS Status; + PFILE_OBJECT FileObject; + LARGE_INTEGER CurrentTime; + FILE_BASIC_INFORMATION FileBasicInfo; + FILE_END_OF_FILE_INFORMATION FileEOFInfo; + BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate; + + PAGED_CODE(); + + FileObject = Context->CurrentIrpSp->FileObject; + /* If Cc isn't initialized, the file was not read nor written, nothing to do */ + if (FileObject->PrivateCacheMap == NULL) + { + return; + } + + /* Get now */ + KeQuerySystemTime(&CurrentTime); + + Fobx = (PFOBX)Context->pFobx; + /* Was the file modified? */ + FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED); + /* We'll set last write if it was modified and user didn't update yet */ + SetLastWrite = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE); + /* File was accessed if: written or read (fastio), we'll update last access if user didn't */ + SetLastAccess = SetLastWrite || + (BooleanFlagOn(FileObject->Flags, FO_FILE_FAST_IO_READ) && + !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS)); + /* We'll set last change if it was modified and user didn't update yet */ + SetLastChange = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE); + + /* Nothing to update? Job done */ + if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange) + { + return; + } + + Fcb = (PFCB)Context->pFcb; + /* By default, we won't issue any MRxSetFileInfoAtCleanup call */ + NeedUpdate = FALSE; + RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo)); + + /* Update lastwrite time if required */ + if (SetLastWrite) + { + NeedUpdate = TRUE; + Fcb->LastWriteTime.QuadPart = CurrentTime.QuadPart; + FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart; + } + + /* Update lastaccess time if required */ + if (SetLastAccess) + { + NeedUpdate = TRUE; + Fcb->LastAccessTime.QuadPart = CurrentTime.QuadPart; + FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart; + } + + /* Update lastchange time if required */ + if (SetLastChange) + { + NeedUpdate = TRUE; + Fcb->LastChangeTime.QuadPart = CurrentTime.QuadPart; + FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart; + } + + /* If one of the date was modified, issue a call to mini-rdr */ + if (NeedUpdate) + { + Context->Info.FileInformationClass = FileBasicInformation; + Context->Info.Buffer = &FileBasicInfo; + Context->Info.Length = sizeof(FileBasicInfo); + + MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context)); + (void)Status; + } + + /* If the file was modified, update its EOF */ + if (FileModified) + { + FileEOFInfo.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart; + + Context->Info.FileInformationClass = FileEndOfFileInformation; + Context->Info.Buffer = &FileEOFInfo; + Context->Info.Length = sizeof(FileEOFInfo); + + MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context)); + (void)Status; + } +} + /* * @implemented */ @@ -1069,6 +1190,13 @@ RxCheckShareAccessPerSrvOpens( return STATUS_SUCCESS; } +VOID +RxCleanupPipeQueues( + PRX_CONTEXT Context) +{ + UNIMPLEMENTED; +} + /* * @implemented */ @@ -1462,8 +1590,9 @@ RxCommonCleanup( NTSTATUS Status; PNET_ROOT NetRoot; PFILE_OBJECT FileObject; - PLARGE_INTEGER TruncateSize; - BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired; + LARGE_INTEGER TruncateSize; + PLARGE_INTEGER TruncateSizePtr; + BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete; PAGED_CODE(); @@ -1545,12 +1674,13 @@ RxCommonCleanup( NetRoot = (PNET_ROOT)Fcb->pNetRoot; FcbTableAcquired = FALSE; - OneLeft = FALSE; + LeftForDelete = FALSE; + OneLeft = (Fcb->UncleanCount == 1); _SEH2_TRY { /* Unclean count and delete on close? Verify whether we're the one */ - if (Fcb->UncleanCount == 1 && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) + if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) { if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE)) { @@ -1572,9 +1702,10 @@ RxCommonCleanup( FcbTableAcquired = TRUE; } + /* That means we'll perform the delete on close! */ if (Fcb->UncleanCount == 1) { - OneLeft = TRUE; + LeftForDelete = TRUE; } else { @@ -1584,18 +1715,82 @@ RxCommonCleanup( } IsFile = FALSE; - TruncateSize = NULL; + TruncateSizePtr = NULL; /* Handle cleanup for pipes and printers */ if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT) { - UNIMPLEMENTED; + RxCleanupPipeQueues(Context); } /* Handle cleanup for files */ else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD) { + Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS; if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE) { - UNIMPLEMENTED; + /* First, unlock */ + FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context); + + /* If there are still locks to release, proceed */ + if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL) + { + RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE); + Context->LowIoContext.ParamsFor.Locks.Flags = 0; + Status = RxLowIoLockControlShell(Context); + } + + /* Fix times and size */ + RxAdjustFileTimesAndSize(Context); + + /* If we're the only one left... */ + if (OneLeft) + { + /* And if we're supposed to delete on close */ + if (LeftForDelete) + { + /* Update the sizes */ + RxAcquirePagingIoResource(Context, Fcb); + Fcb->Header.FileSize.QuadPart = 0; + Fcb->Header.ValidDataLength.QuadPart = 0; + RxReleasePagingIoResource(Context, Fcb); + } + /* Otherwise, call the mini-rdr to adjust sizes */ + else + { + /* File got grown up, fill with zeroes */ + if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) && + (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart)) + { + MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context)); + Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; + } + + /* File was truncated, let mini-rdr proceed */ + if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE)) + { + MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context)); + ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE); + + /* Keep track of file change for Cc uninit */ + TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart; + TruncateSizePtr = &TruncateSize; + } + } + } + + /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */ + if (NeedPurge) + { + if (!OneLeft) + { + NeedPurge = FALSE; + } + } + /* Otherwise, try to see whether we can purge */ + else + { + NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))); + } + IsFile = TRUE; } } @@ -1622,7 +1817,7 @@ RxCommonCleanup( if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL && Fcb->UncleanCount == Fcb->UncachedUncleanCount) { - DPRINT1("Flushing %p due to last cached handle cleanup\n", Context); + DPRINT("Flushing %p due to last cached handle cleanup\n", Context); RxFlushFcbInSystemCache(Fcb, TRUE); } } @@ -1631,7 +1826,7 @@ RxCommonCleanup( /* Always */ if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) { - DPRINT1("Flushing %p on cleanup\n", Context); + DPRINT("Flushing %p on cleanup\n", Context); RxFlushFcbInSystemCache(Fcb, TRUE); } } @@ -1644,32 +1839,32 @@ RxCommonCleanup( if (Fcb->UncachedUncleanCount == Fcb->UncleanCount && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) { - DPRINT1("Flushing FCB in system cache for %p\n", Context); + DPRINT("Flushing FCB in system cache for %p\n", Context); RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE); } } } - /* If purge required, flush */ - if (!OneLeft && NeedPurge) + /* If purge required, and not about to delete, flush */ + if (!LeftForDelete && NeedPurge) { - DPRINT1("Flushing FCB in system cache for %p\n", Context); + DPRINT("Flushing FCB in system cache for %p\n", Context); RxFlushFcbInSystemCache(Fcb, TRUE); } /* If it was a file, drop cache */ if (IsFile) { - DPRINT1("Uninit cache map for file\n"); - RxUninitializeCacheMap(Context, FileObject, TruncateSize); + DPRINT("Uninit cache map for file\n"); + RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr); } - /* If that's the one left, or if it needs purge, flush */ - if (OneLeft || NeedPurge) + /* If that's the one left for deletion, or if it needs purge, flush */ + if (LeftForDelete || NeedPurge) { - RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !OneLeft); - /* Also remove from FCB table */ - if (OneLeft) + RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete); + /* If that's for deletion, also remove from FCB table */ + if (LeftForDelete) { RxRemoveNameNetFcb(Fcb); RxReleaseFcbTableLock(&NetRoot->FcbTable); @@ -4943,12 +5138,43 @@ RxIsMemberOfTopLevelIrpAllocatedContextsList( return Found; } +/* + * @implemented + */ BOOLEAN RxIsOkToPurgeFcb( PFCB Fcb) { - UNIMPLEMENTED; - return FALSE; + PLIST_ENTRY Entry; + + /* No associated SRV_OPEN, it's OK to purge */ + if (IsListEmpty(&Fcb->SrvOpenList)) + { + return TRUE; + } + + /* Only allow to purge if all the associated SRV_OPEN + * - have no outstanding opens ongoing + * - have only read attribute set + */ + for (Entry = Fcb->SrvOpenList.Flink; + Entry != &Fcb->SrvOpenList; + Entry = Entry->Flink) + { + PSRV_OPEN SrvOpen; + + SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks); + + /* Failing previous needs, don't allow purge */ + if (SrvOpen->UncleanFobxCount != 0 || + (SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES) + { + return FALSE; + } + } + + /* All correct, allow purge */ + return TRUE; } /* @@ -5091,6 +5317,14 @@ RxLowIoIoCtlShellCompletion( return Status; } +NTSTATUS +RxLowIoLockControlShell( + IN PRX_CONTEXT RxContext) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + /* * @implemented */ diff --git a/reactos/sdk/lib/drivers/rxce/rxce.c b/reactos/sdk/lib/drivers/rxce/rxce.c index a19832a27e9..9618ec98c3c 100644 --- a/reactos/sdk/lib/drivers/rxce/rxce.c +++ b/reactos/sdk/lib/drivers/rxce/rxce.c @@ -5116,7 +5116,7 @@ RxLowIoCompletionTail( DPRINT("RxLowIoCompletionTail(%p)\n", RxContext); /* Only continue if we're at APC_LEVEL or lower */ - if (KeGetCurrentIrql() >= DISPATCH_LEVEL && + if (RxShouldPostCompletion() && !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL)) { return STATUS_MORE_PROCESSING_REQUIRED; @@ -5755,7 +5755,8 @@ RxpDereferenceAndFinalizeNetFcb( if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE)) { - if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2) + if (RxContext != NULL && RxContext != CHANGE_BUFFERING_STATE_CONTEXT && + RxContext != CHANGE_BUFFERING_STATE_CONTEXT_WAIT) { RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK; } @@ -7807,11 +7808,11 @@ RxTrackerUpdateHistory( { Case = RX_FCBTRACKER_CASE_NULLCONTEXT; } - else if ((ULONG_PTR)RxContext == -1) + else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT) { Case = RX_FCBTRACKER_CASE_CBS_CONTEXT; } - else if ((ULONG_PTR)RxContext == -2) + else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT) { Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT; } @@ -8211,7 +8212,7 @@ __RxAcquireFcb( SpecialContext = FALSE; ContextIsPresent = FALSE; /* Check for special context */ - if ((ULONG_PTR)RxContext == -1 || (ULONG_PTR)RxContext == -2) + if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT || RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT) { SpecialContext = TRUE; } @@ -8374,7 +8375,7 @@ __RxReleaseFcb( RxAcquireSerializationMutex(); BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING); - IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive); + IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource); /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock), * then just release the FCB @@ -8421,7 +8422,7 @@ __RxReleaseFcbForThread( RxAcquireSerializationMutex(); BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING); - IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive); + IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource); /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock), * then just release the FCB