[RXCE]
[reactos.git] / reactos / sdk / lib / drivers / rxce / rxce.c
index e10a14e..8f47f50 100644 (file)
@@ -121,7 +121,14 @@ BOOLEAN RxStopOnLoudCompletion = TRUE;
 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;
@@ -167,6 +174,118 @@ BOOLEAN DumpDispatchRoutine = FALSE;
 
 /* 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
  */
@@ -405,6 +524,8 @@ RxAllocateFcbObject(
         FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
     }
 
+    DPRINT("Allocated %p\n", Buffer);
+
     return Buffer;
 }
 
@@ -1631,8 +1752,12 @@ RxCreateRxContext(
         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));
 
@@ -2435,6 +2560,182 @@ RxFcbTableRemoveFcb(
     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
  */
@@ -2730,7 +3031,7 @@ RxFinalizeNetRoot(
             HashBucket = &FcbTable->HashBuckets[Bucket];
             ListEntry = HashBucket->Flink;
             while (ListEntry != HashBucket)
-            {    
+            {
                 PFCB Fcb;
 
                 Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
@@ -2975,11 +3276,10 @@ RxFinalizeSrvOpen(
         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
@@ -2987,6 +3287,8 @@ RxFinalizeSrvOpen(
         RxFreeFcbObject(ThisSrvOpen);
     }
 
+    RxDereferenceNetFcb(Fcb);
+
     return TRUE;
 }
 
@@ -3690,7 +3992,7 @@ RxFinishFcbInitialization(
     {
         /* 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)
             {
@@ -3906,6 +4208,8 @@ RxFreeFcbObject(
 {
     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)
     {
@@ -4940,7 +5244,7 @@ RxLowIoCompletionTail(
     DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
 
     /* Only continue if we're at APC_LEVEL or lower */
-    if (KeGetCurrentIrql() >= DISPATCH_LEVEL &&
+    if (RxShouldPostCompletion() &&
         !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
     {
         return STATUS_MORE_PROCESSING_REQUIRED;
@@ -5433,6 +5737,67 @@ RxOrphanThisFcb(
 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;
 }
@@ -5518,7 +5883,8 @@ RxpDereferenceAndFinalizeNetFcb(
 
             if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
             {
-                if (RxContext != NULL && RxContext != (PVOID)-1 && RxContext != (PVOID)-2)
+                if (RxContext != NULL && RxContext != CHANGE_BUFFERING_STATE_CONTEXT &&
+                    RxContext != CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
                 {
                     RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
                 }
@@ -6064,7 +6430,7 @@ RxPrefixTableLookupName(
     {
         NODE_TYPE_CODE Type;
 
-        Type = NodeType(Container);
+        Type = (NodeType(Container) & ~RX_SCAVENGER_MASK);
         switch (Type)
         {
             case RDBSS_NTC_SRVCALL:
@@ -6080,7 +6446,9 @@ RxPrefixTableLookupName(
                 break;
 
             default:
+                DPRINT1("Invalid node type: %x\n", Type);
                 ASSERT(FALSE);
+                RxReference(Container);
                 break;
         }
     }
@@ -6241,6 +6609,43 @@ RxProcessFcbChangeBufferingStateRequest(
     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,
@@ -6248,6 +6653,9 @@ RxpTrackDereference(
     _In_ ULONG Line,
     _In_ PVOID Instance)
 {
+    PCSTR InstanceType;
+    ULONG ReferenceCount;
+
     PAGED_CODE();
 
     if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
@@ -6255,7 +6663,53 @@ RxpTrackDereference(
         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;
 }
 
@@ -6266,15 +6720,63 @@ RxpTrackReference(
     _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
@@ -6460,6 +6962,42 @@ RxPurgeFcbInSystemCache(
     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
  */
@@ -6506,6 +7044,155 @@ RxPurgeFobxFromCache(
     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
  */
@@ -6716,6 +7403,112 @@ RxReference(
     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
  */
@@ -6868,6 +7661,110 @@ RxResumeBlockedOperations_Serially(
     RxReleaseSerializationMutex();
 }
 
+/*
+ * @implemented
+ */
+VOID
+RxSetFileSizeWithLock(
+    IN OUT PFCB Fcb,
+    IN PLONGLONG FileSize)
+{
+    PAGED_CODE();
+
+    /* Set attribute and increase version */
+    Fcb->Header.FileSize.QuadPart = *FileSize;
+    ++Fcb->ulFileSizeVersion;
+}
+
+/*
+ * @implemented
+ */
+VOID
+RxScavengeFobxsForNetRoot(
+    PNET_ROOT NetRoot,
+    PFCB PurgingFcb,
+    BOOLEAN SynchronizeWithScavenger)
+{
+    PRDBSS_SCAVENGER Scavenger;
+    PRDBSS_DEVICE_OBJECT RxDeviceObject;
+
+    PAGED_CODE();
+
+    RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
+    Scavenger = RxDeviceObject->pRdbssScavenger;
+
+    /* Wait for the scavenger, if asked to */
+    if (SynchronizeWithScavenger)
+    {
+        KeWaitForSingleObject(&Scavenger->SyncEvent, Executive, KernelMode, FALSE, NULL);
+    }
+
+    RxAcquireScavengerMutex();
+
+    /* If there's nothing left to do... */
+    if (Scavenger->FobxsToBeFinalized <= 0)
+    {
+        RxReleaseScavengerMutex();
+    }
+    else
+    {
+        PLIST_ENTRY Entry;
+        LIST_ENTRY FobxToScavenge;
+
+        InitializeListHead(&FobxToScavenge);
+
+        /* Browse all the FOBXs to finalize */
+        Entry = Scavenger->FobxFinalizationList.Flink;
+        while (Entry != &Scavenger->FobxFinalizationList)
+        {
+            PFOBX Fobx;
+
+            Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
+            Entry = Entry->Flink;
+
+            if (Fobx->SrvOpen != NULL)
+            {
+                PFCB Fcb;
+
+                Fcb = (PFCB)Fobx->SrvOpen->pFcb;
+
+                /* If it matches our NET_ROOT */
+                if ((PNET_ROOT)Fcb->pNetRoot == NetRoot)
+                {
+                    NTSTATUS Status;
+
+                    /* Check whether it matches our FCB */
+                    Status = STATUS_MORE_PROCESSING_REQUIRED;
+                    if (PurgingFcb != NULL && PurgingFcb != Fcb)
+                    {
+                        MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
+                    }
+
+                    /* If so, add it to the list of the FOBXs to scavenge */
+                    if (Status != STATUS_SUCCESS)
+                    {
+                        RxReferenceNetFobx(Fobx);
+                        ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
+
+                        RemoveEntryList(&Fobx->ScavengerFinalizationList);
+                        InsertTailList(&FobxToScavenge, &Fobx->ScavengerFinalizationList);
+                    }
+                }
+            }
+        }
+
+        RxReleaseScavengerMutex();
+
+        /* Now, scavenge all the extracted FOBX */
+        RxpScavengeFobxs(Scavenger, &FobxToScavenge);
+    }
+
+    if (SynchronizeWithScavenger)
+    {
+        KeSetEvent(&Scavenger->SyncEvent, IO_NO_INCREMENT, FALSE);
+    }
+}
+
 /*
  * @implemented
  */
@@ -6990,7 +7887,7 @@ RxScavengerTimerRoutine(
             /* Otherwise, we're inactive again */
             else
             {
-                Scavenger->State == RDBSS_SCAVENGER_INACTIVE;
+                Scavenger->State = RDBSS_SCAVENGER_INACTIVE;
             }
         }
 
@@ -7570,11 +8467,11 @@ RxTrackerUpdateHistory(
     {
         Case = RX_FCBTRACKER_CASE_NULLCONTEXT;
     }
-    else if ((ULONG_PTR)RxContext == -1)
+    else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT)
     {
         Case = RX_FCBTRACKER_CASE_CBS_CONTEXT;
     }
-    else if ((ULONG_PTR)RxContext == -2)
+    else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
     {
         Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT;
     }
@@ -7974,7 +8871,7 @@ __RxAcquireFcb(
     SpecialContext = FALSE;
     ContextIsPresent = FALSE;
     /* Check for special context */
-    if ((ULONG_PTR)RxContext == -1 || (ULONG_PTR)RxContext == -2)
+    if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT || RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
     {
         SpecialContext = TRUE;
     }
@@ -8137,7 +9034,7 @@ __RxReleaseFcb(
     RxAcquireSerializationMutex();
 
     BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
-    IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
+    IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
 
     /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
      * then just release the FCB
@@ -8184,7 +9081,7 @@ __RxReleaseFcbForThread(
     RxAcquireSerializationMutex();
 
     BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
-    IsExclusive = BooleanFlagOn(MrxFcb->Header.Resource->Flag, ResourceOwnedExclusive);
+    IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
 
     /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
      * then just release the FCB