RxInsertWorkQueueItem(
PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
WORK_QUEUE_TYPE WorkQueueType,
- PRX_WORK_DISPATCH_ITEM DispatchItem);
+ PRX_WORK_QUEUE_ITEM WorkQueueItem);
PVOID
RxNewMapUserBuffer(
PRX_CONTEXT RxContext);
+VOID
+NTAPI
+RxpDestroySrvCall(
+ IN PVOID Context);
+
+VOID
+RxpDispatchChangeBufferingStateRequests(
+ PSRV_CALL SrvCall,
+ 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(
PVOID Context);
+PVOID
+NTAPI
+_RxAllocatePoolWithTag(
+ _In_ POOL_TYPE PoolType,
+ _In_ SIZE_T NumberOfBytes,
+ _In_ ULONG Tag);
+
+VOID
+NTAPI
+_RxFreePool(
+ _In_ PVOID Buffer);
+
+VOID
+NTAPI
+_RxFreePoolWithTag(
+ _In_ PVOID Buffer,
+ _In_ ULONG Tag);
+
extern ULONG ReadAheadGranularity;
volatile LONG RxNumberOfActiveFcbs = 0;
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;
RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues;
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
BOOLEAN DumpDispatchRoutine = FALSE;
#endif
+#if RDBSS_ASSERTS
#ifdef ASSERT
#undef ASSERT
#endif
{ \
RxAssert(#exp, __FILE__, __LINE__, NULL); \
}
+#endif
+
+#if RX_POOL_WRAPPER
+#undef RxAllocatePool
+#undef RxAllocatePoolWithTag
+#undef RxFreePool
+
+#define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
+#define RxAllocatePoolWithTag _RxAllocatePoolWithTag
+#define RxFreePool _RxFreePool
+#define RxFreePoolWithTag _RxFreePoolWithTag
+#endif
/* 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
*/
/* Otherwise, allocate it */
else
{
- Buffer = ExAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
+ Buffer = RxAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
if (Buffer == NULL)
{
return NULL;
/* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
if (PoolType != NonPagedPool)
{
- NonPagedFcb = ExAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG);
+ NonPagedFcb = RxAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG);
if (NonPagedFcb == NULL)
{
- ExFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
+ RxFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
return NULL;
}
FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
}
+ DPRINT("Allocated %p\n", Buffer);
+
return Buffer;
}
/* Now, allocate the object */
ObjectSize = ExtensionSize + StructSize + NameLength;
- Object = ExAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag);
+ Object = RxAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag);
if (Object == NULL)
{
return NULL;
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,
}
}
+/*
+ * @implemented
+ */
VOID
RxCompleteSrvOpenKeyAssociation(
IN OUT PSRV_OPEN SrvOpen)
{
- UNIMPLEMENTED;
+ PSRV_CALL SrvCall;
+
+ SrvCall = (PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall;
+ /* Only handle requests if opening was a success */
+ if (SrvOpen->Condition == Condition_Good)
+ {
+ KIRQL OldIrql;
+ BOOLEAN ProcessChange;
+ LIST_ENTRY DiscardedRequests;
+
+ /* Initialize our discarded requests list */
+ InitializeListHead(&DiscardedRequests);
+
+ RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
+
+ /* Transfer our requests in the SRV_CALL */
+ RxTransferList(&SrvCall->BufferingManager.SrvOpenLists[0], &SrvOpen->SrvOpenKeyList);
+
+ /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
+ InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens);
+
+ /* Dispatch requests and get the discarded ones */
+ RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &DiscardedRequests);
+
+ RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
+
+ /* Is there still anything to process? */
+ KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
+ if (IsListEmpty(&SrvCall->BufferingManager.HandlerList))
+ {
+ ProcessChange = FALSE;
+ }
+ else
+ {
+ ProcessChange = (SrvCall->BufferingManager.HandlerInactive == FALSE);
+ if (ProcessChange)
+ {
+ SrvCall->BufferingManager.HandlerInactive = TRUE;
+ }
+ }
+ KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
+
+ /* Yes? Go ahead! */
+ if (ProcessChange)
+ {
+ RxReferenceSrvCall(SrvCall);
+ RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
+ &SrvCall->BufferingManager.HandlerWorkItem,
+ RxProcessChangeBufferingStateRequests, SrvCall);
+ }
+
+ /* And discard left requests */
+ RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
+ }
+ else
+ {
+ InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens);
+ }
}
/*
ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
/* Allocate the context */
- Context = ExAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG);
+ Context = RxAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG);
if (Context == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
RxTransitionVNetRoot(VirtualNetRoot, VRootCondition);
/* Context is not longer needed */
- ExFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
+ RxFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
DPRINT("Status: %x\n", Status);
ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
/* Allocate the context for mini-rdr */
- Calldown = ExAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG);
+ Calldown = RxAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG);
if (Calldown == NULL)
{
SrvCall->Context = NULL;
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();
- /* TODO: Really deallocate stuff - we're leaking as hell! */
+ /* Now, deallocate the memory */
switch (NodeType)
{
case RDBSS_NTC_SRVCALL:
}
case RDBSS_NTC_NETROOT:
- UNIMPLEMENTED;
+ {
+ PNET_ROOT NetRoot;
+
+ NetRoot = (PNET_ROOT)Instance;
+
+ ASSERT(NetRoot->pSrvCall->RxDeviceObject != NULL);
+ ASSERT(RxIsPrefixTableLockAcquired(NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
+ RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
break;
+ }
case RDBSS_NTC_V_NETROOT:
- UNIMPLEMENTED;
+ {
+ PV_NET_ROOT VNetRoot;
+
+ VNetRoot = (PV_NET_ROOT)Instance;
+
+ ASSERT(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject != NULL);
+ ASSERT(RxIsPrefixTableLockAcquired(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
+ RxFinalizeVNetRoot(VNetRoot, TRUE, TRUE);
break;
+ }
case RDBSS_NTC_SRVOPEN:
- UNIMPLEMENTED;
+ {
+ PSRV_OPEN SrvOpen;
+
+ SrvOpen = (PSRV_OPEN)Instance;
+
+ ASSERT(RxIsFcbAcquired(SrvOpen->Fcb));
+ if (SrvOpen->OpenCount == 0)
+ {
+ RxFinalizeSrvOpen(SrvOpen, FALSE, FALSE);
+ }
break;
+ }
case RDBSS_NTC_FOBX:
- UNIMPLEMENTED;
+ {
+ PFOBX Fobx;
+
+ Fobx = (PFOBX)Instance;
+
+ ASSERT(RxIsFcbAcquired(Fobx->SrvOpen->Fcb));
+ RxFinalizeNetFobx(Fobx, TRUE, FALSE);
break;
+ }
}
}
}
}
+VOID
+NTAPI
+RxDispatchChangeBufferingStateRequests(
+ PVOID Context)
+{
+ UNIMPLEMENTED;
+}
+
/*
* @implemented
*/
PRX_WORK_DISPATCH_ITEM DispatchItem;
/* Allocate a bit of context */
- DispatchItem = ExAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
+ DispatchItem = RxAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
if (DispatchItem == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
DispatchItem->WorkQueueItem.Parameter = DispatchItem;
/* Insert item */
- Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, DispatchItem);
+ Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, &DispatchItem->WorkQueueItem);
if (!NT_SUCCESS(Status))
{
- ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
+ RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
}
/*
* @implemented
*/
-BOOLEAN
-RxFinalizeNetFcb(
- OUT PFCB ThisFcb,
- IN BOOLEAN RecursiveFinalize,
- IN BOOLEAN ForceFinalize,
- IN LONG ReferenceCount)
+NTSTATUS
+NTAPI
+RxFinalizeConnection(
+ IN OUT PNET_ROOT NetRoot,
+ IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
+ IN LOGICAL ForceFilesClosed)
{
- PAGED_CODE();
+ NTSTATUS Status;
+ PRX_PREFIX_TABLE PrefixTable;
+ ULONG UncleanAny, UncleanDir;
+ LONG FilesOpen, AdditionalRef;
+ BOOLEAN PrefixLocked, FcbTableLocked, ForceClose;
- DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
- DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
+ PAGED_CODE();
- /* Make sure we have an exclusively acquired FCB */
- ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
- ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
+ ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
- /* We shouldn't force finalization... */
- ASSERT(!ForceFinalize);
+ /* 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);
- /* If recurisve, finalize all the associated SRV_OPEN */
+ /* 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
+ */
+VOID
+RxFinalizeFcbTable(
+ IN OUT PRX_FCB_TABLE FcbTable)
+{
+ USHORT Bucket;
+
+ PAGED_CODE();
+
+ /* Just delete the lock */
+ ExDeleteResourceLite(&FcbTable->TableLock);
+
+ /* And make sure (checked) that the table is really empty... */
+ for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
+ {
+ ASSERT(IsListEmpty(&FcbTable->HashBuckets[Bucket]));
+ }
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxFinalizeNetFcb(
+ OUT PFCB ThisFcb,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize,
+ IN LONG ReferenceCount)
+{
+ PAGED_CODE();
+
+ DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
+ DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
+
+ /* Make sure we have an exclusively acquired FCB */
+ ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
+ ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
+
+ /* We shouldn't force finalization... */
+ ASSERT(!ForceFinalize);
+
+ /* If recurisve, finalize all the associated SRV_OPEN */
if (RecursiveFinalize)
{
PLIST_ENTRY ListEntry;
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)
Entry = ThisFcb->BufferedLocks.List;
ThisFcb->BufferedLocks.List = Entry->Next;
- ExFreePool(Entry);
+ RxFreePool(Entry);
}
}
/* Now, release everything */
if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
{
- ExFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
+ RxFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
}
if (ThisFcb->MRxDispatch != NULL)
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);
return TRUE;
}
+/*
+ * @implemented
+ */
BOOLEAN
-RxFinalizeNetRoot(
- OUT PNET_ROOT ThisNetRoot,
- IN BOOLEAN RecursiveFinalize,
- IN BOOLEAN ForceFinalize
- )
+RxFinalizeNetFobx(
+ _Out_ PFOBX ThisFobx,
+ _In_ BOOLEAN RecursiveFinalize,
+ _In_ BOOLEAN ForceFinalize)
{
- UNIMPLEMENTED;
- return FALSE;
-}
+ PFCB Fcb;
+ PSRV_OPEN SrvOpen;
-BOOLEAN
-RxFinalizeSrvCall(
- OUT PSRV_CALL ThisSrvCall,
- IN BOOLEAN RecursiveFinalize,
- IN BOOLEAN ForceFinalize)
-{
- UNIMPLEMENTED;
- return FALSE;
+ PAGED_CODE();
+
+ ASSERT(NodeType(ThisFobx) == RDBSS_NTC_FOBX);
+
+ /* Only finalize if forced or if there's no ref left */
+ if (ThisFobx->NodeReferenceCount != 0 &&
+ !ForceFinalize)
+ {
+ return FALSE;
+ }
+
+ DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx, ThisFobx->NodeReferenceCount, ForceFinalize);
+
+ SrvOpen = ThisFobx->SrvOpen;
+ Fcb = SrvOpen->Fcb;
+ /* If it wasn't finalized yet, do it */
+ if (!ThisFobx->UpperFinalizationDone)
+ {
+ ASSERT(NodeType(SrvOpen->Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
+ ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
+
+ /* Remove it from the SRV_OPEN */
+ RemoveEntryList(&ThisFobx->FobxQLinks);
+
+ /* If we were used to browse a directory, free the query buffer */
+ if (BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_FREE_UNICODE))
+ {
+ RxFreePoolWithTag(ThisFobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
+ }
+
+ /* Notify the mini-rdr */
+ if (Fcb->MRxDispatch != NULL && Fcb->MRxDispatch->MRxDeallocateForFobx != NULL)
+ {
+ Fcb->MRxDispatch->MRxDeallocateForFobx((PMRX_FOBX)ThisFobx);
+ }
+
+ /* If the SRV_OPEN wasn't closed yet, do it */
+ if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
+ {
+ NTSTATUS Status;
+
+ Status = RxCloseAssociatedSrvOpen(ThisFobx, FALSE);
+ DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen, ThisFobx, Status);
+ }
+
+ /* Finalization done */
+ ThisFobx->UpperFinalizationDone = TRUE;
+ }
+
+ /* If we're still referenced, don't go any further! */
+ if (ThisFobx->NodeReferenceCount != 0)
+ {
+ return FALSE;
+ }
+
+ /* At that point, everything should be closed */
+ ASSERT(IsListEmpty(&ThisFobx->ClosePendingList));
+
+ /* Was the FOBX allocated with another object?
+ * If so, mark the buffer free in said object
+ */
+ if (ThisFobx == Fcb->InternalFobx)
+ {
+ ClearFlag(Fcb->FcbState, FCB_STATE_FOBX_USED);
+ }
+ else if (ThisFobx == SrvOpen->InternalFobx)
+ {
+ ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED);
+ }
+
+ ThisFobx->pSrvOpen = NULL;
+
+ /* A FOBX less */
+ InterlockedDecrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
+
+ RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
+
+ /* If it wasn't allocated with another object, free the FOBX */
+ if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_ENCLOSED_ALLOCATED))
+ {
+ RxFreeFcbObject(ThisFobx);
+ }
+
+ return TRUE;
}
+/*
+ * @implemented
+ */
BOOLEAN
-RxFinalizeSrvOpen(
- OUT PSRV_OPEN ThisSrvOpen,
+RxFinalizeNetRoot(
+ OUT PNET_ROOT ThisNetRoot,
IN BOOLEAN RecursiveFinalize,
IN BOOLEAN ForceFinalize)
{
- UNIMPLEMENTED;
- return FALSE;
-}
-
-NTSTATUS
-RxFindOrConstructVirtualNetRoot(
- IN PRX_CONTEXT RxContext,
- IN PUNICODE_STRING CanonicalName,
- IN NET_ROOT_TYPE NetRootType,
- IN PUNICODE_STRING RemainingName)
-{
- ULONG Flags;
- NTSTATUS Status;
- PVOID Container;
- BOOLEAN Construct;
- PV_NET_ROOT VNetRoot;
- RX_CONNECTION_ID ConnectionID;
- PRDBSS_DEVICE_OBJECT RxDeviceObject;
- LOCK_HOLDING_STATE LockHoldingState;
+ PSRV_CALL SrvCall;
+ PRX_FCB_TABLE FcbTable;
+ PRX_PREFIX_TABLE PrefixTable;
PAGED_CODE();
- RxDeviceObject = RxContext->RxDeviceObject;
- ASSERT(RxDeviceObject->Dispatch != NULL);
- ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
+ ASSERT(NodeType(ThisNetRoot) == RDBSS_NTC_NETROOT);
- /* Ask the mini-rdr for connection ID */
- ConnectionID.SessionID = 0;
- if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
+ PrefixTable = ThisNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
+
+ /* If sme finalization is already ongoing, leave */
+ if (BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS))
{
- Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
- if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
- {
- /* mini-rdr is expected not to fail - unless it's not implemented */
- DPRINT1("Failed to initialize connection ID\n");
- ASSERT(FALSE);
- }
+ return FALSE;
}
- RxContext->Create.NetNamePrefixEntry = NULL;
-
- Status = STATUS_MORE_PROCESSING_REQUIRED;
- RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
- LockHoldingState = LHS_SharedLockHeld;
- Construct = TRUE;
- Flags = 0;
+ /* Mark we're finalizing */
+ SetFlag(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS);
- /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
- while (TRUE)
+ FcbTable = &ThisNetRoot->FcbTable;
+ /* Did caller asked us to finalize any associated FCB? */
+ if (RecursiveFinalize)
{
- PNET_ROOT NetRoot;
- PV_NET_ROOT SavedVNetRoot;
+ USHORT Bucket;
- /* Look in prefix table */
- Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
- if (Container != NULL)
+ /* Browse all the FCBs in our FCB table */
+ RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
+ for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
{
- /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
- if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
- {
- ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
- RxDereferenceSrvCall(Container, LockHoldingState);
- }
- else
+ PLIST_ENTRY HashBucket, ListEntry;
+
+ HashBucket = &FcbTable->HashBuckets[Bucket];
+ ListEntry = HashBucket->Flink;
+ while (ListEntry != HashBucket)
{
- VNetRoot = Container;
- NetRoot = VNetRoot->NetRoot;
+ PFCB Fcb;
- /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
- if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
- NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
- {
- Status = STATUS_BAD_NETWORK_PATH;
- SavedVNetRoot = NULL;
- }
- else
+ Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ ListEntry = ListEntry->Flink;
+
+ /* If the FCB isn't orphaned, then, it's time to purge it */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
{
- LUID LogonId;
- ULONG SessionId;
- PUNICODE_STRING UserName, UserDomain, Password;
+ NTSTATUS Status;
- /* We can reuse if we use same credentials */
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ ASSERT(Status == STATUS_SUCCESS);
+ RxPurgeFcb(Fcb);
+ }
+ }
+ }
+ RxReleaseFcbTableLock(FcbTable);
+ }
+
+ /* Only finalize if forced or if there's a single ref left */
+ if (ThisNetRoot->NodeReferenceCount != 1 && !ForceFinalize)
+ {
+ return FALSE;
+ }
+
+ DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot, &ThisNetRoot->PrefixEntry.Prefix);
+
+ /* If we're still referenced, don't go any further! */
+ if (ThisNetRoot->NodeReferenceCount != 1)
+ {
+ return FALSE;
+ }
+
+ /* Finalize the FCB table (and make sure it's empty!) */
+ RxFinalizeFcbTable(FcbTable);
+
+ /* If name wasn't remove already, do it now */
+ if (!BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
+ {
+ RxRemovePrefixTableEntry(PrefixTable, &ThisNetRoot->PrefixEntry);
+ }
+
+ /* Delete the object */
+ SrvCall = (PSRV_CALL)ThisNetRoot->pSrvCall;
+ RxFreeObject(ThisNetRoot);
+
+ /* And dereference the associated SRV_CALL */
+ if (SrvCall != NULL)
+ {
+ RxDereferenceSrvCall(SrvCall, LHS_ExclusiveLockHeld);
+ }
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxFinalizeSrvCall(
+ OUT PSRV_CALL ThisSrvCall,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ PRX_PREFIX_TABLE PrefixTable;
+
+ PAGED_CODE();
+
+ ASSERT(NodeType(ThisSrvCall) == RDBSS_NTC_SRVCALL);
+
+ PrefixTable = ThisSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
+
+ /* Only finalize if forced or if there's a single ref left */
+ if (ThisSrvCall->NodeReferenceCount != 1 &&
+ !ForceFinalize)
+ {
+ return FALSE;
+ }
+
+ DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall, &ThisSrvCall->PrefixEntry.Prefix);
+
+ /* If it wasn't finalized yet, do it */
+ if (!ThisSrvCall->UpperFinalizationDone)
+ {
+ BOOLEAN WillFree;
+
+ /* Remove ourselves from prefix table */
+ RxRemovePrefixTableEntry(PrefixTable, &ThisSrvCall->PrefixEntry);
+
+ /* Remember our third arg, in case we get queued for later execution */
+ if (ForceFinalize)
+ {
+ SetFlag(ThisSrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
+ }
+
+ /* And done */
+ ThisSrvCall->UpperFinalizationDone = TRUE;
+
+ /* Would defered execution free the object? */
+ WillFree = (ThisSrvCall->NodeReferenceCount == 1);
+
+ /* If we have a device object */
+ if (ThisSrvCall->RxDeviceObject != NULL)
+ {
+ NTSTATUS Status;
+
+ /* If we're not executing in the RDBSS thread, queue for execution within the thread */
+ if (RxGetRDBSSProcess() != IoGetCurrentProcess())
+ {
+ /* Extra ref, as usual */
+ InterlockedIncrement((volatile long *)&ThisSrvCall->NodeReferenceCount);
+ /* And dispatch */
+ RxDispatchToWorkerThread(ThisSrvCall->RxDeviceObject, DelayedWorkQueue, RxpDestroySrvCall, ThisSrvCall);
+
+ /* Return to the caller, in advance, whether we're freeing the object or not */
+ return WillFree;
+ }
+
+ /* If in the right thread already, call the mini-rdr */
+ MINIRDR_CALL_THROUGH(Status, ThisSrvCall->RxDeviceObject->Dispatch,
+ MRxFinalizeSrvCall, ((PMRX_SRV_CALL)ThisSrvCall, ForceFinalize));
+ (void)Status;
+ }
+ }
+
+ /* If we're still referenced, don't go any further! */
+ if (ThisSrvCall->NodeReferenceCount != 1)
+ {
+ return FALSE;
+ }
+
+ /* Don't leak */
+ if (ThisSrvCall->pDomainName != NULL)
+ {
+ RxFreePool(ThisSrvCall->pDomainName);
+ }
+
+ /* And free! */
+ RxTearDownBufferingManager(ThisSrvCall);
+ RxFreeObject(ThisSrvCall);
+
+ return TRUE;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxFinalizeSrvOpen(
+ OUT PSRV_OPEN ThisSrvOpen,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ 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;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxFinalizeVNetRoot(
+ OUT PV_NET_ROOT ThisVNetRoot,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ PNET_ROOT NetRoot;
+ PRX_PREFIX_TABLE PrefixTable;
+
+ PAGED_CODE();
+
+ ASSERT(NodeType(ThisVNetRoot) == RDBSS_NTC_V_NETROOT);
+
+ PrefixTable = ThisVNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
+
+ /* Only finalize if forced or if there's a single ref left */
+ if (ThisVNetRoot->NodeReferenceCount != 1 &&
+ !ForceFinalize)
+ {
+ return FALSE;
+ }
+
+ DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot, &ThisVNetRoot->PrefixEntry.Prefix);
+
+ NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
+ /* If it wasn't finalized yet, do it */
+ if (!ThisVNetRoot->UpperFinalizationDone)
+ {
+ ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
+
+ /* Reference the NetRoot so that it doesn't disappear */
+ RxReferenceNetRoot(NetRoot);
+ RxOrphanSrvOpens(ThisVNetRoot);
+ /* Remove us from the available VNetRoot for NetRoot */
+ RxRemoveVirtualNetRootFromNetRoot(NetRoot, ThisVNetRoot);
+ /* Remove extra ref */
+ RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
+
+ /* Remove ourselves from prefix table */
+ RxRemovePrefixTableEntry(PrefixTable, &ThisVNetRoot->PrefixEntry);
+
+ /* Finalization done */
+ ThisVNetRoot->UpperFinalizationDone = TRUE;
+ }
+
+ /* If we're still referenced, don't go any further! */
+ if (ThisVNetRoot->NodeReferenceCount != 1)
+ {
+ return FALSE;
+ }
+
+ /* If there's an associated device, notify mini-rdr */
+ if (NetRoot->pSrvCall->RxDeviceObject != NULL)
+ {
+ NTSTATUS Status;
+
+ MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
+ MRxFinalizeVNetRoot, ((PMRX_V_NET_ROOT)ThisVNetRoot, FALSE));
+ (void)Status;
+ }
+
+ /* Free parameters */
+ RxUninitializeVNetRootParameters(ThisVNetRoot->pUserName, ThisVNetRoot->pUserDomainName,
+ ThisVNetRoot->pPassword, &ThisVNetRoot->Flags);
+ /* Dereference our NetRoot, we won't reference it anymore */
+ RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
+
+ /* And free the object! */
+ RxFreePoolWithTag(ThisVNetRoot, RX_V_NETROOT_POOLTAG);
+
+ return TRUE;
+}
+
+NTSTATUS
+RxFindOrConstructVirtualNetRoot(
+ IN PRX_CONTEXT RxContext,
+ IN PUNICODE_STRING CanonicalName,
+ IN NET_ROOT_TYPE NetRootType,
+ IN PUNICODE_STRING RemainingName)
+{
+ ULONG Flags;
+ NTSTATUS Status;
+ PVOID Container;
+ BOOLEAN Construct;
+ PV_NET_ROOT VNetRoot;
+ RX_CONNECTION_ID ConnectionID;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ LOCK_HOLDING_STATE LockHoldingState;
+
+ PAGED_CODE();
+
+ RxDeviceObject = RxContext->RxDeviceObject;
+ ASSERT(RxDeviceObject->Dispatch != NULL);
+ ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
+
+ /* Ask the mini-rdr for connection ID */
+ ConnectionID.SessionID = 0;
+ if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
+ {
+ Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
+ if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
+ {
+ /* mini-rdr is expected not to fail - unless it's not implemented */
+ DPRINT1("Failed to initialize connection ID\n");
+ ASSERT(FALSE);
+ }
+ }
+
+ RxContext->Create.NetNamePrefixEntry = NULL;
+
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
+ LockHoldingState = LHS_SharedLockHeld;
+ Construct = TRUE;
+ Flags = 0;
+
+ /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
+ while (TRUE)
+ {
+ PNET_ROOT NetRoot;
+ PV_NET_ROOT SavedVNetRoot;
+
+ /* Look in prefix table */
+ Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
+ if (Container != NULL)
+ {
+ /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
+ if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
+ {
+ ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
+ RxDereferenceSrvCall(Container, LockHoldingState);
+ }
+ else
+ {
+ VNetRoot = Container;
+ NetRoot = VNetRoot->NetRoot;
+
+ /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
+ if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
+ NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
+ {
+ Status = STATUS_BAD_NETWORK_PATH;
+ SavedVNetRoot = NULL;
+ }
+ else
+ {
+ LUID LogonId;
+ ULONG SessionId;
+ PUNICODE_STRING UserName, UserDomain, Password;
+
+ /* We can reuse if we use same credentials */
Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
&SessionId, &UserName,
&UserDomain, &Password,
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);
RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
RxTransitionSrvCall(SrvCall, Condition);
- ExFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
+ RxFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
/* If async, finish it here, otherwise, caller has already finished the stuff */
if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
{
if (Context->Info.Buffer != NULL)
{
- ExFreePool(Context->Info.Buffer);
+ RxFreePool(Context->Info.Buffer);
Context->Info.Buffer = NULL;
}
}
}
}
+/*
+ * @implemented
+ */
+NTSTATUS
+RxFlushFcbInSystemCache(
+ IN PFCB Fcb,
+ IN BOOLEAN SynchronizeWithLazyWriter)
+{
+ IO_STATUS_BLOCK IoStatus;
+
+ PAGED_CODE();
+
+ /* Deal with Cc */
+ CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, &IoStatus);
+ /* If we're asked to sync with LW, do it in case of success */
+ if (SynchronizeWithLazyWriter && NT_SUCCESS(IoStatus.Status))
+ {
+ RxAcquirePagingIoResource((PRX_CONTEXT)NULL, Fcb);
+ RxReleasePagingIoResource((PRX_CONTEXT)NULL, Fcb);
+ }
+
+ DPRINT("Flushing for FCB %p returns %lx\n", Fcb, IoStatus.Status);
+ 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);
+ }
}
+/*
+ * @implemented
+ */
VOID
RxFreeObject(
PVOID pObject)
{
- UNIMPLEMENTED;
+ PAGED_CODE();
+
+ /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
+ if (NodeType(pObject) == RDBSS_NTC_SRVCALL)
+ {
+ PSRV_CALL SrvCall;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+
+ SrvCall = (PSRV_CALL)pObject;
+ DeviceObject = SrvCall->RxDeviceObject;
+ if (DeviceObject != NULL)
+ {
+ if (!BooleanFlagOn(DeviceObject->Dispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
+ {
+ ASSERT(SrvCall->Context == NULL);
+ }
+
+ ASSERT(SrvCall->Context2 == NULL);
+
+ SrvCall->RxDeviceObject = NULL;
+ }
+ }
+ else if (NodeType(pObject) == RDBSS_NTC_NETROOT)
+ {
+ PNET_ROOT NetRoot;
+
+ NetRoot = (PNET_ROOT)pObject;
+ NetRoot->pSrvCall = NULL;
+ NetRoot->NodeTypeCode = NodeType(pObject) | 0xF000;
+ }
+
+ /* And just free the object */
+ 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;
}
/*
PAGED_CODE();
RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
- ASSERT(LowIoContext = &RxContext->LowIoContext);
+ ASSERT(LowIoContext == &RxContext->LowIoContext);
Stack = RxContext->CurrentIrpSp;
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,
return Status;
}
+/*
+ * @implemented
+ */
VOID
-RxInitiateSrvOpenKeyAssociation (
- IN OUT PSRV_OPEN SrvOpen
- )
+RxInitiateSrvOpenKeyAssociation(
+ IN OUT PSRV_OPEN SrvOpen)
{
- UNIMPLEMENTED;
+ PRX_BUFFERING_MANAGER BufferingManager;
+
+ PAGED_CODE();
+
+ SrvOpen->Key = NULL;
+
+ /* Just keep track of the opening request */
+ BufferingManager = &((PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall)->BufferingManager;
+ InterlockedIncrement(&BufferingManager->NumberOfOutstandingOpens);
+
+ InitializeListHead(&SrvOpen->SrvOpenKeyList);
}
/*
RxInsertWorkQueueItem(
PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
WORK_QUEUE_TYPE WorkQueueType,
- PRX_WORK_DISPATCH_ITEM DispatchItem)
+ PRX_WORK_QUEUE_ITEM WorkQueueItem)
{
KIRQL OldIrql;
NTSTATUS Status;
else
{
SpinUpThreads = FALSE;
- DispatchItem->WorkQueueItem.pDeviceObject = pMRxDeviceObject;
+ WorkQueueItem->pDeviceObject = pMRxDeviceObject;
InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
}
/* All fine, insert the item */
- KeInsertQueue(&WorkQueue->Queue, &DispatchItem->WorkQueueItem.List);
+ KeInsertQueue(&WorkQueue->Queue, &WorkQueueItem->List);
/* And start a new worker thread if needed */
if (SpinUpThreads)
CscAgent = FALSE;
- /* Client Side Caching is DFS stuff - we don't support it */
+ /* Client Side Caching is DFS stuff - we don't support it */
if (RxContext->Create.EaLength != 0)
{
UNIMPLEMENTED;
_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;
+
+ 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
+ */
VOID
RxMarkFobxOnClose(
PFOBX Fobx)
{
- UNIMPLEMENTED;
+ PFCB Fcb;
+ PRDBSS_SCAVENGER Scavenger;
+
+ PAGED_CODE();
+
+ /* No FOBX, nothing to mark */
+ if (Fobx == NULL)
+ {
+ return;
+ }
+
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ 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();
}
/*
UNIMPLEMENTED;
}
-/*
- * @implemented
- */
-BOOLEAN
-RxpAcquirePrefixTableLockShared(
- PRX_PREFIX_TABLE pTable,
- BOOLEAN Wait,
- BOOLEAN ProcessBufferingStateChangeRequests)
+VOID
+RxOrphanSrvOpens(
+ IN PV_NET_ROOT ThisVNetRoot)
{
+ PFCB Fcb;
+ USHORT Bucket;
+ PNET_ROOT NetRoot;
+ PRX_FCB_TABLE FcbTable;
+ PRX_PREFIX_TABLE PrefixTable;
+
PAGED_CODE();
- DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
- pTable->TableLock.ActiveEntries);
+ /* Mailslot won't have any SRV_OPEN (to orphan) */
+ NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
+ if (NetRoot->Type == NET_ROOT_MAILSLOT)
+ {
+ return;
+ }
- return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
-}
+ PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
-/*
- * @implemented
- */
-BOOLEAN
-RxpAcquirePrefixTableLockExclusive(
- PRX_PREFIX_TABLE pTable,
- BOOLEAN Wait,
- BOOLEAN ProcessBufferingStateChangeRequests)
-{
- PAGED_CODE();
+ 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;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxpAcquirePrefixTableLockShared(
+ PRX_PREFIX_TABLE pTable,
+ BOOLEAN Wait,
+ BOOLEAN ProcessBufferingStateChangeRequests)
+{
+ PAGED_CODE();
+
+ DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
+ pTable->TableLock.ActiveEntries);
+
+ return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+RxpAcquirePrefixTableLockExclusive(
+ PRX_PREFIX_TABLE pTable,
+ BOOLEAN Wait,
+ BOOLEAN ProcessBufferingStateChangeRequests)
+{
+ PAGED_CODE();
DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
pTable->TableLock.ActiveEntries);
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);
}
return Freed;
}
+/*
+ * @implemented
+ */
LONG
RxpDereferenceNetFcb(
PFCB Fcb)
{
- UNIMPLEMENTED;
- return 0;
+ LONG NewCount;
+
+ PAGED_CODE();
+
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ NewCount = InterlockedDecrement((volatile long *)&Fcb->NodeReferenceCount);
+ ASSERT(NewCount >= 0);
+
+ PRINT_REF_COUNT(NETFCB, NewCount);
+
+ return NewCount;
}
/*
* @implemented
*/
-PRX_PREFIX_ENTRY
-RxPrefixTableInsertName(
- IN OUT PRX_PREFIX_TABLE ThisTable,
- IN OUT PRX_PREFIX_ENTRY ThisEntry,
- IN PVOID Container,
- IN PULONG ContainerRefCount,
- IN USHORT CaseInsensitiveLength,
- IN PRX_CONNECTION_ID ConnectionId
- )
+VOID
+NTAPI
+RxpDestroySrvCall(
+ IN PVOID Context)
{
- PAGED_CODE();
+ NTSTATUS Status;
+ PSRV_CALL SrvCall;
+ BOOLEAN ForceFinalize;
+ PRX_PREFIX_TABLE PrefixTable;
- DPRINT("Insert: %wZ\n", &ThisEntry->Prefix);
+ SrvCall = (PSRV_CALL)Context;
+ /* At this step, RxFinalizeSrvCall already cleaned some fields */
+ ASSERT(SrvCall->UpperFinalizationDone);
- ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
- ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length);
+ PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
+ /* Were we called with ForceFinalize? */
+ ForceFinalize = BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
- /* Copy parameters and compute hash */
- ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength;
- ThisEntry->ContainingRecord = Container;
- ThisEntry->ContainerRefCount = ContainerRefCount;
- InterlockedIncrement((volatile long *)ContainerRefCount);
- ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix);
- DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue);
+ /* Notify mini-rdr */
+ MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch,
+ MRxFinalizeSrvCall, ((PMRX_SRV_CALL)SrvCall,
+ ForceFinalize));
+ (void)Status;
- /* If no path length: this is entry for null path */
- if (ThisEntry->Prefix.Length == 0)
- {
- ThisTable->TableEntryForNull = ThisEntry;
- }
- /* Otherwise, insert in the appropriate bucket */
- else
- {
- InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks);
- }
+ /* Dereference our extra reference (set before queueing) */
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ InterlockedDecrement((volatile long *)&SrvCall->NodeReferenceCount);
+ /* And finalize for real, with the right context */
+ RxFinalizeSrvCall(SrvCall, FALSE, ForceFinalize);
+ RxReleasePrefixTableLock(PrefixTable);
+}
- /* If we had a connection ID, keep track of it */
- if (ConnectionId != NULL)
+/*
+ * @implemented
+ */
+VOID
+RxpDiscardChangeBufferingStateRequests(
+ _Inout_ PLIST_ENTRY DiscardedRequests)
+{
+ PLIST_ENTRY Entry;
+
+ PAGED_CODE();
+
+ /* No requests to discard */
+ if (IsListEmpty(DiscardedRequests))
{
- ThisEntry->ConnectionId.Luid = ConnectionId->Luid;
+ return;
}
- else
+
+ /* Free all the discarded requests */
+ Entry = DiscardedRequests->Flink;
+ while (Entry != DiscardedRequests)
{
- ThisEntry->ConnectionId.Luid.LowPart = 0;
- ThisEntry->ConnectionId.Luid.HighPart = 0;
- }
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
- InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks);
- /* Reflect the changes */
- ++ThisTable->Version;
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
- DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue));
+ DPRINT("Req %p for %p (%p) discarded\n", Request, Request->SrvOpenKey, Request->SrvOpen);
- return ThisEntry;
+ RxPrepareRequestForReuse(Request);
+ RxFreePool(Request);
+ }
}
/*
* @implemented
*/
-PVOID
-RxPrefixTableLookupName(
- IN PRX_PREFIX_TABLE ThisTable,
- IN PUNICODE_STRING CanonicalName,
- OUT PUNICODE_STRING RemainingName,
- IN PRX_CONNECTION_ID ConnectionId)
+VOID
+RxpDispatchChangeBufferingStateRequests(
+ PSRV_CALL SrvCall,
+ PSRV_OPEN SrvOpen,
+ PLIST_ENTRY DiscardedRequests)
{
- PVOID Container;
-
- PAGED_CODE();
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ BOOLEAN StartDispatcher;
+ LIST_ENTRY AcceptedReqs;
+ LIST_ENTRY DispatcherList;
+ PRX_BUFFERING_MANAGER BufferingManager;
- ASSERT(RxIsPrefixTableLockAcquired(ThisTable));
- ASSERT(CanonicalName->Length > 0);
+ /* Initialize our lists */
+ InitializeListHead(&AcceptedReqs);
+ InitializeListHead(DiscardedRequests);
- /* Call the internal helper */
- Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId);
- if (Container == NULL)
- {
- return NULL;
- }
+ /* Transfer the requests to dispatch locally */
+ BufferingManager = &SrvCall->BufferingManager;
+ KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
+ RxTransferList(&DispatcherList, &BufferingManager->DispatcherList);
+ KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
- /* Reference our container before returning it */
- if (RdbssReferenceTracingValue != 0)
+ /* If there were requests */
+ if (!IsListEmpty(&DispatcherList))
{
- NODE_TYPE_CODE Type;
+ PLIST_ENTRY Entry;
- Type = NodeType(Container);
- switch (Type)
+ /* For each of the entries... */
+ Entry = DispatcherList.Flink;
+ while (Entry != &DispatcherList)
{
- case RDBSS_NTC_SRVCALL:
- RxReferenceSrvCall(Container);
- break;
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
- case RDBSS_NTC_NETROOT:
- RxReferenceNetRoot(Container);
- break;
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
- case RDBSS_NTC_V_NETROOT:
- RxReferenceVNetRoot(Container);
- break;
+ /* 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);
- default:
- ASSERT(FALSE);
- break;
+ 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
{
- RxReference(Container);
+ /* 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;
+ }
}
- return Container;
-}
+ /* If there were accepted requests, move them to the buffering manager */
+ if (!IsListEmpty(&AcceptedReqs))
+ {
+ RxTransferList(&BufferingManager->HandlerList, &AcceptedReqs);
+ }
+ KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
-LONG
-RxpReferenceNetFcb(
- PFCB Fcb)
-{
- UNIMPLEMENTED;
- return 0;
+ /* 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
*/
-VOID
-RxpReleasePrefixTableLock(
- PRX_PREFIX_TABLE pTable,
- BOOLEAN ProcessBufferingStateChangeRequests)
+NTSTATUS
+RxpLookupSrvOpenForRequestLite(
+ IN PSRV_CALL SrvCall,
+ IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request)
{
+ NTSTATUS Status;
+ PLIST_ENTRY Entry;
+ PSRV_OPEN SrvOpen;
+
PAGED_CODE();
- DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
- pTable->TableLock.ActiveEntries);
+ 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;
+ }
+ }
+ }
- ExReleaseResourceLite(&pTable->TableLock);
+ /* 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
-NTAPI
-RxPrepareContextForReuse(
- IN OUT PRX_CONTEXT RxContext)
+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();
- /* When we reach that point, make sure mandatory parts are null-ed */
- if (RxContext->MajorFunction == IRP_MJ_CREATE)
- {
- ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
- RxContext->Create.RdrFlags = 0;
- }
- else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
+ /* If still referenced, don't mark it (broken caller) */
+ Node = (PNODE_TYPE_AND_SIZE)Instance;
+ if (Node->NodeReferenceCount > 1)
{
- ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
- ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
+ return;
}
- RxContext->ReferenceCount = 0;
-}
+ DeviceObject = RxGetDeviceObjectOfInstance(Instance);
+ Scavenger = DeviceObject->pRdbssScavenger;
-VOID
+ /* 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;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxPostToWorkerThread(
+ _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
+ _In_ WORK_QUEUE_TYPE WorkQueueType,
+ _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem,
+ _In_ PRX_WORKERTHREAD_ROUTINE Routine,
+ _In_ PVOID pContext)
+{
+ /* Initialize work queue item */
+ pWorkQueueItem->List.Flink = NULL;
+ pWorkQueueItem->WorkerRoutine = Routine;
+ pWorkQueueItem->Parameter = pContext;
+
+ /* And insert it in the work queue */
+ return RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, pWorkQueueItem);
+}
+
+VOID
+RxpProcessChangeBufferingStateRequests(
+ PSRV_CALL SrvCall,
+ BOOLEAN UpdateHandlerState)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+PRX_PREFIX_ENTRY
+RxPrefixTableInsertName(
+ IN OUT PRX_PREFIX_TABLE ThisTable,
+ IN OUT PRX_PREFIX_ENTRY ThisEntry,
+ IN PVOID Container,
+ IN PULONG ContainerRefCount,
+ IN USHORT CaseInsensitiveLength,
+ IN PRX_CONNECTION_ID ConnectionId
+ )
+{
+ PAGED_CODE();
+
+ DPRINT("Insert: %wZ\n", &ThisEntry->Prefix);
+
+ ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
+ ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length);
+
+ /* Copy parameters and compute hash */
+ ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength;
+ ThisEntry->ContainingRecord = Container;
+ ThisEntry->ContainerRefCount = ContainerRefCount;
+ InterlockedIncrement((volatile long *)ContainerRefCount);
+ ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix);
+ DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue);
+
+ /* If no path length: this is entry for null path */
+ if (ThisEntry->Prefix.Length == 0)
+ {
+ ThisTable->TableEntryForNull = ThisEntry;
+ }
+ /* Otherwise, insert in the appropriate bucket */
+ else
+ {
+ InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks);
+ }
+
+ /* If we had a connection ID, keep track of it */
+ if (ConnectionId != NULL)
+ {
+ ThisEntry->ConnectionId.Luid = ConnectionId->Luid;
+ }
+ else
+ {
+ ThisEntry->ConnectionId.Luid.LowPart = 0;
+ ThisEntry->ConnectionId.Luid.HighPart = 0;
+ }
+
+ InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks);
+ /* Reflect the changes */
+ ++ThisTable->Version;
+
+ DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue));
+
+ return ThisEntry;
+}
+
+/*
+ * @implemented
+ */
+PVOID
+RxPrefixTableLookupName(
+ IN PRX_PREFIX_TABLE ThisTable,
+ IN PUNICODE_STRING CanonicalName,
+ OUT PUNICODE_STRING RemainingName,
+ IN PRX_CONNECTION_ID ConnectionId)
+{
+ PVOID Container;
+
+ PAGED_CODE();
+
+ ASSERT(RxIsPrefixTableLockAcquired(ThisTable));
+ ASSERT(CanonicalName->Length > 0);
+
+ /* Call the internal helper */
+ Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId);
+ if (Container == NULL)
+ {
+ return NULL;
+ }
+
+ /* Reference our container before returning it */
+ if (RdbssReferenceTracingValue != 0)
+ {
+ NODE_TYPE_CODE Type;
+
+ Type = (NodeType(Container) & ~RX_SCAVENGER_MASK);
+ switch (Type)
+ {
+ case RDBSS_NTC_SRVCALL:
+ RxReferenceSrvCall(Container);
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ RxReferenceNetRoot(Container);
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ RxReferenceVNetRoot(Container);
+ break;
+
+ default:
+ DPRINT1("Invalid node type: %x\n", Type);
+ ASSERT(FALSE);
+ RxReference(Container);
+ break;
+ }
+ }
+ else
+ {
+ RxReference(Container);
+ }
+
+ return Container;
+}
+
+/*
+ * @implemented
+ */
+LONG
+RxpReferenceNetFcb(
+ PFCB Fcb)
+{
+ LONG NewCount;
+
+ PAGED_CODE();
+
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ NewCount = InterlockedIncrement((volatile long *)&Fcb->NodeReferenceCount);
+
+ PRINT_REF_COUNT(NETFCB, Fcb->NodeReferenceCount);
+
+ return NewCount;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxpReleasePrefixTableLock(
+ PRX_PREFIX_TABLE pTable,
+ BOOLEAN ProcessBufferingStateChangeRequests)
+{
+ PAGED_CODE();
+
+ DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
+ pTable->TableLock.ActiveEntries);
+
+ ExReleaseResourceLite(&pTable->TableLock);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxPrepareContextForReuse(
+ IN OUT PRX_CONTEXT RxContext)
+{
+ PAGED_CODE();
+
+ /* When we reach that point, make sure mandatory parts are null-ed */
+ if (RxContext->MajorFunction == IRP_MJ_CREATE)
+ {
+ ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
+ RxContext->Create.RdrFlags = 0;
+ }
+ else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
+ {
+ ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
+ ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
+ }
+
+ RxContext->ReferenceCount = 0;
+}
+
+/*
+ * @implemented
+ */
+VOID
+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)
+{
+ /* Call internal routine */
+ RxUndoScavengerFinalizationMarking(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;
}
-BOOLEAN
-RxpTrackDereference(
- _In_ ULONG TraceType,
- _In_ PCSTR FileName,
- _In_ ULONG Line,
- _In_ PVOID Instance)
-{
- UNIMPLEMENTED;
- return FALSE;
+/*
+ * @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_ PCSTR FileName,
+ _In_ ULONG Line,
+ _In_ PVOID Instance)
+{
+ PCSTR InstanceType;
+ ULONG ReferenceCount;
+
+ PAGED_CODE();
+
+ if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
+ {
+ return TRUE;
+ }
+
+ 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;
+}
+
+VOID
+RxpTrackReference(
+ _In_ ULONG TraceType,
+ _In_ PCSTR FileName,
+ _In_ ULONG Line,
+ _In_ PVOID Instance)
+{
+ PCSTR InstanceType;
+ ULONG ReferenceCount;
+
+ if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
+ {
+ return;
+ }
+
+ 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(NodeType(Node), RX_SCAVENGER_MASK))
+ {
+ return;
+ }
+
+ /* 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);
+ }
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxPurgeFcb(
+ IN PFCB Fcb)
+{
+ PAGED_CODE();
+
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ /* Reference our FCB so that it doesn't disappear */
+ RxReferenceNetFcb(Fcb);
+ /* Purge Cc if required */
+ if (Fcb->OpenCount != 0)
+ {
+ RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE);
+ }
+
+ /* If it wasn't freed, release the lock */
+ if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
+ {
+ RxReleaseFcb(NULL, Fcb);
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxPurgeFcbInSystemCache(
+ IN PFCB Fcb,
+ IN PLARGE_INTEGER FileOffset OPTIONAL,
+ IN ULONG Length,
+ IN BOOLEAN UninitializeCacheMaps,
+ IN BOOLEAN FlushFile)
+{
+ BOOLEAN Purged;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ /* Try to flush first, if asked */
+ if (FlushFile)
+ {
+ /* If flushing failed, just make some noise */
+ Status = RxFlushFcbInSystemCache(Fcb, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ PVOID CallersAddress, CallersCaller;
+
+ RtlGetCallersAddress(&CallersAddress, &CallersCaller);
+ DPRINT1("Flush failed with status %lx for FCB %p\n", Status, Fcb);
+ DPRINT1("Caller was %p %p\n", CallersAddress, CallersCaller);
+ }
+ }
+
+ /* Deal with Cc for purge */
+ Purged = CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, FileOffset,
+ Length, UninitializeCacheMaps);
+ /* If purge failed, force section closing */
+ if (!Purged)
+ {
+ 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;
+
+ Entry = RemoveHeadList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion);
+ Context = CONTAINING_RECORD(Entry, RX_CONTEXT, RxContextSerializationQLinks);
+
+ RxSignalSynchronousWaiter(Context);
+ }
+
+ RxReleaseScavengerMutex();
+
+ return (SuccessfullPurge > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxpWorkerThreadDispatcher(
+ IN PRX_WORK_QUEUE WorkQueue,
+ IN PLARGE_INTEGER WaitInterval)
+{
+ NTSTATUS Status;
+ PVOID Parameter;
+ PETHREAD CurrentThread;
+ BOOLEAN KillThread, Dereference;
+ PRX_WORK_QUEUE_ITEM WorkQueueItem;
+ PWORKER_THREAD_ROUTINE WorkerRoutine;
+
+ InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
+
+ /* Reference ourselves */
+ CurrentThread = PsGetCurrentThread();
+ Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Infinite loop for worker */
+ KillThread = FALSE;
+ Dereference = FALSE;
+ do
+ {
+ KIRQL OldIrql;
+ PLIST_ENTRY ListEntry;
+
+ /* Remove an entry from the work queue */
+ ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval);
+ if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT)
+ {
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+
+ WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List);
+
+ InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched);
+ InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
+ InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+
+ /* Get the parameters, and null-them in the struct */
+ WorkerRoutine = WorkQueueItem->WorkerRoutine;
+ Parameter = WorkQueueItem->Parameter;
+ DeviceObject = WorkQueueItem->pDeviceObject;
+
+ WorkQueueItem->List.Flink = NULL;
+ WorkQueueItem->WorkerRoutine = NULL;
+ WorkQueueItem->Parameter = NULL;
+ WorkQueueItem->pDeviceObject = NULL;
+
+ /* Call the routine */
+ DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter);
+ WorkerRoutine(Parameter);
+
+ /* Are we going down now? */
+ if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0)
+ {
+ PKEVENT TearDownEvent;
+
+ TearDownEvent = InterlockedExchangePointer((void * volatile*)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
+ if (TearDownEvent != NULL)
+ {
+ KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
+ }
+ }
+
+ InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ }
+
+ /* Shall we shutdown... */
+ KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
+ switch (WorkQueue->State)
+ {
+ /* Our queue is active, kill it if we have no more items to dispatch
+ * and more threads than the required minimum
+ */
+ case RxWorkQueueActive:
+ if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0)
+ {
+ ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
+ if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
+ {
+ KillThread = TRUE;
+ Dereference = TRUE;
+ InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
+ }
+
+ if (KillThread)
+ {
+ InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ }
+ }
+ break;
+
+ /* The queue is inactive: kill it we have more threads than the required minimum */
+ case RxWorkQueueInactive:
+ ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
+ if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
+ {
+ KillThread = TRUE;
+ Dereference = TRUE;
+ InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
+ }
+
+ if (KillThread)
+ {
+ InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ }
+ break;
+
+ /* Rundown in progress..., kill it for sure! */
+ case RxWorkQueueRundownInProgress:
+ {
+ PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext;
+
+ ASSERT(WorkQueue->pRundownContext != NULL);
+
+ RundownContext = WorkQueue->pRundownContext;
+ RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread;
+
+ InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
+ KillThread = TRUE;
+ Dereference = FALSE;
+
+ if (WorkQueue->NumberOfActiveWorkerThreads == 0)
+ {
+ KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ }
+ break;
+
+ default:
+ break;
+ }
+ KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
+ } while (!KillThread);
+
+ DPRINT("Killed worker thread\n");
+
+ /* Do we have to dereference ourselves? */
+ if (Dereference)
+ {
+ ObDereferenceObject(CurrentThread);
+ }
+
+ /* Dump last executed routine */
+ if (DumpDispatchRoutine)
+ {
+ DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+VOID
+RxReference(
+ IN OUT PVOID Instance)
+{
+ NODE_TYPE_CODE NodeType;
+ PNODE_TYPE_AND_SIZE Node;
+
+ PAGED_CODE();
+
+ RxAcquireScavengerMutex();
+
+ /* We can only reference a few structs */
+ NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK;
+ ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
+ (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
+ (NodeType == RDBSS_NTC_FOBX));
+
+ Node = (PNODE_TYPE_AND_SIZE)Instance;
+ InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
+
+ /* Trace refcount if asked */
+ switch (NodeType)
+ {
+ case RDBSS_NTC_SRVCALL:
+ PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
+ break;
+
+ case RDBSS_NTC_SRVOPEN:
+ PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
+ break;
+
+ case RDBSS_NTC_FOBX:
+ PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ RxpUndoScavengerFinalizationMarking(Instance);
+ 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
+RxRemovePrefixTableEntry(
+ IN OUT PRX_PREFIX_TABLE ThisTable,
+ IN OUT PRX_PREFIX_ENTRY Entry)
+{
+ PAGED_CODE();
+
+ ASSERT(NodeType(Entry) == RDBSS_NTC_PREFIX_ENTRY);
+ ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
+
+ /* Check whether we're asked to remove null entry */
+ if (Entry->Prefix.Length == 0)
+ {
+ ThisTable->TableEntryForNull = NULL;
+ }
+ else
+ {
+ RemoveEntryList(&Entry->HashLinks);
+ }
+
+ Entry->ContainingRecord = NULL;
+
+ /* Also remove it from global list */
+ RemoveEntryList(&Entry->MemberQLinks);
+
+ ++ThisTable->Version;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxRemoveVirtualNetRootFromNetRoot(
+ PNET_ROOT NetRoot,
+ PV_NET_ROOT VNetRoot)
+{
+ PRX_PREFIX_TABLE PrefixTable;
+
+ PAGED_CODE();
+
+ PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
+
+ /* Remove the VNetRoot from the list in the NetRoot */
+ --NetRoot->NumberOfVirtualNetRoots;
+ RemoveEntryList(&VNetRoot->NetRootListEntry);
+
+ /* Fix the NetRoot if we were the default VNetRoot */
+ if (NetRoot->DefaultVNetRoot == VNetRoot)
+ {
+ /* Put the first one available */
+ if (!IsListEmpty(&NetRoot->VirtualNetRoots))
+ {
+ NetRoot->DefaultVNetRoot = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry);
+ }
+ /* Otherwise, none */
+ else
+ {
+ NetRoot->DefaultVNetRoot = NULL;
+ }
+ }
+
+ /* If there are still other VNetRoot available, we're done */
+ if (!IsListEmpty(&NetRoot->VirtualNetRoots))
+ {
+ return;
+ }
+
+ /* Otherwise, initiate NetRoot finalization */
+ if (!BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
+ {
+ RxRemovePrefixTableEntry(PrefixTable, &NetRoot->PrefixEntry);
+ SetFlag(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED);
+ }
+
+ /* Notify mini-rdr */
+ if (NetRoot->pSrvCall != NULL && NetRoot->pSrvCall->RxDeviceObject != NULL)
+ {
+ NTSTATUS Status;
+
+ MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
+ MRxFinalizeNetRoot, ((PMRX_NET_ROOT)NetRoot, FALSE));
+ (void)Status;
+ }
}
VOID
-RxpTrackReference(
- _In_ ULONG TraceType,
- _In_ PCSTR FileName,
- _In_ ULONG Line,
- _In_ PVOID Instance)
+RxResumeBlockedOperations_ALL(
+ IN OUT PRX_CONTEXT RxContext)
{
- UNIMPLEMENTED;
+ LIST_ENTRY BlockedOps;
+
+ PAGED_CODE();
+
+ /* Get the blocked operations */
+ RxTransferListWithMutex(&BlockedOps, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex);
+
+ if (!IsListEmpty(&BlockedOps))
+ {
+ UNIMPLEMENTED;
+ }
}
VOID
-RxpUndoScavengerFinalizationMarking(
- PVOID Instance)
+NTAPI
+RxResumeBlockedOperations_Serially(
+ IN OUT PRX_CONTEXT RxContext,
+ IN OUT PLIST_ENTRY BlockingIoQ)
{
+ PAGED_CODE();
+
+ RxAcquireSerializationMutex();
+
+ /* This can only happen on pipes */
+ if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
+ {
+ RxReleaseSerializationMutex();
+ return;
+ }
+
UNIMPLEMENTED;
+
+ RxReleaseSerializationMutex();
}
-NTSTATUS
-RxPurgeFcbInSystemCache(
- IN PFCB Fcb,
- IN PLARGE_INTEGER FileOffset OPTIONAL,
- IN ULONG Length,
- IN BOOLEAN UninitializeCacheMaps,
- IN BOOLEAN FlushFile)
+/*
+ * @implemented
+ */
+VOID
+RxSetFileSizeWithLock(
+ IN OUT PFCB Fcb,
+ IN PLONGLONG FileSize)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PAGED_CODE();
+
+ /* Set attribute and increase version */
+ Fcb->Header.FileSize.QuadPart = *FileSize;
+ ++Fcb->ulFileSizeVersion;
}
/*
* @implemented
*/
VOID
-RxpWorkerThreadDispatcher(
- IN PRX_WORK_QUEUE WorkQueue,
- IN PLARGE_INTEGER WaitInterval)
+RxScavengeFobxsForNetRoot(
+ PNET_ROOT NetRoot,
+ PFCB PurgingFcb,
+ BOOLEAN SynchronizeWithScavenger)
{
- NTSTATUS Status;
- PVOID Parameter;
- PETHREAD CurrentThread;
- BOOLEAN KillThread, Dereference;
- PRX_WORK_QUEUE_ITEM WorkQueueItem;
- PWORKER_THREAD_ROUTINE WorkerRoutine;
+ PRDBSS_SCAVENGER Scavenger;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
- InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ PAGED_CODE();
- /* Reference ourselves */
- CurrentThread = PsGetCurrentThread();
- Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, PsThreadType, KernelMode);
- ASSERT(NT_SUCCESS(Status));
+ RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
+ Scavenger = RxDeviceObject->pRdbssScavenger;
- /* Infinite loop for worker */
- KillThread = FALSE;
- Dereference = FALSE;
- do
+ /* Wait for the scavenger, if asked to */
+ if (SynchronizeWithScavenger)
{
- KIRQL OldIrql;
- PLIST_ENTRY ListEntry;
-
- /* Remove an entry from the work queue */
- ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval);
- if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT)
- {
- PRDBSS_DEVICE_OBJECT DeviceObject;
+ KeWaitForSingleObject(&Scavenger->SyncEvent, Executive, KernelMode, FALSE, NULL);
+ }
- WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List);
+ RxAcquireScavengerMutex();
- InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched);
- InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
- InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ /* If there's nothing left to do... */
+ if (Scavenger->FobxsToBeFinalized <= 0)
+ {
+ RxReleaseScavengerMutex();
+ }
+ else
+ {
+ PLIST_ENTRY Entry;
+ LIST_ENTRY FobxToScavenge;
- /* Get the parameters, and null-them in the struct */
- WorkerRoutine = WorkQueueItem->WorkerRoutine;
- Parameter = WorkQueueItem->Parameter;
- DeviceObject = WorkQueueItem->pDeviceObject;
+ InitializeListHead(&FobxToScavenge);
- WorkQueueItem->List.Flink = NULL;
- WorkQueueItem->WorkerRoutine = NULL;
- WorkQueueItem->Parameter = NULL;
- WorkQueueItem->pDeviceObject = NULL;
+ /* Browse all the FOBXs to finalize */
+ Entry = Scavenger->FobxFinalizationList.Flink;
+ while (Entry != &Scavenger->FobxFinalizationList)
+ {
+ PFOBX Fobx;
- /* Call the routine */
- DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter);
- WorkerRoutine(Parameter);
+ Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
+ Entry = Entry->Flink;
- /* Are we going down now? */
- if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0)
+ if (Fobx->SrvOpen != NULL)
{
- PKEVENT TearDownEvent;
-
- TearDownEvent = InterlockedExchangePointer((volatile PVOID)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
- if (TearDownEvent != NULL)
- {
- KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
- }
- }
+ PFCB Fcb;
- InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
- }
+ Fcb = (PFCB)Fobx->SrvOpen->pFcb;
- /* Shall we shutdown... */
- KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
- switch (WorkQueue->State)
- {
- /* Our queue is active, kill it if we have no more items to dispatch
- * and more threads than the required minimum
- */
- case RxWorkQueueActive:
- if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0)
+ /* If it matches our NET_ROOT */
+ if ((PNET_ROOT)Fcb->pNetRoot == NetRoot)
{
- ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
- if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
- {
- KillThread = TRUE;
- Dereference = TRUE;
- InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
- }
+ NTSTATUS Status;
- if (KillThread)
+ /* Check whether it matches our FCB */
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ if (PurgingFcb != NULL && PurgingFcb != Fcb)
{
- InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
}
- }
- break;
-
- /* The queue is inactive: kill it we have more threads than the required minimum */
- case RxWorkQueueInactive:
- ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
- if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
- {
- KillThread = TRUE;
- Dereference = TRUE;
- InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
- }
-
- if (KillThread)
- {
- InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
- }
- break;
-
- /* Rundown in progress..., kill it for sure! */
- case RxWorkQueueRundownInProgress:
- {
- PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext;
-
- ASSERT(WorkQueue->pRundownContext != NULL);
-
- RundownContext = WorkQueue->pRundownContext;
- RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread;
-
- InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
- KillThread = TRUE;
- Dereference = FALSE;
- if (WorkQueue->NumberOfActiveWorkerThreads == 0)
+ /* If so, add it to the list of the FOBXs to scavenge */
+ if (Status != STATUS_SUCCESS)
{
- KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
- }
+ RxReferenceNetFobx(Fobx);
+ ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
- InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
+ RemoveEntryList(&Fobx->ScavengerFinalizationList);
+ InsertTailList(&FobxToScavenge, &Fobx->ScavengerFinalizationList);
+ }
}
- break;
-
- default:
- break;
+ }
}
- KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
- } while (!KillThread);
- DPRINT("Killed worker thread\n");
+ RxReleaseScavengerMutex();
- /* Do we have to dereference ourselves? */
- if (Dereference)
- {
- ObDereferenceObject(CurrentThread);
+ /* Now, scavenge all the extracted FOBX */
+ RxpScavengeFobxs(Scavenger, &FobxToScavenge);
}
- /* Dump last executed routine */
- if (DumpDispatchRoutine)
+ if (SynchronizeWithScavenger)
{
- DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
+ KeSetEvent(&Scavenger->SyncEvent, IO_NO_INCREMENT, FALSE);
}
-
- PsTerminateSystemThread(STATUS_SUCCESS);
}
-VOID
-RxReference(
- IN OUT PVOID Instance)
+/*
+ * @implemented
+ */
+BOOLEAN
+RxScavengeRelatedFobxs(
+ PFCB Fcb)
{
- NODE_TYPE_CODE NodeType;
- PNODE_TYPE_AND_SIZE Node;
+ PFOBX Fobx;
+ LIST_ENTRY LocalList;
+ PLIST_ENTRY NextEntry;
+ PRDBSS_SCAVENGER Scavenger;
PAGED_CODE();
+ /* First of all, check whether there are FOBX to scavenge */
+ Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
RxAcquireScavengerMutex();
-
- /* We can only reference a few structs */
- NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK;
- ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
- (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
- (NodeType == RDBSS_NTC_FOBX));
-
- Node = (PNODE_TYPE_AND_SIZE)Instance;
- InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
-
- /* Trace refcount if asked */
- switch (NodeType)
+ if (Scavenger->FobxsToBeFinalized <= 0)
{
- case RDBSS_NTC_SRVCALL:
- PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
- break;
+ RxReleaseScavengerMutex();
+ return FALSE;
+ }
- case RDBSS_NTC_NETROOT:
- PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
- break;
+ /* Initialize our local list which will hold all the FOBX to scavenge so
+ * that we don't acquire the scavenger mutex too long
+ */
+ InitializeListHead(&LocalList);
- case RDBSS_NTC_V_NETROOT:
- PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
- break;
+ /* Technically, that condition should all be true... */
+ if (!IsListEmpty(&Scavenger->FobxFinalizationList))
+ {
+ PLIST_ENTRY NextEntry, LastEntry;
- case RDBSS_NTC_SRVOPEN:
- PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
- break;
+ /* Browse all the FCBs to find the matching ones */
+ NextEntry = Scavenger->FobxFinalizationList.Flink;
+ LastEntry = &Scavenger->FobxFinalizationList;
+ while (NextEntry != LastEntry)
+ {
+ Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList);
+ NextEntry = NextEntry->Flink;
+ /* Matching our FCB? Let's finalize it */
+ if (Fobx->pSrvOpen != NULL && Fobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
+ {
+ RxpUndoScavengerFinalizationMarking(Fobx);
+ ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
+ InsertTailList(&LocalList, &Fobx->ScavengerFinalizationList);
+ }
+ }
+ }
- case RDBSS_NTC_FOBX:
- PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
- break;
+ RxReleaseScavengerMutex();
- default:
- ASSERT(FALSE);
- break;
+ /* Nothing to scavenge? Quit */
+ if (IsListEmpty(&LocalList))
+ {
+ return FALSE;
}
- RxpUndoScavengerFinalizationMarking(Instance);
- RxReleaseScavengerMutex();
+ /* Now, finalize all the extracted FOBX */
+ while (!IsListEmpty(&LocalList))
+ {
+ NextEntry = RemoveHeadList(&LocalList);
+ Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList);
+ RxFinalizeNetFobx(Fobx, TRUE, TRUE);
+ }
+
+ return TRUE;
+}
+
+VOID
+RxScavengerFinalizeEntries(
+ PRDBSS_DEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
}
+/*
+ * @implemented
+ */
VOID
NTAPI
-RxResumeBlockedOperations_Serially(
- IN OUT PRX_CONTEXT RxContext,
- IN OUT PLIST_ENTRY BlockingIoQ)
+RxScavengerTimerRoutine(
+ PVOID Context)
{
+ BOOLEAN Requeue;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+ PRDBSS_SCAVENGER Scavenger;
+
PAGED_CODE();
- RxAcquireSerializationMutex();
+ DeviceObject = Context;
+ Scavenger = DeviceObject->pRdbssScavenger;
- /* This can only happen on pipes */
- if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
+ Requeue = FALSE;
+ RxAcquireScavengerMutex();
+ /* If the scavenger was dormant, wake it up! */
+ if (Scavenger->State == RDBSS_SCAVENGER_DORMANT)
{
- RxReleaseSerializationMutex();
- return;
- }
+ /* Done */
+ Scavenger->State = RDBSS_SCAVENGER_ACTIVE;
+ KeResetEvent(&Scavenger->ScavengeEvent);
- UNIMPLEMENTED;
+ /* Scavenger the entries */
+ RxReleaseScavengerMutex();
+ RxScavengerFinalizeEntries(DeviceObject);
+ RxAcquireScavengerMutex();
- RxReleaseSerializationMutex();
-}
+ /* 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;
+ }
+ }
-BOOLEAN
-RxScavengeRelatedFobxs(
- PFCB Fcb)
-{
- UNIMPLEMENTED;
- return FALSE;
+ RxReleaseScavengerMutex();
+
+ /* Requeue an execution */
+ if (Requeue)
+ {
+ RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
+ RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
+ }
+ }
+ else
+ {
+ RxReleaseScavengerMutex();
+ }
+
+ KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE);
}
BOOLEAN
NTSTATUS Status;
PRX_DISPATCHER RxDispatcher;
- Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, PsThreadType, KernelMode);
+ Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
if (!NT_SUCCESS(Status))
{
PsTerminateSystemThread(STATUS_SUCCESS);
InterlockedDecrement(&WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse);
- DPRINT1("WORKQ:SR %lx %lx\n", WorkItem->WorkerRoutine, WorkItem->Parameter);
+ DPRINT("Workqueue: calling %p(%p)\n", WorkItem->WorkerRoutine, WorkItem->Parameter);
WorkItem->WorkerRoutine(WorkItem->Parameter);
}
} while (RxDispatcher->State == RxDispatcherActive);
return Hash;
}
+/*
+ * @implemented
+ */
PVOID
RxTableLookupName(
IN PRX_PREFIX_TABLE ThisTable,
ASSERT(Entry->ContainingRecord != NULL);
Container = Entry->ContainingRecord;
- /* Need to handle NetRoot specific case... */
+ /* If we have a NET_ROOT, let's return a V_NET_ROOT */
if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_NETROOT)
{
- UNIMPLEMENTED;
+ PNET_ROOT NetRoot;
+
+ NetRoot = (PNET_ROOT)Entry->ContainingRecord;
+ /* If there's a default one, perfect, that's a match */
+ if (NetRoot->DefaultVNetRoot != NULL)
+ {
+ Container = NetRoot->DefaultVNetRoot;
+ }
+ /* If none (that shouldn't happen!), try to find one */
+ else
+ {
+ /* Use the first one in the list */
+ if (!IsListEmpty(&NetRoot->VirtualNetRoots))
+ {
+ Container = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry);
+ }
+ /* Really, really, shouldn't happen */
+ else
+ {
+ ASSERT(FALSE);
+ Entry = NULL;
+ Container = NULL;
+ }
+ }
+
break;
}
else if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_V_NETROOT)
return NULL;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+RxTearDownBufferingManager(
+ PSRV_CALL SrvCall)
+{
+ PAGED_CODE();
+
+ /* Nothing to do */
+ 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
+ */
VOID
RxTrackerUpdateHistory(
_Inout_opt_ PRX_CONTEXT RxContext,
_In_ PCSTR FileName,
_In_ ULONG SerialNumber)
{
- UNIMPLEMENTED;
+ PFCB Fcb;
+ RX_FCBTRACKER_CASES Case;
+
+ /* Check for null or special context */
+ if (RxContext == NULL)
+ {
+ Case = RX_FCBTRACKER_CASE_NULLCONTEXT;
+ }
+ else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT)
+ {
+ Case = RX_FCBTRACKER_CASE_CBS_CONTEXT;
+ }
+ else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
+ {
+ Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT;
+ }
+ else
+ {
+ ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT);
+ Case = RX_FCBTRACKER_CASE_NORMAL;
+ }
+
+ /* If caller provided a FCB, update its history */
+ if (MrxFcb != NULL)
+ {
+ Fcb = (PFCB)MrxFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ /* Only one acquire operation, so many release operations... */
+ if (Operation == TRACKER_ACQUIRE_FCB)
+ {
+ ++Fcb->FcbAcquires[Case];
+ }
+ else
+ {
+ ++Fcb->FcbReleases[Case];
+ }
+ }
+
+ /* If we have a normal context, update its history about this function calls */
+ if (Case == RX_FCBTRACKER_CASE_NORMAL)
+ {
+ ULONG TrackerHistoryPointer;
+
+ /* Only one acquire operation, so many release operations... */
+ if (Operation == TRACKER_ACQUIRE_FCB)
+ {
+ InterlockedIncrement(&RxContext->AcquireReleaseFcbTrackerX);
+ }
+ else
+ {
+ InterlockedDecrement(&RxContext->AcquireReleaseFcbTrackerX);
+ }
+
+ /* We only keep track of the 32 first calls */
+ TrackerHistoryPointer = InterlockedExchangeAdd((volatile long *)&RxContext->TrackerHistoryPointer, 1);
+ if (TrackerHistoryPointer < RDBSS_TRACKER_HISTORY_SIZE)
+ {
+ RxContext->TrackerHistory[TrackerHistoryPointer].AcquireRelease = Operation;
+ RxContext->TrackerHistory[TrackerHistoryPointer].LineNumber = LineNumber;
+ RxContext->TrackerHistory[TrackerHistoryPointer].FileName = (PSZ)FileName;
+ RxContext->TrackerHistory[TrackerHistoryPointer].SavedTrackerValue = RxContext->AcquireReleaseFcbTrackerX;
+ RxContext->TrackerHistory[TrackerHistoryPointer].Flags = RxContext->Flags;
+ }
+
+ /* If it's negative, then we released once more than we acquired it?! */
+ ASSERT(RxContext->AcquireReleaseFcbTrackerX >= 0);
+ }
}
VOID
UNIMPLEMENTED;
}
+/*
+ * @implemented
+ */
+VOID
+RxUndoScavengerFinalizationMarking(
+ PVOID Instance)
+{
+ /* Just call internal routine with mutex held */
+ RxAcquireScavengerMutex();
+ RxpUndoScavengerFinalizationMarking(Instance);
+ RxReleaseScavengerMutex();
+}
+
/*
* @implemented
*/
/* Only free what could have been allocated */
if (UserName != NULL)
{
- ExFreePool(UserName);
+ RxFreePool(UserName);
}
if (UserDomainName != NULL)
{
- ExFreePool(UserDomainName);
+ RxFreePool(UserDomainName);
}
if (Password != NULL)
{
- ExFreePool(Password);
+ RxFreePool(Password);
}
/* And remove the possibly set CSC agent flag */
}
}
+/*
+ * @implemented
+ */
VOID
RxVerifyOperationIsLegal(
IN PRX_CONTEXT RxContext)
{
- UNIMPLEMENTED;
+ PIRP Irp;
+ PMRX_FOBX Fobx;
+ BOOLEAN FlagSet;
+ PFILE_OBJECT FileObject;
+ PIO_STACK_LOCATION Stack;
+
+ PAGED_CODE();
+
+ Irp = RxContext->CurrentIrp;
+ Stack = RxContext->CurrentIrpSp;
+ FileObject = Stack->FileObject;
+
+ /* We'll only check stuff on opened files, this requires an IRP and a FO */
+ if (Irp == NULL || FileObject == NULL)
+ {
+ return;
+ }
+
+ /* Set no exception for breakpoint - remember whether is was already set */
+ FlagSet = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
+ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
+
+ /* If we have a CCB, perform a few checks on opened file */
+ Fobx = RxContext->pFobx;
+ if (Fobx != NULL)
+ {
+ PMRX_SRV_OPEN SrvOpen;
+
+ SrvOpen = Fobx->pSrvOpen;
+ if (SrvOpen != NULL)
+ {
+ UCHAR MajorFunction;
+
+ MajorFunction = RxContext->MajorFunction;
+ /* Only allow closing/cleanup operations on renamed files */
+ if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE &&
+ BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
+ {
+ RxContext->IoStatusBlock.Status = STATUS_FILE_RENAMED;
+ ExRaiseStatus(STATUS_FILE_RENAMED);
+ }
+
+ /* Only allow closing/cleanup operations on deleted files */
+ if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE &&
+ BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED))
+ {
+ RxContext->IoStatusBlock.Status = STATUS_FILE_DELETED;
+ ExRaiseStatus(STATUS_FILE_DELETED);
+ }
+ }
+ }
+
+ /* If that's an open operation */
+ if (RxContext->MajorFunction == IRP_MJ_CREATE)
+ {
+ PFILE_OBJECT RelatedFileObject;
+
+ /* We won't allow an open operation relative to a file to be deleted */
+ RelatedFileObject = FileObject->RelatedFileObject;
+ if (RelatedFileObject != NULL)
+ {
+ PMRX_FCB Fcb;
+
+ Fcb = RelatedFileObject->FsContext;
+ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
+ {
+ RxContext->IoStatusBlock.Status = STATUS_DELETE_PENDING;
+ ExRaiseStatus(STATUS_DELETE_PENDING);
+ }
+ }
+ }
+
+ /* If cleanup was completed */
+ if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
+ {
+ if (!BooleanFlagOn(Irp->Flags, IRP_PAGING_IO))
+ {
+ UCHAR MajorFunction;
+
+ /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
+ MajorFunction = Stack->MajorFunction;
+ if (MajorFunction != IRP_MJ_CLOSE && MajorFunction != IRP_MJ_QUERY_INFORMATION &&
+ MajorFunction != IRP_MJ_SET_INFORMATION)
+ {
+ if ((MajorFunction != IRP_MJ_READ && MajorFunction != IRP_MJ_WRITE) ||
+ !BooleanFlagOn(Stack->MinorFunction, IRP_MN_COMPLETE))
+ {
+ RxContext->IoStatusBlock.Status = STATUS_FILE_CLOSED;
+ ExRaiseStatus(STATUS_FILE_CLOSED);
+ }
+ }
+ }
+ }
+
+ /* If flag was already set, don't clear it */
+ if (!FlagSet)
+ {
+ ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
+ }
}
/*
DispatchItem->DispatchRoutine(DispatchItem->DispatchRoutineParameter);
- ExFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
+ RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
+}
+
+/*
+ * @implemented
+ */
+PVOID
+NTAPI
+_RxAllocatePoolWithTag(
+ _In_ POOL_TYPE PoolType,
+ _In_ SIZE_T NumberOfBytes,
+ _In_ ULONG Tag)
+{
+ return ExAllocatePoolWithTagPriority(PoolType, NumberOfBytes, Tag, LowPoolPriority);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+_RxFreePool(
+ _In_ PVOID Buffer)
+{
+ ExFreePoolWithTag(Buffer, 0);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+_RxFreePoolWithTag(
+ _In_ PVOID Buffer,
+ _In_ ULONG Tag)
+{
+ ExFreePoolWithTag(Buffer, Tag);
}
NTSTATUS
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