BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE;
LIST_ENTRY RxSrvCalldownList;
RX_SPIN_LOCK RxStrucSupSpinLock;
-ULONG RdbssReferenceTracingValue;
+#if 0
+ULONG RdbssReferenceTracingValue = (RDBSS_REF_TRACK_SRVCALL | RDBSS_REF_TRACK_NETROOT |
+ RDBSS_REF_TRACK_VNETROOT | RDBSS_REF_TRACK_NETFOBX |
+ RDBSS_REF_TRACK_NETFCB | RDBSS_REF_TRACK_SRVOPEN |
+ RX_PRINT_REF_TRACKING);
+#else
+ULONG RdbssReferenceTracingValue = 0;
+#endif
LARGE_INTEGER RxWorkQueueWaitInterval[RxMaximumWorkQueue];
LARGE_INTEGER RxSpinUpDispatcherWaitInterval;
RX_DISPATCHER RxDispatcher;
/* FUNCTIONS ****************************************************************/
+NTSTATUS
+NTAPI
+RxAcquireExclusiveFcbResourceInMRx(
+ _Inout_ PMRX_FCB Fcb)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+RxAcquireFcbForLazyWrite(
+ PVOID Context,
+ BOOLEAN Wait)
+{
+ PFCB Fcb;
+ BOOLEAN Ret;
+
+ PAGED_CODE();
+
+ Fcb = Context;
+ /* The received context is a FCB */
+ ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+ ASSERT(Fcb->Specific.Fcb.LazyWriteThread == NULL);
+
+ /* Acquire the paging resource (shared) */
+ Ret = ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, Wait);
+ if (Ret)
+ {
+ /* Update tracker information */
+ Fcb->PagingIoResourceFile = __FILE__;
+ Fcb->PagingIoResourceLine = __LINE__;
+ /* Lazy writer thread is the current one */
+ Fcb->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
+
+ /* There is no top level IRP */
+ ASSERT(RxIsThisTheTopLevelIrp(NULL));
+ /* Now, there will be! */
+ Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
+ Fcb->RxDeviceObject, TRUE);
+ /* In case of failure, release the lock and reset everything */
+ if (!Ret)
+ {
+ Fcb->PagingIoResourceFile = NULL;
+ Fcb->PagingIoResourceLine = 0;
+ ExReleaseResourceLite(Fcb->Header.PagingIoResource);
+ Fcb->Specific.Fcb.LazyWriteThread = NULL;
+ }
+ }
+
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+RxAcquireFcbForReadAhead(
+ PVOID Context,
+ BOOLEAN Wait)
+{
+ PFCB Fcb;
+ BOOLEAN Ret;
+
+ PAGED_CODE();
+
+ Fcb = Context;
+ /* The received context is a FCB */
+ ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+
+ Ret = ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait);
+ if (Ret)
+ {
+ /* There is no top level IRP */
+ ASSERT(RxIsThisTheTopLevelIrp(NULL));
+ /* Now, there will be! */
+ Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
+ Fcb->RxDeviceObject, TRUE);
+ /* In case of failure, release the lock and reset everything */
+ if (!Ret)
+ {
+ ExReleaseResourceLite(Fcb->Header.Resource);
+ }
+ }
+
+ return Ret;
+}
+
+VOID
+NTAPI
+RxAcquireFileForNtCreateSection(
+ PFILE_OBJECT FileObject)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxAcquireForCcFlush(
+ PFILE_OBJECT FileObject,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
/*
* @implemented
*/
FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
}
+ DPRINT("Allocated %p\n", Buffer);
+
return Buffer;
}
return NULL;
}
- /* And initialize it */
+ /* Zero it */
RtlZeroMemory(Context, sizeof(RX_CONTEXT));
+
+ /* It was allocated on NP pool, keep track of it! */
+ SetFlag(Context->Flags, RX_CONTEXT_FLAG_FROM_POOL);
+ /* And initialize it */
RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED));
return STATUS_SUCCESS;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxFinalizeConnection(
+ IN OUT PNET_ROOT NetRoot,
+ IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
+ IN LOGICAL ForceFilesClosed)
+{
+ NTSTATUS Status;
+ PRX_PREFIX_TABLE PrefixTable;
+ ULONG UncleanAny, UncleanDir;
+ LONG FilesOpen, AdditionalRef;
+ BOOLEAN PrefixLocked, FcbTableLocked, ForceClose;
+
+ PAGED_CODE();
+
+ ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
+
+ /* Get a BOOLEAN out of LOGICAL
+ * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
+ */
+ ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE);
+
+ /* First, delete any notification change */
+ Status = RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot, ForceClose);
+ /* If it failed, continue if forced */
+ if (Status != STATUS_SUCCESS && !ForceFilesClosed)
+ {
+ return Status;
+ }
+ /* Reset status, in case notification deletion failed */
+ Status = STATUS_SUCCESS;
+
+ PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+
+ PrefixLocked = FALSE;
+ FcbTableLocked = FALSE;
+ FilesOpen = 0;
+ AdditionalRef = 0;
+ UncleanAny = 0;
+ UncleanDir = 0;
+ _SEH2_TRY
+ {
+ RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
+ PrefixLocked = TRUE;
+
+ RxReferenceNetRoot(NetRoot);
+
+ RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
+ FcbTableLocked = TRUE;
+
+ /* If our V_NET_ROOT wasn't finalized yet, proceed! */
+ if (!VNetRoot->ConnectionFinalizationDone)
+ {
+ USHORT Bucket;
+ PRX_FCB_TABLE FcbTable;
+
+ DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix);
+
+ /* We'll browse all its associated FCB to check whether they're open/orphaned */
+ FcbTable = &NetRoot->FcbTable;
+ for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
+ {
+ PLIST_ENTRY BucketList, Entry;
+
+ BucketList = &FcbTable->HashBuckets[Bucket];
+ Entry = BucketList->Flink;
+ while (Entry != BucketList)
+ {
+ PFCB Fcb;
+
+ Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
+ Entry = Entry->Flink;
+
+ /* FCB for this connection, go ahead */
+ if (Fcb->VNetRoot == VNetRoot)
+ {
+ /* It's still open, and no force? Fail and keep track */
+ if (Fcb->UncleanCount > 0 && !ForceClose)
+ {
+ Status = STATUS_CONNECTION_IN_USE;
+ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
+ {
+ ++UncleanDir;
+ }
+ else
+ {
+ ++UncleanAny;
+ }
+ }
+ else
+ {
+ /* Else, force purge */
+ ASSERT(NodeTypeIsFcb(Fcb));
+
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
+
+ RxScavengeRelatedFobxs(Fcb);
+ RxPurgeFcb(Fcb);
+
+ /* We don't need to release FCB lock, FCB finalize will take care of it */
+ }
+ }
+ }
+ }
+
+ /* No files left, our V_NET_ROOT is finalized */
+ if (VNetRoot->NumberOfFobxs == 0)
+ {
+ VNetRoot->ConnectionFinalizationDone = TRUE;
+ }
+ }
+
+ /* Keep Number of open files and track of the extra reference */
+ FilesOpen = VNetRoot->NumberOfFobxs;
+ AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken;
+ /* If force close, caller doesn't want to keep connection alive
+ * and wants it totally close, so drop the V_NET_ROOT too
+ */
+ if (ForceClose)
+ {
+ RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE);
+ }
+ }
+ _SEH2_FINALLY
+ {
+ /* Release what was acquired */
+ if (FcbTableLocked)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ }
+
+ /* If close is forced, only fix status if there are open files */
+ if (ForceClose)
+ {
+ if (Status != STATUS_SUCCESS && UncleanAny != 0)
+ {
+ Status = STATUS_FILES_OPEN;
+ }
+ }
+ /* Else, fix status and fail closing if there are open files */
+ else
+ {
+ if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0)
+ {
+ Status = STATUS_FILES_OPEN;
+ }
+ }
+
+ DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen);
+
+ /* If we're are asked to remove the extra ref, or if closing was a success, do it;
+ * only if it was still referenced!
+ */
+ if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0)
+ {
+ VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
+ RxDereferenceVNetRoot(VNetRoot, LHS_ExclusiveLockHeld);
+ }
+
+ if (PrefixLocked)
+ {
+ RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
+ RxReleasePrefixTableLock(PrefixTable);
+ }
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
/*
* @implemented
*/
HashBucket = &FcbTable->HashBuckets[Bucket];
ListEntry = HashBucket->Flink;
while (ListEntry != HashBucket)
- {
+ {
PFCB Fcb;
Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
}
- /* If enclosed allocation, mark the memory zone free and dereference FCB */
+ /* If enclosed allocation, mark the memory zone free */
if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
{
ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED);
- RxDereferenceNetFcb(Fcb);
}
/* Otherwise, free the memory */
else
RxFreeFcbObject(ThisSrvOpen);
}
+ RxDereferenceNetFcb(Fcb);
+
return TRUE;
}
{
/* If our FCB newly points to a file, initiliaze everything related */
if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE)
-
+
{
if (OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
{
{
PAGED_CODE();
+ DPRINT("Freeing %p\n", Object);
+
/* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
if (NodeType(Object) == RDBSS_NTC_FOBX || NodeType(Object) == RDBSS_NTC_SRVOPEN)
{
DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
/* Only continue if we're at APC_LEVEL or lower */
- if (KeGetCurrentIrql() >= DISPATCH_LEVEL &&
+ if (RxShouldPostCompletion() &&
!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
{
return STATUS_MORE_PROCESSING_REQUIRED;
VOID
RxOrphanSrvOpens(
IN PV_NET_ROOT ThisVNetRoot)
+{
+ PFCB Fcb;
+ USHORT Bucket;
+ PNET_ROOT NetRoot;
+ PRX_FCB_TABLE FcbTable;
+ PRX_PREFIX_TABLE PrefixTable;
+
+ PAGED_CODE();
+
+ /* Mailslot won't have any SRV_OPEN (to orphan) */
+ NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
+ if (NetRoot->Type == NET_ROOT_MAILSLOT)
+ {
+ return;
+ }
+
+ PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
+ ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
+
+ FcbTable = &NetRoot->FcbTable;
+ RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
+
+ _SEH2_TRY
+ {
+ /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
+ for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
+ {
+ PLIST_ENTRY BucketList, Entry;
+
+ BucketList = &FcbTable->HashBuckets[Bucket];
+ Entry = BucketList->Flink;
+ while (Entry != BucketList)
+ {
+ Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
+ Entry = Entry->Flink;
+
+ ASSERT(NodeTypeIsFcb(Fcb));
+ RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
+ }
+ }
+
+ /* Of course, don't forget about NULL-entry */
+ if (FcbTable->TableEntryForNull != NULL)
+ {
+ Fcb = CONTAINING_RECORD(FcbTable->TableEntryForNull, FCB, FcbTableEntry.HashLinks);
+ ASSERT(NodeTypeIsFcb(Fcb));
+ RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
+ }
+ }
+ _SEH2_FINALLY
+ {
+ RxReleaseFcbTableLock(FcbTable);
+ }
+ _SEH2_END;
+}
+
+VOID
+RxOrphanSrvOpensForThisFcb(
+ IN PFCB Fcb,
+ IN PV_NET_ROOT ThisVNetRoot,
+ IN BOOLEAN OrphanAll)
{
UNIMPLEMENTED;
}
if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
{
- if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2)
+ if (RxContext != NULL && RxContext != CHANGE_BUFFERING_STATE_CONTEXT &&
+ RxContext != CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
{
RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
}
{
NODE_TYPE_CODE Type;
- Type = NodeType(Container);
+ Type = (NodeType(Container) & ~RX_SCAVENGER_MASK);
switch (Type)
{
case RDBSS_NTC_SRVCALL:
break;
default:
+ DPRINT1("Invalid node type: %x\n", Type);
ASSERT(FALSE);
+ RxReference(Container);
break;
}
}
UNIMPLEMENTED;
}
+/*
+ * @implemented
+ */
+VOID
+RxpScavengeFobxs(
+ PRDBSS_SCAVENGER Scavenger,
+ PLIST_ENTRY FobxToScavenge)
+{
+ /* Explore the whole list of FOBX to scavenge */
+ while (!IsListEmpty(FobxToScavenge))
+ {
+ PFCB Fcb;
+ PFOBX Fobx;
+ PLIST_ENTRY Entry;
+
+ Entry = RemoveHeadList(FobxToScavenge);
+ Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
+ Fcb = (PFCB)Fobx->SrvOpen->pFcb;
+
+ /* Try to acquire the lock exclusively to perform finalization */
+ if (RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS)
+ {
+ RxDereferenceNetRoot(Fobx, LHS_LockNotHeld);
+ }
+ else
+ {
+ RxReferenceNetFcb(Fcb);
+ RxDereferenceNetRoot(Fobx, LHS_ExclusiveLockHeld);
+
+ if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
+ {
+ RxReleaseFcb(NULL, Fcb);
+ }
+ }
+ }
+}
+
BOOLEAN
RxpTrackDereference(
_In_ ULONG TraceType,
_In_ ULONG Line,
_In_ PVOID Instance)
{
+ PCSTR InstanceType;
+ ULONG ReferenceCount;
+
PAGED_CODE();
if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
return TRUE;
}
- UNIMPLEMENTED;
+ switch (TraceType)
+ {
+ case RDBSS_REF_TRACK_SRVCALL:
+ InstanceType = "SrvCall";
+ ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETROOT:
+ InstanceType = "NetRoot";
+ ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_VNETROOT:
+ InstanceType = "VNetRoot";
+ ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETFOBX:
+ InstanceType = "NetFobx";
+ ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETFCB:
+ InstanceType = "NetFcb";
+ ReferenceCount = ((PFCB)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_SRVOPEN:
+ InstanceType = "SrvOpen";
+ ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount;
+ break;
+
+ default:
+ DPRINT1("Invalid node type!\n");
+ return TRUE;
+ }
+
+ if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING))
+ {
+ UNIMPLEMENTED;
+ }
+
+ if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING))
+ {
+ DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount);
+ }
+
return TRUE;
}
_In_ ULONG Line,
_In_ PVOID Instance)
{
+ PCSTR InstanceType;
+ ULONG ReferenceCount;
+
if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
{
return;
}
- UNIMPLEMENTED;
-}
+ switch (TraceType)
+ {
+ case RDBSS_REF_TRACK_SRVCALL:
+ InstanceType = "SrvCall";
+ ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount;
+ break;
-/*
+ case RDBSS_REF_TRACK_NETROOT:
+ InstanceType = "NetRoot";
+ ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_VNETROOT:
+ InstanceType = "VNetRoot";
+ ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETFOBX:
+ InstanceType = "NetFobx";
+ ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_NETFCB:
+ InstanceType = "NetFcb";
+ ReferenceCount = ((PFCB)Instance)->NodeReferenceCount;
+ break;
+
+ case RDBSS_REF_TRACK_SRVOPEN:
+ InstanceType = "SrvOpen";
+ ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount;
+ break;
+
+ default:
+ DPRINT1("Invalid node type!\n");
+ return;
+ }
+
+ if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING))
+ {
+ UNIMPLEMENTED;
+ }
+
+ if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING))
+ {
+ DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount);
+ }
+}
+
+/*
* @implemented
*/
VOID
return Status;
}
+/*
+ * @implemented
+ */
+BOOLEAN
+RxPurgeFobx(
+ PFOBX pFobx)
+{
+ NTSTATUS Status;
+ PFCB FcbToBePurged;
+
+ PAGED_CODE();
+
+ /* Get the associated FCB */
+ FcbToBePurged = (PFCB)pFobx->pSrvOpen->pFcb;
+ Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ /* Purge it */
+ Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
+ if (Status != STATUS_SUCCESS)
+ {
+ DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged, pFobx);
+ return FALSE;
+ }
+
+ /* And flush */
+ if (!MmFlushImageSection(&FcbToBePurged->NonPaged->SectionObjectPointers, MmFlushForWrite))
+ {
+ DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged, pFobx);
+ return FALSE;
+ }
+
+ DPRINT("Purge OK for %p (%p)\n", FcbToBePurged, pFobx);
+ return TRUE;
+}
+
/*
* @implemented
*/
return Status;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+RxPurgeRelatedFobxs(
+ PNET_ROOT NetRoot,
+ PRX_CONTEXT RxContext,
+ BOOLEAN AttemptFinalization,
+ PFCB PurgingFcb)
+{
+ PLIST_ENTRY Entry;
+ ULONG SuccessfullPurge;
+ PRDBSS_SCAVENGER Scavenger;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx;
+
+ PAGED_CODE();
+
+ RxDeviceObject = RxContext->RxDeviceObject;
+ Scavenger = RxDeviceObject->pRdbssScavenger;
+ PurgeSyncCtx = &NetRoot->PurgeSyncronizationContext;
+
+ RxAcquireScavengerMutex();
+
+ /* If there's already a purge in progress */
+ if (PurgeSyncCtx->PurgeInProgress)
+ {
+ /* Add our RX_CONTEXT to the current run */
+ InsertTailList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion,
+ &RxContext->RxContextSerializationQLinks);
+
+ /* And wait until it's done */
+ RxReleaseScavengerMutex();
+ RxWaitSync(RxContext);
+ RxAcquireScavengerMutex();
+ }
+
+ /* Start the purge */
+ PurgeSyncCtx->PurgeInProgress = TRUE;
+
+ /* While the purge is still handling our NET_ROOT, do nothing but wait */
+ while (Scavenger->CurrentNetRootForClosePendingProcessing == NetRoot)
+ {
+ RxReleaseScavengerMutex();
+ KeWaitForSingleObject(&Scavenger->ClosePendingProcessingSyncEvent, Executive,
+ KernelMode, TRUE, NULL);
+ RxAcquireScavengerMutex();
+ }
+
+ /* Now, for all the entries */
+ SuccessfullPurge = 0;
+ Entry = Scavenger->ClosePendingFobxsList.Flink;
+ while (Entry != &Scavenger->ClosePendingFobxsList)
+ {
+ PFCB Fcb;
+ PFOBX Fobx;
+ BOOLEAN Success;
+
+ Fobx = CONTAINING_RECORD(Entry, FOBX, ClosePendingList);
+ DPRINT("Dealing with FOBX: %p\n", Fobx);
+
+ Entry = Entry->Flink;
+
+ /* If it's not matching our NET_ROOT, ignore */
+ if (Fobx->pSrvOpen == NULL ||
+ Fobx->pSrvOpen->pFcb == NULL ||
+ ((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot == NULL ||
+ (PNET_ROOT)((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot->pNetRoot != NetRoot)
+ {
+ continue;
+ }
+
+ /* Determine if it matches our FCB */
+ Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
+ if (PurgingFcb != NULL && NodeType(PurgingFcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
+ PurgingFcb != Fcb)
+ {
+ NTSTATUS Status;
+
+ MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
+ if (Status == STATUS_SUCCESS)
+ {
+ continue;
+ }
+ }
+
+ /* Matching, we'll purge it */
+ RemoveEntryList(&Fobx->ClosePendingList);
+
+ /* Reference it so that it doesn't disappear */
+ RxReferenceNetFobx(Fobx);
+
+ RxReleaseScavengerMutex();
+
+ /* And purge */
+ Success = RxPurgeFobx(Fobx);
+ if (Success)
+ {
+ ++SuccessfullPurge;
+ }
+
+ /* If we don't have to finalize it (or if we cannot acquire lock exclusively
+ * Just normally dereference
+ */
+ if ((AttemptFinalization == DONT_ATTEMPT_FINALIZE_ON_PURGE) ||
+ RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS)
+ {
+ RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
+ }
+ /* Otherwise, finalize */
+ else
+ {
+ RxReferenceNetFcb(Fcb);
+ RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
+ if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
+ {
+ RxReleaseFcb(NULL, Fcb);
+ }
+ }
+
+ if (!Success)
+ {
+ DPRINT1("Failed purging %p (%p)\n", Fcb, Fobx);
+ }
+
+ RxAcquireScavengerMutex();
+ }
+
+ /* If no contexts left, purge is not running */
+ if (IsListEmpty(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion))
+ {
+ PurgeSyncCtx->PurgeInProgress = FALSE;
+ }
+ /* Otherwise, notify a waiter it can start */
+ else
+ {
+ PRX_CONTEXT Context;
+
+ Entry = RemoveHeadList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion);
+ Context = CONTAINING_RECORD(Entry, RX_CONTEXT, RxContextSerializationQLinks);
+
+ RxSignalSynchronousWaiter(Context);
+ }
+
+ RxReleaseScavengerMutex();
+
+ return (SuccessfullPurge > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
+}
+
/*
* @implemented
*/
RxReleaseScavengerMutex();
}
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxReinitializeContext(
+ IN OUT PRX_CONTEXT RxContext)
+{
+ PIRP Irp;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ ULONG InitialContextFlags, SavedFlags;
+
+ PAGED_CODE();
+
+ /* Backup a few flags */
+ Irp = RxContext->CurrentIrp;
+ RxDeviceObject = RxContext->RxDeviceObject;
+ SavedFlags = RxContext->Flags & RX_CONTEXT_PRESERVED_FLAGS;
+ InitialContextFlags = RxContext->Flags & RX_CONTEXT_INITIALIZATION_FLAGS;
+
+ /* Reset our context */
+ RxPrepareContextForReuse(RxContext);
+
+ /* Zero everything */
+ RtlZeroMemory(&RxContext->MajorFunction, sizeof(RX_CONTEXT) - FIELD_OFFSET(RX_CONTEXT, MajorFunction));
+
+ /* Restore saved flags */
+ RxContext->Flags = SavedFlags;
+ /* And reinit the context */
+ RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, RxContext);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxReleaseFcbFromLazyWrite(
+ PVOID Context)
+{
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ Fcb = Context;
+ /* The received context is a FCB */
+ ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+
+ /* Lazy writer is releasing lock, so forget about it */
+ Fcb->Specific.Fcb.LazyWriteThread = NULL;
+
+ /* If we were top level IRP, unwind */
+ if (RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP)
+ {
+ RxUnwindTopLevelIrp(NULL);
+ }
+
+ /* And finally, release the lock */
+ Fcb->PagingIoResourceFile = NULL;
+ Fcb->PagingIoResourceLine = 0;
+ ExReleaseResourceLite(Fcb->Header.PagingIoResource);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+RxReleaseFcbFromReadAhead(
+ PVOID Context)
+{
+ PFCB Fcb;
+
+ PAGED_CODE();
+
+ Fcb = Context;
+ /* The received context is a FCB */
+ ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
+ ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
+
+ /* Top Level IRP is CC */
+ ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
+ RxUnwindTopLevelIrp(NULL);
+
+ ExReleaseResourceLite(Fcb->Header.Resource);
+}
+
+VOID
+NTAPI
+RxReleaseFileForNtCreateSection(
+ PFILE_OBJECT FileObject)
+{
+ UNIMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxReleaseForCcFlush(
+ PFILE_OBJECT FileObject,
+ PDEVICE_OBJECT DeviceObject)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
/*
* @implemented
*/
RxReleaseSerializationMutex();
}
+/*
+ * @implemented
+ */
+VOID
+RxSetFileSizeWithLock(
+ IN OUT PFCB Fcb,
+ IN PLONGLONG FileSize)
+{
+ PAGED_CODE();
+
+ /* Set attribute and increase version */
+ Fcb->Header.FileSize.QuadPart = *FileSize;
+ ++Fcb->ulFileSizeVersion;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxScavengeFobxsForNetRoot(
+ PNET_ROOT NetRoot,
+ PFCB PurgingFcb,
+ BOOLEAN SynchronizeWithScavenger)
+{
+ PRDBSS_SCAVENGER Scavenger;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+
+ PAGED_CODE();
+
+ RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
+ Scavenger = RxDeviceObject->pRdbssScavenger;
+
+ /* Wait for the scavenger, if asked to */
+ if (SynchronizeWithScavenger)
+ {
+ KeWaitForSingleObject(&Scavenger->SyncEvent, Executive, KernelMode, FALSE, NULL);
+ }
+
+ RxAcquireScavengerMutex();
+
+ /* If there's nothing left to do... */
+ if (Scavenger->FobxsToBeFinalized <= 0)
+ {
+ RxReleaseScavengerMutex();
+ }
+ else
+ {
+ PLIST_ENTRY Entry;
+ LIST_ENTRY FobxToScavenge;
+
+ InitializeListHead(&FobxToScavenge);
+
+ /* Browse all the FOBXs to finalize */
+ Entry = Scavenger->FobxFinalizationList.Flink;
+ while (Entry != &Scavenger->FobxFinalizationList)
+ {
+ PFOBX Fobx;
+
+ Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
+ Entry = Entry->Flink;
+
+ if (Fobx->SrvOpen != NULL)
+ {
+ PFCB Fcb;
+
+ Fcb = (PFCB)Fobx->SrvOpen->pFcb;
+
+ /* If it matches our NET_ROOT */
+ if ((PNET_ROOT)Fcb->pNetRoot == NetRoot)
+ {
+ NTSTATUS Status;
+
+ /* Check whether it matches our FCB */
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+ if (PurgingFcb != NULL && PurgingFcb != Fcb)
+ {
+ MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
+ }
+
+ /* If so, add it to the list of the FOBXs to scavenge */
+ if (Status != STATUS_SUCCESS)
+ {
+ RxReferenceNetFobx(Fobx);
+ ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
+
+ RemoveEntryList(&Fobx->ScavengerFinalizationList);
+ InsertTailList(&FobxToScavenge, &Fobx->ScavengerFinalizationList);
+ }
+ }
+ }
+ }
+
+ RxReleaseScavengerMutex();
+
+ /* Now, scavenge all the extracted FOBX */
+ RxpScavengeFobxs(Scavenger, &FobxToScavenge);
+ }
+
+ if (SynchronizeWithScavenger)
+ {
+ KeSetEvent(&Scavenger->SyncEvent, IO_NO_INCREMENT, FALSE);
+ }
+}
+
/*
* @implemented
*/
/* Otherwise, we're inactive again */
else
{
- Scavenger->State == RDBSS_SCAVENGER_INACTIVE;
+ Scavenger->State = RDBSS_SCAVENGER_INACTIVE;
}
}
{
Case = RX_FCBTRACKER_CASE_NULLCONTEXT;
}
- else if ((ULONG_PTR)RxContext == -1)
+ else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT)
{
Case = RX_FCBTRACKER_CASE_CBS_CONTEXT;
}
- else if ((ULONG_PTR)RxContext == -2)
+ else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
{
Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT;
}
SpecialContext = FALSE;
ContextIsPresent = FALSE;
/* Check for special context */
- if ((ULONG_PTR)RxContext == -1 || (ULONG_PTR)RxContext == -2)
+ if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT || RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
{
SpecialContext = TRUE;
}
RxAcquireSerializationMutex();
BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
- IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
+ IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
/* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
* then just release the FCB
RxAcquireSerializationMutex();
BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
- IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
+ IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
/* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
* then just release the FCB