PSRV_OPEN SrvOpen,
PLIST_ENTRY DiscardedRequests);
+VOID
+NTAPI
+RxScavengerTimerRoutine(
+ PVOID Context);
+
+VOID
+NTAPI
+RxTimerDispatch(
+ _In_ struct _KDPC *Dpc,
+ _In_opt_ PVOID DeferredContext,
+ _In_opt_ PVOID SystemArgument1,
+ _In_opt_ PVOID SystemArgument2);
+
VOID
NTAPI
RxWorkItemDispatcher(
BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE;
LIST_ENTRY RxSrvCalldownList;
RX_SPIN_LOCK RxStrucSupSpinLock;
-ULONG RdbssReferenceTracingValue;
+#if 0
+ULONG RdbssReferenceTracingValue = (RDBSS_REF_TRACK_SRVCALL | RDBSS_REF_TRACK_NETROOT |
+ RDBSS_REF_TRACK_VNETROOT | RDBSS_REF_TRACK_NETFOBX |
+ RDBSS_REF_TRACK_NETFCB | RDBSS_REF_TRACK_SRVOPEN |
+ RX_PRINT_REF_TRACKING);
+#else
+ULONG RdbssReferenceTracingValue = 0;
+#endif
LARGE_INTEGER RxWorkQueueWaitInterval[RxMaximumWorkQueue];
LARGE_INTEGER RxSpinUpDispatcherWaitInterval;
RX_DISPATCHER RxDispatcher;
FAST_MUTEX RxLowIoPagingIoSyncMutex;
BOOLEAN RxContinueFromAssert = TRUE;
ULONG RxExplodePoolTags = 1;
+LARGE_INTEGER RxTimerInterval;
+RX_SPIN_LOCK RxTimerLock;
+LIST_ENTRY RxTimerQueueHead;
+LIST_ENTRY RxRecurrentWorkItemsList;
+KDPC RxTimerDpc;
+KTIMER RxTimer;
+ULONG RxTimerTickCount;
#if DBG
BOOLEAN DumpDispatchRoutine = TRUE;
#else
/* FUNCTIONS ****************************************************************/
+NTSTATUS
+NTAPI
+RxAcquireExclusiveFcbResourceInMRx(
+ _Inout_ PMRX_FCB Fcb)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+RxAcquireFcbForLazyWrite(
+ PVOID Context,
+ BOOLEAN Wait)
+{
+ PFCB Fcb;
+ BOOLEAN Ret;
+
+ PAGED_CODE();
+
+ Fcb = Context;
+ /* The received context is a FCB */
+ ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+ ASSERT(Fcb->Specific.Fcb.LazyWriteThread == NULL);
+
+ /* Acquire the paging resource (shared) */
+ Ret = ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, Wait);
+ if (Ret)
+ {
+ /* Update tracker information */
+ Fcb->PagingIoResourceFile = __FILE__;
+ Fcb->PagingIoResourceLine = __LINE__;
+ /* Lazy writer thread is the current one */
+ Fcb->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
+
+ /* There is no top level IRP */
+ ASSERT(RxIsThisTheTopLevelIrp(NULL));
+ /* Now, there will be! */
+ Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
+ Fcb->RxDeviceObject, TRUE);
+ /* In case of failure, release the lock and reset everything */
+ if (!Ret)
+ {
+ Fcb->PagingIoResourceFile = NULL;
+ Fcb->PagingIoResourceLine = 0;
+ ExReleaseResourceLite(Fcb->Header.PagingIoResource);
+ Fcb->Specific.Fcb.LazyWriteThread = NULL;
+ }
+ }
+
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+RxAcquireFcbForReadAhead(
+ PVOID Context,
+ BOOLEAN Wait)
+{
+ PFCB Fcb;
+ BOOLEAN Ret;
+
+ PAGED_CODE();
+
+ Fcb = Context;
+ /* The received context is a FCB */
+ ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+
+ Ret = ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait);
+ if (Ret)
+ {
+ /* There is no top level IRP */
+ ASSERT(RxIsThisTheTopLevelIrp(NULL));
+ /* Now, there will be! */
+ Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
+ Fcb->RxDeviceObject, TRUE);
+ /* In case of failure, release the lock and reset everything */
+ if (!Ret)
+ {
+ ExReleaseResourceLite(Fcb->Header.Resource);
+ }
+ }
+
+ return Ret;
+}
+
+VOID
+NTAPI
+RxAcquireFileForNtCreateSection(
+ PFILE_OBJECT FileObject)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxAcquireForCcFlush(
+ PFILE_OBJECT FileObject,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
/*
* @implemented
*/
FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
}
+ DPRINT("Allocated %p\n", Buffer);
+
return Buffer;
}
RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxChangeBufferingState(
+ PSRV_OPEN SrvOpen,
+ PVOID Context,
+ BOOLEAN ComputeNewState)
+{
+ PFCB Fcb;
+ NTSTATUS Status, MiniStatus;
+ ULONG NewBufferingState, OldBufferingState;
+
+ PAGED_CODE();
+
+ DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen, Context, ComputeNewState);
+
+ Fcb = (PFCB)SrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+ /* First of all, mark that buffering state is changing */
+ SetFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
+
+ /* Assume success */
+ Status = STATUS_SUCCESS;
+ _SEH2_TRY
+ {
+ /* If we're asked to compute a new state, ask the mini-rdr for it */
+ if (ComputeNewState)
+ {
+ MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxComputeNewBufferingState,
+ ((PMRX_SRV_OPEN)SrvOpen, Context, &NewBufferingState));
+ if (MiniStatus != STATUS_SUCCESS)
+ {
+ NewBufferingState = 0;
+ }
+ }
+ else
+ {
+ /* If not, use SRV_OPEN state */
+ NewBufferingState = SrvOpen->BufferingFlags;
+ }
+
+ /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
+ if ((Fcb->ShareAccess.SharedRead + Fcb->ShareAccess.SharedWrite + Fcb->ShareAccess.SharedDelete) == 0 && !ComputeNewState)
+ {
+ SetFlag(NewBufferingState, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES);
+ }
+
+ /* If there's a lock operation to complete, clear that flag */
+ if (Fcb->OutstandingLockOperationsCount != 0)
+ {
+ ClearFlag(NewBufferingState, FCB_STATE_LOCK_BUFFERING_ENABLED);
+ }
+
+ /* Get the old state */
+ OldBufferingState = Fcb->FcbState & FCB_STATE_BUFFERING_STATE_MASK;
+ DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags);
+
+ /* If we're dropping write cache, then flush the FCB */
+ if (BooleanFlagOn(OldBufferingState, FCB_STATE_WRITECACHING_ENABLED) &&
+ !BooleanFlagOn(NewBufferingState, FCB_STATE_WRITECACHING_ENABLED))
+ {
+ DPRINT("Flushing\n");
+
+ Status = RxFlushFcbInSystemCache(Fcb, TRUE);
+ }
+
+ /* If we're dropping read cache, then purge */
+ if (Fcb->UncleanCount == 0 ||
+ (BooleanFlagOn(OldBufferingState, FCB_STATE_READCACHING_ENABLED) &&
+ !BooleanFlagOn(NewBufferingState, FCB_STATE_READCACHING_ENABLED)) ||
+ BooleanFlagOn(NewBufferingState, FCB_STATE_DELETE_ON_CLOSE))
+ {
+ DPRINT("Purging\n");
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("Previous flush failed with status: %lx\n", Status);
+ }
+
+ CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, TRUE);
+ }
+
+ /* If there's already a change pending in SRV_OPEN */
+ if (ComputeNewState && BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
+ {
+ /* If there's a FOBX at least */
+ if (!IsListEmpty(&SrvOpen->FobxList))
+ {
+ PRX_CONTEXT RxContext;
+
+ /* Create a fake context to pass to the mini-rdr */
+ RxContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
+ if (RxContext != NULL)
+ {
+ PFOBX Fobx;
+
+ RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
+
+ /* Give the first FOBX */
+ Fobx = CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks);
+ RxContext->pFobx = (PMRX_FOBX)Fobx;
+ RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
+
+ /* If there was a delayed close, perform it */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
+ {
+ DPRINT("Oplock break close for %p\n", SrvOpen);
+
+ RxCloseAssociatedSrvOpen(Fobx, RxContext);
+ }
+ /* Otherwise, inform the mini-rdr about completion */
+ else
+ {
+ MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxCompleteBufferingStateChangeRequest,
+ (RxContext, (PMRX_SRV_OPEN)SrvOpen, Context));
+ (void)MiniStatus;
+ }
+
+ RxDereferenceAndDeleteRxContext(RxContext);
+ }
+ }
+ }
+
+ /* Set the new state */
+ Fcb->FcbState ^= (NewBufferingState ^ Fcb->FcbState) & FCB_STATE_BUFFERING_STATE_MASK;
+ }
+ _SEH2_FINALLY
+ {
+ /* Job done, clear the flag */
+ ClearFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
+
+ if (!BooleanFlagOn(NewBufferingState, FCB_STATE_FILETIMECACHEING_ENABLED))
+ {
+ ClearFlag(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET);
+ }
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
NTSTATUS
RxCheckVNetRootCredentials(
PRX_CONTEXT RxContext,
return NULL;
}
- /* And initialize it */
+ /* Zero it */
RtlZeroMemory(Context, sizeof(RX_CONTEXT));
+
+ /* It was allocated on NP pool, keep track of it! */
+ SetFlag(Context->Flags, RX_CONTEXT_FLAG_FROM_POOL);
+ /* And initialize it */
RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED));
return VNetRoot;
}
+/*
+ * @implemented
+ */
VOID
RxDereference(
IN OUT PVOID Instance,
/* We have to be locked exclusively */
if (LockHoldingState != LHS_ExclusiveLockHeld)
{
- UNIMPLEMENTED;
+ if ((NodeType == RDBSS_NTC_FOBX && RefCount == 0) ||
+ (NodeType >= RDBSS_NTC_SRVCALL && NodeType <= RDBSS_NTC_V_NETROOT))
+ {
+ RxpMarkInstanceForScavengedFinalization(Instance);
+ }
+
RxReleaseScavengerMutex();
return;
}
+ else
+ {
+ if (BooleanFlagOn(NodeType, RX_SCAVENGER_MASK))
+ {
+ RxpUndoScavengerFinalizationMarking(Instance);
+ }
+ }
RxReleaseScavengerMutex();
}
}
+VOID
+NTAPI
+RxDispatchChangeBufferingStateRequests(
+ PVOID Context)
+{
+ UNIMPLEMENTED;
+}
+
/*
* @implemented
*/
return STATUS_SUCCESS;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxFinalizeConnection(
+ IN OUT PNET_ROOT NetRoot,
+ IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
+ IN LOGICAL ForceFilesClosed)
+{
+ NTSTATUS Status;
+ PRX_PREFIX_TABLE PrefixTable;
+ ULONG UncleanAny, UncleanDir;
+ LONG FilesOpen, AdditionalRef;
+ BOOLEAN PrefixLocked, FcbTableLocked, ForceClose;
+
+ PAGED_CODE();
+
+ ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
+
+ /* Get a BOOLEAN out of LOGICAL
+ * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
+ */
+ ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE);
+
+ /* First, delete any notification change */
+ Status = RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot, ForceClose);
+ /* If it failed, continue if forced */
+ if (Status != STATUS_SUCCESS && !ForceFilesClosed)
+ {
+ return Status;
+ }
+ /* Reset status, in case notification deletion failed */
+ Status = STATUS_SUCCESS;
+
+ PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+
+ PrefixLocked = FALSE;
+ FcbTableLocked = FALSE;
+ FilesOpen = 0;
+ AdditionalRef = 0;
+ UncleanAny = 0;
+ UncleanDir = 0;
+ _SEH2_TRY
+ {
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ PrefixLocked = TRUE;
+
+ RxReferenceNetRoot(NetRoot);
+
+ RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
+ FcbTableLocked = TRUE;
+
+ /* If our V_NET_ROOT wasn't finalized yet, proceed! */
+ if (!VNetRoot->ConnectionFinalizationDone)
+ {
+ USHORT Bucket;
+ PRX_FCB_TABLE FcbTable;
+
+ DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix);
+
+ /* We'll browse all its associated FCB to check whether they're open/orphaned */
+ FcbTable = &NetRoot->FcbTable;
+ for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
+ {
+ PLIST_ENTRY BucketList, Entry;
+
+ BucketList = &FcbTable->HashBuckets[Bucket];
+ Entry = BucketList->Flink;
+ while (Entry != BucketList)
+ {
+ PFCB Fcb;
+
+ Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
+ Entry = Entry->Flink;
+
+ /* FCB for this connection, go ahead */
+ if (Fcb->VNetRoot == VNetRoot)
+ {
+ /* It's still open, and no force? Fail and keep track */
+ if (Fcb->UncleanCount > 0 && !ForceClose)
+ {
+ Status = STATUS_CONNECTION_IN_USE;
+ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
+ {
+ ++UncleanDir;
+ }
+ else
+ {
+ ++UncleanAny;
+ }
+ }
+ else
+ {
+ /* Else, force purge */
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
+
+ RxScavengeRelatedFobxs(Fcb);
+ RxPurgeFcb(Fcb);
+
+ /* We don't need to release FCB lock, FCB finalize will take care of it */
+ }
+ }
+ }
+ }
+
+ /* No files left, our V_NET_ROOT is finalized */
+ if (VNetRoot->NumberOfFobxs == 0)
+ {
+ VNetRoot->ConnectionFinalizationDone = TRUE;
+ }
+ }
+
+ /* Keep Number of open files and track of the extra reference */
+ FilesOpen = VNetRoot->NumberOfFobxs;
+ AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken;
+ /* If force close, caller doesn't want to keep connection alive
+ * and wants it totally close, so drop the V_NET_ROOT too
+ */
+ if (ForceClose)
+ {
+ RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE);
+ }
+ }
+ _SEH2_FINALLY
+ {
+ /* Release what was acquired */
+ if (FcbTableLocked)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ }
+
+ /* If close is forced, only fix status if there are open files */
+ if (ForceClose)
+ {
+ if (Status != STATUS_SUCCESS && UncleanAny != 0)
+ {
+ Status = STATUS_FILES_OPEN;
+ }
+ }
+ /* Else, fix status and fail closing if there are open files */
+ else
+ {
+ if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0)
+ {
+ Status = STATUS_FILES_OPEN;
+ }
+ }
+
+ DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen);
+
+ /* If we're are asked to remove the extra ref, or if closing was a success, do it;
+ * only if it was still referenced!
+ */
+ if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0)
+ {
+ VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
+ RxDereferenceVNetRoot(VNetRoot, LHS_ExclusiveLockHeld);
+ }
+
+ if (PrefixLocked)
+ {
+ RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
+ RxReleasePrefixTableLock(PrefixTable);
+ }
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
/*
* @implemented
*/
ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
- DPRINT("Finalizing FCB open: %d (%d)", ThisFcb->OpenCount, ForceFinalize);
+ DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb->OpenCount, ForceFinalize);
/* If finalization was not already initiated, go ahead */
if (!ThisFcb->UpperFinalizationDone)
ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
- RxDereferenceNetRoot(ThisFcb->pNetRoot, LHS_LockNotHeld);
+ RxDereferenceVNetRoot(ThisFcb->VNetRoot, LHS_LockNotHeld);
ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
ASSERT(!ThisFcb->fMiniInited);
HashBucket = &FcbTable->HashBuckets[Bucket];
ListEntry = HashBucket->Flink;
while (ListEntry != HashBucket)
- {
+ {
PFCB Fcb;
Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
return TRUE;
}
-BOOLEAN
+/*
+ * @implemented
+ */
+BOOLEAN
RxFinalizeSrvOpen(
OUT PSRV_OPEN ThisSrvOpen,
IN BOOLEAN RecursiveFinalize,
IN BOOLEAN ForceFinalize)
{
- UNIMPLEMENTED;
- return FALSE;
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ /* We have to have a SRV_OPEN */
+ ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN);
+
+ /* If that's a recursive finalization, finalize any related FOBX */
+ if (RecursiveFinalize)
+ {
+ PLIST_ENTRY ListEntry;
+
+ ListEntry = ThisSrvOpen->FobxList.Flink;
+ while (ListEntry != &ThisSrvOpen->FobxList)
+ {
+ PFOBX Fobx;
+
+ Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
+ ListEntry = ListEntry->Flink;
+ RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
+ }
+ }
+
+ /* If we have still references, don't finalize unless forced */
+ if (ThisSrvOpen->NodeReferenceCount != 0 &&
+ !ForceFinalize)
+ {
+ return FALSE;
+ }
+
+ DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize);
+
+ /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
+ Fcb = (PFCB)ThisSrvOpen->pFcb;
+ if ((!ThisSrvOpen->UpperFinalizationDone && ThisSrvOpen->Condition != Condition_Good) ||
+ BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
+ {
+ PV_NET_ROOT VNetRoot;
+
+ /* Associated FCB can't be fake one */
+ ASSERT(NodeType(Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
+ ASSERT(RxIsFcbAcquiredExclusive (Fcb));
+
+ /* Purge any pending operation */
+ RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen);
+
+ /* If the FCB wasn't orphaned, inform the mini-rdr about close */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ NTSTATUS Status;
+
+ MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen));
+ (void)Status;
+ }
+
+ /* Remove ourselves from the FCB */
+ RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
+ InitializeListHead(&ThisSrvOpen->SrvOpenQLinks);
+ ++Fcb->SrvOpenListVersion;
+
+ /* If we have a V_NET_ROOT, dereference it */
+ VNetRoot = (PV_NET_ROOT)ThisSrvOpen->pVNetRoot;
+ if (VNetRoot != NULL)
+ {
+ InterlockedDecrement((volatile long *)&VNetRoot->pNetRoot->NumberOfSrvOpens);
+ RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
+ ThisSrvOpen->pVNetRoot = NULL;
+ }
+
+ /* Finalization done */
+ ThisSrvOpen->UpperFinalizationDone = TRUE;
+ }
+
+ /* Don't free memory if still referenced */
+ if (ThisSrvOpen->NodeReferenceCount != 0)
+ {
+ return FALSE;
+ }
+
+ /* No key association left */
+ ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList));
+
+ /* If we're still in some FCB, remove us */
+ if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks))
+ {
+ RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
+ }
+
+ /* If enclosed allocation, mark the memory zone free */
+ if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
+ {
+ ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED);
+ }
+ /* Otherwise, free the memory */
+ else
+ {
+ RxFreeFcbObject(ThisSrvOpen);
+ }
+
+ RxDereferenceNetFcb(Fcb);
+
+ return TRUE;
}
/*
IN RX_FILE_TYPE FileType,
IN PFCB_INIT_PACKET InitPacket OPTIONAL)
{
- NODE_TYPE_CODE OldType;
+ RX_FILE_TYPE OldType;
PAGED_CODE();
DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
- OldType = Fcb->Header.NodeTypeCode;
- Fcb->Header.NodeTypeCode = FileType;
+ OldType = NodeType(Fcb);
+ NodeType(Fcb) = FileType;
/* If mini-rdr already did the job for mailslot attributes, 0 the rest */
if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
{
if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
{
- /* If our FCB newly points to a file, initiliaz everything related */
- if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE &&
- OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
+ /* If our FCB newly points to a file, initiliaze everything related */
+ if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE)
+
{
- RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
- FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, &RxLockOperationCompletion,
- &RxUnlockOperation);
+ if (OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
+ {
+ RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
+ FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, RxLockOperationCompletion,
+ RxUnlockOperation);
- ((PFCB)Fcb)->BufferedLocks.List = NULL;
- ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
+ ((PFCB)Fcb)->BufferedLocks.List = NULL;
+ ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
- Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
+ Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
+ }
}
+ /* If not a file, validate type */
else
{
ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
return IoStatus.Status;
}
+/*
+ * @implemented
+ */
VOID
RxFreeFcbObject(
PVOID Object)
{
- UNIMPLEMENTED;
+ PAGED_CODE();
+
+ DPRINT("Freeing %p\n", Object);
+
+ /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
+ if (NodeType(Object) == RDBSS_NTC_FOBX || NodeType(Object) == RDBSS_NTC_SRVOPEN)
+ {
+ RxFreePoolWithTag(Object, RX_FCB_POOLTAG);
+ }
+ /* If that's a FCB... */
+ else if (NodeTypeIsFcb(Object))
+ {
+ PFCB Fcb;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+
+ Fcb = (PFCB)Object;
+ DeviceObject = Fcb->RxDeviceObject;
+
+ /* Delete per stream contexts */
+ FsRtlTeardownPerStreamContexts(&Fcb->Header);
+
+ SetFlag(Fcb->Header.Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH);
+
+ /* If there was a non-paged FCB allocated, free it */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
+ {
+ RxFreePoolWithTag(Fcb->NonPaged, RX_NONPAGEDFCB_POOLTAG);
+ }
+
+ /* Free the FCB */
+ RxFreePool(Fcb);
+
+ /* Update statistics */
+ InterlockedDecrement(&RxNumberOfActiveFcbs);
+ InterlockedDecrement((volatile long *)&DeviceObject->NumberOfActiveFcbs);
+ }
}
/*
RxFreePool(pObject);
}
+/*
+ * @implemented
+ */
+VOID
+RxGatherRequestsForSrvOpen(
+ IN OUT PSRV_CALL SrvCall,
+ IN PSRV_OPEN SrvOpen,
+ IN OUT PLIST_ENTRY RequestsListHead)
+{
+ KIRQL OldIrql;
+ LIST_ENTRY Discarded, *Entry;
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
+
+ /* Dispatch any pending operation first */
+ RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &Discarded);
+
+ /* Then, get any entry related to our key and SRV_OPEN */
+ KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
+ Entry = SrvCall->BufferingManager.HandlerList.Flink;
+ while (Entry != &SrvCall->BufferingManager.HandlerList)
+ {
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+ if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
+ {
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(RequestsListHead, &Request->ListEntry);
+ }
+ }
+ KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
+
+ /* Perform the same search in the last change list */
+ Entry = SrvCall->BufferingManager.LastChanceHandlerList.Flink;
+ while (Entry != &SrvCall->BufferingManager.LastChanceHandlerList)
+ {
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+ if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
+ {
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(RequestsListHead, &Request->ListEntry);
+ }
+ }
+
+ /* Discard the discarded requests */
+ RxpDiscardChangeBufferingStateRequests(&Discarded);
+}
+
+/*
+ * @implemented
+ */
+PRDBSS_DEVICE_OBJECT
+RxGetDeviceObjectOfInstance(
+ PVOID Instance)
+{
+ NODE_TYPE_CODE NodeType;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+
+ PAGED_CODE();
+
+ /* We only handle a few object types */
+ NodeType = NodeType(Instance);
+ ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
+ (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) || (NodeType == RDBSS_NTC_FOBX));
+
+ /* Get the device object depending on the object */
+ switch (NodeType)
+ {
+ case RDBSS_NTC_FOBX:
+ {
+ PFOBX Fobx;
+
+ Fobx = (PFOBX)Instance;
+ DeviceObject = Fobx->RxDeviceObject;
+ break;
+ }
+
+ case RDBSS_NTC_SRVCALL:
+ {
+ PSRV_CALL SrvCall;
+
+ SrvCall = (PSRV_CALL)Instance;
+ DeviceObject = SrvCall->RxDeviceObject;
+ break;
+ }
+
+ case RDBSS_NTC_NETROOT:
+ {
+ PNET_ROOT NetRoot;
+
+ NetRoot = (PNET_ROOT)Instance;
+ DeviceObject = NetRoot->pSrvCall->RxDeviceObject;
+ break;
+ }
+
+ case RDBSS_NTC_V_NETROOT:
+ {
+ PV_NET_ROOT VNetRoot;
+
+ VNetRoot = (PV_NET_ROOT)Instance;
+ DeviceObject = VNetRoot->pNetRoot->pSrvCall->RxDeviceObject;
+ break;
+ }
+
+ case RDBSS_NTC_SRVOPEN:
+ {
+ PSRV_OPEN SrvOpen;
+
+ SrvOpen = (PSRV_OPEN)Instance;
+ DeviceObject = ((PFCB)SrvOpen->pFcb)->RxDeviceObject;
+ break;
+ }
+
+ default:
+ DeviceObject = NULL;
+ break;
+ }
+
+ /* Job done */
+ return DeviceObject;
+}
+
/*
* @implemented
*/
return STATUS_NOT_IMPLEMENTED;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxInitializeRxTimer(
+ VOID)
+{
+ PAGED_CODE();
+
+ RxTimerInterval.QuadPart = -550000;
+ KeInitializeSpinLock(&RxTimerLock);
+ InitializeListHead(&RxTimerQueueHead);
+ InitializeListHead(&RxRecurrentWorkItemsList);
+ KeInitializeDpc(&RxTimerDpc, RxTimerDispatch, NULL);
+ KeInitializeTimer(&RxTimer);
+ RxTimerTickCount = 0;
+
+ return STATUS_SUCCESS;
+}
+
NTSTATUS
RxInitializeVNetRootParameters(
PRX_CONTEXT RxContext,
_SEH2_END;
}
+/*
+ * @implemented
+ */
NTSTATUS
RxLowIoCompletionTail(
IN PRX_CONTEXT RxContext)
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;
Operation = RxContext->LowIoContext.Operation;
if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
{
+ /* Remove ourselves from the list and resume operations */
if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
{
- UNIMPLEMENTED;
- Status = STATUS_NOT_IMPLEMENTED;
+ ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ RemoveEntryList(&RxContext->RxContextSerializationQLinks);
+ RxContext->RxContextSerializationQLinks.Flink = NULL;
+ RxContext->RxContextSerializationQLinks.Blink = NULL;
+ ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ RxResumeBlockedOperations_ALL(RxContext);
}
}
else
return Irp->AssociatedIrp.SystemBuffer;
}
+/*
+ * @implemented
+ */
VOID
RxMarkFobxOnCleanup(
PFOBX pFobx,
PBOOLEAN NeedPurge)
{
- UNIMPLEMENTED;
-}
+ PFCB Fcb;
+ PFOBX ScavengerFobx;
+ LARGE_INTEGER TickCount;
+ PRDBSS_SCAVENGER Scavenger;
-VOID
-RxMarkFobxOnClose(
- PFOBX Fobx)
-{
- UNIMPLEMENTED;
+ PAGED_CODE();
+
+ /* No FOBX, nothing to mark */
+ if (pFobx == NULL)
+ {
+ return;
+ }
+
+ /* Query time for close */
+ KeQueryTickCount(&TickCount);
+
+ Fcb = (PFCB)pFobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
+ RxAcquireScavengerMutex();
+
+ ScavengerFobx = NULL;
+ /* If that's not a file, or even not a disk resource, just mark as dormant */
+ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE || Fcb->VNetRoot->pNetRoot->DeviceType != FILE_DEVICE_DISK)
+ {
+ SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
+ InitializeListHead(&pFobx->ClosePendingList);
+ ++Scavenger->NumberOfDormantFiles;
+ }
+ else
+ {
+ ASSERT(Scavenger->NumberOfDormantFiles >= 0);
+ /* If we're about to reach the maximum dormant of FOBX */
+ if (Scavenger->NumberOfDormantFiles >= Scavenger->MaximumNumberOfDormantFiles)
+ {
+ /* This should never be wrong... */
+ if (!IsListEmpty(&Scavenger->ClosePendingFobxsList))
+ {
+ /* Then, take the first from the list (oldest) and save it for later purge */
+ ScavengerFobx = CONTAINING_RECORD(Scavenger->ClosePendingFobxsList.Flink, FOBX, ClosePendingList);
+ if (ScavengerFobx->pSrvOpen != NULL && ScavengerFobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
+ {
+ *NeedPurge = TRUE;
+ ScavengerFobx = NULL;
+ }
+ else
+ {
+ RxReferenceNetFobx(ScavengerFobx);
+ }
+ }
+ }
+
+ /* Mark ourselves as dormant */
+ SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
+ pFobx->CloseTime.QuadPart = TickCount.QuadPart;
+
+ /* And insert us in the list of dormant files */
+ InsertTailList(&Scavenger->ClosePendingFobxsList, &pFobx->ClosePendingList);
+ /* If scavenger was inactive, start it */
+ if (Scavenger->NumberOfDormantFiles++ == 0 && Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
+ {
+ Scavenger->State = RDBSS_SCAVENGER_DORMANT;
+ RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem, RxScavengerTimerRoutine,
+ Fcb->RxDeviceObject, Scavenger->TimeLimit);
+ }
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* If we had reached max */
+ if (ScavengerFobx != NULL)
+ {
+ NTSTATUS Status;
+
+ /* Purge the oldest FOBX */
+ Status = RxPurgeFobxFromCache(ScavengerFobx);
+ if (Status != STATUS_SUCCESS)
+ {
+ *NeedPurge = TRUE;
+ }
+ }
}
/*
* @implemented
*/
-PVOID
-RxNewMapUserBuffer(
- PRX_CONTEXT RxContext)
+VOID
+RxMarkFobxOnClose(
+ PFOBX Fobx)
{
- PIRP Irp;
+ PFCB Fcb;
+ PRDBSS_SCAVENGER Scavenger;
PAGED_CODE();
- Irp = RxContext->CurrentIrp;
- if (Irp->MdlAddress != NULL)
+ /* No FOBX, nothing to mark */
+ if (Fobx == NULL)
{
- return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ return;
}
- return Irp->UserBuffer;
-}
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
-BOOLEAN
-NTAPI
-RxNoOpAcquire(
- IN PVOID Fcb,
- IN BOOLEAN Wait)
-{
- UNIMPLEMENTED;
+ Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
+
+ RxAcquireScavengerMutex();
+ /* Only mark it if it was already marked as dormant */
+ if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT))
+ {
+ /* If FCB wasn't already decrement, do it now */
+ if (!Fobx->fOpenCountDecremented)
+ {
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+ InterlockedDecrement((volatile long *)&Fcb->OpenCount);
+
+ Fobx->fOpenCountDecremented = TRUE;
+ }
+
+ /* We're no longer dormant */
+ InterlockedDecrement(&Scavenger->NumberOfDormantFiles);
+ ClearFlag(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
+ }
+
+ /* If we were inserted in the scavenger, drop ourselves out */
+ if (!IsListEmpty(&Fobx->ClosePendingList))
+ {
+ RemoveEntryList(&Fobx->ClosePendingList);
+ InitializeListHead(&Fobx->ClosePendingList);
+ }
+
+ RxReleaseScavengerMutex();
+}
+
+/*
+ * @implemented
+ */
+PVOID
+RxNewMapUserBuffer(
+ PRX_CONTEXT RxContext)
+{
+ PIRP Irp;
+
+ PAGED_CODE();
+
+ Irp = RxContext->CurrentIrp;
+ if (Irp->MdlAddress != NULL)
+ {
+ return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ }
+
+ return Irp->UserBuffer;
+}
+
+BOOLEAN
+NTAPI
+RxNoOpAcquire(
+ IN PVOID Fcb,
+ IN BOOLEAN Wait)
+{
+ UNIMPLEMENTED;
return FALSE;
}
VOID
RxOrphanSrvOpens(
IN PV_NET_ROOT ThisVNetRoot)
+{
+ PFCB Fcb;
+ USHORT Bucket;
+ PNET_ROOT NetRoot;
+ PRX_FCB_TABLE FcbTable;
+ PRX_PREFIX_TABLE PrefixTable;
+
+ PAGED_CODE();
+
+ /* Mailslot won't have any SRV_OPEN (to orphan) */
+ NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
+ if (NetRoot->Type == NET_ROOT_MAILSLOT)
+ {
+ return;
+ }
+
+ PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
+
+ FcbTable = &NetRoot->FcbTable;
+ RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
+
+ _SEH2_TRY
+ {
+ /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
+ for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
+ {
+ PLIST_ENTRY BucketList, Entry;
+
+ BucketList = &FcbTable->HashBuckets[Bucket];
+ Entry = BucketList->Flink;
+ while (Entry != BucketList)
+ {
+ Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
+ Entry = Entry->Flink;
+
+ ASSERT(NodeTypeIsFcb(Fcb));
+ RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
+ }
+ }
+
+ /* Of course, don't forget about NULL-entry */
+ if (FcbTable->TableEntryForNull != NULL)
+ {
+ Fcb = CONTAINING_RECORD(FcbTable->TableEntryForNull, FCB, FcbTableEntry.HashLinks);
+ ASSERT(NodeTypeIsFcb(Fcb));
+ RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
+ }
+ }
+ _SEH2_FINALLY
+ {
+ RxReleaseFcbTableLock(FcbTable);
+ }
+ _SEH2_END;
+}
+
+VOID
+RxOrphanSrvOpensForThisFcb(
+ IN PFCB Fcb,
+ IN PV_NET_ROOT ThisVNetRoot,
+ IN BOOLEAN OrphanAll)
{
UNIMPLEMENTED;
}
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;
}
}
/* If locking was OK (or not needed!), attempt finalization */
- if (NT_SUCCESS(Status))
+ if (Status == STATUS_SUCCESS)
{
Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
}
RxReleasePrefixTableLock(PrefixTable);
}
+/*
+ * @implemented
+ */
VOID
RxpDiscardChangeBufferingStateRequests(
_Inout_ PLIST_ENTRY DiscardedRequests)
{
- UNIMPLEMENTED;
+ PLIST_ENTRY Entry;
+
+ PAGED_CODE();
+
+ /* No requests to discard */
+ if (IsListEmpty(DiscardedRequests))
+ {
+ return;
+ }
+
+ /* Free all the discarded requests */
+ Entry = DiscardedRequests->Flink;
+ while (Entry != DiscardedRequests)
+ {
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
+
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+
+ DPRINT("Req %p for %p (%p) discarded\n", Request, Request->SrvOpenKey, Request->SrvOpen);
+
+ RxPrepareRequestForReuse(Request);
+ RxFreePool(Request);
+ }
}
+/*
+ * @implemented
+ */
VOID
RxpDispatchChangeBufferingStateRequests(
PSRV_CALL SrvCall,
PSRV_OPEN SrvOpen,
PLIST_ENTRY DiscardedRequests)
{
- UNIMPLEMENTED;
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ BOOLEAN StartDispatcher;
+ LIST_ENTRY AcceptedReqs;
+ LIST_ENTRY DispatcherList;
+ PRX_BUFFERING_MANAGER BufferingManager;
+
+ /* Initialize our lists */
+ InitializeListHead(&AcceptedReqs);
+ InitializeListHead(DiscardedRequests);
+
+ /* Transfer the requests to dispatch locally */
+ BufferingManager = &SrvCall->BufferingManager;
+ KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
+ RxTransferList(&DispatcherList, &BufferingManager->DispatcherList);
+ KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
+
+ /* If there were requests */
+ if (!IsListEmpty(&DispatcherList))
+ {
+ PLIST_ENTRY Entry;
+
+ /* For each of the entries... */
+ Entry = DispatcherList.Flink;
+ while (Entry != &DispatcherList)
+ {
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
+
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+
+ /* If we have been provided a SRV_OPEN, see whether it matches */
+ if (SrvOpen != NULL)
+ {
+ /* Match, the request is accepted */
+ if (Request->SrvOpenKey == SrvOpen->Key)
+ {
+ Request->SrvOpen = SrvOpen;
+ RxReferenceSrvOpen(SrvOpen);
+
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(&AcceptedReqs, &Request->ListEntry);
+
+ /* Move to the next entry */
+ continue;
+ }
+ else
+ {
+ Status = STATUS_PENDING;
+ }
+ }
+ else
+ {
+ /* No SRV_OPEN provided, try to find one */
+ Status = RxpLookupSrvOpenForRequestLite(SrvCall, Request);
+ }
+
+ /* We found a matching SRV_OPEN, accept the request */
+ if (Status == STATUS_SUCCESS)
+ {
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(&AcceptedReqs, &Request->ListEntry);
+ }
+ /* Another run might help handling it, don't discard it */
+ else if (Status == STATUS_PENDING)
+ {
+ continue;
+ }
+ /* Otherwise, discard the request */
+ else
+ {
+ ASSERT(Status == STATUS_NOT_FOUND);
+
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(DiscardedRequests, &Request->ListEntry);
+ }
+ }
+ }
+
+ KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
+ /* Nothing to dispatch, no need to start dispatcher */
+ if (IsListEmpty(&DispatcherList))
+ {
+ StartDispatcher = FALSE;
+ }
+ else
+ {
+ /* Transfer back the list of the not treated entries to the buffering manager */
+ RxTransferList(&BufferingManager->DispatcherList, &DispatcherList);
+ StartDispatcher = (BufferingManager->DispatcherActive == FALSE);
+ /* If the dispatcher isn't active, start it */
+ if (StartDispatcher)
+ {
+ BufferingManager->DispatcherActive = TRUE;
+ }
+ }
+
+ /* If there were accepted requests, move them to the buffering manager */
+ if (!IsListEmpty(&AcceptedReqs))
+ {
+ RxTransferList(&BufferingManager->HandlerList, &AcceptedReqs);
+ }
+ KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
+
+ /* If we're to start the dispatcher, do it */
+ if (StartDispatcher)
+ {
+ RxReferenceSrvCall(SrvCall);
+ DPRINT("Starting dispatcher\n");
+ RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
+ &BufferingManager->DispatcherWorkItem,
+ RxDispatchChangeBufferingStateRequests, SrvCall);
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxpLookupSrvOpenForRequestLite(
+ IN PSRV_CALL SrvCall,
+ IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request)
+{
+ NTSTATUS Status;
+ PLIST_ENTRY Entry;
+ PSRV_OPEN SrvOpen;
+
+ PAGED_CODE();
+
+ Status = STATUS_SUCCESS;
+ /* Browse all our associated SRV_OPENs to find the one! */
+ for (Entry = SrvCall->BufferingManager.SrvOpenLists[0].Flink;
+ Entry != &SrvCall->BufferingManager.SrvOpenLists[0];
+ Entry = Entry->Flink)
+ {
+ /* Same key, not orphaned, this is ours */
+ SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenKeyList);
+ if (SrvOpen->Key == Request->SrvOpenKey)
+ {
+ if (!BooleanFlagOn(SrvOpen->pFcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ RxReferenceSrvOpen(SrvOpen);
+ break;
+ }
+ }
+ }
+
+ /* We didn't manage to find a SRV_OPEN */
+ if (Entry == &SrvCall->BufferingManager.SrvOpenLists[0])
+ {
+ SrvOpen = NULL;
+
+ /* The coming open might help, mark as pending for later retry */
+ if (SrvCall->BufferingManager.NumberOfOutstandingOpens != 0)
+ {
+ Status = STATUS_PENDING;
+ }
+ /* Else, it's a complete failure */
+ else
+ {
+ Status = STATUS_NOT_FOUND;
+ }
+ }
+
+ /* Return the (not) found SRV_OPEN */
+ Request->SrvOpen = SrvOpen;
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxpMarkInstanceForScavengedFinalization(
+ PVOID Instance)
+{
+ NODE_TYPE_CODE NodeType;
+ PNODE_TYPE_AND_SIZE Node;
+ PRDBSS_SCAVENGER Scavenger;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+ PLIST_ENTRY ScavengerHead, InstEntry;
+
+ PAGED_CODE();
+
+ /* If still referenced, don't mark it (broken caller) */
+ Node = (PNODE_TYPE_AND_SIZE)Instance;
+ if (Node->NodeReferenceCount > 1)
+ {
+ return;
+ }
+
+ DeviceObject = RxGetDeviceObjectOfInstance(Instance);
+ Scavenger = DeviceObject->pRdbssScavenger;
+
+ /* Mark the node */
+ NodeType = NodeType(Instance);
+ SetFlag(NodeType(Node), RX_SCAVENGER_MASK);
+ DPRINT("Node %p has now the scavenger mark!\n", Instance);
+
+ /* Increase the count in the scavenger, and queue it */
+ ScavengerHead = NULL;
+ switch (NodeType)
+ {
+ case RDBSS_NTC_FOBX:
+ ++Scavenger->FobxsToBeFinalized;
+ ScavengerHead = &Scavenger->FobxFinalizationList;
+ InstEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVCALL:
+ ++Scavenger->SrvCallsToBeFinalized;
+ ScavengerHead = &Scavenger->SrvCallFinalizationList;
+ InstEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ ++Scavenger->NetRootsToBeFinalized;
+ ScavengerHead = &Scavenger->NetRootFinalizationList;
+ InstEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ ++Scavenger->VNetRootsToBeFinalized;
+ ScavengerHead = &Scavenger->VNetRootFinalizationList;
+ InstEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVOPEN:
+ ++Scavenger->SrvOpensToBeFinalized;
+ ScavengerHead = &Scavenger->SrvOpenFinalizationList;
+ InstEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
+ break;
+ }
+
+ /* Extra ref for scavenger */
+ InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
+
+ /* If matching type */
+ if (ScavengerHead != NULL)
+ {
+ /* Insert in the scavenger list */
+ InsertTailList(ScavengerHead, InstEntry);
+
+ /* And if it wasn't started, start it */
+ if (Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
+ {
+ Scavenger->State = RDBSS_SCAVENGER_DORMANT;
+ RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
+ RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxPostOneShotTimerRequest(
+ IN PRDBSS_DEVICE_OBJECT pDeviceObject,
+ IN PRX_WORK_ITEM pWorkItem,
+ IN PRX_WORKERTHREAD_ROUTINE Routine,
+ IN PVOID pContext,
+ IN LARGE_INTEGER TimeInterval)
+{
+ KIRQL OldIrql;
+
+ ASSERT(pWorkItem != NULL);
+
+ /* Prepare the work item */
+ ExInitializeWorkItem(&pWorkItem->WorkQueueItem, Routine, pContext);
+ pWorkItem->WorkQueueItem.pDeviceObject = pDeviceObject;
+
+ /* Last tick can be computed with the number of times it was caller (timertickcount)
+ * and the interval between calls
+ */
+ KeAcquireSpinLock(&RxTimerLock, &OldIrql);
+ pWorkItem->LastTick = (TimeInterval.QuadPart / 550000) + RxTimerTickCount + 1;
+ /* Insert in work queue */
+ InsertTailList(&RxTimerQueueHead, &pWorkItem->WorkQueueItem.List);
+ KeReleaseSpinLock(&RxTimerLock, OldIrql);
+
+ /* If there are queued events, queue an execution */
+ if (IsListEmpty(&RxTimerQueueHead))
+ {
+ KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
+ }
+
+ return STATUS_SUCCESS;
}
/*
{
NODE_TYPE_CODE Type;
- Type = NodeType(Container);
+ Type = (NodeType(Container) & ~RX_SCAVENGER_MASK);
switch (Type)
{
case RDBSS_NTC_SRVCALL:
break;
default:
+ DPRINT1("Invalid node type: %x\n", Type);
ASSERT(FALSE);
+ RxReference(Container);
break;
}
}
* @implemented
*/
VOID
-NTAPI
+RxPrepareRequestForReuse(
+ PCHANGE_BUFFERING_STATE_REQUEST Request)
+{
+ PSRV_OPEN SrvOpen;
+
+ PAGED_CODE();
+
+ SrvOpen = Request->SrvOpen;
+
+ /* If the request was already prepared for service */
+ if (BooleanFlagOn(Request->Flags, RX_REQUEST_PREPARED_FOR_HANDLING))
+ {
+ /* We have to dereference the associated SRV_OPEN depending on the lock */
+ if (RxIsFcbAcquiredExclusive(SrvOpen->pFcb))
+ {
+ RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
+ }
+ else
+ {
+ RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
+ }
+ }
+ /* Otherwise, just dereference */
+ else if (SrvOpen != NULL)
+ {
+ RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
+ }
+
+ Request->SrvOpen = NULL;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
RxProcessChangeBufferingStateRequests(
_In_ PVOID SrvCall)
{
RxpProcessChangeBufferingStateRequests(SrvCall, TRUE);
}
+/*
+ * @implemented
+ */
+VOID
+RxProcessChangeBufferingStateRequestsForSrvOpen(
+ PSRV_OPEN SrvOpen)
+{
+ LONG NumberOfBufferingChangeRequests, LockedOldBufferingToken, OldBufferingToken;
+
+ /* Get the current number of change requests */
+ NumberOfBufferingChangeRequests = ((PSRV_CALL)SrvOpen->pVNetRoot->pNetRoot->pSrvCall)->BufferingManager.CumulativeNumberOfBufferingChangeRequests;
+ /* Get our old token */
+ OldBufferingToken = SrvOpen->BufferingToken;
+ LockedOldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken,
+ NumberOfBufferingChangeRequests,
+ NumberOfBufferingChangeRequests);
+ /* If buffering state changed in between, process changes */
+ if (OldBufferingToken != LockedOldBufferingToken)
+ {
+ PFCB Fcb;
+ NTSTATUS Status;
+
+ /* Acquire the FCB and start processing */
+ Fcb = (PFCB)SrvOpen->pFcb;
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ if (Status == STATUS_SUCCESS)
+ {
+ RxProcessFcbChangeBufferingStateRequest(Fcb);
+ RxReleaseFcb(NULL, Fcb);
+ }
+ }
+}
+
VOID
RxProcessFcbChangeBufferingStateRequest(
PFCB Fcb)
UNIMPLEMENTED;
}
+/*
+ * @implemented
+ */
+VOID
+RxpScavengeFobxs(
+ PRDBSS_SCAVENGER Scavenger,
+ PLIST_ENTRY FobxToScavenge)
+{
+ /* Explore the whole list of FOBX to scavenge */
+ while (!IsListEmpty(FobxToScavenge))
+ {
+ PFCB Fcb;
+ PFOBX Fobx;
+ PLIST_ENTRY Entry;
+
+ Entry = RemoveHeadList(FobxToScavenge);
+ Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
+ Fcb = (PFCB)Fobx->SrvOpen->pFcb;
+
+ /* Try to acquire the lock exclusively to perform finalization */
+ if (RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS)
+ {
+ RxDereferenceNetRoot(Fobx, LHS_LockNotHeld);
+ }
+ else
+ {
+ RxReferenceNetFcb(Fcb);
+ RxDereferenceNetRoot(Fobx, LHS_ExclusiveLockHeld);
+
+ if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
+ {
+ RxReleaseFcb(NULL, Fcb);
+ }
+ }
+ }
+}
+
BOOLEAN
RxpTrackDereference(
_In_ ULONG TraceType,
_In_ ULONG Line,
_In_ PVOID Instance)
{
+ PCSTR InstanceType;
+ ULONG ReferenceCount;
+
PAGED_CODE();
if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
return TRUE;
}
- UNIMPLEMENTED;
+ switch (TraceType)
+ {
+ case RDBSS_REF_TRACK_SRVCALL:
+ InstanceType = "SrvCall";
+ ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETROOT:
+ InstanceType = "NetRoot";
+ ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_VNETROOT:
+ InstanceType = "VNetRoot";
+ ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETFOBX:
+ InstanceType = "NetFobx";
+ ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETFCB:
+ InstanceType = "NetFcb";
+ ReferenceCount = ((PFCB)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_SRVOPEN:
+ InstanceType = "SrvOpen";
+ ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount;
+ break;
+
+ default:
+ DPRINT1("Invalid node type!\n");
+ return TRUE;
+ }
+
+ if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING))
+ {
+ UNIMPLEMENTED;
+ }
+
+ if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING))
+ {
+ DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount);
+ }
+
return TRUE;
}
_In_ ULONG Line,
_In_ PVOID Instance)
{
+ PCSTR InstanceType;
+ ULONG ReferenceCount;
+
if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
{
return;
}
- UNIMPLEMENTED;
+ switch (TraceType)
+ {
+ case RDBSS_REF_TRACK_SRVCALL:
+ InstanceType = "SrvCall";
+ ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETROOT:
+ InstanceType = "NetRoot";
+ ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_VNETROOT:
+ InstanceType = "VNetRoot";
+ ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETFOBX:
+ InstanceType = "NetFobx";
+ ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETFCB:
+ InstanceType = "NetFcb";
+ ReferenceCount = ((PFCB)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_SRVOPEN:
+ InstanceType = "SrvOpen";
+ ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount;
+ break;
+
+ default:
+ DPRINT1("Invalid node type!\n");
+ return;
+ }
+
+ if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING))
+ {
+ UNIMPLEMENTED;
+ }
+
+ if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING))
+ {
+ DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount);
+ }
}
+/*
+ * @implemented
+ */
VOID
RxpUndoScavengerFinalizationMarking(
PVOID Instance)
{
+ PLIST_ENTRY ListEntry;
PNODE_TYPE_AND_SIZE Node;
+ PRDBSS_SCAVENGER Scavenger;
PAGED_CODE();
Node = (PNODE_TYPE_AND_SIZE)Instance;
/* There's no marking - nothing to do */
- if (!BooleanFlagOn(Node->NodeTypeCode, RX_SCAVENGER_MASK))
+ if (!BooleanFlagOn(NodeType(Node), RX_SCAVENGER_MASK))
{
return;
}
- UNIMPLEMENTED;
+ /* First of all, remove the mark */
+ ClearFlag(NodeType(Node), RX_SCAVENGER_MASK);
+ DPRINT("Node %p no longer has the scavenger mark\n");
+
+ /* And now, remove from the scavenger */
+ Scavenger = RxGetDeviceObjectOfInstance(Instance)->pRdbssScavenger;
+ switch (NodeType(Node))
+ {
+ case RDBSS_NTC_FOBX:
+ --Scavenger->FobxsToBeFinalized;
+ ListEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVCALL:
+ --Scavenger->SrvCallsToBeFinalized;
+ ListEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ --Scavenger->NetRootsToBeFinalized;
+ ListEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ --Scavenger->VNetRootsToBeFinalized;
+ ListEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVOPEN:
+ --Scavenger->SrvOpensToBeFinalized;
+ ListEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
+ break;
+ }
+
+ /* Also, remove the extra ref from the scavenger */
+ RemoveEntryList(ListEntry);
+ InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxPurgeChangeBufferingStateRequestsForSrvOpen(
+ PSRV_OPEN SrvOpen)
+{
+ PSRV_CALL SrvCall;
+ LIST_ENTRY Discarded;
+
+ PAGED_CODE();
+
+ ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
+
+ /* Initialize our discarded list */
+ InitializeListHead(&Discarded);
+
+ SrvCall = (PSRV_CALL)SrvOpen->Fcb->VNetRoot->pNetRoot->pSrvCall;
+ RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
+
+ /* Set the flag, and get the requests */
+ InitializeListHead(&SrvOpen->SrvOpenKeyList);
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED);
+ RxGatherRequestsForSrvOpen(SrvCall, SrvOpen, &Discarded);
+
+ RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
+
+ /* If there were discarded requests */
+ if (!IsListEmpty(&Discarded))
+ {
+ /* And a pending buffering state change */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
+ {
+ /* Clear the flag, and set the associated event - job done */
+ RxAcquireSerializationMutex();
+ ClearFlag(SrvOpen->Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
+ if (SrvOpen->Fcb->pBufferingStateChangeCompletedEvent != NULL)
+ {
+ KeSetEvent(SrvOpen->Fcb->pBufferingStateChangeCompletedEvent, IO_NETWORK_INCREMENT, FALSE);
+ }
+ RxReleaseSerializationMutex();
+ }
+
+ /* Drop the discarded requests */
+ RxpDiscardChangeBufferingStateRequests(&Discarded);
+ }
}
/*
/* If purge failed, force section closing */
if (!Purged)
{
- MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
+ MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
+
+ RxReleaseFcb(NULL, Fcb);
+ Purged = MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
+ RxAcquireExclusiveFcb(NULL, Fcb);
+ }
+
+ /* Return appropriate status */
+ Status = (Purged ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
+ DPRINT("Purge for FCB %p returns %lx\n", Fcb, Status);
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxPurgeFobx(
+ PFOBX pFobx)
+{
+ NTSTATUS Status;
+ PFCB FcbToBePurged;
+
+ PAGED_CODE();
+
+ /* Get the associated FCB */
+ FcbToBePurged = (PFCB)pFobx->pSrvOpen->pFcb;
+ Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ /* Purge it */
+ Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
+ if (Status != STATUS_SUCCESS)
+ {
+ DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged, pFobx);
+ return FALSE;
+ }
+
+ /* And flush */
+ if (!MmFlushImageSection(&FcbToBePurged->NonPaged->SectionObjectPointers, MmFlushForWrite))
+ {
+ DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged, pFobx);
+ return FALSE;
+ }
+
+ DPRINT("Purge OK for %p (%p)\n", FcbToBePurged, pFobx);
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxPurgeFobxFromCache(
+ PFOBX FobxToBePurged)
+{
+ NTSTATUS Status;
+ PFCB FcbToBePurged;
+
+ PAGED_CODE();
+
+ FcbToBePurged = (PFCB)FobxToBePurged->pSrvOpen->pFcb;
+ ASSERT(FcbToBePurged != NULL);
+
+ /* If we cannot have our FCB exclusively, give up */
+ Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
+ if (Status != STATUS_SUCCESS)
+ {
+ RxDereferenceNetFobx(FobxToBePurged, LHS_LockNotHeld);
+ return Status;
+ }
+
+ /* Don't let the FCB disappear */
+ RxReferenceNetFcb(FcbToBePurged);
+
+ /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
+ if (BooleanFlagOn(FobxToBePurged->Flags, FOBX_FLAG_SRVOPEN_CLOSED) || FobxToBePurged->pSrvOpen->UncleanFobxCount != 0)
+ {
+ DPRINT("FCB purge skipped\n");
+ }
+ else
+ {
+ Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
+ }
+
+ RxDereferenceNetFobx(FobxToBePurged, LHS_ExclusiveLockHeld);
+ /* Drop our extra reference */
+ if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged, NULL, FALSE, FALSE))
+ {
+ RxReleaseFcb(NULL, FcbToBePurged);
+ }
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxPurgeRelatedFobxs(
+ PNET_ROOT NetRoot,
+ PRX_CONTEXT RxContext,
+ BOOLEAN AttemptFinalization,
+ PFCB PurgingFcb)
+{
+ PLIST_ENTRY Entry;
+ ULONG SuccessfullPurge;
+ PRDBSS_SCAVENGER Scavenger;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx;
+
+ PAGED_CODE();
+
+ RxDeviceObject = RxContext->RxDeviceObject;
+ Scavenger = RxDeviceObject->pRdbssScavenger;
+ PurgeSyncCtx = &NetRoot->PurgeSyncronizationContext;
+
+ RxAcquireScavengerMutex();
+
+ /* If there's already a purge in progress */
+ if (PurgeSyncCtx->PurgeInProgress)
+ {
+ /* Add our RX_CONTEXT to the current run */
+ InsertTailList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion,
+ &RxContext->RxContextSerializationQLinks);
+
+ /* And wait until it's done */
+ RxReleaseScavengerMutex();
+ RxWaitSync(RxContext);
+ RxAcquireScavengerMutex();
+ }
+
+ /* Start the purge */
+ PurgeSyncCtx->PurgeInProgress = TRUE;
+
+ /* While the purge is still handling our NET_ROOT, do nothing but wait */
+ while (Scavenger->CurrentNetRootForClosePendingProcessing == NetRoot)
+ {
+ RxReleaseScavengerMutex();
+ KeWaitForSingleObject(&Scavenger->ClosePendingProcessingSyncEvent, Executive,
+ KernelMode, TRUE, NULL);
+ RxAcquireScavengerMutex();
+ }
+
+ /* Now, for all the entries */
+ SuccessfullPurge = 0;
+ Entry = Scavenger->ClosePendingFobxsList.Flink;
+ while (Entry != &Scavenger->ClosePendingFobxsList)
+ {
+ PFCB Fcb;
+ PFOBX Fobx;
+ BOOLEAN Success;
+
+ Fobx = CONTAINING_RECORD(Entry, FOBX, ClosePendingList);
+ DPRINT("Dealing with FOBX: %p\n", Fobx);
+
+ Entry = Entry->Flink;
+
+ /* If it's not matching our NET_ROOT, ignore */
+ if (Fobx->pSrvOpen == NULL ||
+ Fobx->pSrvOpen->pFcb == NULL ||
+ ((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot == NULL ||
+ (PNET_ROOT)((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot->pNetRoot != NetRoot)
+ {
+ continue;
+ }
+
+ /* Determine if it matches our FCB */
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ if (PurgingFcb != NULL && NodeType(PurgingFcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
+ PurgingFcb != Fcb)
+ {
+ NTSTATUS Status;
+
+ MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
+ if (Status == STATUS_SUCCESS)
+ {
+ continue;
+ }
+ }
+
+ /* Matching, we'll purge it */
+ RemoveEntryList(&Fobx->ClosePendingList);
+
+ /* Reference it so that it doesn't disappear */
+ RxReferenceNetFobx(Fobx);
+
+ RxReleaseScavengerMutex();
+
+ /* And purge */
+ Success = RxPurgeFobx(Fobx);
+ if (Success)
+ {
+ ++SuccessfullPurge;
+ }
+
+ /* If we don't have to finalize it (or if we cannot acquire lock exclusively
+ * Just normally dereference
+ */
+ if ((AttemptFinalization == DONT_ATTEMPT_FINALIZE_ON_PURGE) ||
+ RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS)
+ {
+ RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
+ }
+ /* Otherwise, finalize */
+ else
+ {
+ RxReferenceNetFcb(Fcb);
+ RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
+ if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
+ {
+ RxReleaseFcb(NULL, Fcb);
+ }
+ }
+
+ if (!Success)
+ {
+ DPRINT1("Failed purging %p (%p)\n", Fcb, Fobx);
+ }
+
+ RxAcquireScavengerMutex();
+ }
+
+ /* If no contexts left, purge is not running */
+ if (IsListEmpty(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion))
+ {
+ PurgeSyncCtx->PurgeInProgress = FALSE;
+ }
+ /* Otherwise, notify a waiter it can start */
+ else
+ {
+ PRX_CONTEXT Context;
- RxReleaseFcb(NULL, Fcb);
- Purged = MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
- RxAcquireExclusiveFcb(NULL, Fcb);
+ Entry = RemoveHeadList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion);
+ Context = CONTAINING_RECORD(Entry, RX_CONTEXT, RxContextSerializationQLinks);
+
+ RxSignalSynchronousWaiter(Context);
}
- /* Return appropriate status */
- Status = (Purged ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
- DPRINT("Purge for FCB %p returns %lx\n", Fcb, Status);
+ RxReleaseScavengerMutex();
- return Status;
+ return (SuccessfullPurge > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
/*
RxReleaseScavengerMutex();
}
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxReinitializeContext(
+ IN OUT PRX_CONTEXT RxContext)
+{
+ PIRP Irp;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ ULONG InitialContextFlags, SavedFlags;
+
+ PAGED_CODE();
+
+ /* Backup a few flags */
+ Irp = RxContext->CurrentIrp;
+ RxDeviceObject = RxContext->RxDeviceObject;
+ SavedFlags = RxContext->Flags & RX_CONTEXT_PRESERVED_FLAGS;
+ InitialContextFlags = RxContext->Flags & RX_CONTEXT_INITIALIZATION_FLAGS;
+
+ /* Reset our context */
+ RxPrepareContextForReuse(RxContext);
+
+ /* Zero everything */
+ RtlZeroMemory(&RxContext->MajorFunction, sizeof(RX_CONTEXT) - FIELD_OFFSET(RX_CONTEXT, MajorFunction));
+
+ /* Restore saved flags */
+ RxContext->Flags = SavedFlags;
+ /* And reinit the context */
+ RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, RxContext);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxReleaseFcbFromLazyWrite(
+ PVOID Context)
+{
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ Fcb = Context;
+ /* The received context is a FCB */
+ ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+
+ /* Lazy writer is releasing lock, so forget about it */
+ Fcb->Specific.Fcb.LazyWriteThread = NULL;
+
+ /* If we were top level IRP, unwind */
+ if (RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP)
+ {
+ RxUnwindTopLevelIrp(NULL);
+ }
+
+ /* And finally, release the lock */
+ Fcb->PagingIoResourceFile = NULL;
+ Fcb->PagingIoResourceLine = 0;
+ ExReleaseResourceLite(Fcb->Header.PagingIoResource);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxReleaseFcbFromReadAhead(
+ PVOID Context)
+{
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ Fcb = Context;
+ /* The received context is a FCB */
+ ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+
+ /* Top Level IRP is CC */
+ ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
+ RxUnwindTopLevelIrp(NULL);
+
+ ExReleaseResourceLite(Fcb->Header.Resource);
+}
+
+VOID
+NTAPI
+RxReleaseFileForNtCreateSection(
+ PFILE_OBJECT FileObject)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxReleaseForCcFlush(
+ PFILE_OBJECT FileObject,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxRemoveNameNetFcb(
+ OUT PFCB ThisFcb)
+{
+ PNET_ROOT NetRoot;
+
+ PAGED_CODE();
+
+ ASSERT(NodeTypeIsFcb(ThisFcb));
+
+ /* Just remove the entry from the FCB_TABLE */
+ NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
+ ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
+ ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
+
+ RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
+ DPRINT("FCB (%p) %wZ removed\n", ThisFcb, &ThisFcb->FcbTableEntry.Path);
+ /* Mark, so that we don't try to do it twice */
+ SetFlag(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED);
+}
+
/*
* @implemented
*/
}
}
+VOID
+RxResumeBlockedOperations_ALL(
+ IN OUT PRX_CONTEXT RxContext)
+{
+ LIST_ENTRY BlockedOps;
+
+ PAGED_CODE();
+
+ /* Get the blocked operations */
+ RxTransferListWithMutex(&BlockedOps, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex);
+
+ if (!IsListEmpty(&BlockedOps))
+ {
+ UNIMPLEMENTED;
+ }
+}
+
VOID
NTAPI
RxResumeBlockedOperations_Serially(
RxReleaseSerializationMutex();
}
+/*
+ * @implemented
+ */
+VOID
+RxSetFileSizeWithLock(
+ IN OUT PFCB Fcb,
+ IN PLONGLONG FileSize)
+{
+ PAGED_CODE();
+
+ /* Set attribute and increase version */
+ Fcb->Header.FileSize.QuadPart = *FileSize;
+ ++Fcb->ulFileSizeVersion;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxScavengeFobxsForNetRoot(
+ PNET_ROOT NetRoot,
+ PFCB PurgingFcb,
+ BOOLEAN SynchronizeWithScavenger)
+{
+ PRDBSS_SCAVENGER Scavenger;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+
+ PAGED_CODE();
+
+ RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
+ Scavenger = RxDeviceObject->pRdbssScavenger;
+
+ /* Wait for the scavenger, if asked to */
+ if (SynchronizeWithScavenger)
+ {
+ KeWaitForSingleObject(&Scavenger->SyncEvent, Executive, KernelMode, FALSE, NULL);
+ }
+
+ RxAcquireScavengerMutex();
+
+ /* If there's nothing left to do... */
+ if (Scavenger->FobxsToBeFinalized <= 0)
+ {
+ RxReleaseScavengerMutex();
+ }
+ else
+ {
+ PLIST_ENTRY Entry;
+ LIST_ENTRY FobxToScavenge;
+
+ InitializeListHead(&FobxToScavenge);
+
+ /* Browse all the FOBXs to finalize */
+ Entry = Scavenger->FobxFinalizationList.Flink;
+ while (Entry != &Scavenger->FobxFinalizationList)
+ {
+ PFOBX Fobx;
+
+ Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
+ Entry = Entry->Flink;
+
+ if (Fobx->SrvOpen != NULL)
+ {
+ PFCB Fcb;
+
+ Fcb = (PFCB)Fobx->SrvOpen->pFcb;
+
+ /* If it matches our NET_ROOT */
+ if ((PNET_ROOT)Fcb->pNetRoot == NetRoot)
+ {
+ NTSTATUS Status;
+
+ /* Check whether it matches our FCB */
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ if (PurgingFcb != NULL && PurgingFcb != Fcb)
+ {
+ MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
+ }
+
+ /* If so, add it to the list of the FOBXs to scavenge */
+ if (Status != STATUS_SUCCESS)
+ {
+ RxReferenceNetFobx(Fobx);
+ ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
+
+ RemoveEntryList(&Fobx->ScavengerFinalizationList);
+ InsertTailList(&FobxToScavenge, &Fobx->ScavengerFinalizationList);
+ }
+ }
+ }
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* Now, scavenge all the extracted FOBX */
+ RxpScavengeFobxs(Scavenger, &FobxToScavenge);
+ }
+
+ if (SynchronizeWithScavenger)
+ {
+ KeSetEvent(&Scavenger->SyncEvent, IO_NO_INCREMENT, FALSE);
+ }
+}
+
/*
* @implemented
*/
return TRUE;
}
+VOID
+RxScavengerFinalizeEntries(
+ PRDBSS_DEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxScavengerTimerRoutine(
+ PVOID Context)
+{
+ BOOLEAN Requeue;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+ PRDBSS_SCAVENGER Scavenger;
+
+ PAGED_CODE();
+
+ DeviceObject = Context;
+ Scavenger = DeviceObject->pRdbssScavenger;
+
+ Requeue = FALSE;
+ RxAcquireScavengerMutex();
+ /* If the scavenger was dormant, wake it up! */
+ if (Scavenger->State == RDBSS_SCAVENGER_DORMANT)
+ {
+ /* Done */
+ Scavenger->State = RDBSS_SCAVENGER_ACTIVE;
+ KeResetEvent(&Scavenger->ScavengeEvent);
+
+ /* Scavenger the entries */
+ RxReleaseScavengerMutex();
+ RxScavengerFinalizeEntries(DeviceObject);
+ RxAcquireScavengerMutex();
+
+ /* If we're still active (race) */
+ if (Scavenger->State == RDBSS_SCAVENGER_ACTIVE)
+ {
+ /* If there are new entries to scavenge, stay dormant and requeue a run */
+ if (Scavenger->NumberOfDormantFiles + Scavenger->SrvCallsToBeFinalized +
+ Scavenger->NetRootsToBeFinalized + Scavenger->VNetRootsToBeFinalized +
+ Scavenger->FcbsToBeFinalized + Scavenger->SrvOpensToBeFinalized +
+ Scavenger->FobxsToBeFinalized != 0)
+ {
+ Requeue = TRUE;
+ Scavenger->State = RDBSS_SCAVENGER_DORMANT;
+ }
+ /* Otherwise, we're inactive again */
+ else
+ {
+ Scavenger->State = RDBSS_SCAVENGER_INACTIVE;
+ }
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* Requeue an execution */
+ if (Requeue)
+ {
+ RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
+ RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
+ }
+ }
+ else
+ {
+ RxReleaseScavengerMutex();
+ }
+
+ KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE);
+}
+
BOOLEAN
RxScavengeVNetRoots(
PRDBSS_DEVICE_OBJECT RxDeviceObject)
return STATUS_SUCCESS;
}
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxTimerDispatch(
+ _In_ struct _KDPC *Dpc,
+ _In_opt_ PVOID DeferredContext,
+ _In_opt_ PVOID SystemArgument1,
+ _In_opt_ PVOID SystemArgument2)
+{
+ BOOLEAN Set;
+ LIST_ENTRY LocalList;
+ PLIST_ENTRY ListEntry;
+ PRX_WORK_ITEM WorkItem;
+
+ InitializeListHead(&LocalList);
+
+ KeAcquireSpinLockAtDpcLevel(&RxTimerLock);
+ ++RxTimerTickCount;
+
+ /* Find any entry matching */
+ if (!IsListEmpty(&RxTimerQueueHead))
+ {
+ ListEntry = RxTimerQueueHead.Flink;
+ do
+ {
+ WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
+ if (WorkItem->LastTick == RxTimerTickCount)
+ {
+ ListEntry = ListEntry->Flink;
+
+ RemoveEntryList(&WorkItem->WorkQueueItem.List);
+ InsertTailList(&LocalList, &WorkItem->WorkQueueItem.List);
+ }
+ else
+ {
+ ListEntry = ListEntry->Flink;
+ }
+ } while (ListEntry != &RxTimerQueueHead);
+ }
+ /* Do we have to requeue a later execution? */
+ Set = !IsListEmpty(&RxTimerQueueHead);
+
+ KeReleaseSpinLockFromDpcLevel(&RxTimerLock);
+
+ /* Requeue if list wasn't empty */
+ if (Set)
+ {
+ KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
+ }
+
+ /* If we had matching entries */
+ if (!IsListEmpty(&LocalList))
+ {
+ /* Post them, one after another */
+ ListEntry = LocalList.Flink;
+ do
+ {
+ WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
+ ListEntry = ListEntry->Flink;
+
+ WorkItem->WorkQueueItem.List.Flink = NULL;
+ WorkItem->WorkQueueItem.List.Blink = NULL;
+ RxPostToWorkerThread(WorkItem->WorkQueueItem.pDeviceObject, CriticalWorkQueue,
+ &WorkItem->WorkQueueItem, WorkItem->WorkQueueItem.WorkerRoutine,
+ WorkItem->WorkQueueItem.Parameter);
+ }
+ while (ListEntry != &LocalList);
+ }
+}
+
/*
* @implemented
*/
{
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;
}
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;
}
UNIMPLEMENTED;
}
- /* Nor missing contexts... */
+ /* If we don't have a context, assume we can wait! */
if (RxContext == NULL)
{
- UNIMPLEMENTED;
+ CanWait = TRUE;
}
+ else
+ {
+ /* That said: we have a real context! */
+ ContextIsPresent = TRUE;
- /* That said: we have a real context! */
- ContextIsPresent = TRUE;
+ /* If we've been cancelled in between, give up */
+ Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- /* If we've been cancelled in between, give up */
- Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
- if (!NT_SUCCESS(Status))
- {
- return Status;
+ /* Can we wait? */
+ CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
}
- /* Can we wait? */
- CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
-
while (TRUE)
{
/* Assume we cannot lock */
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
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