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;
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 ****************************************************************/
/* 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;
}
/* 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 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);
}
return STATUS_SUCCESS;
}
+/*
+ * @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
*/
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
- )
-{
- UNIMPLEMENTED;
- return FALSE;
-}
-
-BOOLEAN
-RxFinalizeSrvCall(
- OUT PSRV_CALL ThisSrvCall,
- 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
-RxFinalizeSrvOpen(
- OUT PSRV_OPEN ThisSrvOpen,
- IN BOOLEAN RecursiveFinalize,
- IN BOOLEAN ForceFinalize)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ PAGED_CODE();
-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;
+ ASSERT(NodeType(ThisFobx) == RDBSS_NTC_FOBX);
- PAGED_CODE();
+ /* Only finalize if forced or if there's no ref left */
+ if (ThisFobx->NodeReferenceCount != 0 &&
+ !ForceFinalize)
+ {
+ return FALSE;
+ }
- RxDeviceObject = RxContext->RxDeviceObject;
- ASSERT(RxDeviceObject->Dispatch != NULL);
- ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
+ DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx, ThisFobx->NodeReferenceCount, ForceFinalize);
- /* Ask the mini-rdr for connection ID */
- ConnectionID.SessionID = 0;
- if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
+ SrvOpen = ThisFobx->SrvOpen;
+ Fcb = SrvOpen->Fcb;
+ /* If it wasn't finalized yet, do it */
+ if (!ThisFobx->UpperFinalizationDone)
{
- Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
- if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
+ 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))
{
- /* mini-rdr is expected not to fail - unless it's not implemented */
- DPRINT1("Failed to initialize connection ID\n");
- ASSERT(FALSE);
+ RxFreePoolWithTag(ThisFobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
}
- }
- RxContext->Create.NetNamePrefixEntry = NULL;
+ /* Notify the mini-rdr */
+ if (Fcb->MRxDispatch != NULL && Fcb->MRxDispatch->MRxDeallocateForFobx != NULL)
+ {
+ Fcb->MRxDispatch->MRxDeallocateForFobx((PMRX_FOBX)ThisFobx);
+ }
- Status = STATUS_MORE_PROCESSING_REQUIRED;
- RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
- LockHoldingState = LHS_SharedLockHeld;
- Construct = TRUE;
- Flags = 0;
+ /* If the SRV_OPEN wasn't closed yet, do it */
+ if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
+ {
+ NTSTATUS Status;
- /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
- while (TRUE)
+ 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)
{
- PNET_ROOT NetRoot;
- PV_NET_ROOT SavedVNetRoot;
+ return FALSE;
+ }
- /* 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;
+ /* At that point, everything should be closed */
+ ASSERT(IsListEmpty(&ThisFobx->ClosePendingList));
- /* 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;
+ /* 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);
+ }
- /* We can reuse if we use same credentials */
- Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
- &SessionId, &UserName,
- &UserDomain, &Password,
- &Flags);
- if (NT_SUCCESS(Status))
- {
- SavedVNetRoot = VNetRoot;
- Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
- &LogonId, UserName,
- UserDomain, Password,
- Flags);
- if (Status == STATUS_MORE_PROCESSING_REQUIRED)
- {
- PLIST_ENTRY ListEntry;
+ ThisFobx->pSrvOpen = NULL;
- for (ListEntry = NetRoot->VirtualNetRoots.Flink;
- ListEntry != &NetRoot->VirtualNetRoots;
- ListEntry = ListEntry->Flink)
- {
- SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
- Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
- &LogonId, UserName,
- UserDomain, Password,
- Flags);
- if (Status != STATUS_MORE_PROCESSING_REQUIRED)
- {
- break;
- }
- }
+ /* A FOBX less */
+ InterlockedDecrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
- if (ListEntry == &NetRoot->VirtualNetRoots)
- {
- SavedVNetRoot = NULL;
- }
- }
+ RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
- if (!NT_SUCCESS(Status))
- {
- SavedVNetRoot = NULL;
- }
+ /* If it wasn't allocated with another object, free the FOBX */
+ if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_ENCLOSED_ALLOCATED))
+ {
+ RxFreeFcbObject(ThisFobx);
+ }
- RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
- }
- }
+ return TRUE;
+}
- /* We'll fail, if we had referenced a VNetRoot, dereference it */
- if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
- {
- if (SavedVNetRoot == NULL)
- {
- RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
- }
- }
- /* Reference VNetRoot we'll keep, and dereference current */
- else if (SavedVNetRoot != VNetRoot)
- {
- RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
- if (SavedVNetRoot != NULL)
- {
- RxReferenceVNetRoot(SavedVNetRoot);
- }
- }
- }
+/*
+ * @implemented
+ */
+BOOLEAN
+RxFinalizeNetRoot(
+ OUT PNET_ROOT ThisNetRoot,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ PSRV_CALL SrvCall;
+ PRX_FCB_TABLE FcbTable;
+ PRX_PREFIX_TABLE PrefixTable;
- /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
- if (Status != STATUS_MORE_PROCESSING_REQUIRED)
- {
- Construct = FALSE;
- break;
- }
- }
+ PAGED_CODE();
- /* If we're locked exclusive, we won't loop again, it was the second pass */
- if (LockHoldingState != LHS_SharedLockHeld)
- {
- break;
- }
+ ASSERT(NodeType(ThisNetRoot) == RDBSS_NTC_NETROOT);
- /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
- if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
- {
- RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
- LockHoldingState = LHS_ExclusiveLockHeld;
- break;
- }
+ PrefixTable = ThisNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
- RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
- RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
- LockHoldingState = LHS_ExclusiveLockHeld;
+ /* If sme finalization is already ongoing, leave */
+ if (BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS))
+ {
+ return FALSE;
}
- /* We didn't fail, and didn't find any VNetRoot, construct one */
- if (Construct)
- {
- ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
+ /* Mark we're finalizing */
+ SetFlag(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS);
- Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
- ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
+ FcbTable = &ThisNetRoot->FcbTable;
+ /* Did caller asked us to finalize any associated FCB? */
+ if (RecursiveFinalize)
+ {
+ USHORT Bucket;
- if (Status == STATUS_SUCCESS)
+ /* Browse all the FCBs in our FCB table */
+ RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
+ for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
{
- DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
- DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
- ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
+ PLIST_ENTRY HashBucket, ListEntry;
- RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
- RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
- RemainingName->MaximumLength = RemainingName->Length;
+ HashBucket = &FcbTable->HashBuckets[Bucket];
+ ListEntry = HashBucket->Flink;
+ while (ListEntry != HashBucket)
+ {
+ PFCB Fcb;
- if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
- {
- DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
+ 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))
+ {
+ NTSTATUS Status;
+
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ ASSERT(Status == STATUS_SUCCESS);
+ RxPurgeFcb(Fcb);
+ }
}
- VNetRoot->Flags |= Flags;
}
+ RxReleaseFcbTableLock(FcbTable);
}
- /* Release the prefix table - caller expects it to be released */
- if (LockHoldingState != LHS_LockNotHeld)
+ /* Only finalize if forced or if there's a single ref left */
+ if (ThisNetRoot->NodeReferenceCount != 1 && !ForceFinalize)
{
- RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
+ return FALSE;
}
- /* If we failed creating, quit */
- if (Status != STATUS_SUCCESS)
+ 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)
{
- DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
- return Status;
+ return FALSE;
}
- /* Otherwise, wait until the VNetRoot is stable */
- DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
- RxWaitForStableVNetRoot(VNetRoot, RxContext);
- /* It's all good, update the RX_CONTEXT with all our structs */
- if (VNetRoot->Condition == Condition_Good)
- {
- PNET_ROOT NetRoot;
+ /* Finalize the FCB table (and make sure it's empty!) */
+ RxFinalizeFcbTable(FcbTable);
- NetRoot = VNetRoot->NetRoot;
- RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
- RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
- RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
+ /* If name wasn't remove already, do it now */
+ if (!BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
+ {
+ RxRemovePrefixTableEntry(PrefixTable, &ThisNetRoot->PrefixEntry);
}
- else
+
+ /* Delete the object */
+ SrvCall = (PSRV_CALL)ThisNetRoot->pSrvCall;
+ RxFreeObject(ThisNetRoot);
+
+ /* And dereference the associated SRV_CALL */
+ if (SrvCall != NULL)
{
- RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
- RxContext->Create.pVNetRoot = NULL;
- Status = STATUS_BAD_NETWORK_PATH;
+ RxDereferenceSrvCall(SrvCall, LHS_ExclusiveLockHeld);
}
- return Status;
+ return TRUE;
}
/*
* @implemented
*/
-NTSTATUS
-RxFindOrCreateConnections(
- _In_ PRX_CONTEXT RxContext,
- _In_ PUNICODE_STRING CanonicalName,
- _In_ NET_ROOT_TYPE NetRootType,
- _Out_ PUNICODE_STRING LocalNetRootName,
- _Out_ PUNICODE_STRING FilePathName,
- _Inout_ PLOCK_HOLDING_STATE LockState,
- _In_ PRX_CONNECTION_ID RxConnectionId)
+BOOLEAN
+RxFinalizeSrvCall(
+ OUT PSRV_CALL ThisSrvCall,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
{
- PVOID Container;
- PSRV_CALL SrvCall;
- PNET_ROOT NetRoot;
- PV_NET_ROOT VNetRoot;
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
PRX_PREFIX_TABLE PrefixTable;
- UNICODE_STRING RemainingName, NetRootName;
PAGED_CODE();
- DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
- RxContext, CanonicalName, NetRootType, LocalNetRootName,
- FilePathName, LockState, RxConnectionId);
+ ASSERT(NodeType(ThisSrvCall) == RDBSS_NTC_SRVCALL);
- *FilePathName = *CanonicalName;
- LocalNetRootName->Length = 0;
- LocalNetRootName->MaximumLength = 0;
- LocalNetRootName->Buffer = CanonicalName->Buffer;
+ PrefixTable = ThisSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
- /* UNC path, split it */
- if (FilePathName->Buffer[1] == ';')
+ /* Only finalize if forced or if there's a single ref left */
+ if (ThisSrvCall->NodeReferenceCount != 1 &&
+ !ForceFinalize)
{
- BOOLEAN Slash;
- USHORT i, Length;
+ return FALSE;
+ }
- Slash = FALSE;
- for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
- {
- if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
- {
- Slash = TRUE;
- break;
- }
- }
+ DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall, &ThisSrvCall->PrefixEntry.Prefix);
- if (!Slash)
+ /* 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)
{
- return STATUS_OBJECT_NAME_INVALID;
+ SetFlag(ThisSrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
}
- FilePathName->Buffer = &FilePathName->Buffer[i];
- Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
- LocalNetRootName->Length = Length;
- LocalNetRootName->MaximumLength = Length;
- FilePathName->Length -= Length;
+ /* And done */
+ ThisSrvCall->UpperFinalizationDone = TRUE;
- DPRINT("CanonicalName: %wZ\n", CanonicalName);
- DPRINT(" -> FilePathName: %wZ\n", FilePathName);
- DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
- }
+ /* Would defered execution free the object? */
+ WillFree = (ThisSrvCall->NodeReferenceCount == 1);
- Container = NULL;
- PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
+ /* If we have a device object */
+ if (ThisSrvCall->RxDeviceObject != NULL)
+ {
+ NTSTATUS Status;
- _SEH2_TRY
- {
-RetryLookup:
- ASSERT(*LockState != LHS_LockNotHeld);
-
- /* If previous lookup left something, dereference it */
- if (Container != NULL)
- {
- switch (NodeType(Container))
+ /* If we're not executing in the RDBSS thread, queue for execution within the thread */
+ if (RxGetRDBSSProcess() != IoGetCurrentProcess())
{
- case RDBSS_NTC_SRVCALL:
- RxDereferenceSrvCall(Container, *LockState);
- break;
-
- case RDBSS_NTC_NETROOT:
- RxDereferenceNetRoot(Container, *LockState);
- break;
+ /* Extra ref, as usual */
+ InterlockedIncrement((volatile long *)&ThisSrvCall->NodeReferenceCount);
+ /* And dispatch */
+ RxDispatchToWorkerThread(ThisSrvCall->RxDeviceObject, DelayedWorkQueue, RxpDestroySrvCall, ThisSrvCall);
- case RDBSS_NTC_V_NETROOT:
- RxDereferenceVNetRoot(Container, *LockState);
- break;
-
- default:
- /* Should never happen */
- ASSERT(FALSE);
- break;
+ /* 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;
}
+ }
- /* Look for our NetRoot in prefix table */
- Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
- DPRINT("Container %p for path %wZ\n", Container, FilePathName);
+ /* If we're still referenced, don't go any further! */
+ if (ThisSrvCall->NodeReferenceCount != 1)
+ {
+ return FALSE;
+ }
- while (TRUE)
- {
- UNICODE_STRING SrvCallName;
+ /* Don't leak */
+ if (ThisSrvCall->pDomainName != NULL)
+ {
+ RxFreePool(ThisSrvCall->pDomainName);
+ }
- SrvCall = NULL;
- NetRoot = NULL;
- VNetRoot = NULL;
+ /* And free! */
+ RxTearDownBufferingManager(ThisSrvCall);
+ RxFreeObject(ThisSrvCall);
- /* Assume we didn't succeed */
- RxContext->Create.pVNetRoot = NULL;
- RxContext->Create.pNetRoot = NULL;
- RxContext->Create.pSrvCall = NULL;
- RxContext->Create.Type = NetRootType;
+ return TRUE;
+}
- /* If we found something */
- if (Container != NULL)
- {
- /* A VNetRoot */
- if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
- {
- VNetRoot = Container;
- /* Use its NetRoot */
- NetRoot = VNetRoot->NetRoot;
+/*
+ * @implemented
+ */
+BOOLEAN
+RxFinalizeSrvOpen(
+ OUT PSRV_OPEN ThisSrvOpen,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ PFCB Fcb;
- /* If it's not stable, wait for it to be stable */
- if (NetRoot->Condition == Condition_InTransition)
- {
- RxReleasePrefixTableLock(PrefixTable);
- DPRINT("Waiting for stable condition for: %p\n", NetRoot);
- RxWaitForStableNetRoot(NetRoot, RxContext);
- RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
- *LockState = LHS_ExclusiveLockHeld;
+ PAGED_CODE();
- /* Now that's it's ok, retry lookup to find what we want */
- if (NetRoot->Condition == Condition_Good)
- {
- goto RetryLookup;
- }
- }
+ /* We have to have a SRV_OPEN */
+ ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN);
- /* Is the associated netroot good? */
- if (NetRoot->Condition == Condition_Good)
- {
- SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
+ /* If that's a recursive finalization, finalize any related FOBX */
+ if (RecursiveFinalize)
+ {
+ PLIST_ENTRY ListEntry;
- /* If it is, and SrvCall as well, then, we have our active connection */
- if (SrvCall->Condition == Condition_Good &&
- SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
- {
- RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
- RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
- RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
+ for (ListEntry = ThisSrvOpen->FobxList.Flink;
+ ListEntry != &ThisSrvOpen->FobxList;
+ ListEntry = ListEntry->Flink)
+ {
+ PFOBX Fobx;
- Status = STATUS_CONNECTION_ACTIVE;
- _SEH2_LEAVE;
- }
- }
+ Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
+ RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
+ }
+ }
- /* If VNetRoot was well constructed, it means the connection is active */
- if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
- {
- Status = STATUS_CONNECTION_ACTIVE;
- }
- else
- {
- Status = VNetRoot->ConstructionStatus;
- }
+ /* If we have still references, don't finalize unless forced */
+ if (ThisSrvOpen->NodeReferenceCount != 0 &&
+ !ForceFinalize)
+ {
+ return FALSE;
+ }
- RxDereferenceVNetRoot(VNetRoot, *LockState);
- _SEH2_LEAVE;
- }
- /* Can only be a SrvCall */
- else
- {
- ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
- SrvCall = Container;
+ DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize);
- /* Wait for the SRV_CALL to be stable */
- if (SrvCall->Condition == Condition_InTransition)
- {
- RxReleasePrefixTableLock(PrefixTable);
- DPRINT("Waiting for stable condition for: %p\n", SrvCall);
- RxWaitForStableSrvCall(SrvCall, RxContext);
- RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
- *LockState = LHS_ExclusiveLockHeld;
+ /* 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;
- /* It went good, loop again to find what we look for */
- if (SrvCall->Condition == Condition_Good)
- {
- goto RetryLookup;
- }
- }
+ /* Associated FCB can't be fake one */
+ ASSERT(NodeType(Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
+ ASSERT(RxIsFcbAcquiredExclusive (Fcb));
- /* If it's not good... */
- if (SrvCall->Condition != Condition_Good)
- {
- /* But SRV_CALL was well constructed, assume a connection was active */
- if (SrvCall->Status == STATUS_SUCCESS)
- {
- Status = STATUS_CONNECTION_ACTIVE;
- }
- else
- {
- Status = SrvCall->Status;
- }
+ /* Purge any pending operation */
+ RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen);
- RxDereferenceSrvCall(SrvCall, *LockState);
- _SEH2_LEAVE;
- }
- }
- }
+ /* If the FCB wasn't orphaned, inform the mini-rdr about close */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ NTSTATUS Status;
- /* If we found a SRV_CALL not matching our DO, quit */
- if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
- SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
- {
- RxDereferenceSrvCall(SrvCall, *LockState);
- Status = STATUS_BAD_NETWORK_NAME;
- _SEH2_LEAVE;
- }
+ MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen));
+ (void)Status;
+ }
- /* Now, we want exclusive lock */
- if (*LockState == LHS_SharedLockHeld)
- {
- if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
- {
- RxReleasePrefixTableLock(PrefixTable);
- RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
- *LockState = LHS_ExclusiveLockHeld;
- goto RetryLookup;
- }
+ /* Remove ourselves from the FCB */
+ RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
+ InitializeListHead(&ThisSrvOpen->SrvOpenQLinks);
+ ++Fcb->SrvOpenListVersion;
- RxReleasePrefixTableLock(PrefixTable);
- *LockState = LHS_ExclusiveLockHeld;
- }
+ /* 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;
+ }
- ASSERT(*LockState == LHS_ExclusiveLockHeld);
+ /* Finalization done */
+ ThisSrvOpen->UpperFinalizationDone = TRUE;
+ }
- /* If we reach that point, we found something, no need to create something */
- if (Container != NULL)
- {
- break;
- }
+ /* Don't free memory if still referenced */
+ if (ThisSrvOpen->NodeReferenceCount != 0)
+ {
+ return FALSE;
+ }
- /* Get the name for the SRV_CALL */
- RxExtractServerName(FilePathName, &SrvCallName, NULL);
- DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
- /* And create the SRV_CALL */
- SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
- if (SrvCall == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- _SEH2_LEAVE;
- }
+ /* No key association left */
+ ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList));
- /* Reset RX_CONTEXT, so far, connection creation isn't a success */
- RxReferenceSrvCall(SrvCall);
- RxContext->Create.pVNetRoot = NULL;
- RxContext->Create.pNetRoot = NULL;
- RxContext->Create.pSrvCall = NULL;
- RxContext->Create.Type = NetRootType;
- Container = SrvCall;
+ /* If we're still in some FCB, remove us */
+ if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks))
+ {
+ RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
+ }
- /* Construct SRV_CALL, ie, use mini-rdr */
- Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
- ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
- if (Status != STATUS_SUCCESS)
- {
- DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
- RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
- RxDereferenceSrvCall(SrvCall, *LockState);
- RxReleasePrefixTableLock(PrefixTable);
- _SEH2_LEAVE;
- }
+ /* If enclosed allocation, mark the memory zone free and dereference FCB */
+ if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
+ {
+ ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED);
+ RxDereferenceNetFcb(Fcb);
+ }
+ /* Otherwise, free the memory */
+ else
+ {
+ RxFreeFcbObject(ThisSrvOpen);
+ }
- /* Loop again to make use of SRV_CALL stable condition wait */
- }
+ return TRUE;
+}
- /* At that point, we have a stable SRV_CALL (either found or constructed) */
- ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
- ASSERT(NetRoot == NULL && VNetRoot == NULL);
- ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
+/*
+ * @implemented
+ */
+BOOLEAN
+RxFinalizeVNetRoot(
+ OUT PV_NET_ROOT ThisVNetRoot,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ PNET_ROOT NetRoot;
+ PRX_PREFIX_TABLE PrefixTable;
- /* Call mini-rdr to get NetRoot name */
- SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
- /* And create the NetRoot with that name */
- NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
- if (NetRoot == NULL)
- {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- _SEH2_LEAVE;
- }
- NetRoot->Type = NetRootType;
+ PAGED_CODE();
- RxDereferenceSrvCall(SrvCall, *LockState);
+ ASSERT(NodeType(ThisVNetRoot) == RDBSS_NTC_V_NETROOT);
- /* Finally, create the associated VNetRoot */
- VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
- if (VNetRoot == NULL)
- {
- RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
- Status = STATUS_INSUFFICIENT_RESOURCES;
- _SEH2_LEAVE;
- }
- RxReferenceVNetRoot(VNetRoot);
-
- /* We're get closer! */
- NetRoot->Condition = Condition_InTransition;
- RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
- RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
- RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
-
- /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
- Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
- if (!NT_SUCCESS(Status))
- {
- RxTransitionVNetRoot(VNetRoot, Condition_Bad);
- DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
- RxDereferenceVNetRoot(VNetRoot, *LockState);
-
- RxContext->Create.pNetRoot = NULL;
- RxContext->Create.pVNetRoot = NULL;
- }
- else
- {
- PIO_STACK_LOCATION Stack;
-
- ASSERT(*LockState == LHS_ExclusiveLockHeld);
+ PrefixTable = ThisVNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
- Stack = RxContext->CurrentIrpSp;
- if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
- {
- RxExclusivePrefixTableLockToShared(PrefixTable);
- *LockState = LHS_SharedLockHeld;
- }
- }
- }
- _SEH2_FINALLY
+ /* Only finalize if forced or if there's a single ref left */
+ if (ThisVNetRoot->NodeReferenceCount != 1 &&
+ !ForceFinalize)
{
- if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
- {
- if (*LockState != LHS_LockNotHeld)
- {
- RxReleasePrefixTableLock(PrefixTable);
- *LockState = LHS_LockNotHeld;
- }
- }
+ return FALSE;
}
- _SEH2_END;
- DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
- return Status;
-}
+ DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot, &ThisVNetRoot->PrefixEntry.Prefix);
-/*
- * @implemented
- */
-VOID
-NTAPI
-RxFinishFcbInitialization(
- IN OUT PMRX_FCB Fcb,
- IN RX_FILE_TYPE FileType,
- IN PFCB_INIT_PACKET InitPacket OPTIONAL)
-{
- NODE_TYPE_CODE OldType;
+ NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
+ /* If it wasn't finalized yet, do it */
+ if (!ThisVNetRoot->UpperFinalizationDone)
+ {
+ ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
- PAGED_CODE();
+ /* 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);
- DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
+ /* Remove ourselves from prefix table */
+ RxRemovePrefixTableEntry(PrefixTable, &ThisVNetRoot->PrefixEntry);
- OldType = Fcb->Header.NodeTypeCode;
- Fcb->Header.NodeTypeCode = 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)
- {
- FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ /* Finalization done */
+ ThisVNetRoot->UpperFinalizationDone = TRUE;
}
- /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
- else if (InitPacket != NULL)
+
+ /* If we're still referenced, don't go any further! */
+ if (ThisVNetRoot->NodeReferenceCount != 1)
{
- FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
- InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
- InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
- InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
- InitPacket->pValidDataLength->QuadPart);
+ return FALSE;
}
- if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
- FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
+ /* If there's an associated device, notify mini-rdr */
+ if (NetRoot->pSrvCall->RxDeviceObject != NULL)
{
- /* If our FCB newly points to a file, initiliaz everything related */
- if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE &&
- !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;
+ NTSTATUS Status;
- Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
- }
- else
- {
- ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
- }
+ 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;
}
-/*
- * @implemented
- */
NTSTATUS
-RxFinishSrvCallConstruction(
- PMRX_SRVCALLDOWN_STRUCTURE Calldown)
+RxFindOrConstructVirtualNetRoot(
+ IN PRX_CONTEXT RxContext,
+ IN PUNICODE_STRING CanonicalName,
+ IN NET_ROOT_TYPE NetRootType,
+ IN PUNICODE_STRING RemainingName)
{
+ ULONG Flags;
NTSTATUS Status;
- PSRV_CALL SrvCall;
- PRX_CONTEXT Context;
- RX_BLOCK_CONDITION Condition;
- PRX_PREFIX_TABLE PrefixTable;
+ PVOID Container;
+ BOOLEAN Construct;
+ PV_NET_ROOT VNetRoot;
+ RX_CONNECTION_ID ConnectionID;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ LOCK_HOLDING_STATE LockHoldingState;
- DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
+ PAGED_CODE();
- SrvCall = (PSRV_CALL)Calldown->SrvCall;
- Context = Calldown->RxContext;
- PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
+ RxDeviceObject = RxContext->RxDeviceObject;
+ ASSERT(RxDeviceObject->Dispatch != NULL);
+ ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
- /* We have a winner, notify him */
- if (Calldown->BestFinisher != NULL)
+ /* Ask the mini-rdr for connection ID */
+ ConnectionID.SessionID = 0;
+ if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
{
- DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
-
- ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
-
- MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
- MRxSrvCallWinnerNotify,
- ((PMRX_SRV_CALL)SrvCall, TRUE,
- Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
- if (Status != STATUS_SUCCESS)
- {
- Condition = Condition_Bad;
- }
- else
+ Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
+ if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
{
- Condition = Condition_Good;
+ /* mini-rdr is expected not to fail - unless it's not implemented */
+ DPRINT1("Failed to initialize connection ID\n");
+ ASSERT(FALSE);
}
}
- /* Otherwise, just fail our SRV_CALL */
- else
- {
- Status = Calldown->CallbackContexts[0].Status;
- Condition = Condition_Bad;
- }
-
- RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
- RxTransitionSrvCall(SrvCall, Condition);
- ExFreePoolWithTag(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))
- {
- DPRINT("Finishing async call\n");
-
- RxReleasePrefixTableLock(PrefixTable);
+ RxContext->Create.NetNamePrefixEntry = NULL;
- /* Make sure we weren't cancelled in-between */
- if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
- {
- Status = STATUS_CANCELLED;
- }
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
+ LockHoldingState = LHS_SharedLockHeld;
+ Construct = TRUE;
+ Flags = 0;
- /* In case that was a create, context can be reused */
- if (Context->MajorFunction == IRP_MJ_CREATE)
- {
- RxpPrepareCreateContextForReuse(Context);
- }
+ /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
+ while (TRUE)
+ {
+ PNET_ROOT NetRoot;
+ PV_NET_ROOT SavedVNetRoot;
- /* If that's a failure, reset everything and return failure */
- if (Status != STATUS_SUCCESS)
+ /* Look in prefix table */
+ Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
+ if (Container != NULL)
{
- Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
- if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
+ /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
+ if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
{
- if (Context->Info.Buffer != NULL)
- {
- ExFreePool(Context->Info.Buffer);
- Context->Info.Buffer = NULL;
- }
+ ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
+ RxDereferenceSrvCall(Container, LockHoldingState);
}
- Context->CurrentIrp->IoStatus.Information = 0;
- Context->CurrentIrp->IoStatus.Status = Status;
- RxCompleteRequest(Context, Status);
- }
- /* Otherwise, call resume routine and done! */
- else
- {
- Status = Context->ResumeRoutine(Context);
- if (Status != STATUS_PENDING)
+ else
{
- RxCompleteRequest(Context, Status);
- }
-
- DPRINT("Not completing, pending\n");
- }
- }
-
- RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
- return Status;
-}
-
-/*
- * @implemented
- */
-VOID
-NTAPI
-RxFinishSrvCallConstructionDispatcher(
- IN PVOID Context)
-{
- KIRQL OldIrql;
- BOOLEAN Direct, KeepLoop;
+ VNetRoot = Container;
+ NetRoot = VNetRoot->NetRoot;
- DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
+ /* 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,
+ &Flags);
+ if (NT_SUCCESS(Status))
+ {
+ SavedVNetRoot = VNetRoot;
+ Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
+ &LogonId, UserName,
+ UserDomain, Password,
+ Flags);
+ if (Status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ PLIST_ENTRY ListEntry;
+
+ for (ListEntry = NetRoot->VirtualNetRoots.Flink;
+ ListEntry != &NetRoot->VirtualNetRoots;
+ ListEntry = ListEntry->Flink)
+ {
+ SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
+ Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
+ &LogonId, UserName,
+ UserDomain, Password,
+ Flags);
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ break;
+ }
+ }
+
+ if (ListEntry == &NetRoot->VirtualNetRoots)
+ {
+ SavedVNetRoot = NULL;
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ SavedVNetRoot = NULL;
+ }
+
+ RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
+ }
+ }
+
+ /* We'll fail, if we had referenced a VNetRoot, dereference it */
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
+ {
+ if (SavedVNetRoot == NULL)
+ {
+ RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
+ }
+ }
+ /* Reference VNetRoot we'll keep, and dereference current */
+ else if (SavedVNetRoot != VNetRoot)
+ {
+ RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
+ if (SavedVNetRoot != NULL)
+ {
+ RxReferenceVNetRoot(SavedVNetRoot);
+ }
+ }
+ }
+
+ /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ Construct = FALSE;
+ break;
+ }
+ }
+
+ /* If we're locked exclusive, we won't loop again, it was the second pass */
+ if (LockHoldingState != LHS_SharedLockHeld)
+ {
+ break;
+ }
+
+ /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
+ if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
+ {
+ RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
+ LockHoldingState = LHS_ExclusiveLockHeld;
+ break;
+ }
+
+ RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
+ RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
+ LockHoldingState = LHS_ExclusiveLockHeld;
+ }
+
+ /* We didn't fail, and didn't find any VNetRoot, construct one */
+ if (Construct)
+ {
+ ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
+
+ Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
+ ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
+
+ if (Status == STATUS_SUCCESS)
+ {
+ DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
+ DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
+ ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
+
+ RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
+ RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
+ RemainingName->MaximumLength = RemainingName->Length;
+
+ if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
+ {
+ DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
+ }
+ VNetRoot->Flags |= Flags;
+ }
+ }
+
+ /* Release the prefix table - caller expects it to be released */
+ if (LockHoldingState != LHS_LockNotHeld)
+ {
+ RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
+ }
+
+ /* If we failed creating, quit */
+ if (Status != STATUS_SUCCESS)
+ {
+ DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
+ return Status;
+ }
+
+ /* Otherwise, wait until the VNetRoot is stable */
+ DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
+ RxWaitForStableVNetRoot(VNetRoot, RxContext);
+ /* It's all good, update the RX_CONTEXT with all our structs */
+ if (VNetRoot->Condition == Condition_Good)
+ {
+ PNET_ROOT NetRoot;
+
+ NetRoot = VNetRoot->NetRoot;
+ RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+ RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
+ RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
+ }
+ else
+ {
+ RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
+ RxContext->Create.pVNetRoot = NULL;
+ Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxFindOrCreateConnections(
+ _In_ PRX_CONTEXT RxContext,
+ _In_ PUNICODE_STRING CanonicalName,
+ _In_ NET_ROOT_TYPE NetRootType,
+ _Out_ PUNICODE_STRING LocalNetRootName,
+ _Out_ PUNICODE_STRING FilePathName,
+ _Inout_ PLOCK_HOLDING_STATE LockState,
+ _In_ PRX_CONNECTION_ID RxConnectionId)
+{
+ PVOID Container;
+ PSRV_CALL SrvCall;
+ PNET_ROOT NetRoot;
+ PV_NET_ROOT VNetRoot;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PRX_PREFIX_TABLE PrefixTable;
+ UNICODE_STRING RemainingName, NetRootName;
+
+ PAGED_CODE();
+
+ DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
+ RxContext, CanonicalName, NetRootType, LocalNetRootName,
+ FilePathName, LockState, RxConnectionId);
+
+ *FilePathName = *CanonicalName;
+ LocalNetRootName->Length = 0;
+ LocalNetRootName->MaximumLength = 0;
+ LocalNetRootName->Buffer = CanonicalName->Buffer;
+
+ /* UNC path, split it */
+ if (FilePathName->Buffer[1] == ';')
+ {
+ BOOLEAN Slash;
+ USHORT i, Length;
+
+ Slash = FALSE;
+ for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
+ {
+ if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
+ {
+ Slash = TRUE;
+ break;
+ }
+ }
+
+ if (!Slash)
+ {
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ FilePathName->Buffer = &FilePathName->Buffer[i];
+ Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
+ LocalNetRootName->Length = Length;
+ LocalNetRootName->MaximumLength = Length;
+ FilePathName->Length -= Length;
+
+ DPRINT("CanonicalName: %wZ\n", CanonicalName);
+ DPRINT(" -> FilePathName: %wZ\n", FilePathName);
+ DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
+ }
+
+ Container = NULL;
+ PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
+
+ _SEH2_TRY
+ {
+RetryLookup:
+ ASSERT(*LockState != LHS_LockNotHeld);
+
+ /* If previous lookup left something, dereference it */
+ if (Container != NULL)
+ {
+ switch (NodeType(Container))
+ {
+ case RDBSS_NTC_SRVCALL:
+ RxDereferenceSrvCall(Container, *LockState);
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ RxDereferenceNetRoot(Container, *LockState);
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ RxDereferenceVNetRoot(Container, *LockState);
+ break;
+
+ default:
+ /* Should never happen */
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ /* Look for our NetRoot in prefix table */
+ Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
+ DPRINT("Container %p for path %wZ\n", Container, FilePathName);
+
+ while (TRUE)
+ {
+ UNICODE_STRING SrvCallName;
+
+ SrvCall = NULL;
+ NetRoot = NULL;
+ VNetRoot = NULL;
+
+ /* Assume we didn't succeed */
+ RxContext->Create.pVNetRoot = NULL;
+ RxContext->Create.pNetRoot = NULL;
+ RxContext->Create.pSrvCall = NULL;
+ RxContext->Create.Type = NetRootType;
+
+ /* If we found something */
+ if (Container != NULL)
+ {
+ /* A VNetRoot */
+ if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
+ {
+ VNetRoot = Container;
+ /* Use its NetRoot */
+ NetRoot = VNetRoot->NetRoot;
+
+ /* If it's not stable, wait for it to be stable */
+ if (NetRoot->Condition == Condition_InTransition)
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ DPRINT("Waiting for stable condition for: %p\n", NetRoot);
+ RxWaitForStableNetRoot(NetRoot, RxContext);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ *LockState = LHS_ExclusiveLockHeld;
+
+ /* Now that's it's ok, retry lookup to find what we want */
+ if (NetRoot->Condition == Condition_Good)
+ {
+ goto RetryLookup;
+ }
+ }
+
+ /* Is the associated netroot good? */
+ if (NetRoot->Condition == Condition_Good)
+ {
+ SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
+
+ /* If it is, and SrvCall as well, then, we have our active connection */
+ if (SrvCall->Condition == Condition_Good &&
+ SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
+ {
+ RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+ RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
+ RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
+
+ Status = STATUS_CONNECTION_ACTIVE;
+ _SEH2_LEAVE;
+ }
+ }
+
+ /* If VNetRoot was well constructed, it means the connection is active */
+ if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
+ {
+ Status = STATUS_CONNECTION_ACTIVE;
+ }
+ else
+ {
+ Status = VNetRoot->ConstructionStatus;
+ }
+
+ RxDereferenceVNetRoot(VNetRoot, *LockState);
+ _SEH2_LEAVE;
+ }
+ /* Can only be a SrvCall */
+ else
+ {
+ ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
+ SrvCall = Container;
+
+ /* Wait for the SRV_CALL to be stable */
+ if (SrvCall->Condition == Condition_InTransition)
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ DPRINT("Waiting for stable condition for: %p\n", SrvCall);
+ RxWaitForStableSrvCall(SrvCall, RxContext);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ *LockState = LHS_ExclusiveLockHeld;
+
+ /* It went good, loop again to find what we look for */
+ if (SrvCall->Condition == Condition_Good)
+ {
+ goto RetryLookup;
+ }
+ }
+
+ /* If it's not good... */
+ if (SrvCall->Condition != Condition_Good)
+ {
+ /* But SRV_CALL was well constructed, assume a connection was active */
+ if (SrvCall->Status == STATUS_SUCCESS)
+ {
+ Status = STATUS_CONNECTION_ACTIVE;
+ }
+ else
+ {
+ Status = SrvCall->Status;
+ }
+
+ RxDereferenceSrvCall(SrvCall, *LockState);
+ _SEH2_LEAVE;
+ }
+ }
+ }
+
+ /* If we found a SRV_CALL not matching our DO, quit */
+ if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
+ SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
+ {
+ RxDereferenceSrvCall(SrvCall, *LockState);
+ Status = STATUS_BAD_NETWORK_NAME;
+ _SEH2_LEAVE;
+ }
+
+ /* Now, we want exclusive lock */
+ if (*LockState == LHS_SharedLockHeld)
+ {
+ if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ *LockState = LHS_ExclusiveLockHeld;
+ goto RetryLookup;
+ }
+
+ RxReleasePrefixTableLock(PrefixTable);
+ *LockState = LHS_ExclusiveLockHeld;
+ }
+
+ ASSERT(*LockState == LHS_ExclusiveLockHeld);
+
+ /* If we reach that point, we found something, no need to create something */
+ if (Container != NULL)
+ {
+ break;
+ }
+
+ /* Get the name for the SRV_CALL */
+ RxExtractServerName(FilePathName, &SrvCallName, NULL);
+ DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
+ /* And create the SRV_CALL */
+ SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
+ if (SrvCall == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+
+ /* Reset RX_CONTEXT, so far, connection creation isn't a success */
+ RxReferenceSrvCall(SrvCall);
+ RxContext->Create.pVNetRoot = NULL;
+ RxContext->Create.pNetRoot = NULL;
+ RxContext->Create.pSrvCall = NULL;
+ RxContext->Create.Type = NetRootType;
+ Container = SrvCall;
+
+ /* Construct SRV_CALL, ie, use mini-rdr */
+ Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
+ ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
+ if (Status != STATUS_SUCCESS)
+ {
+ DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ RxDereferenceSrvCall(SrvCall, *LockState);
+ RxReleasePrefixTableLock(PrefixTable);
+ _SEH2_LEAVE;
+ }
+
+ /* Loop again to make use of SRV_CALL stable condition wait */
+ }
+
+ /* At that point, we have a stable SRV_CALL (either found or constructed) */
+ ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
+ ASSERT(NetRoot == NULL && VNetRoot == NULL);
+ ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
+
+ /* Call mini-rdr to get NetRoot name */
+ SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
+ /* And create the NetRoot with that name */
+ NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
+ if (NetRoot == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+ NetRoot->Type = NetRootType;
+
+ RxDereferenceSrvCall(SrvCall, *LockState);
+
+ /* Finally, create the associated VNetRoot */
+ VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
+ if (VNetRoot == NULL)
+ {
+ RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ _SEH2_LEAVE;
+ }
+ RxReferenceVNetRoot(VNetRoot);
+
+ /* We're get closer! */
+ NetRoot->Condition = Condition_InTransition;
+ RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
+ RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
+ RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+
+ /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
+ Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
+ if (!NT_SUCCESS(Status))
+ {
+ RxTransitionVNetRoot(VNetRoot, Condition_Bad);
+ DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
+ RxDereferenceVNetRoot(VNetRoot, *LockState);
+
+ RxContext->Create.pNetRoot = NULL;
+ RxContext->Create.pVNetRoot = NULL;
+ }
+ else
+ {
+ PIO_STACK_LOCATION Stack;
+
+ ASSERT(*LockState == LHS_ExclusiveLockHeld);
+
+ Stack = RxContext->CurrentIrpSp;
+ if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
+ {
+ RxExclusivePrefixTableLockToShared(PrefixTable);
+ *LockState = LHS_SharedLockHeld;
+ }
+ }
+ }
+ _SEH2_FINALLY
+ {
+ if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
+ {
+ if (*LockState != LHS_LockNotHeld)
+ {
+ RxReleasePrefixTableLock(PrefixTable);
+ *LockState = LHS_LockNotHeld;
+ }
+ }
+ }
+ _SEH2_END;
+
+ DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxFinishFcbInitialization(
+ IN OUT PMRX_FCB Fcb,
+ IN RX_FILE_TYPE FileType,
+ IN PFCB_INIT_PACKET InitPacket OPTIONAL)
+{
+ NODE_TYPE_CODE OldType;
+
+ PAGED_CODE();
+
+ DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
+
+ OldType = Fcb->Header.NodeTypeCode;
+ Fcb->Header.NodeTypeCode = 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)
+ {
+ FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+ /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
+ else if (InitPacket != NULL)
+ {
+ FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
+ InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
+ InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
+ InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
+ InitPacket->pValidDataLength->QuadPart);
+ }
+
+ 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)
+ {
+ RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
+ FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, &RxLockOperationCompletion,
+ &RxUnlockOperation);
+
+ ((PFCB)Fcb)->BufferedLocks.List = NULL;
+ ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
+
+ Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
+ }
+ else
+ {
+ ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
+ }
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxFinishSrvCallConstruction(
+ PMRX_SRVCALLDOWN_STRUCTURE Calldown)
+{
+ NTSTATUS Status;
+ PSRV_CALL SrvCall;
+ PRX_CONTEXT Context;
+ RX_BLOCK_CONDITION Condition;
+ PRX_PREFIX_TABLE PrefixTable;
+
+ DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
+
+ SrvCall = (PSRV_CALL)Calldown->SrvCall;
+ Context = Calldown->RxContext;
+ PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
+
+ /* We have a winner, notify him */
+ if (Calldown->BestFinisher != NULL)
+ {
+ DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
+
+ ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
+
+ MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
+ MRxSrvCallWinnerNotify,
+ ((PMRX_SRV_CALL)SrvCall, TRUE,
+ Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
+ if (Status != STATUS_SUCCESS)
+ {
+ Condition = Condition_Bad;
+ }
+ else
+ {
+ Condition = Condition_Good;
+ }
+ }
+ /* Otherwise, just fail our SRV_CALL */
+ else
+ {
+ Status = Calldown->CallbackContexts[0].Status;
+ Condition = Condition_Bad;
+ }
+
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ RxTransitionSrvCall(SrvCall, Condition);
+ 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))
+ {
+ DPRINT("Finishing async call\n");
+
+ RxReleasePrefixTableLock(PrefixTable);
+
+ /* Make sure we weren't cancelled in-between */
+ if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
+ {
+ Status = STATUS_CANCELLED;
+ }
+
+ /* In case that was a create, context can be reused */
+ if (Context->MajorFunction == IRP_MJ_CREATE)
+ {
+ RxpPrepareCreateContextForReuse(Context);
+ }
+
+ /* If that's a failure, reset everything and return failure */
+ if (Status != STATUS_SUCCESS)
+ {
+ Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
+ if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
+ {
+ if (Context->Info.Buffer != NULL)
+ {
+ RxFreePool(Context->Info.Buffer);
+ Context->Info.Buffer = NULL;
+ }
+ }
+ Context->CurrentIrp->IoStatus.Information = 0;
+ Context->CurrentIrp->IoStatus.Status = Status;
+ RxCompleteRequest(Context, Status);
+ }
+ /* Otherwise, call resume routine and done! */
+ else
+ {
+ Status = Context->ResumeRoutine(Context);
+ if (Status != STATUS_PENDING)
+ {
+ RxCompleteRequest(Context, Status);
+ }
+
+ DPRINT("Not completing, pending\n");
+ }
+ }
+
+ RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxFinishSrvCallConstructionDispatcher(
+ IN PVOID Context)
+{
+ KIRQL OldIrql;
+ BOOLEAN Direct, KeepLoop;
+
+ DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
/* In case of failure of starting dispatcher, context is not set
* We keep track of it to fail associated SRV_CALL
*/
Direct = (Context == NULL);
- /* Separated thread, loop forever */
- while (TRUE)
+ /* Separated thread, loop forever */
+ while (TRUE)
+ {
+ PLIST_ENTRY ListEntry;
+ PMRX_SRVCALLDOWN_STRUCTURE Calldown;
+
+ /* If there are no SRV_CALL to finalize left, just finish thread */
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
+ if (IsListEmpty(&RxSrvCalldownList))
+ {
+ KeepLoop = FALSE;
+ RxSrvCallConstructionDispatcherActive = FALSE;
+ }
+ /* Otherwise, get the SRV_CALL to finish construction */
+ else
+ {
+ ListEntry = RemoveHeadList(&RxSrvCalldownList);
+ KeepLoop = TRUE;
+ }
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+
+ /* Nothing to do */
+ if (!KeepLoop)
+ {
+ break;
+ }
+
+ /* If direct is set, reset the finisher to avoid electing a winner
+ * and fail SRV_CALL (see upper comment)
+ */
+ Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
+ if (Direct)
+ {
+ Calldown->BestFinisher = NULL;
+ }
+ /* Finish SRV_CALL construction */
+ RxFinishSrvCallConstruction(Calldown);
+ }
+}
+
+/*
+ * @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)
+{
+ PAGED_CODE();
+
+ /* 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)
+{
+ 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;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxGetFileSizeWithLock(
+ IN PFCB Fcb,
+ OUT PLONGLONG FileSize)
+{
+ PAGED_CODE();
+
+ *FileSize = Fcb->Header.FileSize.QuadPart;
+}
+
+/*
+ * @implemented
+ */
+PEPROCESS
+NTAPI
+RxGetRDBSSProcess(
+ VOID)
+{
+ return RxData.OurProcess;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxInitializeBufferingManager(
+ PSRV_CALL SrvCall)
+{
+ KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
+ InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
+ InitializeListHead(&SrvCall->BufferingManager.HandlerList);
+ InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
+ SrvCall->BufferingManager.DispatcherActive = FALSE;
+ SrvCall->BufferingManager.HandlerInactive = FALSE;
+ SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
+ SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
+ InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
+ ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxInitializeContext(
+ IN PIRP Irp,
+ IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
+ IN ULONG InitialContextFlags,
+ IN OUT PRX_CONTEXT RxContext)
+{
+ PIO_STACK_LOCATION Stack;
+
+ /* Initialize our various fields */
+ RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
+ RxContext->NodeByteSize = sizeof(RX_CONTEXT);
+ RxContext->ReferenceCount = 1;
+ RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
+ RxContext->RxDeviceObject = RxDeviceObject;
+ KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
+ RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
+ InitializeListHead(&RxContext->BlockedOperations);
+ RxContext->MRxCancelRoutine = NULL;
+ RxContext->ResumeRoutine = NULL;
+ RxContext->Flags |= InitialContextFlags;
+ RxContext->CurrentIrp = Irp;
+ RxContext->LastExecutionThread = PsGetCurrentThread();
+ RxContext->OriginalThread = RxContext->LastExecutionThread;
+
+ /* If've got no IRP, mark RX_CONTEXT */
+ if (Irp == NULL)
+ {
+ RxContext->CurrentIrpSp = NULL;
+ RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
+ RxContext->MinorFunction = 0;
+ }
+ else
+ {
+ /* Otherwise, first determine whether we are performing async operation */
+ Stack = IoGetCurrentIrpStackLocation(Irp);
+ if (Stack->FileObject != NULL)
+ {
+ PFCB Fcb;
+
+ Fcb = Stack->FileObject->FsContext;
+ if (!IoIsOperationSynchronous(Irp) ||
+ ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
+ (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
+ (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
+ }
+ }
+
+ if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
+ }
+ if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
+ }
+
+ /* Set proper flags if TopLevl IRP/Device */
+ if (!RxIsThisTheTopLevelIrp(Irp))
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
+ }
+ if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
+ }
+
+ /* Copy stack information */
+ RxContext->MajorFunction = Stack->MajorFunction;
+ RxContext->MinorFunction = Stack->MinorFunction;
+ ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
+ RxContext->CurrentIrpSp = Stack;
+
+ /* If we have a FO associated, learn for more */
+ if (Stack->FileObject != NULL)
+ {
+ PFCB Fcb;
+ PFOBX Fobx;
+
+ /* Get the FCB and CCB (FOBX) */
+ Fcb = Stack->FileObject->FsContext;
+ Fobx = Stack->FileObject->FsContext2;
+ RxContext->pFcb = (PMRX_FCB)Fcb;
+ if (Fcb != NULL && NodeTypeIsFcb(Fcb))
+ {
+ RxContext->NonPagedFcb = Fcb->NonPaged;
+ }
+
+ /* We have a FOBX, this not a DFS opening, keep track of it */
+ if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
+ {
+ RxContext->pFobx = (PMRX_FOBX)Fobx;
+ RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
+ if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
+ {
+ RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
+ }
+ }
+ else
+ {
+ RxContext->pFobx = NULL;
+ }
+
+ /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
+ if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
+ Fobx != NULL)
+ {
+ PV_NET_ROOT VNetRoot = NULL;
+
+ if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
+ {
+ VNetRoot = Fcb->VNetRoot;
+ }
+ else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
+ {
+ VNetRoot = (PV_NET_ROOT)Fobx;
+ }
+
+ if (VNetRoot != NULL)
+ {
+ RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
+ }
+ }
+
+ /* Remember if that's a write through file */
+ RxContext->RealDevice = Stack->FileObject->DeviceObject;
+ if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
+ {
+ RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
+ }
+ }
+ }
+
+ if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
+ {
+ DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
+ RxContext, RxContext->MinorFunction, Irp,
+ PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
+ RxContext->SerialNumber);
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxInitializeDispatcher(
+ VOID)
+{
+ NTSTATUS Status;
+ HANDLE ThreadHandle;
+
+ PAGED_CODE();
+
+ RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
+ RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL;
+
+ /* Set appropriate timeouts: 10s & 60s */
+ RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
+ RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
+ RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
+ RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
+
+ RxDispatcher.NumberOfProcessors = 1;
+ RxDispatcher.OwnerProcess = IoGetCurrentProcess();
+ RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues;
+
+ /* Initialize our dispatchers */
+ Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher);
+ if (!NT_SUCCESS(Status))
{
- PLIST_ENTRY ListEntry;
- PMRX_SRVCALLDOWN_STRUCTURE Calldown;
+ return Status;
+ }
- /* If there are no SRV_CALL to finalize left, just finish thread */
- KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
- if (IsListEmpty(&RxSrvCalldownList))
- {
- KeepLoop = FALSE;
- RxSrvCallConstructionDispatcherActive = FALSE;
- }
- /* Otherwise, get the SRV_CALL to finish construction */
- else
- {
- ListEntry = RemoveHeadList(&RxSrvCalldownList);
- KeepLoop = TRUE;
- }
- KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+ Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- /* Nothing to do */
- if (!KeepLoop)
- {
- break;
- }
+ /* And start them */
+ RxDispatcher.State = RxDispatcherActive;
+ InitializeListHead(&RxDispatcher.SpinUpRequests);
+ KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock);
+ KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0);
+ KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0);
+ Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL,
+ NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher);
+ if (NT_SUCCESS(Status))
+ {
+ ZwClose(ThreadHandle);
+ }
- /* If direct is set, reset the finisher to avoid electing a winner
- * and fail SRV_CALL (see upper comment)
- */
- Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
- if (Direct)
- {
- Calldown->BestFinisher = NULL;
- }
- /* Finish SRV_CALL construction */
- RxFinishSrvCallConstruction(Calldown);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxInitializeFcbTable(
+ IN OUT PRX_FCB_TABLE FcbTable,
+ IN BOOLEAN CaseInsensitiveMatch)
+{
+ USHORT i;
+
+ PAGED_CODE();
+
+ FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
+ FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
+
+ ExInitializeResourceLite(&FcbTable->TableLock);
+ FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
+ FcbTable->Version = 0;
+ FcbTable->TableEntryForNull = NULL;
+
+ FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
+ for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
+ {
+ InitializeListHead(&FcbTable->HashBuckets[i]);
}
+
+ FcbTable->Lookups = 0;
+ FcbTable->FailedLookups = 0;
+ FcbTable->Compares = 0;
}
+/*
+ * @implemented
+ */
VOID
-RxFreeFcbObject(
- PVOID Object)
+NTAPI
+RxInitializeLowIoContext(
+ OUT PLOWIO_CONTEXT LowIoContext,
+ IN ULONG Operation)
{
- UNIMPLEMENTED;
+ PRX_CONTEXT RxContext;
+ PIO_STACK_LOCATION Stack;
+
+ PAGED_CODE();
+
+ RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
+ ASSERT(LowIoContext == &RxContext->LowIoContext);
+
+ Stack = RxContext->CurrentIrpSp;
+
+ KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
+ RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread();
+ RxContext->LowIoContext.Operation = Operation;
+
+ switch (Operation)
+ {
+ case LOWIO_OP_READ:
+ case LOWIO_OP_WRITE:
+ /* In case of RW, set a canary, to make sure these fields are properly set
+ * they will be asserted when lowio request will be submit to mini-rdr
+ * See LowIoSubmit()
+ */
+ RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
+ RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
+ RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
+
+ /* Keep track of paging IOs */
+ if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
+ {
+ RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO;
+ }
+ else
+ {
+ RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
+ }
+
+ break;
+
+ case LOWIO_OP_FSCTL:
+ case LOWIO_OP_IOCTL:
+ /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
+ RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
+ RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL;
+ RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
+ RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
+ break;
+
+ /* Nothing to do for these */
+ case LOWIO_OP_SHAREDLOCK:
+ case LOWIO_OP_EXCLUSIVELOCK:
+ case LOWIO_OP_UNLOCK:
+ case LOWIO_OP_UNLOCK_MULTIPLE:
+ case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
+ case LOWIO_OP_CLEAROUT:
+ break;
+
+ default:
+ /* Should never happen */
+ ASSERT(FALSE);
+ break;
+ }
}
+/*
+ * @implemented
+ */
VOID
-RxFreeObject(
- PVOID pObject)
+RxInitializeLowIoPerFcbInfo(
+ PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
{
- UNIMPLEMENTED;
+ PAGED_CODE();
+
+ InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
+ InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxInitializeMRxDispatcher(
+ IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
+{
+ PAGED_CODE();
+
+ pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
+ pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
+
+ return STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
-RxGetFileSizeWithLock(
- IN PFCB Fcb,
- OUT PLONGLONG FileSize)
+RxInitializePrefixTable(
+ IN OUT PRX_PREFIX_TABLE ThisTable,
+ IN ULONG TableSize OPTIONAL,
+ IN BOOLEAN CaseInsensitiveMatch)
{
PAGED_CODE();
- *FileSize = Fcb->Header.FileSize.QuadPart;
+ if (TableSize == 0)
+ {
+ TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH;
+ }
+
+ ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
+ ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
+ InitializeListHead(&ThisTable->MemberQueue);
+ ThisTable->Version = 0;
+ ThisTable->TableEntryForNull = NULL;
+ ThisTable->IsNetNameTable = FALSE;
+ ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
+ ThisTable->TableSize = TableSize;
+
+ if (TableSize > 0)
+ {
+ USHORT i;
+
+ for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
+ {
+ InitializeListHead(&ThisTable->HashBuckets[i]);
+ }
+ }
}
/*
* @implemented
*/
-PEPROCESS
-NTAPI
-RxGetRDBSSProcess(
- VOID)
+VOID
+RxInitializePurgeSyncronizationContext(
+ PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
{
- return RxData.OurProcess;
+ PAGED_CODE();
+
+ InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
+ PurgeSyncronizationContext->PurgeInProgress = FALSE;
+}
+
+NTSTATUS
+RxInitializeSrvCallParameters(
+ IN PRX_CONTEXT RxContext,
+ IN OUT PSRV_CALL SrvCall)
+{
+ PAGED_CODE();
+
+ SrvCall->pPrincipalName = NULL;
+
+ /* We only have stuff to initialize for file opening from DFS */
+ if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ ASSERT(RxContext->Create.EaBuffer != NULL);
+
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS
-RxInitializeBufferingManager(
- PSRV_CALL SrvCall)
+NTAPI
+RxInitializeRxTimer(
+ VOID)
{
- KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
- InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
- InitializeListHead(&SrvCall->BufferingManager.HandlerList);
- InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
- SrvCall->BufferingManager.DispatcherActive = FALSE;
- SrvCall->BufferingManager.HandlerInactive = FALSE;
- SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
- SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
- InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
- ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
+ PAGED_CODE();
+
+ RxTimerInterval.HighPart = -1;
+ RxTimerInterval.LowPart = -550000;
+ KeInitializeSpinLock(&RxTimerLock);
+ InitializeListHead(&RxTimerQueueHead);
+ InitializeListHead(&RxRecurrentWorkItemsList);
+ KeInitializeDpc(&RxTimerDpc, RxTimerDispatch, NULL);
+ KeInitializeTimer(&RxTimer);
+ RxTimerTickCount = 0;
return STATUS_SUCCESS;
}
-/*
- * @implemented
- */
-VOID
-NTAPI
-RxInitializeContext(
- IN PIRP Irp,
- IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
- IN ULONG InitialContextFlags,
- IN OUT PRX_CONTEXT RxContext)
+NTSTATUS
+RxInitializeVNetRootParameters(
+ PRX_CONTEXT RxContext,
+ OUT LUID *LogonId,
+ OUT PULONG SessionId,
+ OUT PUNICODE_STRING *UserNamePtr,
+ OUT PUNICODE_STRING *UserDomainNamePtr,
+ OUT PUNICODE_STRING *PasswordPtr,
+ OUT PULONG Flags)
{
- PIO_STACK_LOCATION Stack;
+ NTSTATUS Status;
+ PACCESS_TOKEN Token;
- /* Initialize our various fields */
- RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
- RxContext->NodeByteSize = sizeof(RX_CONTEXT);
- RxContext->ReferenceCount = 1;
- RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
- RxContext->RxDeviceObject = RxDeviceObject;
- KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
- RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
- InitializeListHead(&RxContext->BlockedOperations);
- RxContext->MRxCancelRoutine = NULL;
- RxContext->ResumeRoutine = NULL;
- RxContext->Flags |= InitialContextFlags;
- RxContext->CurrentIrp = Irp;
- RxContext->LastExecutionThread = PsGetCurrentThread();
- RxContext->OriginalThread = RxContext->LastExecutionThread;
+ PAGED_CODE();
- /* If've got no IRP, mark RX_CONTEXT */
- if (Irp == NULL)
+ DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
+ LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
+
+ *UserNamePtr = NULL;
+ *UserDomainNamePtr = NULL;
+ *PasswordPtr = NULL;
+ /* By default, that's not CSC instance */
+ *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
+
+ Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
+ if (SeTokenIsRestricted(Token))
{
- RxContext->CurrentIrpSp = NULL;
- RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
- RxContext->MinorFunction = 0;
+ return STATUS_ACCESS_DENIED;
}
- else
+
+ /* Get LogonId */
+ Status = SeQueryAuthenticationIdToken(Token, LogonId);
+ if (!NT_SUCCESS(Status))
{
- /* Otherwise, first determine whether we are performing async operation */
- Stack = IoGetCurrentIrpStackLocation(Irp);
- if (Stack->FileObject != NULL)
- {
- PFCB Fcb;
+ return Status;
+ }
- Fcb = Stack->FileObject->FsContext;
- if (!IoIsOperationSynchronous(Irp) ||
- ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
- (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
- (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
- {
- RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
- }
- }
+ /* And SessionId */
+ Status = SeQuerySessionIdToken(Token, SessionId);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
- {
- RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
- }
- if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
- {
- RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
- }
+ if (RxContext->Create.UserName.Buffer != NULL)
+ {
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Leave;
+ }
- /* Set proper flags if TopLevl IRP/Device */
- if (!RxIsThisTheTopLevelIrp(Irp))
- {
- RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
- }
- if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
- {
- RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
- }
+ /* Deal with connection credentials */
+ if (RxContext->Create.UserDomainName.Buffer != NULL)
+ {
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Leave;
+ }
- /* Copy stack information */
- RxContext->MajorFunction = Stack->MajorFunction;
- RxContext->MinorFunction = Stack->MinorFunction;
- ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
- RxContext->CurrentIrpSp = Stack;
+ if (RxContext->Create.Password.Buffer != NULL)
+ {
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Leave;
+ }
- /* If we have a FO associated, learn for more */
- if (Stack->FileObject != NULL)
+Leave:
+ if (NT_SUCCESS(Status))
+ {
+ /* If that's a CSC instance, mark it as such */
+ if (RxIsThisACscAgentOpen(RxContext))
{
- PFCB Fcb;
- PFOBX Fobx;
-
- /* Get the FCB and CCB (FOBX) */
- Fcb = Stack->FileObject->FsContext;
- Fobx = Stack->FileObject->FsContext2;
- RxContext->pFcb = (PMRX_FCB)Fcb;
- if (Fcb != NULL && NodeTypeIsFcb(Fcb))
- {
- RxContext->NonPagedFcb = Fcb->NonPaged;
- }
-
- /* We have a FOBX, this not a DFS opening, keep track of it */
- if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
- {
- RxContext->pFobx = (PMRX_FOBX)Fobx;
- RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
- if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
- {
- RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
- }
- }
- else
- {
- RxContext->pFobx = NULL;
- }
+ *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE;
+ }
+ return Status;
+ }
- /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
- if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
- Fobx != NULL)
- {
- PV_NET_ROOT VNetRoot = NULL;
+ return Status;
+}
- if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
- {
- VNetRoot = Fcb->VNetRoot;
- }
- else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
- {
- VNetRoot = (PV_NET_ROOT)Fobx;
- }
+/*
+ * @implemented
+ */
+VOID
+RxInitializeWorkQueue(
+ PRX_WORK_QUEUE WorkQueue,
+ WORK_QUEUE_TYPE WorkQueueType,
+ ULONG MaximumNumberOfWorkerThreads,
+ ULONG MinimumNumberOfWorkerThreads)
+{
+ PAGED_CODE();
- if (VNetRoot != NULL)
- {
- RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
- }
- }
+ WorkQueue->Type = WorkQueueType;
+ WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
+ WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
- /* Remember if that's a write through file */
- RxContext->RealDevice = Stack->FileObject->DeviceObject;
- if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
- {
- RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
- }
- }
- }
+ WorkQueue->State = RxWorkQueueActive;
+ WorkQueue->SpinUpRequestPending = FALSE;
+ WorkQueue->pRundownContext = NULL;
+ WorkQueue->NumberOfWorkItemsDispatched = 0;
+ WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
+ WorkQueue->CumulativeQueueLength = 0;
+ WorkQueue->NumberOfSpinUpRequests = 0;
+ WorkQueue->NumberOfActiveWorkerThreads = 0;
+ WorkQueue->NumberOfIdleWorkerThreads = 0;
+ WorkQueue->NumberOfFailedSpinUpRequests = 0;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
+ WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
+ WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
+ WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
+ WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
+ WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
+ WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
+ WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
+ WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
+ WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
- if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
- {
- DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
- RxContext, RxContext->MinorFunction, Irp,
- PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
- RxContext->SerialNumber);
- }
+ KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
+ KeInitializeSpinLock(&WorkQueue->SpinLock);
}
/*
* @implemented
*/
NTSTATUS
-NTAPI
-RxInitializeDispatcher(
- VOID)
+RxInitializeWorkQueueDispatcher(
+ PRX_WORK_QUEUE_DISPATCHER Dispatcher)
{
NTSTATUS Status;
- HANDLE ThreadHandle;
+ ULONG MaximumNumberOfWorkerThreads;
PAGED_CODE();
- RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
- RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL;
-
- /* Set appropriate timeouts: 10s & 60s */
- RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
- RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
- RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
- RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
+ /* Number of threads will depend on system capacity */
+ if (MmQuerySystemSize() != MmLargeSystem)
+ {
+ MaximumNumberOfWorkerThreads = 5;
+ }
+ else
+ {
+ MaximumNumberOfWorkerThreads = 10;
+ }
- RxDispatcher.NumberOfProcessors = 1;
- RxDispatcher.OwnerProcess = IoGetCurrentProcess();
- RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues;
+ /* Initialize the work queues */
+ RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue,
+ MaximumNumberOfWorkerThreads, 1);
+ RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1);
+ RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1);
- /* Initialize our dispatchers */
- Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher);
+ /* And start the worker threads */
+ Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue],
+ RxBootstrapWorkerThreadDispatcher,
+ &Dispatcher->WorkQueue[HyperCriticalWorkQueue]);
if (!NT_SUCCESS(Status))
{
return Status;
}
- Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject);
+ Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue],
+ RxBootstrapWorkerThreadDispatcher,
+ &Dispatcher->WorkQueue[CriticalWorkQueue]);
if (!NT_SUCCESS(Status))
{
return Status;
}
- /* And start them */
- RxDispatcher.State = RxDispatcherActive;
- InitializeListHead(&RxDispatcher.SpinUpRequests);
- KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock);
- KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0);
- KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0);
- Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL,
- NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher);
- if (NT_SUCCESS(Status))
- {
- ZwClose(ThreadHandle);
- }
-
+ Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue],
+ RxBootstrapWorkerThreadDispatcher,
+ &Dispatcher->WorkQueue[DelayedWorkQueue]);
return Status;
}
* @implemented
*/
VOID
-RxInitializeFcbTable(
- IN OUT PRX_FCB_TABLE FcbTable,
- IN BOOLEAN CaseInsensitiveMatch)
+RxInitiateSrvOpenKeyAssociation(
+ IN OUT PSRV_OPEN SrvOpen)
{
- USHORT i;
+ PRX_BUFFERING_MANAGER BufferingManager;
PAGED_CODE();
- FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
- FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
-
- ExInitializeResourceLite(&FcbTable->TableLock);
- FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
- FcbTable->Version = 0;
- FcbTable->TableEntryForNull = NULL;
+ SrvOpen->Key = NULL;
- FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
- for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
- {
- InitializeListHead(&FcbTable->HashBuckets[i]);
- }
+ /* Just keep track of the opening request */
+ BufferingManager = &((PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall)->BufferingManager;
+ InterlockedIncrement(&BufferingManager->NumberOfOutstandingOpens);
- FcbTable->Lookups = 0;
- FcbTable->FailedLookups = 0;
- FcbTable->Compares = 0;
+ InitializeListHead(&SrvOpen->SrvOpenKeyList);
}
/*
* @implemented
*/
-VOID
-NTAPI
-RxInitializeLowIoContext(
- OUT PLOWIO_CONTEXT LowIoContext,
- IN ULONG Operation)
+NTSTATUS
+RxInsertWorkQueueItem(
+ PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
+ WORK_QUEUE_TYPE WorkQueueType,
+ PRX_WORK_QUEUE_ITEM WorkQueueItem)
{
- PRX_CONTEXT RxContext;
- PIO_STACK_LOCATION Stack;
-
- PAGED_CODE();
-
- RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
- ASSERT(LowIoContext = &RxContext->LowIoContext);
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ BOOLEAN SpinUpThreads;
+ PRX_WORK_QUEUE WorkQueue;
- Stack = RxContext->CurrentIrpSp;
+ /* No dispatcher, nothing to insert */
+ if (RxDispatcher.State != RxDispatcherActive)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
- KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
- RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread();
- RxContext->LowIoContext.Operation = Operation;
+ /* Get the work queue */
+ WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType];
- switch (Operation)
+ KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
+ /* Only insert if the work queue is in decent state */
+ if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL)
{
- case LOWIO_OP_READ:
- case LOWIO_OP_WRITE:
- /* In case of RW, set a canary, to make sure these fields are properly set
- * they will be asserted when lowio request will be submit to mini-rdr
- * See LowIoSubmit()
- */
- RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
- RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
- RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ SpinUpThreads = FALSE;
+ WorkQueueItem->pDeviceObject = pMRxDeviceObject;
+ InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
+ WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
+ InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
- /* Keep track of paging IOs */
- if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
- {
- RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO;
- }
- else
- {
- RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
- }
+ /* If required (and possible!), spin up a new worker thread */
+ if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched &&
+ WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads &&
+ !WorkQueue->SpinUpRequestPending)
+ {
+ WorkQueue->SpinUpRequestPending = TRUE;
+ SpinUpThreads = TRUE;
+ }
- break;
+ Status = STATUS_SUCCESS;
+ }
+ KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
- case LOWIO_OP_FSCTL:
- case LOWIO_OP_IOCTL:
- /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
- RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
- RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0;
- RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL;
- RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0;
- RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
- RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
- break;
+ /* If we failed, return and still not insert item */
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- /* Nothing to do for these */
- case LOWIO_OP_SHAREDLOCK:
- case LOWIO_OP_EXCLUSIVELOCK:
- case LOWIO_OP_UNLOCK:
- case LOWIO_OP_UNLOCK_MULTIPLE:
- case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
- case LOWIO_OP_CLEAROUT:
- break;
+ /* All fine, insert the item */
+ KeInsertQueue(&WorkQueue->Queue, &WorkQueueItem->List);
- default:
- /* Should never happen */
- ASSERT(FALSE);
- break;
+ /* And start a new worker thread if needed */
+ if (SpinUpThreads)
+ {
+ RxSpinUpWorkerThreads(WorkQueue);
}
+
+ return Status;
}
-/*
- * @implemented
- */
-VOID
-RxInitializeLowIoPerFcbInfo(
- PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
+BOOLEAN
+RxIsThisACscAgentOpen(
+ IN PRX_CONTEXT RxContext)
{
- PAGED_CODE();
+ BOOLEAN CscAgent;
- InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
- InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
-}
+ CscAgent = FALSE;
-/*
- * @implemented
- */
-NTSTATUS
-RxInitializeMRxDispatcher(
- IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
-{
- PAGED_CODE();
+ /* Client Side Caching is DFS stuff - we don't support it */
+ if (RxContext->Create.EaLength != 0)
+ {
+ UNIMPLEMENTED;
+ }
- pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
- pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
+ if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL &&
+ ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA)
+ {
+ CscAgent = TRUE;
+ }
- return STATUS_SUCCESS;
+ return CscAgent;
}
-/*
- * @implemented
- */
VOID
-RxInitializePrefixTable(
- IN OUT PRX_PREFIX_TABLE ThisTable,
- IN ULONG TableSize OPTIONAL,
- IN BOOLEAN CaseInsensitiveMatch)
+RxLockUserBuffer(
+ IN PRX_CONTEXT RxContext,
+ IN LOCK_OPERATION Operation,
+ IN ULONG BufferLength)
{
+ PIRP Irp;
+ PMDL Mdl = NULL;
+
PAGED_CODE();
- if (TableSize == 0)
- {
- TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH;
+ _SEH2_TRY
+ {
+ Irp = RxContext->CurrentIrp;
+ /* If we already have a MDL, make sure it's locked */
+ if (Irp->MdlAddress != NULL)
+ {
+ ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress));
+ }
+ else
+ {
+ /* That likely means the driver asks for buffered IOs - we don't support it! */
+ ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION));
+
+ /* If we have a real length */
+ if (BufferLength > 0)
+ {
+ /* Allocate a MDL and lock it */
+ Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
+ if (Mdl == NULL)
+ {
+ RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES;
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
+ }
+ }
}
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ NTSTATUS Status;
- ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
- ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
- InitializeListHead(&ThisTable->MemberQueue);
- ThisTable->Version = 0;
- ThisTable->TableEntryForNull = NULL;
- ThisTable->IsNetNameTable = FALSE;
- ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
- ThisTable->TableSize = TableSize;
+ Status = _SEH2_GetExceptionCode();
- if (TableSize > 0)
- {
- USHORT i;
+ /* Free the possible MDL we have allocated */
+ IoFreeMdl(Mdl);
+ Irp->MdlAddress = NULL;
- for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
+ RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT;
+
+ /* Fix status */
+ if (!FsRtlIsNtstatusExpected(Status))
{
- InitializeListHead(&ThisTable->HashBuckets[i]);
+ Status = STATUS_INVALID_USER_BUFFER;
}
+
+ RxContext->IoStatusBlock.Status = Status;
+ ExRaiseStatus(Status);
}
+ _SEH2_END;
}
/*
* @implemented
*/
-VOID
-RxInitializePurgeSyncronizationContext(
- PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
-{
- PAGED_CODE();
-
- InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
- PurgeSyncronizationContext->PurgeInProgress = FALSE;
-}
-
-NTSTATUS
-RxInitializeSrvCallParameters(
- IN PRX_CONTEXT RxContext,
- IN OUT PSRV_CALL SrvCall)
-{
- PAGED_CODE();
-
- SrvCall->pPrincipalName = NULL;
-
- /* We only have stuff to initialize for file opening from DFS */
- if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
- {
- return STATUS_SUCCESS;
- }
-
- ASSERT(RxContext->Create.EaBuffer != NULL);
-
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
NTSTATUS
-RxInitializeVNetRootParameters(
- PRX_CONTEXT RxContext,
- OUT LUID *LogonId,
- OUT PULONG SessionId,
- OUT PUNICODE_STRING *UserNamePtr,
- OUT PUNICODE_STRING *UserDomainNamePtr,
- OUT PUNICODE_STRING *PasswordPtr,
- OUT PULONG Flags)
+RxLowIoCompletionTail(
+ IN PRX_CONTEXT RxContext)
{
NTSTATUS Status;
- PACCESS_TOKEN Token;
+ USHORT Operation;
PAGED_CODE();
- DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
- LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
-
- *UserNamePtr = NULL;
- *UserDomainNamePtr = NULL;
- *PasswordPtr = NULL;
- /* By default, that's not CSC instance */
- *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
-
- Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
- if (SeTokenIsRestricted(Token))
- {
- return STATUS_ACCESS_DENIED;
- }
+ DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
- /* Get LogonId */
- Status = SeQueryAuthenticationIdToken(Token, LogonId);
- if (!NT_SUCCESS(Status))
+ /* Only continue if we're at APC_LEVEL or lower */
+ if (KeGetCurrentIrql() >= DISPATCH_LEVEL &&
+ !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
{
- return Status;
+ return STATUS_MORE_PROCESSING_REQUIRED;
}
- /* And SessionId */
- Status = SeQuerySessionIdToken(Token, SessionId);
- if (!NT_SUCCESS(Status))
+ /* Call the completion routine */
+ DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine);
+ Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
+ if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY)
{
return Status;
}
- if (RxContext->Create.UserName.Buffer != NULL)
- {
- UNIMPLEMENTED;
- Status = STATUS_NOT_IMPLEMENTED;
- goto Leave;
- }
-
- /* Deal with connection credentials */
- if (RxContext->Create.UserDomainName.Buffer != NULL)
+ /* If it was a RW operation, for a paging file ... */
+ Operation = RxContext->LowIoContext.Operation;
+ if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
{
- UNIMPLEMENTED;
- Status = STATUS_NOT_IMPLEMENTED;
- goto Leave;
+ /* Remove ourselves from the list and resume operations */
+ if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
+ {
+ ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ RemoveEntryList(&RxContext->RxContextSerializationQLinks);
+ RxContext->RxContextSerializationQLinks.Flink = NULL;
+ RxContext->RxContextSerializationQLinks.Blink = NULL;
+ ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ RxResumeBlockedOperations_ALL(RxContext);
+ }
}
-
- if (RxContext->Create.Password.Buffer != NULL)
+ else
{
- UNIMPLEMENTED;
- Status = STATUS_NOT_IMPLEMENTED;
- goto Leave;
+ /* Sanity check: we had known operation */
+ ASSERT(Operation < LOWIO_OP_MAXIMUM);
}
-Leave:
- if (NT_SUCCESS(Status))
+ /* If not sync operation, complete now. Otherwise, caller has already completed */
+ if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
{
- /* If that's a CSC instance, mark it as such */
- if (RxIsThisACscAgentOpen(RxContext))
- {
- *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE;
- }
- return Status;
+ RxCompleteRequest(RxContext, Status);
}
+ DPRINT("Status: %x\n", Status);
return Status;
}
/*
* @implemented
*/
-VOID
-RxInitializeWorkQueue(
- PRX_WORK_QUEUE WorkQueue,
- WORK_QUEUE_TYPE WorkQueueType,
- ULONG MaximumNumberOfWorkerThreads,
- ULONG MinimumNumberOfWorkerThreads)
+NTSTATUS
+NTAPI
+RxLowIoPopulateFsctlInfo(
+ IN PRX_CONTEXT RxContext)
{
- PAGED_CODE();
-
- WorkQueue->Type = WorkQueueType;
- WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
- WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
+ PMDL Mdl;
+ PIRP Irp;
+ UCHAR Method;
+ PIO_STACK_LOCATION Stack;
- WorkQueue->State = RxWorkQueueActive;
- WorkQueue->SpinUpRequestPending = FALSE;
- WorkQueue->pRundownContext = NULL;
- WorkQueue->NumberOfWorkItemsDispatched = 0;
- WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
- WorkQueue->CumulativeQueueLength = 0;
- WorkQueue->NumberOfSpinUpRequests = 0;
- WorkQueue->NumberOfActiveWorkerThreads = 0;
- WorkQueue->NumberOfIdleWorkerThreads = 0;
- WorkQueue->NumberOfFailedSpinUpRequests = 0;
- WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
- WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
- WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
- WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
- WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
- WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
- WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
- WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
- WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
- WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
- WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
- WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
- WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
+ PAGED_CODE();
- KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
- KeInitializeSpinLock(&WorkQueue->SpinLock);
-}
+ DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext);
-/*
- * @implemented
- */
-NTSTATUS
-RxInitializeWorkQueueDispatcher(
- PRX_WORK_QUEUE_DISPATCHER Dispatcher)
-{
- NTSTATUS Status;
- ULONG MaximumNumberOfWorkerThreads;
+ Irp = RxContext->CurrentIrp;
+ Stack = RxContext->CurrentIrpSp;
- PAGED_CODE();
+ /* Copy stack parameters */
+ RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
+ RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength;
+ RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength;
+ RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction;
+ Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
- /* Number of threads will depend on system capacity */
- if (MmQuerySystemSize() != MmLargeSystem)
+ /* Same buffer in case of buffered */
+ if (Method == METHOD_BUFFERED)
{
- MaximumNumberOfWorkerThreads = 5;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ return STATUS_SUCCESS;
}
- else
+
+ /* Two buffers for neither */
+ if (Method == METHOD_NEITHER)
{
- MaximumNumberOfWorkerThreads = 10;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
+
+ return STATUS_SUCCESS;
}
- /* Initialize the work queues */
- RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue,
- MaximumNumberOfWorkerThreads, 1);
- RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1);
- RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1);
+ /* Only IN/OUT remain */
+ ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT);
- /* And start the worker threads */
- Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue],
- RxBootstrapWorkerThreadDispatcher,
- &Dispatcher->WorkQueue[HyperCriticalWorkQueue]);
- if (!NT_SUCCESS(Status))
+ /* Use system buffer for input */
+ RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ /* And MDL for output */
+ Mdl = Irp->MdlAddress;
+ if (Mdl != NULL)
{
- return Status;
- }
-
- Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue],
- RxBootstrapWorkerThreadDispatcher,
- &Dispatcher->WorkQueue[CriticalWorkQueue]);
- if (!NT_SUCCESS(Status))
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+ if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
{
- return Status;
+ RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
}
- Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue],
- RxBootstrapWorkerThreadDispatcher,
- &Dispatcher->WorkQueue[DelayedWorkQueue]);
- return Status;
-}
-
-VOID
-RxInitiateSrvOpenKeyAssociation (
- IN OUT PSRV_OPEN SrvOpen
- )
-{
- UNIMPLEMENTED;
+ return STATUS_SUCCESS;
}
-/*
- * @implemented
- */
NTSTATUS
-RxInsertWorkQueueItem(
- PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
- WORK_QUEUE_TYPE WorkQueueType,
- PRX_WORK_DISPATCH_ITEM DispatchItem)
+NTAPI
+RxLowIoSubmit(
+ IN PRX_CONTEXT RxContext,
+ IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine)
{
- KIRQL OldIrql;
NTSTATUS Status;
- BOOLEAN SpinUpThreads;
- PRX_WORK_QUEUE WorkQueue;
+ USHORT Operation;
+ BOOLEAN Synchronous;
+ PLOWIO_CONTEXT LowIoContext;
- /* No dispatcher, nothing to insert */
- if (RxDispatcher.State != RxDispatcherActive)
- {
- return STATUS_UNSUCCESSFUL;
- }
+ DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine);
- /* Get the work queue */
- WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType];
+ PAGED_CODE();
- KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
- /* Only insert if the work queue is in decent state */
- if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL)
+ LowIoContext = &RxContext->LowIoContext;
+ Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+
+ LowIoContext->CompletionRoutine = CompletionRoutine;
+
+ Status = STATUS_SUCCESS;
+ Operation = LowIoContext->Operation;
+ switch (Operation)
{
- Status = STATUS_UNSUCCESSFUL;
+ case LOWIO_OP_READ:
+ case LOWIO_OP_WRITE:
+ /* Check that the parameters were properly set by caller
+ * See comment in RxInitializeLowIoContext()
+ */
+ ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE);
+ ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE);
+
+ /* Lock the buffer */
+ RxLockUserBuffer(RxContext,
+ (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess),
+ LowIoContext->ParamsFor.ReadWrite.ByteCount);
+ if (RxNewMapUserBuffer(RxContext) == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress;
+
+ /* If that's a paging IO, initialize serial operation */
+ if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
+ {
+ PFCB Fcb;
+
+ Fcb = (PFCB)RxContext->pFcb;
+
+ ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
+ if (Operation == LOWIO_OP_READ)
+ {
+ InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks);
+ }
+ else
+ {
+ InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks);
+ }
+
+ ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
+ }
+
+ break;
+
+ case LOWIO_OP_FSCTL:
+ case LOWIO_OP_IOCTL:
+ /* Set FSCTL/IOCTL parameters */
+ Status = RxLowIoPopulateFsctlInfo(RxContext);
+ /* Check whether we're consistent: a length means a buffer */
+ if (NT_SUCCESS(Status))
+ {
+ if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 &&
+ LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
+ (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 &&
+ LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ /* Nothing to do */
+ case LOWIO_OP_SHAREDLOCK:
+ case LOWIO_OP_EXCLUSIVELOCK:
+ case LOWIO_OP_UNLOCK:
+ case LOWIO_OP_UNLOCK_MULTIPLE:
+ case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
+ case LOWIO_OP_CLEAROUT:
+ break;
+
+ default:
+ ASSERT(FALSE);
+ Status = STATUS_INVALID_PARAMETER;
+ break;
}
- else
+
+ /* No need to perform extra init in case of posting */
+ RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED;
+
+ /* Preflight checks were OK, time to submit */
+ if (NT_SUCCESS(Status))
{
- SpinUpThreads = FALSE;
- DispatchItem->WorkQueueItem.pDeviceObject = pMRxDeviceObject;
- InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
- WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
- InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
+ PMINIRDR_DISPATCH Dispatch;
- /* If required (and possible!), spin up a new worker thread */
- if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched &&
- WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads &&
- !WorkQueue->SpinUpRequestPending)
+ if (!Synchronous)
{
- WorkQueue->SpinUpRequestPending = TRUE;
- SpinUpThreads = TRUE;
+ InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
+ /* If not synchronous, we're likely to return before the operation is finished */
+ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
+ {
+ IoMarkIrpPending(RxContext->CurrentIrp);
+ }
}
- Status = STATUS_SUCCESS;
- }
- KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
+ Dispatch = RxContext->RxDeviceObject->Dispatch;
+ if (Dispatch != NULL)
+ {
+ /* We'll try to execute until the mini-rdr doesn't return pending */
+ do
+ {
+ RxContext->IoStatusBlock.Information = 0;
- /* If we failed, return and still not insert item */
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
+ MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext));
+ if (Status == STATUS_PENDING)
+ {
+ /* Unless it's not synchronous, caller will be happy with pending op */
+ if (!Synchronous)
+ {
+ return Status;
+ }
- /* All fine, insert the item */
- KeInsertQueue(&WorkQueue->Queue, &DispatchItem->WorkQueueItem.List);
+ RxWaitSync(RxContext);
+ Status = RxContext->IoStatusBlock.Status;
+ }
+ else
+ {
+ if (!Synchronous)
+ {
+ /* We had marked the IRP pending, whereas the operation finished, drop that */
+ if (Status != STATUS_RETRY)
+ {
+ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
+ {
+ RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED;
+ }
- /* And start a new worker thread if needed */
- if (SpinUpThreads)
- {
- RxSpinUpWorkerThreads(WorkQueue);
+ InterlockedDecrement((volatile long *)&RxContext->ReferenceCount);
+ }
+ }
+ }
+ } while (Status == STATUS_PENDING);
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
}
- return Status;
+ /* Call completion and return */
+ RxContext->IoStatusBlock.Status = Status;
+ LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL;
+ return RxLowIoCompletionTail(RxContext);
}
-BOOLEAN
-RxIsThisACscAgentOpen(
+/*
+ * @implemented
+ */
+PVOID
+RxMapSystemBuffer(
IN PRX_CONTEXT RxContext)
{
- BOOLEAN CscAgent;
-
- CscAgent = FALSE;
+ PIRP Irp;
- /* Client Side Caching is DFS stuff - we don't support it */
- if (RxContext->Create.EaLength != 0)
- {
- UNIMPLEMENTED;
- }
+ PAGED_CODE();
- if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL &&
- ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA)
+ Irp = RxContext->CurrentIrp;
+ /* We should have a MDL (buffered IOs are not supported!) */
+ if (Irp->MdlAddress != NULL)
{
- CscAgent = TRUE;
+ ASSERT(FALSE);
+ return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
}
- return CscAgent;
+ /* Just return system buffer */
+ return Irp->AssociatedIrp.SystemBuffer;
}
+/*
+ * @implemented
+ */
VOID
-RxLockUserBuffer(
- IN PRX_CONTEXT RxContext,
- IN LOCK_OPERATION Operation,
- IN ULONG BufferLength)
+RxMarkFobxOnCleanup(
+ PFOBX pFobx,
+ PBOOLEAN NeedPurge)
{
- PIRP Irp;
- PMDL Mdl = NULL;
+ 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));
- PAGED_CODE();
+ Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
+ RxAcquireScavengerMutex();
- _SEH2_TRY
+ 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)
{
- Irp = RxContext->CurrentIrp;
- /* If we already have a MDL, make sure it's locked */
- if (Irp->MdlAddress != NULL)
- {
- ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress));
- }
- else
+ 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)
{
- /* That likely means the driver asks for buffered IOs - we don't support it! */
- ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION));
-
- /* If we have a real length */
- if (BufferLength > 0)
+ /* This should never be wrong... */
+ if (!IsListEmpty(&Scavenger->ClosePendingFobxsList))
{
- /* Allocate a MDL and lock it */
- Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
- if (Mdl == NULL)
+ /* 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))
{
- RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES;
- ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ *NeedPurge = TRUE;
+ ScavengerFobx = NULL;
+ }
+ else
+ {
+ RxReferenceNetFobx(ScavengerFobx);
}
-
- MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
}
}
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- NTSTATUS Status;
- Status = _SEH2_GetExceptionCode();
+ /* Mark ourselves as dormant */
+ SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
+ pFobx->CloseTime.QuadPart = TickCount.QuadPart;
- /* Free the possible MDL we have allocated */
- IoFreeMdl(Mdl);
- Irp->MdlAddress = NULL;
+ /* 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);
+ }
+ }
- RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT;
+ RxReleaseScavengerMutex();
- /* Fix status */
- if (!FsRtlIsNtstatusExpected(Status))
+ /* If we had reached max */
+ if (ScavengerFobx != NULL)
+ {
+ NTSTATUS Status;
+
+ /* Purge the oldest FOBX */
+ Status = RxPurgeFobxFromCache(ScavengerFobx);
+ if (Status != STATUS_SUCCESS)
{
- Status = STATUS_INVALID_USER_BUFFER;
+ *NeedPurge = TRUE;
}
-
- RxContext->IoStatusBlock.Status = Status;
- ExRaiseStatus(Status);
}
- _SEH2_END;
}
-NTSTATUS
-RxLowIoCompletionTail(
- IN PRX_CONTEXT RxContext)
+/*
+ * @implemented
+ */
+VOID
+RxMarkFobxOnClose(
+ PFOBX Fobx)
{
- NTSTATUS Status;
- USHORT Operation;
+ PFCB Fcb;
+ PRDBSS_SCAVENGER Scavenger;
PAGED_CODE();
- DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
-
- /* Only continue if we're at APC_LEVEL or lower */
- if (KeGetCurrentIrql() >= DISPATCH_LEVEL &&
- !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
+ /* No FOBX, nothing to mark */
+ if (Fobx == NULL)
{
- return STATUS_MORE_PROCESSING_REQUIRED;
+ return;
}
- /* Call the completion routine */
- DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine);
- Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
- if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY)
- {
- return Status;
- }
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
- /* If it was a RW operation, for a paging file ... */
- Operation = RxContext->LowIoContext.Operation;
- if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
+ 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 (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
+ /* If FCB wasn't already decrement, do it now */
+ if (!Fobx->fOpenCountDecremented)
{
- UNIMPLEMENTED;
- Status = STATUS_NOT_IMPLEMENTED;
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ ASSERT(NodeTypeIsFcb(Fcb));
+ InterlockedDecrement((volatile long *)&Fcb->OpenCount);
+
+ Fobx->fOpenCountDecremented = TRUE;
}
- }
- else
- {
- /* Sanity check: we had known operation */
- ASSERT(Operation < LOWIO_OP_MAXIMUM);
+
+ /* We're no longer dormant */
+ InterlockedDecrement(&Scavenger->NumberOfDormantFiles);
+ ClearFlag(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
}
- /* If not sync operation, complete now. Otherwise, caller has already completed */
- if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
+ /* If we were inserted in the scavenger, drop ourselves out */
+ if (!IsListEmpty(&Fobx->ClosePendingList))
{
- RxCompleteRequest(RxContext, Status);
+ RemoveEntryList(&Fobx->ClosePendingList);
+ InitializeListHead(&Fobx->ClosePendingList);
}
- DPRINT("Status: %x\n", Status);
- return Status;
+ RxReleaseScavengerMutex();
}
/*
* @implemented
*/
-NTSTATUS
-NTAPI
-RxLowIoPopulateFsctlInfo(
- IN PRX_CONTEXT RxContext)
+PVOID
+RxNewMapUserBuffer(
+ PRX_CONTEXT RxContext)
{
- PMDL Mdl;
PIRP Irp;
- UCHAR Method;
- PIO_STACK_LOCATION Stack;
PAGED_CODE();
- DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext);
-
Irp = RxContext->CurrentIrp;
- Stack = RxContext->CurrentIrpSp;
-
- /* Copy stack parameters */
- RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
- RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength;
- RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength;
- RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction;
- Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
-
- /* Same buffer in case of buffered */
- if (Method == METHOD_BUFFERED)
+ if (Irp->MdlAddress != NULL)
{
- RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
- RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
-
- return STATUS_SUCCESS;
+ return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
}
- /* Two buffers for neither */
- if (Method == METHOD_NEITHER)
- {
- RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer;
- RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
+ return Irp->UserBuffer;
+}
- return STATUS_SUCCESS;
- }
+BOOLEAN
+NTAPI
+RxNoOpAcquire(
+ IN PVOID Fcb,
+ IN BOOLEAN Wait)
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
- /* Only IN/OUT remain */
- ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT);
+VOID
+NTAPI
+RxNoOpRelease(
+ IN PVOID Fcb)
+{
+ UNIMPLEMENTED;
+}
- /* Use system buffer for input */
- RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
- /* And MDL for output */
- Mdl = Irp->MdlAddress;
- if (Mdl != NULL)
- {
- RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
- if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- }
- else
- {
- RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
- }
+VOID
+RxOrphanThisFcb(
+ PFCB Fcb)
+{
+ UNIMPLEMENTED;
+}
- return STATUS_SUCCESS;
+VOID
+RxOrphanSrvOpens(
+ IN PV_NET_ROOT ThisVNetRoot)
+{
+ UNIMPLEMENTED;
}
-NTSTATUS
-NTAPI
-RxLowIoSubmit(
- IN PRX_CONTEXT RxContext,
- IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine)
+/*
+ * @implemented
+ */
+BOOLEAN
+RxpAcquirePrefixTableLockShared(
+ PRX_PREFIX_TABLE pTable,
+ BOOLEAN Wait,
+ BOOLEAN ProcessBufferingStateChangeRequests)
{
- NTSTATUS Status;
- USHORT Operation;
- BOOLEAN Synchronous;
- PLOWIO_CONTEXT LowIoContext;
+ PAGED_CODE();
- DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine);
+ DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
+ pTable->TableLock.ActiveEntries);
- PAGED_CODE();
+ return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
+}
- LowIoContext = &RxContext->LowIoContext;
- Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+/*
+ * @implemented
+ */
+BOOLEAN
+RxpAcquirePrefixTableLockExclusive(
+ PRX_PREFIX_TABLE pTable,
+ BOOLEAN Wait,
+ BOOLEAN ProcessBufferingStateChangeRequests)
+{
+ PAGED_CODE();
- LowIoContext->CompletionRoutine = CompletionRoutine;
+ DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
+ pTable->TableLock.ActiveEntries);
- Status = STATUS_SUCCESS;
- Operation = LowIoContext->Operation;
- switch (Operation)
- {
- case LOWIO_OP_READ:
- case LOWIO_OP_WRITE:
- /* Check that the parameters were properly set by caller
- * See comment in RxInitializeLowIoContext()
- */
- ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE);
- ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE);
+ return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait);
+}
- /* Lock the buffer */
- RxLockUserBuffer(RxContext,
- (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess),
- LowIoContext->ParamsFor.ReadWrite.ByteCount);
- if (RxNewMapUserBuffer(RxContext) == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress;
+/*
+ * @implemented
+ */
+BOOLEAN
+RxpDereferenceAndFinalizeNetFcb(
+ OUT PFCB ThisFcb,
+ IN PRX_CONTEXT RxContext,
+ IN BOOLEAN RecursiveFinalize,
+ IN BOOLEAN ForceFinalize)
+{
+ NTSTATUS Status;
+ ULONG References;
+ PNET_ROOT NetRoot;
+ BOOLEAN ResourceAcquired, NetRootReferenced, Freed;
- /* If that's a paging IO, initialize serial operation */
- if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
- {
- PFCB Fcb;
+ PAGED_CODE();
- Fcb = (PFCB)RxContext->pFcb;
+ ASSERT(!ForceFinalize);
+ ASSERT(NodeTypeIsFcb(ThisFcb));
+ ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
- ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
- RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
- if (Operation == LOWIO_OP_READ)
- {
- InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks);
- }
- else
- {
- InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks);
- }
+ /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
+ References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount);
+ if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1))
+ {
+ return FALSE;
+ }
- ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
- }
+ Freed = FALSE;
+ Status = STATUS_SUCCESS;
+ NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
+ ResourceAcquired = FALSE;
+ NetRootReferenced = FALSE;
+ /* If FCB isn't orphaned, it still have context attached */
+ if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ /* Don't let NetRoot go away before we're done */
+ RxReferenceNetRoot(NetRoot);
+ NetRootReferenced = TRUE;
- break;
+ /* Try to acquire the table lock exclusively */
+ if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable))
+ {
+ RxReferenceNetFcb(ThisFcb);
- case LOWIO_OP_FSCTL:
- case LOWIO_OP_IOCTL:
- /* Set FSCTL/IOCTL parameters */
- Status = RxLowIoPopulateFsctlInfo(RxContext);
- /* Check whether we're consistent: a length means a buffer */
- if (NT_SUCCESS(Status))
+ if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
{
- if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 &&
- LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
- (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 &&
- LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL))
+ if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2)
{
- Status = STATUS_INVALID_PARAMETER;
+ RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
}
- }
- break;
- /* Nothing to do */
- case LOWIO_OP_SHAREDLOCK:
- case LOWIO_OP_EXCLUSIVELOCK:
- case LOWIO_OP_UNLOCK:
- case LOWIO_OP_UNLOCK_MULTIPLE:
- case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
- case LOWIO_OP_CLEAROUT:
- break;
+ RxReleaseFcb(RxContext, ThisFcb);
- default:
- ASSERT(FALSE);
- Status = STATUS_INVALID_PARAMETER;
- break;
- }
+ RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
- /* No need to perform extra init in case of posting */
- RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED;
+ Status = RxAcquireExclusiveFcb(RxContext, ThisFcb);
+ }
- /* Preflight checks were OK, time to submit */
- if (NT_SUCCESS(Status))
- {
- PMINIRDR_DISPATCH Dispatch;
+ References = RxDereferenceNetFcb(ThisFcb);
- if (!Synchronous)
- {
- InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
- /* If not synchronous, we're likely to return before the operation is finished */
- if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
- {
- IoMarkIrpPending(RxContext->CurrentIrp);
- }
+ ResourceAcquired = TRUE;
}
+ }
- Dispatch = RxContext->RxDeviceObject->Dispatch;
- if (Dispatch != NULL)
- {
- /* We'll try to execute until the mini-rdr doesn't return pending */
- do
- {
- RxContext->IoStatusBlock.Information = 0;
-
- MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext));
- if (Status == STATUS_PENDING)
- {
- /* Unless it's not synchronous, caller will be happy with pending op */
- if (!Synchronous)
- {
- return Status;
- }
+ /* If locking was OK (or not needed!), attempt finalization */
+ if (Status == STATUS_SUCCESS)
+ {
+ Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
+ }
- RxWaitSync(RxContext);
- Status = RxContext->IoStatusBlock.Status;
- }
- else
- {
- if (!Synchronous)
- {
- /* We had marked the IRP pending, whereas the operation finished, drop that */
- if (Status != STATUS_RETRY)
- {
- if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
- {
- RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED;
- }
+ /* Release table lock if acquired */
+ if (ResourceAcquired)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ }
- InterlockedDecrement((volatile long *)&RxContext->ReferenceCount);
- }
- }
- }
- } while (Status == STATUS_PENDING);
- }
- else
- {
- Status = STATUS_INVALID_PARAMETER;
- }
+ /* We don't need the NetRoot anylonger */
+ if (NetRootReferenced)
+ {
+ RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld);
}
- /* Call completion and return */
- RxContext->IoStatusBlock.Status = Status;
- LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL;
- return RxLowIoCompletionTail(RxContext);
+ return Freed;
}
/*
* @implemented
*/
-PVOID
-RxMapSystemBuffer(
- IN PRX_CONTEXT RxContext)
+LONG
+RxpDereferenceNetFcb(
+ PFCB Fcb)
{
- PIRP Irp;
+ LONG NewCount;
PAGED_CODE();
- Irp = RxContext->CurrentIrp;
- /* We should have a MDL (buffered IOs are not supported!) */
- if (Irp->MdlAddress != NULL)
- {
- ASSERT(FALSE);
- return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
- }
+ ASSERT(NodeTypeIsFcb(Fcb));
- /* Just return system buffer */
- return Irp->AssociatedIrp.SystemBuffer;
-}
+ NewCount = InterlockedDecrement((volatile long *)&Fcb->NodeReferenceCount);
+ ASSERT(NewCount >= 0);
-VOID
-RxMarkFobxOnCleanup(
- PFOBX pFobx,
- PBOOLEAN NeedPurge)
-{
- UNIMPLEMENTED;
+ PRINT_REF_COUNT(NETFCB, NewCount);
+
+ return NewCount;
}
+/*
+ * @implemented
+ */
VOID
-RxMarkFobxOnClose(
- PFOBX Fobx)
+NTAPI
+RxpDestroySrvCall(
+ IN PVOID Context)
{
- UNIMPLEMENTED;
+ NTSTATUS Status;
+ PSRV_CALL SrvCall;
+ BOOLEAN ForceFinalize;
+ PRX_PREFIX_TABLE PrefixTable;
+
+ SrvCall = (PSRV_CALL)Context;
+ /* At this step, RxFinalizeSrvCall already cleaned some fields */
+ ASSERT(SrvCall->UpperFinalizationDone);
+
+ PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
+ /* Were we called with ForceFinalize? */
+ ForceFinalize = BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
+
+ /* Notify mini-rdr */
+ MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch,
+ MRxFinalizeSrvCall, ((PMRX_SRV_CALL)SrvCall,
+ ForceFinalize));
+ (void)Status;
+
+ /* 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);
}
/*
* @implemented
*/
-PVOID
-RxNewMapUserBuffer(
- PRX_CONTEXT RxContext)
+VOID
+RxpDiscardChangeBufferingStateRequests(
+ _Inout_ PLIST_ENTRY DiscardedRequests)
{
- PIRP Irp;
+ PLIST_ENTRY Entry;
PAGED_CODE();
- Irp = RxContext->CurrentIrp;
- if (Irp->MdlAddress != NULL)
+ /* No requests to discard */
+ if (IsListEmpty(DiscardedRequests))
{
- return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ return;
}
- return Irp->UserBuffer;
+ /* Free all the discarded requests */
+ Entry = DiscardedRequests->Flink;
+ while (Entry != DiscardedRequests)
+ {
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
+
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+
+ DPRINT("Req %p for %p (%p) discarded\n", Request, Request->SrvOpenKey, Request->SrvOpen);
+
+ RxPrepareRequestForReuse(Request);
+ RxFreePool(Request);
+ }
}
-BOOLEAN
-NTAPI
-RxNoOpAcquire(
- IN PVOID Fcb,
- IN BOOLEAN Wait)
+/*
+ * @implemented
+ */
+VOID
+RxpDispatchChangeBufferingStateRequests(
+ PSRV_CALL SrvCall,
+ PSRV_OPEN SrvOpen,
+ PLIST_ENTRY DiscardedRequests)
{
- UNIMPLEMENTED;
- return FALSE;
-}
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ BOOLEAN StartDispatcher;
+ LIST_ENTRY AcceptedReqs;
+ LIST_ENTRY DispatcherList;
+ PRX_BUFFERING_MANAGER BufferingManager;
+
+ /* Initialize our lists */
+ InitializeListHead(&AcceptedReqs);
+ InitializeListHead(DiscardedRequests);
+
+ /* Transfer the requests to dispatch locally */
+ BufferingManager = &SrvCall->BufferingManager;
+ KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
+ RxTransferList(&DispatcherList, &BufferingManager->DispatcherList);
+ KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
+
+ /* If there were requests */
+ if (!IsListEmpty(&DispatcherList))
+ {
+ PLIST_ENTRY Entry;
+
+ /* For each of the entries... */
+ Entry = DispatcherList.Flink;
+ while (Entry != &DispatcherList)
+ {
+ PCHANGE_BUFFERING_STATE_REQUEST Request;
+
+ Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
+ Entry = Entry->Flink;
+
+ /* If we have been provided a SRV_OPEN, see whether it matches */
+ if (SrvOpen != NULL)
+ {
+ /* Match, the request is accepted */
+ if (Request->SrvOpenKey == SrvOpen->Key)
+ {
+ Request->SrvOpen = SrvOpen;
+ RxReferenceSrvOpen(SrvOpen);
+
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(&AcceptedReqs, &Request->ListEntry);
+
+ /* Move to the next entry */
+ continue;
+ }
+ else
+ {
+ Status = STATUS_PENDING;
+ }
+ }
+ else
+ {
+ /* No SRV_OPEN provided, try to find one */
+ Status = RxpLookupSrvOpenForRequestLite(SrvCall, Request);
+ }
+
+ /* We found a matching SRV_OPEN, accept the request */
+ if (Status == STATUS_SUCCESS)
+ {
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(&AcceptedReqs, &Request->ListEntry);
+ }
+ /* Another run might help handling it, don't discard it */
+ else if (Status == STATUS_PENDING)
+ {
+ continue;
+ }
+ /* Otherwise, discard the request */
+ else
+ {
+ ASSERT(Status == STATUS_NOT_FOUND);
+
+ RemoveEntryList(&Request->ListEntry);
+ InsertTailList(DiscardedRequests, &Request->ListEntry);
+ }
+ }
+ }
-VOID
-NTAPI
-RxNoOpRelease(
- IN PVOID Fcb)
-{
- UNIMPLEMENTED;
-}
+ KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
+ /* Nothing to dispatch, no need to start dispatcher */
+ if (IsListEmpty(&DispatcherList))
+ {
+ StartDispatcher = FALSE;
+ }
+ else
+ {
+ /* Transfer back the list of the not treated entries to the buffering manager */
+ RxTransferList(&BufferingManager->DispatcherList, &DispatcherList);
+ StartDispatcher = (BufferingManager->DispatcherActive == FALSE);
+ /* If the dispatcher isn't active, start it */
+ if (StartDispatcher)
+ {
+ BufferingManager->DispatcherActive = TRUE;
+ }
+ }
-VOID
-RxOrphanThisFcb(
- PFCB Fcb)
-{
- UNIMPLEMENTED;
+ /* If there were accepted requests, move them to the buffering manager */
+ if (!IsListEmpty(&AcceptedReqs))
+ {
+ RxTransferList(&BufferingManager->HandlerList, &AcceptedReqs);
+ }
+ KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
+
+ /* If we're to start the dispatcher, do it */
+ if (StartDispatcher)
+ {
+ RxReferenceSrvCall(SrvCall);
+ DPRINT("Starting dispatcher\n");
+ RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
+ &BufferingManager->DispatcherWorkItem,
+ RxDispatchChangeBufferingStateRequests, SrvCall);
+ }
}
/*
* @implemented
*/
-BOOLEAN
-RxpAcquirePrefixTableLockShared(
- PRX_PREFIX_TABLE pTable,
- BOOLEAN Wait,
- 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("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, 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;
+ }
+ }
+ }
- return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
-}
+ /* We didn't manage to find a SRV_OPEN */
+ if (Entry == &SrvCall->BufferingManager.SrvOpenLists[0])
+ {
+ SrvOpen = NULL;
-/*
- * @implemented
- */
-BOOLEAN
-RxpAcquirePrefixTableLockExclusive(
- PRX_PREFIX_TABLE pTable,
- BOOLEAN Wait,
- BOOLEAN ProcessBufferingStateChangeRequests)
-{
- PAGED_CODE();
+ /* 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;
+ }
+ }
- DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
- pTable->TableLock.ActiveEntries);
+ /* Return the (not) found SRV_OPEN */
+ Request->SrvOpen = SrvOpen;
- return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait);
+ return Status;
}
/*
* @implemented
*/
-BOOLEAN
-RxpDereferenceAndFinalizeNetFcb(
- OUT PFCB ThisFcb,
- IN PRX_CONTEXT RxContext,
- IN BOOLEAN RecursiveFinalize,
- IN BOOLEAN ForceFinalize)
+VOID
+RxpMarkInstanceForScavengedFinalization(
+ PVOID Instance)
{
- NTSTATUS Status;
- ULONG References;
- PNET_ROOT NetRoot;
- BOOLEAN ResourceAcquired, NetRootReferenced, Freed;
+ NODE_TYPE_CODE NodeType;
+ PNODE_TYPE_AND_SIZE Node;
+ PRDBSS_SCAVENGER Scavenger;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+ PLIST_ENTRY ScavengerHead, InstEntry;
PAGED_CODE();
- ASSERT(!ForceFinalize);
- ASSERT(NodeTypeIsFcb(ThisFcb));
- ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
-
- /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
- References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount);
- if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1))
+ /* If still referenced, don't mark it (broken caller) */
+ Node = (PNODE_TYPE_AND_SIZE)Instance;
+ if (Node->NodeReferenceCount > 1)
{
- return FALSE;
+ return;
}
- Freed = FALSE;
- Status = STATUS_SUCCESS;
- NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
- ResourceAcquired = FALSE;
- NetRootReferenced = FALSE;
- /* If FCB isn't orphaned, it still have context attached */
- if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
+ DeviceObject = RxGetDeviceObjectOfInstance(Instance);
+ Scavenger = DeviceObject->pRdbssScavenger;
+
+ /* Mark the node */
+ NodeType = NodeType(Instance);
+ SetFlag(NodeType(Node), RX_SCAVENGER_MASK);
+ DPRINT("Node %p has now the scavenger mark!\n", Instance);
+
+ /* Increase the count in the scavenger, and queue it */
+ ScavengerHead = NULL;
+ switch (NodeType)
{
- /* Don't let NetRoot go away before we're done */
- RxReferenceNetRoot(NetRoot);
- NetRootReferenced = TRUE;
+ case RDBSS_NTC_FOBX:
+ ++Scavenger->FobxsToBeFinalized;
+ ScavengerHead = &Scavenger->FobxFinalizationList;
+ InstEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
+ break;
- /* Try to acquire the table lock exclusively */
- if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable))
- {
- RxReferenceNetFcb(ThisFcb);
+ case RDBSS_NTC_SRVCALL:
+ ++Scavenger->SrvCallsToBeFinalized;
+ ScavengerHead = &Scavenger->SrvCallFinalizationList;
+ InstEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
+ break;
- if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
- {
- if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2)
- {
- RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
- }
+ case RDBSS_NTC_NETROOT:
+ ++Scavenger->NetRootsToBeFinalized;
+ ScavengerHead = &Scavenger->NetRootFinalizationList;
+ InstEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
- RxReleaseFcb(RxContext, ThisFcb);
+ case RDBSS_NTC_V_NETROOT:
+ ++Scavenger->VNetRootsToBeFinalized;
+ ScavengerHead = &Scavenger->VNetRootFinalizationList;
+ InstEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
- RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
+ case RDBSS_NTC_SRVOPEN:
+ ++Scavenger->SrvOpensToBeFinalized;
+ ScavengerHead = &Scavenger->SrvOpenFinalizationList;
+ InstEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
+ break;
+ }
- Status = RxAcquireExclusiveFcb(RxContext, ThisFcb);
- }
+ /* Extra ref for scavenger */
+ InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
- References = RxDereferenceNetFcb(ThisFcb);
+ /* If matching type */
+ if (ScavengerHead != NULL)
+ {
+ /* Insert in the scavenger list */
+ InsertTailList(ScavengerHead, InstEntry);
- ResourceAcquired = TRUE;
+ /* 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);
}
}
+}
- /* If locking was OK (or not needed!), attempt finalization */
- if (NT_SUCCESS(Status))
- {
- Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
- }
+/*
+ * @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;
- /* Release table lock if acquired */
- if (ResourceAcquired)
- {
- RxReleaseFcbTableLock(&NetRoot->FcbTable);
- }
+ ASSERT(pWorkItem != NULL);
- /* We don't need the NetRoot anylonger */
- if (NetRootReferenced)
+ /* 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))
{
- RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld);
+ KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
}
- return Freed;
+ return STATUS_SUCCESS;
}
-LONG
-RxpDereferenceNetFcb(
- PFCB Fcb)
+/*
+ * @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;
- return 0;
}
/*
RxReference(Container);
}
- return Container;
-}
-
-LONG
-RxpReferenceNetFcb(
- PFCB Fcb)
-{
- UNIMPLEMENTED;
- return 0;
+ 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
-RxpReleasePrefixTableLock(
- PRX_PREFIX_TABLE pTable,
- BOOLEAN ProcessBufferingStateChangeRequests)
+NTAPI
+RxProcessChangeBufferingStateRequests(
+ _In_ PVOID SrvCall)
{
- PAGED_CODE();
-
- DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
- pTable->TableLock.ActiveEntries);
-
- ExReleaseResourceLite(&pTable->TableLock);
+ /* Call internal routine */
+ RxUndoScavengerFinalizationMarking(SrvCall);
+ RxpProcessChangeBufferingStateRequests(SrvCall, TRUE);
}
/*
* @implemented
*/
VOID
-NTAPI
-RxPrepareContextForReuse(
- IN OUT PRX_CONTEXT RxContext)
+RxProcessChangeBufferingStateRequestsForSrvOpen(
+ PSRV_OPEN SrvOpen)
{
- PAGED_CODE();
+ LONG NumberOfBufferingChangeRequests, OldBufferingToken;
- /* When we reach that point, make sure mandatory parts are null-ed */
- if (RxContext->MajorFunction == IRP_MJ_CREATE)
+ /* Get the current number of change requests */
+ NumberOfBufferingChangeRequests = ((PSRV_CALL)SrvOpen->pVNetRoot->pNetRoot->pSrvCall)->BufferingManager.CumulativeNumberOfBufferingChangeRequests;
+ /* Get our old token */
+ OldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken,
+ NumberOfBufferingChangeRequests, NumberOfBufferingChangeRequests);
+ /* Do we have stuff to process? */
+ if (OldBufferingToken != SrvOpen->BufferingToken)
{
- 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);
- }
+ PFCB Fcb;
+ NTSTATUS Status;
- RxContext->ReferenceCount = 0;
+ /* Acquire the FCB and start processing */
+ Fcb = (PFCB)SrvOpen->pFcb;
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ if (Status == STATUS_SUCCESS)
+ {
+ RxProcessFcbChangeBufferingStateRequest(Fcb);
+ RxReleaseFcb(NULL, Fcb);
+ }
+ }
}
VOID
_In_ ULONG Line,
_In_ PVOID Instance)
{
+ PAGED_CODE();
+
+ if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
+ {
+ return TRUE;
+ }
+
UNIMPLEMENTED;
- return FALSE;
+ return TRUE;
}
VOID
_In_ ULONG Line,
_In_ PVOID Instance)
{
+ if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
+ {
+ return;
+ }
+
UNIMPLEMENTED;
}
+/*
+ * @implemented
+ */
VOID
RxpUndoScavengerFinalizationMarking(
PVOID Instance)
{
+ PLIST_ENTRY ListEntry;
PNODE_TYPE_AND_SIZE Node;
+ PRDBSS_SCAVENGER Scavenger;
PAGED_CODE();
Node = (PNODE_TYPE_AND_SIZE)Instance;
/* There's no marking - nothing to do */
- if (!BooleanFlagOn(Node->NodeTypeCode, RX_SCAVENGER_MASK))
+ if (!BooleanFlagOn(NodeType(Node), RX_SCAVENGER_MASK))
{
return;
}
- UNIMPLEMENTED;
+ /* First of all, remove the mark */
+ ClearFlag(NodeType(Node), RX_SCAVENGER_MASK);
+ DPRINT("Node %p no longer has the scavenger mark\n");
+
+ /* And now, remove from the scavenger */
+ Scavenger = RxGetDeviceObjectOfInstance(Instance)->pRdbssScavenger;
+ switch (NodeType(Node))
+ {
+ case RDBSS_NTC_FOBX:
+ --Scavenger->FobxsToBeFinalized;
+ ListEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVCALL:
+ --Scavenger->SrvCallsToBeFinalized;
+ ListEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_NETROOT:
+ --Scavenger->NetRootsToBeFinalized;
+ ListEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_V_NETROOT:
+ --Scavenger->VNetRootsToBeFinalized;
+ ListEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
+ break;
+
+ case RDBSS_NTC_SRVOPEN:
+ --Scavenger->SrvOpensToBeFinalized;
+ ListEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
+ break;
+ }
+
+ /* Also, remove the extra ref from the scavenger */
+ RemoveEntryList(ListEntry);
+ InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxPurgeChangeBufferingStateRequestsForSrvOpen(
+ PSRV_OPEN SrvOpen)
+{
+ PSRV_CALL SrvCall;
+ LIST_ENTRY Discarded;
+
+ PAGED_CODE();
+
+ ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
+
+ /* Initialize our discarded list */
+ InitializeListHead(&Discarded);
+
+ SrvCall = (PSRV_CALL)SrvOpen->Fcb->VNetRoot->pNetRoot->pSrvCall;
+ RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
+
+ /* Set the flag, and get the requests */
+ InitializeListHead(&SrvOpen->SrvOpenKeyList);
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED);
+ RxGatherRequestsForSrvOpen(SrvCall, SrvOpen, &Discarded);
+
+ RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
+
+ /* If there were discarded requests */
+ if (!IsListEmpty(&Discarded))
+ {
+ /* And a pending buffering state change */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
+ {
+ /* Clear the flag, and set the associated event - job done */
+ RxAcquireSerializationMutex();
+ ClearFlag(SrvOpen->Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
+ if (SrvOpen->Fcb->pBufferingStateChangeCompletedEvent != NULL)
+ {
+ KeSetEvent(SrvOpen->Fcb->pBufferingStateChangeCompletedEvent, IO_NETWORK_INCREMENT, FALSE);
+ }
+ RxReleaseSerializationMutex();
+ }
+
+ /* Drop the discarded requests */
+ RxpDiscardChangeBufferingStateRequests(&Discarded);
+ }
+}
+
+/*
+ * @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 BOOLEAN UninitializeCacheMaps,
IN BOOLEAN FlushFile)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ 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
+ */
+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;
}
/*
/* Reference ourselves */
CurrentThread = PsGetCurrentThread();
- Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, PsThreadType, KernelMode);
+ Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
ASSERT(NT_SUCCESS(Status));
/* Infinite loop for worker */
{
PKEVENT TearDownEvent;
- TearDownEvent = InterlockedExchangePointer((volatile PVOID)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
+ TearDownEvent = InterlockedExchangePointer((void * volatile*)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
if (TearDownEvent != NULL)
{
KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
} while (!KillThread);
- DPRINT("Killed worker thread\n");
+ 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
+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));
- /* Do we have to dereference ourselves? */
- if (Dereference)
+ /* Check whether we're asked to remove null entry */
+ if (Entry->Prefix.Length == 0)
{
- ObDereferenceObject(CurrentThread);
+ ThisTable->TableEntryForNull = NULL;
}
-
- /* Dump last executed routine */
- if (DumpDispatchRoutine)
+ else
{
- DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
+ RemoveEntryList(&Entry->HashLinks);
}
- PsTerminateSystemThread(STATUS_SUCCESS);
+ Entry->ContainingRecord = NULL;
+
+ /* Also remove it from global list */
+ RemoveEntryList(&Entry->MemberQLinks);
+
+ ++ThisTable->Version;
}
+/*
+ * @implemented
+ */
VOID
-RxReference(
- IN OUT PVOID Instance)
+RxRemoveVirtualNetRootFromNetRoot(
+ PNET_ROOT NetRoot,
+ PV_NET_ROOT VNetRoot)
{
- NODE_TYPE_CODE NodeType;
- PNODE_TYPE_AND_SIZE Node;
+ PRX_PREFIX_TABLE PrefixTable;
PAGED_CODE();
- RxAcquireScavengerMutex();
+ PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
- /* 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));
+ /* Remove the VNetRoot from the list in the NetRoot */
+ --NetRoot->NumberOfVirtualNetRoots;
+ RemoveEntryList(&VNetRoot->NetRootListEntry);
- Node = (PNODE_TYPE_AND_SIZE)Instance;
- InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
+ /* 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;
+ }
+ }
- /* Trace refcount if asked */
- switch (NodeType)
+ /* If there are still other VNetRoot available, we're done */
+ if (!IsListEmpty(&NetRoot->VirtualNetRoots))
{
- case RDBSS_NTC_SRVCALL:
- PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
- break;
+ return;
+ }
- case RDBSS_NTC_NETROOT:
- PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
- break;
+ /* 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);
+ }
- case RDBSS_NTC_V_NETROOT:
- PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
- break;
+ /* Notify mini-rdr */
+ if (NetRoot->pSrvCall != NULL && NetRoot->pSrvCall->RxDeviceObject != NULL)
+ {
+ NTSTATUS Status;
- case RDBSS_NTC_SRVOPEN:
- PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
- break;
+ MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
+ MRxFinalizeNetRoot, ((PMRX_NET_ROOT)NetRoot, FALSE));
+ (void)Status;
+ }
+}
- case RDBSS_NTC_FOBX:
- PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
- break;
+VOID
+RxResumeBlockedOperations_ALL(
+ IN OUT PRX_CONTEXT RxContext)
+{
+ LIST_ENTRY BlockedOps;
- default:
- ASSERT(FALSE);
- break;
- }
+ PAGED_CODE();
- RxpUndoScavengerFinalizationMarking(Instance);
- RxReleaseScavengerMutex();
+ /* Get the blocked operations */
+ RxTransferListWithMutex(&BlockedOps, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex);
+
+ if (!IsListEmpty(&BlockedOps))
+ {
+ UNIMPLEMENTED;
+ }
}
VOID
RxReleaseSerializationMutex();
}
+/*
+ * @implemented
+ */
BOOLEAN
RxScavengeRelatedFobxs(
PFCB Fcb)
+{
+ 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();
+ if (Scavenger->FobxsToBeFinalized <= 0)
+ {
+ RxReleaseScavengerMutex();
+ return FALSE;
+ }
+
+ /* 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);
+
+ /* Technically, that condition should all be true... */
+ if (!IsListEmpty(&Scavenger->FobxFinalizationList))
+ {
+ PLIST_ENTRY NextEntry, LastEntry;
+
+ /* 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);
+ }
+ }
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* Nothing to scavenge? Quit */
+ if (IsListEmpty(&LocalList))
+ {
+ return FALSE;
+ }
+
+ /* 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;
- return FALSE;
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxScavengerTimerRoutine(
+ PVOID Context)
+{
+ BOOLEAN Requeue;
+ PRDBSS_DEVICE_OBJECT DeviceObject;
+ PRDBSS_SCAVENGER Scavenger;
+
+ PAGED_CODE();
+
+ DeviceObject = Context;
+ Scavenger = DeviceObject->pRdbssScavenger;
+
+ Requeue = FALSE;
+ RxAcquireScavengerMutex();
+ /* If the scavenger was dormant, wake it up! */
+ if (Scavenger->State == RDBSS_SCAVENGER_DORMANT)
+ {
+ /* Done */
+ Scavenger->State = RDBSS_SCAVENGER_ACTIVE;
+ KeResetEvent(&Scavenger->ScavengeEvent);
+
+ /* Scavenger the entries */
+ RxReleaseScavengerMutex();
+ RxScavengerFinalizeEntries(DeviceObject);
+ RxAcquireScavengerMutex();
+
+ /* If we're still active (race) */
+ if (Scavenger->State == RDBSS_SCAVENGER_ACTIVE)
+ {
+ /* If there are new entries to scavenge, stay dormant and requeue a run */
+ if (Scavenger->NumberOfDormantFiles + Scavenger->SrvCallsToBeFinalized +
+ Scavenger->NetRootsToBeFinalized + Scavenger->VNetRootsToBeFinalized +
+ Scavenger->FcbsToBeFinalized + Scavenger->SrvOpensToBeFinalized +
+ Scavenger->FobxsToBeFinalized != 0)
+ {
+ Requeue = TRUE;
+ Scavenger->State = RDBSS_SCAVENGER_DORMANT;
+ }
+ /* Otherwise, we're inactive again */
+ else
+ {
+ Scavenger->State == RDBSS_SCAVENGER_INACTIVE;
+ }
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* Requeue an execution */
+ if (Requeue)
+ {
+ RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
+ RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
+ }
+ }
+ else
+ {
+ RxReleaseScavengerMutex();
+ }
+
+ KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE);
}
BOOLEAN
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
*/
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 */
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
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 */