xref: /reactos/sdk/lib/drivers/rxce/rxce.c (revision 53221834)
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2017 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:        See COPYING in the top level directory
21  * PROJECT:          ReactOS kernel
22  * FILE:             sdk/lib/drivers/rxce/rxce.c
23  * PURPOSE:          RXCE library
24  * PROGRAMMER:       Pierre Schweitzer (pierre@reactos.org)
25  */
26 
27 /* INCLUDES *****************************************************************/
28 
29 #include <rx.h>
30 #include <pseh/pseh2.h>
31 #include <dfs.h>
32 
33 #define NDEBUG
34 #include <debug.h>
35 
36 VOID
37 RxAssert(
38     PVOID Assert,
39     PVOID File,
40     ULONG Line,
41     PVOID Message);
42 
43 VOID
44 NTAPI
45 RxCreateSrvCallCallBack(
46     IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context);
47 
48 NTSTATUS
49 RxFinishSrvCallConstruction(
50     PMRX_SRVCALLDOWN_STRUCTURE Calldown);
51 
52 VOID
53 NTAPI
54 RxFinishSrvCallConstructionDispatcher(
55     IN PVOID Context);
56 
57 NTSTATUS
58 RxInsertWorkQueueItem(
59     PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
60     WORK_QUEUE_TYPE WorkQueueType,
61     PRX_WORK_QUEUE_ITEM WorkQueueItem);
62 
63 PVOID
64 RxNewMapUserBuffer(
65     PRX_CONTEXT RxContext);
66 
67 VOID
68 NTAPI
69 RxpDestroySrvCall(
70     IN PVOID Context);
71 
72 VOID
73 RxpDispatchChangeBufferingStateRequests(
74     PSRV_CALL SrvCall,
75     PSRV_OPEN SrvOpen,
76     PLIST_ENTRY DiscardedRequests);
77 
78 VOID
79 NTAPI
80 RxScavengerTimerRoutine(
81     PVOID Context);
82 
83 VOID
84 NTAPI
85 RxTimerDispatch(
86     _In_ struct _KDPC *Dpc,
87     _In_opt_ PVOID DeferredContext,
88     _In_opt_ PVOID SystemArgument1,
89     _In_opt_ PVOID SystemArgument2);
90 
91 VOID
92 NTAPI
93 RxWorkItemDispatcher(
94     PVOID Context);
95 
96 PVOID
97 NTAPI
98 _RxAllocatePoolWithTag(
99     _In_ POOL_TYPE PoolType,
100     _In_ SIZE_T NumberOfBytes,
101     _In_ ULONG Tag);
102 
103 VOID
104 NTAPI
105 _RxFreePool(
106     _In_ PVOID Buffer);
107 
108 VOID
109 NTAPI
110 _RxFreePoolWithTag(
111     _In_ PVOID Buffer,
112     _In_ ULONG Tag);
113 
114 extern ULONG ReadAheadGranularity;
115 
116 volatile LONG RxNumberOfActiveFcbs = 0;
117 ULONG SerialNumber = 1;
118 PVOID RxNull =  NULL;
119 volatile ULONG RxContextSerialNumberCounter;
120 BOOLEAN RxStopOnLoudCompletion = TRUE;
121 BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE;
122 LIST_ENTRY RxSrvCalldownList;
123 RX_SPIN_LOCK RxStrucSupSpinLock;
124 #if 0
125 ULONG RdbssReferenceTracingValue = (RDBSS_REF_TRACK_SRVCALL | RDBSS_REF_TRACK_NETROOT |
126                                     RDBSS_REF_TRACK_VNETROOT | RDBSS_REF_TRACK_NETFOBX |
127                                     RDBSS_REF_TRACK_NETFCB | RDBSS_REF_TRACK_SRVOPEN |
128                                     RX_PRINT_REF_TRACKING);
129 #else
130 ULONG RdbssReferenceTracingValue = 0;
131 #endif
132 LARGE_INTEGER RxWorkQueueWaitInterval[RxMaximumWorkQueue];
133 LARGE_INTEGER RxSpinUpDispatcherWaitInterval;
134 RX_DISPATCHER RxDispatcher;
135 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues;
136 FAST_MUTEX RxLowIoPagingIoSyncMutex;
137 BOOLEAN RxContinueFromAssert = TRUE;
138 ULONG RxExplodePoolTags = 1;
139 LARGE_INTEGER RxTimerInterval;
140 RX_SPIN_LOCK RxTimerLock;
141 LIST_ENTRY RxTimerQueueHead;
142 LIST_ENTRY RxRecurrentWorkItemsList;
143 KDPC RxTimerDpc;
144 KTIMER RxTimer;
145 ULONG RxTimerTickCount;
146 FAST_MUTEX RxContextPerFileSerializationMutex;
147 #if DBG
148 BOOLEAN DumpDispatchRoutine = TRUE;
149 #else
150 BOOLEAN DumpDispatchRoutine = FALSE;
151 #endif
152 
153 #if RDBSS_ASSERTS
154 #ifdef ASSERT
155 #undef ASSERT
156 #endif
157 
158 #define ASSERT(exp)                               \
159     if (!(exp))                                   \
160     {                                             \
161         RxAssert(#exp, __FILE__, __LINE__, NULL); \
162     }
163 #endif
164 
165 #if RX_POOL_WRAPPER
166 #undef RxAllocatePool
167 #undef RxAllocatePoolWithTag
168 #undef RxFreePool
169 
170 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
171 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
172 #define RxFreePool _RxFreePool
173 #define RxFreePoolWithTag _RxFreePoolWithTag
174 #endif
175 
176 /* FUNCTIONS ****************************************************************/
177 
178 /*
179  * @implemented
180  */
181 NTSTATUS
182 NTAPI
183 RxAcquireExclusiveFcbResourceInMRx(
184     _Inout_ PMRX_FCB Fcb)
185 {
186     return RxAcquireExclusiveFcb(NULL, (PFCB)Fcb);
187 }
188 
189 /*
190  * @implemented
191  */
192 BOOLEAN
193 NTAPI
194 RxAcquireFcbForLazyWrite(
195     PVOID Context,
196     BOOLEAN Wait)
197 {
198     PFCB Fcb;
199     BOOLEAN Ret;
200 
201     PAGED_CODE();
202 
203     Fcb = Context;
204     /* The received context is a FCB */
205     ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
206     ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
207     ASSERT(Fcb->Specific.Fcb.LazyWriteThread == NULL);
208 
209     /* Acquire the paging resource (shared) */
210     Ret = ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, Wait);
211     if (Ret)
212     {
213         /* Update tracker information */
214         Fcb->PagingIoResourceFile = __FILE__;
215         Fcb->PagingIoResourceLine = __LINE__;
216         /* Lazy writer thread is the current one */
217         Fcb->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
218 
219         /* There is no top level IRP */
220         ASSERT(RxIsThisTheTopLevelIrp(NULL));
221         /* Now, there will be! */
222         Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
223                                           Fcb->RxDeviceObject, TRUE);
224         /* In case of failure, release the lock and reset everything */
225         if (!Ret)
226         {
227             Fcb->PagingIoResourceFile = NULL;
228             Fcb->PagingIoResourceLine = 0;
229             ExReleaseResourceLite(Fcb->Header.PagingIoResource);
230             Fcb->Specific.Fcb.LazyWriteThread = NULL;
231         }
232     }
233 
234     return Ret;
235 }
236 
237 /*
238  * @implemented
239  */
240 BOOLEAN
241 NTAPI
242 RxAcquireFcbForReadAhead(
243     PVOID Context,
244     BOOLEAN Wait)
245 {
246     PFCB Fcb;
247     BOOLEAN Ret;
248 
249     PAGED_CODE();
250 
251     Fcb = Context;
252     /* The received context is a FCB */
253     ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
254     ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
255 
256     Ret = ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait);
257     if (Ret)
258     {
259         /* There is no top level IRP */
260         ASSERT(RxIsThisTheTopLevelIrp(NULL));
261         /* Now, there will be! */
262         Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
263                                           Fcb->RxDeviceObject, TRUE);
264         /* In case of failure, release the lock and reset everything */
265         if (!Ret)
266         {
267             ExReleaseResourceLite(Fcb->Header.Resource);
268         }
269     }
270 
271     return Ret;
272 }
273 
274 VOID
275 NTAPI
276 RxAcquireFileForNtCreateSection(
277     PFILE_OBJECT FileObject)
278 {
279     UNIMPLEMENTED;
280 }
281 
282 NTSTATUS
283 NTAPI
284 RxAcquireForCcFlush(
285     PFILE_OBJECT FileObject,
286     PDEVICE_OBJECT DeviceObject)
287 {
288     UNIMPLEMENTED;
289     return STATUS_NOT_IMPLEMENTED;
290 }
291 
292 /*
293  * @implemented
294  */
295 VOID
296 RxAddVirtualNetRootToNetRoot(
297     PNET_ROOT NetRoot,
298     PV_NET_ROOT VNetRoot)
299 {
300     PAGED_CODE();
301 
302     DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot, VNetRoot);
303 
304     /* Insert in the VNetRoot list - make sure lock is held */
305     ASSERT(RxIsPrefixTableLockExclusive(NetRoot->SrvCall->RxDeviceObject->pRxNetNameTable));
306 
307     VNetRoot->pNetRoot = (PMRX_NET_ROOT)NetRoot;
308     ++NetRoot->NumberOfVirtualNetRoots;
309     InsertTailList(&NetRoot->VirtualNetRoots, &VNetRoot->NetRootListEntry);
310 }
311 
312 /*
313  * @implemented
314  */
315 PVOID
316 RxAllocateFcbObject(
317     PRDBSS_DEVICE_OBJECT RxDeviceObject,
318     NODE_TYPE_CODE NodeType,
319     POOL_TYPE PoolType,
320     ULONG NameSize,
321     PVOID AlreadyAllocatedObject)
322 {
323     PFCB Fcb;
324     PFOBX Fobx;
325     PSRV_OPEN SrvOpen;
326     PVOID Buffer, PAPNBuffer;
327     PNON_PAGED_FCB NonPagedFcb;
328     PMINIRDR_DISPATCH Dispatch;
329     ULONG NonPagedSize, FobxSize, SrvOpenSize, FcbSize;
330 
331     PAGED_CODE();
332 
333     Dispatch = RxDeviceObject->Dispatch;
334 
335     NonPagedSize = 0;
336     FobxSize = 0;
337     SrvOpenSize = 0;
338     FcbSize = 0;
339 
340     Fcb = NULL;
341     Fobx = NULL;
342     SrvOpen = NULL;
343     NonPagedFcb = NULL;
344     PAPNBuffer = NULL;
345 
346     /* If we ask for FOBX, just allocate FOBX and its extension if asked */
347     if (NodeType == RDBSS_NTC_FOBX)
348     {
349         FobxSize = sizeof(FOBX);
350         if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
351         {
352             FobxSize += QuadAlign(Dispatch->MRxFobxSize);
353         }
354     }
355     /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
356     else if (NodeType == RDBSS_NTC_SRVOPEN || NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
357     {
358         SrvOpenSize = sizeof(SRV_OPEN);
359         if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
360         {
361             SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
362         }
363 
364         FobxSize = sizeof(FOBX);
365         if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
366         {
367             FobxSize += QuadAlign(Dispatch->MRxFobxSize);
368         }
369     }
370     /* Otherwise, we're asked to allocate a FCB */
371     else
372     {
373         /* So, allocate the FCB and its extension if asked */
374         FcbSize = sizeof(FCB);
375         if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
376         {
377             FcbSize += QuadAlign(Dispatch->MRxFcbSize);
378         }
379 
380         /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
381          * Otherwise, it will be allocated later on, specifically
382          */
383         if (PoolType == NonPagedPool)
384         {
385             NonPagedSize = sizeof(NON_PAGED_FCB);
386         }
387 
388         /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
389         if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
390         {
391             SrvOpenSize = sizeof(SRV_OPEN);
392             if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
393             {
394                 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
395             }
396 
397             FobxSize = sizeof(FOBX);
398             if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
399             {
400                 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
401             }
402         }
403     }
404 
405     /* If we already have a buffer, go ahead */
406     if (AlreadyAllocatedObject != NULL)
407     {
408         Buffer = AlreadyAllocatedObject;
409     }
410     /* Otherwise, allocate it */
411     else
412     {
413         Buffer = RxAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
414         if (Buffer == NULL)
415         {
416             return NULL;
417         }
418     }
419 
420     /* Now, get the pointers - FOBX is easy */
421     if (NodeType == RDBSS_NTC_FOBX)
422     {
423         Fobx = Buffer;
424     }
425     /* SRV_OPEN first, FOBX next */
426     else if (NodeType == RDBSS_NTC_SRVOPEN)
427     {
428         SrvOpen = Buffer;
429         Fobx = Add2Ptr(Buffer, SrvOpenSize);
430     }
431     else if (NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
432     {
433         SrvOpen = Buffer;
434     }
435     else
436     {
437         /* FCB first, and if needed, SRV_OPEN next, FOBX last */
438         Fcb = Buffer;
439         if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
440         {
441             SrvOpen = Add2Ptr(Buffer, FcbSize);
442             Fobx = Add2Ptr(Buffer, FcbSize + SrvOpenSize);
443         }
444 
445         /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
446         if (PoolType != NonPagedPool)
447         {
448             NonPagedFcb = RxAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG);
449             if (NonPagedFcb == NULL)
450             {
451                 RxFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
452                 return NULL;
453             }
454 
455             PAPNBuffer = Add2Ptr(Buffer, FcbSize + SrvOpenSize + FobxSize);
456         }
457         /* Otherwise, just point at the right place in what has been allocated previously */
458         else
459         {
460             NonPagedFcb = Add2Ptr(Fobx, FobxSize);
461             PAPNBuffer = Add2Ptr(Fobx, FobxSize + NonPagedSize);
462         }
463     }
464 
465     /* If we have allocated a SRV_OPEN, initialize it */
466     if (SrvOpen != NULL)
467     {
468         ZeroAndInitializeNodeType(SrvOpen, RDBSS_NTC_SRVOPEN, SrvOpenSize);
469 
470         if (NodeType == RDBSS_NTC_SRVOPEN)
471         {
472             SrvOpen->InternalFobx = Fobx;
473         }
474         else
475         {
476             SrvOpen->InternalFobx = NULL;
477             SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
478         }
479 
480         if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
481         {
482             SrvOpen->Context = Add2Ptr(SrvOpen, sizeof(SRV_OPEN));
483         }
484 
485         InitializeListHead(&SrvOpen->SrvOpenQLinks);
486     }
487 
488     /* If we have allocated a FOBX, initialize it */
489     if (Fobx != NULL)
490     {
491         ZeroAndInitializeNodeType(Fobx, RDBSS_NTC_FOBX, FobxSize);
492 
493         if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
494         {
495             Fobx->Context = Add2Ptr(Fobx, sizeof(FOBX));
496         }
497     }
498 
499     /* If we have allocated a FCB, initialize it */
500     if (Fcb != NULL)
501     {
502         ZeroAndInitializeNodeType(Fcb, RDBSS_STORAGE_NTC(FileTypeNotYetKnown), FcbSize);
503 
504         Fcb->NonPaged = NonPagedFcb;
505         ZeroAndInitializeNodeType(Fcb->NonPaged, RDBSS_NTC_NONPAGED_FCB, sizeof(NON_PAGED_FCB));
506 #if DBG
507         Fcb->CopyOfNonPaged = NonPagedFcb;
508         NonPagedFcb->FcbBackPointer = Fcb;
509 #endif
510 
511         Fcb->InternalSrvOpen = SrvOpen;
512         Fcb->InternalFobx = Fobx;
513 
514         Fcb->PrivateAlreadyPrefixedName.Length = NameSize;
515         Fcb->PrivateAlreadyPrefixedName.MaximumLength = NameSize;
516         Fcb->PrivateAlreadyPrefixedName.Buffer = PAPNBuffer;
517 
518         if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
519         {
520             Fcb->Context = Add2Ptr(Fcb, sizeof(FCB));
521         }
522 
523         ZeroAndInitializeNodeType(&Fcb->FcbTableEntry, RDBSS_NTC_FCB_TABLE_ENTRY, sizeof(RX_FCB_TABLE_ENTRY));
524 
525         InterlockedIncrement(&RxNumberOfActiveFcbs);
526         InterlockedIncrement((volatile long *)&RxDeviceObject->NumberOfActiveFcbs);
527 
528         ExInitializeFastMutex(&NonPagedFcb->AdvancedFcbHeaderMutex);
529         FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
530     }
531 
532     DPRINT("Allocated %p\n", Buffer);
533 
534     return Buffer;
535 }
536 
537 /*
538  * @implemented
539  */
540 PVOID
541 RxAllocateObject(
542     NODE_TYPE_CODE NodeType,
543     PMINIRDR_DISPATCH MRxDispatch,
544     ULONG NameLength)
545 {
546     ULONG Tag, ObjectSize;
547     PVOID Object, *Extension;
548     PRX_PREFIX_ENTRY PrefixEntry;
549     USHORT StructSize, ExtensionSize;
550 
551     PAGED_CODE();
552 
553     /* Select the node to allocate and always deal with the fact we may have to manage its extension */
554     ExtensionSize = 0;
555     switch (NodeType)
556     {
557         case RDBSS_NTC_SRVCALL:
558             Tag = RX_SRVCALL_POOLTAG;
559             StructSize = sizeof(SRV_CALL);
560             if (MRxDispatch != NULL && BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
561             {
562                 ExtensionSize = QuadAlign(MRxDispatch->MRxSrvCallSize);
563             }
564             break;
565 
566         case RDBSS_NTC_NETROOT:
567             Tag = RX_NETROOT_POOLTAG;
568             StructSize = sizeof(NET_ROOT);
569             if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_NET_ROOT_EXTENSION))
570             {
571                 ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize);
572             }
573             break;
574 
575         case RDBSS_NTC_V_NETROOT:
576             Tag = RX_V_NETROOT_POOLTAG;
577             StructSize = sizeof(V_NET_ROOT);
578             if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_V_NET_ROOT_EXTENSION))
579             {
580                 ExtensionSize = QuadAlign(MRxDispatch->MRxVNetRootSize);
581             }
582             break;
583 
584         default:
585             ASSERT(FALSE);
586             break;
587     }
588 
589     /* Now, allocate the object */
590     ObjectSize = ExtensionSize + StructSize + NameLength;
591     Object = RxAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag);
592     if (Object == NULL)
593     {
594         return NULL;
595     }
596     /* Initialize it */
597     ZeroAndInitializeNodeType(Object, NodeType, ObjectSize);
598 
599     /* For SRV_CALL and NETROOT, the name points to the prefix table name */
600     switch (NodeType)
601     {
602         case RDBSS_NTC_SRVCALL:
603             PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry;
604             Extension = &((PSRV_CALL)Object)->Context;
605             ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix;
606             break;
607 
608         case RDBSS_NTC_NETROOT:
609             PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry;
610             Extension = &((PNET_ROOT)Object)->Context;
611             ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix;
612             break;
613 
614         case RDBSS_NTC_V_NETROOT:
615             PrefixEntry = &((PV_NET_ROOT)Object)->PrefixEntry;
616             Extension = &((PV_NET_ROOT)Object)->Context;
617             break;
618 
619         default:
620             ASSERT(FALSE);
621             break;
622     }
623 
624     /* Set the prefix table unicode string */
625     RtlZeroMemory(PrefixEntry, sizeof(RX_PREFIX_ENTRY));
626     PrefixEntry->NodeTypeCode = RDBSS_NTC_PREFIX_ENTRY;
627     PrefixEntry->NodeByteSize = sizeof(RX_PREFIX_ENTRY);
628     PrefixEntry->Prefix.Length = NameLength;
629     PrefixEntry->Prefix.MaximumLength = NameLength;
630     PrefixEntry->Prefix.Buffer = Add2Ptr(Object, ExtensionSize + StructSize);
631 
632     /* Return the extension if we are asked to manage it */
633     if (ExtensionSize != 0)
634     {
635         *Extension = Add2Ptr(Object, StructSize);
636     }
637 
638     return Object;
639 }
640 
641 /*
642  * @implemented
643  */
644 VOID
645 RxAssert(
646     PVOID Assert,
647     PVOID File,
648     ULONG Line,
649     PVOID Message)
650 {
651     CHAR Response[2];
652     CONTEXT Context;
653 
654     /* If we're not asked to continue, just stop the system */
655     if (!RxContinueFromAssert)
656     {
657         KeBugCheckEx(RDBSS_FILE_SYSTEM, RDBSS_BUG_CHECK_ASSERT | Line, 0, 0, 0);
658     }
659 
660     /* Otherwise, capture context to offer the user to dump it */
661     RtlCaptureContext(&Context);
662 
663     /* Loop until the user hits 'i' */
664     while (TRUE)
665     {
666         /* If no file provided, use empty name */
667         if (File == NULL)
668         {
669             File = "";
670         }
671 
672         /* If no message provided, use empty one */
673         if (Message == NULL)
674         {
675             Message = "";
676         }
677 
678         /* Display the message */
679         DbgPrint("\n*** Assertion failed: %s%s\n***   Source File: %s, line %ld\n\n", Message, Assert, File, Line);
680         /* And ask the user */
681         DbgPrompt("Break, Ignore (bi)? ", Response, sizeof(Response));
682         /* If he asks for ignore, quit
683          * In case of invalid input, ask again
684          */
685         if (Response[0] != 'B' && Response[0] != 'b')
686         {
687             if (Response[0] == 'I' || Response[0] == 'i')
688             {
689                 return;
690             }
691 
692             continue;
693         }
694 
695         /* Break: offer the user to dump the context and break */
696         DbgPrint("Execute '!cxr %lx' to dump context\n", &Context);
697         DbgBreakPoint();
698 
699         /* Continue looping, so that after dump, execution can continue (with ignore) */
700     }
701 }
702 
703 /*
704  * @implemented
705  */
706 VOID
707 NTAPI
708 RxBootstrapWorkerThreadDispatcher(
709    IN PVOID WorkQueue)
710 {
711     PRX_WORK_QUEUE RxWorkQueue;
712 
713     PAGED_CODE();
714 
715     RxWorkQueue = WorkQueue;
716     RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
717 }
718 
719 /*
720  * @implemented
721  */
722 VOID
723 RxCancelBlockingOperation(
724     IN OUT PRX_CONTEXT RxContext)
725 {
726     PFOBX Fobx;
727     BOOLEAN PostRequest;
728 
729     PAGED_CODE();
730 
731     Fobx = (PFOBX)RxContext->pFobx;
732     PostRequest = FALSE;
733 
734     /* Acquire the pipe mutex */
735     ExAcquireFastMutex(&RxContextPerFileSerializationMutex);
736 
737     /* If that's a blocking pipe operation which is not the CCB one, then handle it */
738     if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION) &&
739         RxContext->RxContextSerializationQLinks.Flink != NULL &&
740         RxContext != CONTAINING_RECORD(&Fobx->Specific.NamedPipe.ReadSerializationQueue, RX_CONTEXT, RxContextSerializationQLinks) &&
741         RxContext != CONTAINING_RECORD(&Fobx->Specific.NamedPipe.WriteSerializationQueue, RX_CONTEXT, RxContextSerializationQLinks))
742     {
743         /* Clear it! */
744         ClearFlag(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
745 
746         /* Drop it off the list */
747         RemoveEntryList(&RxContext->RxContextSerializationQLinks);
748         RxContext->RxContextSerializationQLinks.Flink = NULL;
749         RxContext->RxContextSerializationQLinks.Blink = NULL;
750 
751         /* Set we've been cancelled */
752         RxContext->IoStatusBlock.Status = STATUS_CANCELLED;
753 
754         /*
755          * If it's async, we'll post completion, otherwise, we signal to waiters
756          * it's being cancelled
757          */
758         if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
759         {
760             PostRequest = TRUE;
761         }
762         else
763         {
764             RxSignalSynchronousWaiter(RxContext);
765         }
766     }
767 
768     /* Done */
769     ExReleaseFastMutex(&RxContextPerFileSerializationMutex);
770 
771     /* Post if async */
772     if (PostRequest)
773     {
774         RxFsdPostRequest(RxContext);
775     }
776 }
777 
778 /*
779  * @implemented
780  */
781 NTSTATUS
782 NTAPI
783 RxChangeBufferingState(
784     PSRV_OPEN SrvOpen,
785     PVOID Context,
786     BOOLEAN ComputeNewState)
787 {
788     PFCB Fcb;
789     NTSTATUS Status, MiniStatus;
790     ULONG NewBufferingState, OldBufferingState;
791 
792     PAGED_CODE();
793 
794     DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen, Context, ComputeNewState);
795 
796     Fcb = (PFCB)SrvOpen->pFcb;
797     ASSERT(NodeTypeIsFcb(Fcb));
798     /* First of all, mark that buffering state is changing */
799     SetFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
800 
801     /* Assume success */
802     Status = STATUS_SUCCESS;
803     _SEH2_TRY
804     {
805         /* If we're asked to compute a new state, ask the mini-rdr for it */
806         if (ComputeNewState)
807         {
808             MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxComputeNewBufferingState,
809                                  ((PMRX_SRV_OPEN)SrvOpen, Context, &NewBufferingState));
810             if (MiniStatus != STATUS_SUCCESS)
811             {
812                 NewBufferingState = 0;
813             }
814         }
815         else
816         {
817             /* If not, use SRV_OPEN state */
818             NewBufferingState = SrvOpen->BufferingFlags;
819         }
820 
821         /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
822         if ((Fcb->ShareAccess.SharedRead + Fcb->ShareAccess.SharedWrite + Fcb->ShareAccess.SharedDelete) == 0 && !ComputeNewState)
823         {
824             SetFlag(NewBufferingState, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES);
825         }
826 
827         /* If there's a lock operation to complete, clear that flag */
828         if (Fcb->OutstandingLockOperationsCount != 0)
829         {
830             ClearFlag(NewBufferingState, FCB_STATE_LOCK_BUFFERING_ENABLED);
831         }
832 
833         /* Get the old state */
834         OldBufferingState = Fcb->FcbState & FCB_STATE_BUFFERING_STATE_MASK;
835         DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags);
836 
837         /* If we're dropping write cache, then flush the FCB */
838         if (BooleanFlagOn(OldBufferingState, FCB_STATE_WRITECACHING_ENABLED) &&
839             !BooleanFlagOn(NewBufferingState, FCB_STATE_WRITECACHING_ENABLED))
840         {
841             DPRINT("Flushing\n");
842 
843             Status = RxFlushFcbInSystemCache(Fcb, TRUE);
844         }
845 
846         /* If we're dropping read cache, then purge */
847         if (Fcb->UncleanCount == 0 ||
848             (BooleanFlagOn(OldBufferingState, FCB_STATE_READCACHING_ENABLED) &&
849              !BooleanFlagOn(NewBufferingState, FCB_STATE_READCACHING_ENABLED)) ||
850             BooleanFlagOn(NewBufferingState, FCB_STATE_DELETE_ON_CLOSE))
851         {
852             DPRINT("Purging\n");
853 
854             if (!NT_SUCCESS(Status))
855             {
856                  DPRINT("Previous flush failed with status: %lx\n", Status);
857             }
858 
859             CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, TRUE);
860         }
861 
862         /* If there's already a change pending in SRV_OPEN */
863         if (ComputeNewState && BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
864         {
865             /* If there's a FOBX at least */
866             if (!IsListEmpty(&SrvOpen->FobxList))
867             {
868                 PRX_CONTEXT RxContext;
869 
870                 /* Create a fake context to pass to the mini-rdr */
871                 RxContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
872                 if (RxContext != NULL)
873                 {
874                     PFOBX Fobx;
875 
876                     RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
877 
878                     /* Give the first FOBX */
879                     Fobx = CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks);
880                     RxContext->pFobx = (PMRX_FOBX)Fobx;
881                     RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
882 
883                     /* If there was a delayed close, perform it */
884                     if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
885                     {
886                         DPRINT("Oplock break close for %p\n", SrvOpen);
887 
888                         RxCloseAssociatedSrvOpen(Fobx, RxContext);
889                     }
890                     /* Otherwise, inform the mini-rdr about completion */
891                     else
892                     {
893                         MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxCompleteBufferingStateChangeRequest,
894                                              (RxContext, (PMRX_SRV_OPEN)SrvOpen, Context));
895                         (void)MiniStatus;
896                     }
897 
898                     RxDereferenceAndDeleteRxContext(RxContext);
899                 }
900             }
901         }
902 
903         /* Set the new state */
904         Fcb->FcbState ^= (NewBufferingState ^ Fcb->FcbState) & FCB_STATE_BUFFERING_STATE_MASK;
905     }
906     _SEH2_FINALLY
907     {
908         /* Job done, clear the flag */
909         ClearFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
910 
911         if (!BooleanFlagOn(NewBufferingState, FCB_STATE_FILETIMECACHEING_ENABLED))
912         {
913             ClearFlag(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET);
914         }
915     }
916     _SEH2_END;
917 
918     return Status;
919 }
920 
921 NTSTATUS
922 RxCheckVNetRootCredentials(
923     PRX_CONTEXT RxContext,
924     PV_NET_ROOT VNetRoot,
925     PLUID LogonId,
926     PUNICODE_STRING UserName,
927     PUNICODE_STRING UserDomain,
928     PUNICODE_STRING Password,
929     ULONG Flags)
930 {
931     PAGED_CODE();
932 
933     /* If that's a UNC name, there's nothing to process */
934     if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME) &&
935         (BooleanFlagOn(VNetRoot->Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE) ||
936          Flags != 0))
937     {
938         return STATUS_MORE_PROCESSING_REQUIRED;
939     }
940 
941     /* Compare the logon ID in the VNetRoot with the one provided */
942     if (RtlCompareMemory(&VNetRoot->LogonId, LogonId, sizeof(LUID)) != sizeof(LUID))
943     {
944         return STATUS_MORE_PROCESSING_REQUIRED;
945     }
946 
947     /* No credential provided? That's OK */
948     if (UserName == NULL && UserDomain == NULL && Password == NULL)
949     {
950         return STATUS_SUCCESS;
951     }
952 
953     /* Left to do! */
954     UNIMPLEMENTED;
955     return STATUS_NOT_IMPLEMENTED;
956 }
957 
958 NTSTATUS
959 RxCompleteRequest(
960       PRX_CONTEXT Context,
961       NTSTATUS Status)
962 {
963     PIRP Irp;
964 
965     PAGED_CODE();
966 
967     DPRINT("RxCompleteRequest(%p, %lx)\n", Context, Status);
968 
969     ASSERT(Context != NULL);
970     ASSERT(Context->CurrentIrp != NULL);
971     Irp = Context->CurrentIrp;
972 
973     /* Debug what the caller asks for */
974     if (Context->LoudCompletionString != NULL)
975     {
976         DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
977         /* Does the user asks to stop on failed completion */
978         if (!NT_SUCCESS(Status) && RxStopOnLoudCompletion)
979         {
980             DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
981         }
982     }
983 
984     /* Complete for real */
985     Context->CurrentIrp = NULL;
986     RxCompleteRequest_Real(Context, Irp, Status);
987 
988     DPRINT("Status: %lx\n", Status);
989     return Status;
990 }
991 
992 /*
993  * @implemented
994  */
995 VOID
996 RxCompleteRequest_Real(
997     IN PRX_CONTEXT RxContext,
998     IN PIRP Irp,
999     IN NTSTATUS Status)
1000 {
1001     CCHAR Boost;
1002     KIRQL OldIrql;
1003     PIO_STACK_LOCATION Stack;
1004 
1005     DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext, Irp, Status);
1006 
1007     /* Nothing to complete, just free context */
1008     if (Irp == NULL)
1009     {
1010         DPRINT("NULL IRP for %p\n", RxContext);
1011         if (RxContext != NULL)
1012         {
1013             RxDereferenceAndDeleteRxContext_Real(RxContext);
1014         }
1015 
1016         return;
1017     }
1018 
1019     /* Remove cancel routine */
1020     IoAcquireCancelSpinLock(&OldIrql);
1021     IoSetCancelRoutine(Irp, NULL);
1022     IoReleaseCancelSpinLock(OldIrql);
1023 
1024     /* Select the boost, given the success/paging operation */
1025     if (NT_SUCCESS(Status) || !BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO))
1026     {
1027         Boost = IO_DISK_INCREMENT;
1028     }
1029     else
1030     {
1031         Irp->IoStatus.Information = 0;
1032         Boost = IO_NO_INCREMENT;
1033     }
1034     Irp->IoStatus.Status = Status;
1035 
1036     if (RxContext != NULL)
1037     {
1038         ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
1039         if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
1040         {
1041             DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
1042                    RxContext->MinorFunction, RxContext, Irp,
1043                    Status, Irp->IoStatus.Information, RxContext->SerialNumber);
1044         }
1045     }
1046 
1047     /* If that's an opening, there might be a canonical name allocated,
1048      * if completion isn't pending, release it
1049      */
1050     Stack = IoGetCurrentIrpStackLocation(Irp);
1051     if (Stack->MajorFunction == IRP_MJ_CREATE && Status != STATUS_PENDING &&
1052         RxContext != NULL)
1053     {
1054         if (BooleanFlagOn(RxContext->Create.Flags, 2))
1055         {
1056             Stack->FileObject->FileName.Length += sizeof(WCHAR);
1057         }
1058 
1059         RxpPrepareCreateContextForReuse(RxContext);
1060         ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
1061     }
1062 
1063     /* If it's a write, validate the correct behavior of the operation */
1064     if (Stack->MajorFunction == IRP_MJ_WRITE)
1065     {
1066         if (NT_SUCCESS(Irp->IoStatus.Status))
1067         {
1068             ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
1069         }
1070     }
1071 
1072     /* If it's pending, make sure IRP is marked as such */
1073     if (RxContext != NULL)
1074     {
1075         if (RxContext->PendingReturned)
1076         {
1077             ASSERT(BooleanFlagOn(Stack->Control, SL_PENDING_RETURNED));
1078         }
1079     }
1080 
1081     /* Complete now */
1082     DPRINT("Completing IRP with %x/%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information);
1083     IoCompleteRequest(Irp, Boost);
1084 
1085     /* If there's a context, dereference it */
1086     if (RxContext != NULL)
1087     {
1088         RxDereferenceAndDeleteRxContext_Real(RxContext);
1089     }
1090 }
1091 
1092 /*
1093  * @implemented
1094  */
1095 VOID
1096 RxCompleteSrvOpenKeyAssociation(
1097     IN OUT PSRV_OPEN SrvOpen)
1098 {
1099     PSRV_CALL SrvCall;
1100 
1101     SrvCall = (PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall;
1102     /* Only handle requests if opening was a success */
1103     if (SrvOpen->Condition == Condition_Good)
1104     {
1105         KIRQL OldIrql;
1106         BOOLEAN ProcessChange;
1107         LIST_ENTRY DiscardedRequests;
1108 
1109         /* Initialize our discarded requests list */
1110         InitializeListHead(&DiscardedRequests);
1111 
1112         RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
1113 
1114         /* Transfer our requests in the SRV_CALL */
1115         RxTransferList(&SrvCall->BufferingManager.SrvOpenLists[0], &SrvOpen->SrvOpenKeyList);
1116 
1117         /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
1118         InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens);
1119 
1120         /* Dispatch requests and get the discarded ones */
1121         RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &DiscardedRequests);
1122 
1123         RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
1124 
1125         /* Is there still anything to process? */
1126         KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
1127         if (IsListEmpty(&SrvCall->BufferingManager.HandlerList))
1128         {
1129             ProcessChange = FALSE;
1130         }
1131         else
1132         {
1133             ProcessChange = (SrvCall->BufferingManager.HandlerInactive == FALSE);
1134             if (ProcessChange)
1135             {
1136                 SrvCall->BufferingManager.HandlerInactive = TRUE;
1137             }
1138         }
1139         KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
1140 
1141         /* Yes? Go ahead! */
1142         if (ProcessChange)
1143         {
1144             RxReferenceSrvCall(SrvCall);
1145             RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
1146                                  &SrvCall->BufferingManager.HandlerWorkItem,
1147                                  RxProcessChangeBufferingStateRequests, SrvCall);
1148         }
1149 
1150         /* And discard left requests */
1151         RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
1152     }
1153     else
1154     {
1155         InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens);
1156     }
1157 }
1158 
1159 /*
1160  * @implemented
1161  */
1162 NTSTATUS
1163 RxConstructNetRoot(
1164     IN PRX_CONTEXT RxContext,
1165     IN PSRV_CALL SrvCall,
1166     IN PNET_ROOT NetRoot,
1167     IN PV_NET_ROOT VirtualNetRoot,
1168     OUT PLOCK_HOLDING_STATE LockHoldingState)
1169 {
1170     NTSTATUS Status;
1171     PRX_PREFIX_TABLE PrefixTable;
1172     PMRX_CREATENETROOT_CONTEXT Context;
1173     RX_BLOCK_CONDITION RootCondition, VRootCondition;
1174 
1175     PAGED_CODE();
1176 
1177     DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext, SrvCall, NetRoot,
1178            VirtualNetRoot, LockHoldingState);
1179 
1180     /* Validate the lock is exclusively held */
1181     PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
1182     ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
1183 
1184     /* Allocate the context */
1185     Context = RxAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG);
1186     if (Context == NULL)
1187     {
1188         return STATUS_INSUFFICIENT_RESOURCES;
1189     }
1190 
1191     /* We can release lock now */
1192     RxReleasePrefixTableLock(PrefixTable);
1193     *LockHoldingState = LHS_LockNotHeld;
1194 
1195     RootCondition = Condition_Bad;
1196     VRootCondition = Condition_Bad;
1197 
1198     /* Initialize the context */
1199     RtlZeroMemory(Context, sizeof(MRX_CREATENETROOT_CONTEXT));
1200     KeInitializeEvent(&Context->FinishEvent, SynchronizationEvent, FALSE);
1201     Context->RxContext = RxContext;
1202     Context->pVNetRoot = VirtualNetRoot;
1203     Context->Callback = RxCreateNetRootCallBack;
1204 
1205     /* And call the mini-rdr */
1206     MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot, (Context));
1207     if (Status == STATUS_PENDING)
1208     {
1209         /* Wait for the mini-rdr to be done */
1210         KeWaitForSingleObject(&Context->FinishEvent, Executive, KernelMode, FALSE, NULL);
1211         /* Update the structures condition according to mini-rdr return */
1212         if (NT_SUCCESS(Context->NetRootStatus))
1213         {
1214             if (NT_SUCCESS(Context->VirtualNetRootStatus))
1215             {
1216                 RootCondition = Condition_Good;
1217                 VRootCondition = Condition_Good;
1218                 Status = STATUS_SUCCESS;
1219             }
1220             else
1221             {
1222                 RootCondition = Condition_Good;
1223                 Status = Context->VirtualNetRootStatus;
1224             }
1225         }
1226         else
1227         {
1228             Status = Context->VirtualNetRootStatus;
1229             if (NT_SUCCESS(Status))
1230             {
1231                 Status = Context->NetRootStatus;
1232             }
1233         }
1234     }
1235     else
1236     {
1237         /* It has to return STATUS_PENDING! */
1238         ASSERT(FALSE);
1239     }
1240 
1241     /* Acquire lock again - for caller lock status will remain unchanged */
1242     ASSERT(*LockHoldingState == LHS_LockNotHeld);
1243     RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
1244     *LockHoldingState = LHS_ExclusiveLockHeld;
1245 
1246     /* Do the transition to the condition got from mini-rdr */
1247     RxTransitionNetRoot(NetRoot, RootCondition);
1248     RxTransitionVNetRoot(VirtualNetRoot, VRootCondition);
1249 
1250     /* Context is not longer needed */
1251     RxFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
1252 
1253     DPRINT("Status: %x\n", Status);
1254 
1255     return Status;
1256 }
1257 
1258 /*
1259  * @implemented
1260  */
1261 NTSTATUS
1262 RxConstructSrvCall(
1263     IN PRX_CONTEXT RxContext,
1264     IN PSRV_CALL SrvCall,
1265     OUT PLOCK_HOLDING_STATE LockHoldingState)
1266 {
1267     NTSTATUS Status;
1268     PRX_PREFIX_TABLE PrefixTable;
1269     PRDBSS_DEVICE_OBJECT RxDeviceObject;
1270     PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1271     PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext;
1272 
1273     PAGED_CODE();
1274 
1275     DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext, SrvCall, LockHoldingState);
1276 
1277     /* Validate the lock is exclusively held */
1278     RxDeviceObject = RxContext->RxDeviceObject;
1279     PrefixTable = RxDeviceObject->pRxNetNameTable;
1280     ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
1281 
1282     /* Allocate the context for mini-rdr */
1283     Calldown = RxAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG);
1284     if (Calldown == NULL)
1285     {
1286         SrvCall->Context = NULL;
1287         SrvCall->Condition = Condition_Bad;
1288         RxReleasePrefixTableLock(PrefixTable);
1289         *LockHoldingState = LHS_LockNotHeld;
1290         return STATUS_INSUFFICIENT_RESOURCES;
1291     }
1292 
1293     /* Initialize it */
1294     RtlZeroMemory(Calldown, sizeof(MRX_SRVCALLDOWN_STRUCTURE));
1295 
1296     SrvCall->Context = NULL;
1297     SrvCall->Condition = Condition_InTransition;
1298 
1299     RxReleasePrefixTableLock(PrefixTable);
1300     *LockHoldingState = LHS_LockNotHeld;
1301 
1302     CallbackContext = &Calldown->CallbackContexts[0];
1303     DPRINT("CalldownContext %p for %wZ\n", CallbackContext, &RxDeviceObject->DeviceName);
1304     DPRINT("With calldown %p and SrvCall %p\n", Calldown, SrvCall);
1305     CallbackContext->SrvCalldownStructure = Calldown;
1306     CallbackContext->CallbackContextOrdinal = 0;
1307     CallbackContext->RxDeviceObject = RxDeviceObject;
1308 
1309     RxReferenceSrvCall(SrvCall);
1310 
1311     /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1312     if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1313     {
1314         RxPrePostIrp(RxContext, RxContext->CurrentIrp);
1315     }
1316     else
1317     {
1318         KeInitializeEvent(&Calldown->FinishEvent, SynchronizationEvent, FALSE);
1319     }
1320 
1321     Calldown->NumberToWait = 1;
1322     Calldown->NumberRemaining = 1;
1323     Calldown->RxContext = RxContext;
1324     Calldown->SrvCall = (PMRX_SRV_CALL)SrvCall;
1325     Calldown->CallBack = RxCreateSrvCallCallBack;
1326     Calldown->BestFinisher = NULL;
1327     CallbackContext->Status = STATUS_BAD_NETWORK_PATH;
1328     InitializeListHead(&Calldown->SrvCalldownList);
1329 
1330     /* Call the mini-rdr */
1331     ASSERT(RxDeviceObject->Dispatch != NULL);
1332     ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
1333     ASSERT(RxDeviceObject->Dispatch->MRxCreateSrvCall != NULL);
1334     Status = RxDeviceObject->Dispatch->MRxCreateSrvCall((PMRX_SRV_CALL)SrvCall, CallbackContext);
1335     /* It has to return STATUS_PENDING! */
1336     ASSERT(Status == STATUS_PENDING);
1337 
1338     /* No async, start completion */
1339     if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1340     {
1341         KeWaitForSingleObject(&Calldown->FinishEvent, Executive, KernelMode, FALSE, NULL);
1342 
1343         /* Finish construction - we'll notify mini-rdr it's the winner */
1344         Status = RxFinishSrvCallConstruction(Calldown);
1345         if (!NT_SUCCESS(Status))
1346         {
1347             RxReleasePrefixTableLock(PrefixTable);
1348             *LockHoldingState = LHS_LockNotHeld;
1349         }
1350         else
1351         {
1352             ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
1353             *LockHoldingState = LHS_ExclusiveLockHeld;
1354         }
1355     }
1356 
1357     DPRINT("RxConstructSrvCall() = Status: %x\n", Status);
1358     return Status;
1359 }
1360 
1361 /*
1362  * @implemented
1363  */
1364 NTSTATUS
1365 RxConstructVirtualNetRoot(
1366     IN PRX_CONTEXT RxContext,
1367     IN PUNICODE_STRING CanonicalName,
1368     IN NET_ROOT_TYPE NetRootType,
1369     OUT PV_NET_ROOT *VirtualNetRootPointer,
1370     OUT PLOCK_HOLDING_STATE LockHoldingState,
1371     OUT PRX_CONNECTION_ID RxConnectionId)
1372 {
1373     NTSTATUS Status;
1374     PV_NET_ROOT VNetRoot;
1375     RX_BLOCK_CONDITION Condition;
1376     UNICODE_STRING LocalNetRootName, FilePathName;
1377 
1378     PAGED_CODE();
1379 
1380     ASSERT(*LockHoldingState != LHS_LockNotHeld);
1381 
1382     VNetRoot = NULL;
1383     Condition = Condition_Bad;
1384     /* Before creating the VNetRoot, try to find the appropriate connection */
1385     Status = RxFindOrCreateConnections(RxContext, CanonicalName, NetRootType,
1386                                        &LocalNetRootName, &FilePathName,
1387                                        LockHoldingState, RxConnectionId);
1388     /* Found and active */
1389     if (Status == STATUS_CONNECTION_ACTIVE)
1390     {
1391         /* We need a new VNetRoot */
1392         VNetRoot = RxCreateVNetRoot(RxContext, (PNET_ROOT)RxContext->Create.pVNetRoot->pNetRoot,
1393                                     CanonicalName, &LocalNetRootName, &FilePathName, RxConnectionId);
1394         if (VNetRoot != NULL)
1395         {
1396             RxReferenceVNetRoot(VNetRoot);
1397         }
1398 
1399         /* Dereference previous VNetRoot */
1400         RxDereferenceVNetRoot(RxContext->Create.pVNetRoot->pNetRoot, *LockHoldingState);
1401         /* Reset and start construct (new structures will replace old ones) */
1402         RxContext->Create.pSrvCall = NULL;
1403         RxContext->Create.pNetRoot = NULL;
1404         RxContext->Create.pVNetRoot = NULL;
1405 
1406         /* Construct new NetRoot */
1407         if (VNetRoot != NULL)
1408         {
1409             Status = RxConstructNetRoot(RxContext, (PSRV_CALL)VNetRoot->pNetRoot->pSrvCall,
1410                                         (PNET_ROOT)VNetRoot->pNetRoot, VNetRoot, LockHoldingState);
1411             if (NT_SUCCESS(Status))
1412             {
1413                 Condition = Condition_Good;
1414             }
1415         }
1416         else
1417         {
1418             Status = STATUS_INSUFFICIENT_RESOURCES;
1419         }
1420     }
1421     else
1422     {
1423         /* If it failed creating the connection, leave */
1424         if (Status != STATUS_SUCCESS)
1425         {
1426             if (*LockHoldingState != LHS_LockNotHeld)
1427             {
1428                 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1429                 *LockHoldingState = LHS_LockNotHeld;
1430             }
1431 
1432             *VirtualNetRootPointer = VNetRoot;
1433             DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status);
1434             return Status;
1435         }
1436 
1437         *LockHoldingState = LHS_ExclusiveLockHeld;
1438 
1439         VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
1440         Condition = Condition_Good;
1441     }
1442 
1443     /* We have a non stable VNetRoot - transition it */
1444     if (VNetRoot != NULL && !StableCondition(VNetRoot->Condition))
1445     {
1446         RxTransitionVNetRoot(VNetRoot, Condition);
1447     }
1448 
1449     /* If recreation failed */
1450     if (Status != STATUS_SUCCESS)
1451     {
1452         /* Dereference potential VNetRoot */
1453         if (VNetRoot != NULL)
1454         {
1455             ASSERT(*LockHoldingState != LHS_LockNotHeld);
1456             RxDereferenceVNetRoot(VNetRoot, *LockHoldingState);
1457             VNetRoot = NULL;
1458         }
1459 
1460         /* Release lock */
1461         if (*LockHoldingState != LHS_LockNotHeld)
1462         {
1463             RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1464             *LockHoldingState = LHS_LockNotHeld;
1465         }
1466 
1467         /* Set NULL ptr */
1468         *VirtualNetRootPointer = VNetRoot;
1469         return Status;
1470     }
1471 
1472     /* Return the allocated VNetRoot */
1473     *VirtualNetRootPointer = VNetRoot;
1474     return Status;
1475 }
1476 
1477 /*
1478  * @implemented
1479  */
1480 PFCB
1481 RxCreateNetFcb(
1482     IN PRX_CONTEXT RxContext,
1483     IN PV_NET_ROOT VNetRoot,
1484     IN PUNICODE_STRING Name)
1485 {
1486     PFCB Fcb;
1487     BOOLEAN FakeFcb;
1488     PNET_ROOT NetRoot;
1489     POOL_TYPE PoolType;
1490     NODE_TYPE_CODE NodeType;
1491     PIO_STACK_LOCATION Stack;
1492     PRDBSS_DEVICE_OBJECT RxDeviceObject;
1493 
1494     PAGED_CODE();
1495 
1496     /* We need a decent VNetRoot */
1497     ASSERT(VNetRoot != NULL && NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
1498 
1499     NetRoot = (PNET_ROOT)VNetRoot->pNetRoot;
1500     ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
1501     ASSERT((PMRX_NET_ROOT)NetRoot == RxContext->Create.pNetRoot);
1502 
1503     RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
1504     ASSERT(RxDeviceObject == RxContext->RxDeviceObject);
1505 
1506     Stack = RxContext->CurrentIrpSp;
1507 
1508     /* Do we need to create a fake FCB? Like for renaming */
1509     FakeFcb = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY) &&
1510               !BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS);
1511     ASSERT(FakeFcb || RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
1512 
1513     PoolType = (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE) ? NonPagedPool : PagedPool);
1514     NodeType = (FakeFcb) ? RDBSS_NTC_OPENTARGETDIR_FCB : RDBSS_STORAGE_NTC(FileTypeNotYetKnown);
1515 
1516     /* Allocate the FCB */
1517     Fcb = RxAllocateFcbObject(RxDeviceObject, NodeType, PoolType,
1518                               NetRoot->InnerNamePrefix.Length + Name->Length, NULL);
1519     if (Fcb == NULL)
1520     {
1521         return NULL;
1522     }
1523 
1524     /* Initialize the FCB */
1525     Fcb->CachedNetRootType = NetRoot->Type;
1526     Fcb->RxDeviceObject = RxDeviceObject;
1527     Fcb->MRxDispatch = RxDeviceObject->Dispatch;
1528     Fcb->VNetRoot = VNetRoot;
1529     Fcb->pNetRoot = VNetRoot->pNetRoot;
1530 
1531     InitializeListHead(&Fcb->SrvOpenList);
1532     Fcb->SrvOpenListVersion = 0;
1533 
1534     Fcb->FcbTableEntry.Path.Length = Name->Length;
1535     Fcb->FcbTableEntry.Path.MaximumLength = Name->Length;
1536     Fcb->FcbTableEntry.Path.Buffer = Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Length);
1537     RtlMoveMemory(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Buffer,
1538                   NetRoot->InnerNamePrefix.Length);
1539     RtlMoveMemory(Fcb->FcbTableEntry.Path.Buffer, Name->Buffer, Name->Length);
1540 
1541     /* Copy back parameters from RxContext */
1542     if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH))
1543     {
1544         Fcb->FcbState |= FCB_STATE_ADDEDBACKSLASH;
1545     }
1546 
1547     InitializeListHead(&Fcb->NonPaged->TransitionWaitList);
1548 
1549     if (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE))
1550     {
1551         Fcb->FcbState |= FCB_STATE_PAGING_FILE;
1552     }
1553 
1554     if (RxContext->MajorFunction == IRP_MJ_CREATE && BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH))
1555     {
1556         Fcb->FcbState |= FCB_STATE_SPECIAL_PATH;
1557     }
1558 
1559     Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource;
1560     ExInitializeResourceLite(Fcb->Header.Resource);
1561 
1562     Fcb->Header.PagingIoResource = &Fcb->NonPaged->PagingIoResource;
1563     ExInitializeResourceLite(Fcb->Header.PagingIoResource);
1564 
1565     Fcb->BufferedLocks.Resource = &Fcb->NonPaged->BufferedLocksResource;
1566     ExInitializeResourceLite(Fcb->BufferedLocks.Resource);
1567 
1568     /* Fake FCB doesn't go in prefix table */
1569     if (FakeFcb)
1570     {
1571         Fcb->FcbState |= (FCB_STATE_FAKEFCB | FCB_STATE_NAME_ALREADY_REMOVED);
1572         InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
1573         DPRINT("Fake FCB: %p\n", Fcb);
1574     }
1575     else
1576     {
1577         RxFcbTableInsertFcb(&NetRoot->FcbTable, Fcb);
1578     }
1579 
1580     RxReferenceVNetRoot(VNetRoot);
1581     InterlockedIncrement((volatile long *)&Fcb->pNetRoot->NumberOfFcbs);
1582 
1583     Fcb->ulFileSizeVersion = 0;
1584 
1585     DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path);
1586     RxReferenceNetFcb(Fcb);
1587 
1588     return Fcb;
1589 }
1590 
1591 /*
1592  * @implemented
1593  */
1594 PMRX_FOBX
1595 NTAPI
1596 RxCreateNetFobx(
1597     OUT PRX_CONTEXT RxContext,
1598     IN PMRX_SRV_OPEN MrxSrvOpen)
1599 {
1600     PFCB Fcb;
1601     PFOBX Fobx;
1602     ULONG Flags;
1603     PNET_ROOT NetRoot;
1604     PSRV_OPEN SrvOpen;
1605     POOL_TYPE PoolType;
1606 
1607     PAGED_CODE();
1608 
1609     SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1610     ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
1611     ASSERT(NodeTypeIsFcb(SrvOpen->Fcb));
1612     ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
1613 
1614     Fcb = SrvOpen->Fcb;
1615     PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1616     /* Can we use pre-allocated FOBX? */
1617     if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FOBX_USED) && Fcb->InternalSrvOpen == (PSRV_OPEN)MrxSrvOpen)
1618     {
1619         Fobx = Fcb->InternalFobx;
1620         /* Call allocate to initialize the FOBX */
1621         RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1622         /* Mark it used now */
1623         Fcb->FcbState |= FCB_STATE_FOBX_USED;
1624         Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1625     }
1626     else if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED))
1627     {
1628         Fobx = SrvOpen->InternalFobx;
1629         /* Call allocate to initialize the FOBX */
1630         RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1631         /* Mark it used now */
1632         SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
1633         Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1634     }
1635     else
1636     {
1637         /* Last case, we cannot, allocate a FOBX */
1638         Fobx = RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, NULL);
1639         Flags = 0;
1640     }
1641 
1642     /* Allocation failed! */
1643     if (Fobx == NULL)
1644     {
1645         return NULL;
1646     }
1647 
1648     /* Set flags */
1649     Fobx->Flags = Flags;
1650 
1651     /* Initialize throttling */
1652     NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
1653     if (NetRoot != NULL)
1654     {
1655         if (NetRoot->DeviceType == FILE_DEVICE_DISK)
1656         {
1657             RxInitializeThrottlingState(&Fobx->Specific.DiskFile.LockThrottlingState,
1658                                         NetRoot->DiskParameters.LockThrottlingParameters.Increment,
1659                                         NetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay);
1660         }
1661         else if (NetRoot->DeviceType == FILE_DEVICE_NAMED_PIPE)
1662         {
1663             RxInitializeThrottlingState(&Fobx->Specific.NamedPipe.ThrottlingState,
1664                                         NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.Increment,
1665                                         NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.MaximumDelay);
1666         }
1667     }
1668 
1669     /* Propagate flags fron RxContext */
1670     if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME))
1671     {
1672         Fobx->Flags |= FOBX_FLAG_UNC_NAME;
1673     }
1674 
1675     if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
1676     {
1677         Fobx->Flags |= FOBX_FLAG_BACKUP_INTENT;
1678     }
1679 
1680     /* Continue init */
1681     Fobx->FobxSerialNumber = 0;
1682     Fobx->SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1683     Fobx->NodeReferenceCount = 1;
1684     Fobx->RxDeviceObject = Fcb->RxDeviceObject;
1685 
1686     RxReferenceSrvOpen(SrvOpen);
1687     InterlockedIncrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
1688 
1689     InsertTailList(&SrvOpen->FobxList, &Fobx->FobxQLinks);
1690     InitializeListHead(&Fobx->ScavengerFinalizationList);
1691     InitializeListHead(&Fobx->ClosePendingList);
1692 
1693     Fobx->CloseTime.QuadPart = 0;
1694     Fobx->fOpenCountDecremented = FALSE;
1695 
1696     DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx, Fobx->SrvOpen, Fobx->SrvOpen->pFcb);
1697 
1698     return (PMRX_FOBX)Fobx;
1699 }
1700 
1701 /*
1702  * @implemented
1703  */
1704 PNET_ROOT
1705 RxCreateNetRoot(
1706     IN PSRV_CALL SrvCall,
1707     IN PUNICODE_STRING Name,
1708     IN ULONG NetRootFlags,
1709     IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
1710 {
1711     PNET_ROOT NetRoot;
1712     USHORT CaseInsensitiveLength;
1713     PRX_PREFIX_TABLE PrefixTable;
1714 
1715     DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall, Name, NetRootFlags, RxConnectionId);
1716 
1717     PAGED_CODE();
1718 
1719     /* We need a SRV_CALL */
1720     ASSERT(SrvCall != NULL);
1721 
1722     PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
1723     ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
1724 
1725     /* Get name length */
1726     CaseInsensitiveLength = SrvCall->PrefixEntry.Prefix.Length + Name->Length;
1727     if (CaseInsensitiveLength > MAXUSHORT)
1728     {
1729         return NULL;
1730     }
1731 
1732     /* Allocate the NetRoot */
1733     NetRoot = RxAllocateObject(RDBSS_NTC_NETROOT, SrvCall->RxDeviceObject->Dispatch,
1734                                CaseInsensitiveLength);
1735     if (NetRoot == NULL)
1736     {
1737         return NULL;
1738     }
1739 
1740     /* Construct name */
1741     RtlMoveMemory(Add2Ptr(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Length),
1742                   Name->Buffer, Name->Length);
1743     if (SrvCall->PrefixEntry.Prefix.Length != 0)
1744     {
1745         RtlMoveMemory(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Buffer,
1746                       SrvCall->PrefixEntry.Prefix.Length);
1747     }
1748 
1749     if (!BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
1750     {
1751         CaseInsensitiveLength = SrvCall->PrefixEntry.CaseInsensitiveLength;
1752     }
1753     /* Inisert in prefix table */
1754     RxPrefixTableInsertName(PrefixTable, &NetRoot->PrefixEntry, NetRoot,
1755                             (PULONG)&NetRoot->NodeReferenceCount, CaseInsensitiveLength,
1756                             RxConnectionId);
1757 
1758     /* Prepare the FCB table */
1759     RxInitializeFcbTable(&NetRoot->FcbTable, TRUE);
1760 
1761     InitializeListHead(&NetRoot->TransitionWaitList);
1762     InitializeListHead(&NetRoot->ScavengerFinalizationList);
1763     InitializeListHead(&NetRoot->VirtualNetRoots);
1764 
1765     RxInitializePurgeSyncronizationContext(&NetRoot->PurgeSyncronizationContext);
1766 
1767     NetRoot->SerialNumberForEnum = SerialNumber++;
1768     NetRoot->Flags |= NetRootFlags;
1769     NetRoot->DiskParameters.ClusterSize = 1;
1770     NetRoot->DiskParameters.ReadAheadGranularity = ReadAheadGranularity;
1771     NetRoot->SrvCall = SrvCall;
1772 
1773     RxReferenceSrvCall(SrvCall);
1774 
1775     DPRINT("NetRootName: %wZ (%p)\n", NetRoot->pNetRootName, NetRoot);
1776     return NetRoot;
1777 }
1778 
1779 /*
1780  * @implemented
1781  */
1782 VOID
1783 NTAPI
1784 RxCreateNetRootCallBack(
1785     IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext)
1786 {
1787     PAGED_CODE();
1788 
1789     KeSetEvent(&CreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1790 }
1791 
1792 /*
1793  * @implemented
1794  */
1795 PRX_CONTEXT
1796 NTAPI
1797 RxCreateRxContext(
1798     IN PIRP Irp,
1799     IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
1800     IN ULONG InitialContextFlags)
1801 {
1802     KIRQL OldIrql;
1803     PRX_CONTEXT Context;
1804 
1805     ASSERT(RxDeviceObject != NULL);
1806 
1807     DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp, RxDeviceObject, InitialContextFlags);
1808 
1809 #if DBG
1810     InterlockedIncrement((volatile LONG *)&RxFsdEntryCount);
1811 #endif
1812     InterlockedIncrement((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts);
1813 
1814     /* Allocate the context from our lookaside list */
1815     Context = ExAllocateFromNPagedLookasideList(&RxContextLookasideList);
1816     if (Context == NULL)
1817     {
1818         return NULL;
1819     }
1820 
1821     /* Zero it */
1822     RtlZeroMemory(Context, sizeof(RX_CONTEXT));
1823 
1824     /* It was allocated on NP pool, keep track of it! */
1825     SetFlag(Context->Flags, RX_CONTEXT_FLAG_FROM_POOL);
1826     /* And initialize it */
1827     RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
1828     ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED));
1829 
1830     /* Add it to our global list */
1831     KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1832     InsertTailList(&RxActiveContexts, &Context->ContextListEntry);
1833     KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1834 
1835     DPRINT("Context: %p\n", Context);
1836     return Context;
1837 }
1838 
1839 /*
1840  * @implemented
1841  */
1842 PSRV_CALL
1843 RxCreateSrvCall(
1844     IN PRX_CONTEXT RxContext,
1845     IN PUNICODE_STRING Name,
1846     IN PUNICODE_STRING InnerNamePrefix OPTIONAL,
1847     IN PRX_CONNECTION_ID RxConnectionId)
1848 {
1849     ULONG NameLength;
1850     PSRV_CALL SrvCall;
1851 
1852     PAGED_CODE();
1853 
1854     DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext, Name, InnerNamePrefix, RxConnectionId);
1855 
1856     ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
1857 
1858     /* Get the name length */
1859     NameLength = Name->Length + 2 * sizeof(WCHAR);
1860     if (InnerNamePrefix != NULL)
1861     {
1862         NameLength += InnerNamePrefix->Length;
1863     }
1864 
1865     /* Allocate the object */
1866     SrvCall = RxAllocateObject(RDBSS_NTC_SRVCALL, NULL, NameLength);
1867     if (SrvCall == NULL)
1868     {
1869         return NULL;
1870     }
1871 
1872     /* Initialize it */
1873     SrvCall->SerialNumberForEnum = SerialNumber++;
1874     SrvCall->RxDeviceObject = RxContext->RxDeviceObject;
1875     RxInitializeBufferingManager(SrvCall);
1876     InitializeListHead(&SrvCall->TransitionWaitList);
1877     InitializeListHead(&SrvCall->ScavengerFinalizationList);
1878     RxInitializePurgeSyncronizationContext(&SrvCall->PurgeSyncronizationContext);
1879     RxInitializeSrvCallParameters(RxContext, SrvCall);
1880     RtlMoveMemory(SrvCall->PrefixEntry.Prefix.Buffer, Name->Buffer, Name->Length);
1881     SrvCall->PrefixEntry.Prefix.MaximumLength = Name->Length + 2 * sizeof(WCHAR);
1882     SrvCall->PrefixEntry.Prefix.Length = Name->Length;
1883     RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &SrvCall->PrefixEntry,
1884                             SrvCall, (PULONG)&SrvCall->NodeReferenceCount, Name->Length, RxConnectionId);
1885 
1886     DPRINT("SrvCallName: %wZ (%p)\n", SrvCall->pSrvCallName, SrvCall);
1887     return SrvCall;
1888 }
1889 
1890 /*
1891  * @implemented
1892  */
1893 VOID
1894 NTAPI
1895 RxCreateSrvCallCallBack(
1896     IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context)
1897 {
1898     KIRQL OldIrql;
1899     PSRV_CALL SrvCall;
1900     PRX_CONTEXT RxContext;
1901     ULONG NumberRemaining;
1902     BOOLEAN StartDispatcher;
1903     PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1904 
1905     DPRINT("RxCreateSrvCallCallBack(%p)\n", Context);
1906 
1907     /* Get our context structures */
1908     Calldown = Context->SrvCalldownStructure;
1909     SrvCall = (PSRV_CALL)Calldown->SrvCall;
1910 
1911     /* If it is a success, that's the winner */
1912     KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1913     if (Context->Status == STATUS_SUCCESS)
1914     {
1915         Calldown->BestFinisherOrdinal = Context->CallbackContextOrdinal;
1916         Calldown->BestFinisher = Context->RxDeviceObject;
1917     }
1918     NumberRemaining = --Calldown->NumberRemaining;
1919     SrvCall->Status = Context->Status;
1920     KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1921 
1922     /* Still some to ask, keep going */
1923     if (NumberRemaining != 0)
1924     {
1925         return;
1926     }
1927 
1928     /* If that's not async, signal we're done */
1929     RxContext = Calldown->RxContext;
1930     if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1931     {
1932         KeSetEvent(&Calldown->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1933         return;
1934     }
1935     /* If that's a mailslot, finish construction, no more to do */
1936     else if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
1937     {
1938         RxFinishSrvCallConstruction(Calldown);
1939         return;
1940     }
1941 
1942     /* Queue our finish call for delayed completion */
1943     DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1944     KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1945     InsertTailList(&RxSrvCalldownList, &Calldown->SrvCalldownList);
1946     StartDispatcher = !RxSrvCallConstructionDispatcherActive;
1947     KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1948 
1949     /* If we have to start dispatcher, go ahead */
1950     if (StartDispatcher)
1951     {
1952         NTSTATUS Status;
1953 
1954         Status = RxDispatchToWorkerThread(RxFileSystemDeviceObject, CriticalWorkQueue,
1955                                           RxFinishSrvCallConstructionDispatcher, &RxSrvCalldownList);
1956         if (!NT_SUCCESS(Status))
1957         {
1958             /* It failed - run it manually.... */
1959             RxFinishSrvCallConstructionDispatcher(NULL);
1960         }
1961     }
1962 }
1963 
1964 /*
1965  * @implemented
1966  */
1967 PSRV_OPEN
1968 RxCreateSrvOpen(
1969     IN PV_NET_ROOT VNetRoot,
1970     IN OUT PFCB Fcb)
1971 {
1972     ULONG Flags;
1973     PSRV_OPEN SrvOpen;
1974     POOL_TYPE PoolType;
1975 
1976     PAGED_CODE();
1977 
1978     ASSERT(NodeTypeIsFcb(Fcb));
1979     ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1980 
1981     PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1982 
1983     _SEH2_TRY
1984     {
1985         SrvOpen = Fcb->InternalSrvOpen;
1986         /* Check whethet we have to allocate a new SRV_OPEN */
1987         if (Fcb->InternalSrvOpen == NULL || BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED) ||
1988             BooleanFlagOn(Fcb->InternalSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED) ||
1989             !IsListEmpty(&Fcb->InternalSrvOpen->SrvOpenQLinks))
1990         {
1991             /* Proceed */
1992             SrvOpen = RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1993                                           RDBSS_NTC_SRVOPEN, PoolType, 0, NULL);
1994             Flags = 0;
1995         }
1996         else
1997         {
1998             /* Otherwise, just use internal one and initialize it */
1999             RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
2000                                 RDBSS_NTC_INTERNAL_SRVOPEN, PoolType, 0,
2001                                 Fcb->InternalSrvOpen);
2002             Fcb->FcbState |= FCB_STATE_SRVOPEN_USED;
2003             Flags = SRVOPEN_FLAG_ENCLOSED_ALLOCATED | SRVOPEN_FLAG_FOBX_USED;
2004         }
2005 
2006         /* If SrvOpen was properly allocated, initialize it */
2007         if (SrvOpen != NULL)
2008         {
2009             SrvOpen->Flags = Flags;
2010             SrvOpen->pFcb = RX_GET_MRX_FCB(Fcb);
2011             SrvOpen->pAlreadyPrefixedName = &Fcb->PrivateAlreadyPrefixedName;
2012             SrvOpen->pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
2013             SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
2014             SrvOpen->NodeReferenceCount = 1;
2015 
2016             RxReferenceVNetRoot(VNetRoot);
2017             RxReferenceNetFcb(Fcb);
2018 
2019             InsertTailList(&Fcb->SrvOpenList, &SrvOpen->SrvOpenQLinks);
2020             ++Fcb->SrvOpenListVersion;
2021 
2022             InitializeListHead(&SrvOpen->ScavengerFinalizationList);
2023             InitializeListHead(&SrvOpen->TransitionWaitList);
2024             InitializeListHead(&SrvOpen->FobxList);
2025             InitializeListHead(&SrvOpen->SrvOpenKeyList);
2026         }
2027     }
2028     _SEH2_FINALLY
2029     {
2030         if (_SEH2_AbnormalTermination())
2031         {
2032             if (SrvOpen != NULL)
2033             {
2034                 RxFinalizeSrvOpen(SrvOpen, TRUE, TRUE);
2035                 SrvOpen = NULL;
2036             }
2037         }
2038         else
2039         {
2040             DPRINT("SrvOpen %p for FCB %p\n", SrvOpen, SrvOpen->pFcb);
2041         }
2042     }
2043     _SEH2_END;
2044 
2045     return SrvOpen;
2046 }
2047 
2048 /*
2049  * @implemented
2050  */
2051 PV_NET_ROOT
2052 RxCreateVNetRoot(
2053     IN PRX_CONTEXT RxContext,
2054     IN PNET_ROOT NetRoot,
2055     IN PUNICODE_STRING CanonicalName,
2056     IN PUNICODE_STRING LocalNetRootName,
2057     IN PUNICODE_STRING FilePath,
2058     IN PRX_CONNECTION_ID RxConnectionId)
2059 {
2060     NTSTATUS Status;
2061     PV_NET_ROOT VNetRoot;
2062     USHORT CaseInsensitiveLength;
2063 
2064     PAGED_CODE();
2065 
2066     DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext, NetRoot, CanonicalName,
2067            LocalNetRootName, FilePath, RxConnectionId);
2068 
2069     /* Lock must be held exclusively */
2070     ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
2071 
2072     /* Check for overflow */
2073     if (LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length > MAXUSHORT)
2074     {
2075         return NULL;
2076     }
2077 
2078     /* Get name length and allocate VNetRoot */
2079     CaseInsensitiveLength = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
2080     VNetRoot = RxAllocateObject(RDBSS_NTC_V_NETROOT, NetRoot->SrvCall->RxDeviceObject->Dispatch,
2081                                 CaseInsensitiveLength);
2082     if (VNetRoot == NULL)
2083     {
2084         return NULL;
2085     }
2086 
2087     /* Initialize its connection parameters */
2088     Status = RxInitializeVNetRootParameters(RxContext, &VNetRoot->LogonId, &VNetRoot->SessionId,
2089                                             &VNetRoot->pUserName, &VNetRoot->pUserDomainName,
2090                                             &VNetRoot->pPassword, &VNetRoot->Flags);
2091     if (!NT_SUCCESS(Status))
2092     {
2093         RxUninitializeVNetRootParameters(VNetRoot->pUserName, VNetRoot->pUserDomainName,
2094                                          VNetRoot->pPassword, &VNetRoot->Flags);
2095         RxFreeObject(VNetRoot);
2096 
2097         return NULL;
2098     }
2099 
2100     /* Set name */
2101     RtlMoveMemory(VNetRoot->PrefixEntry.Prefix.Buffer, CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
2102 
2103     VNetRoot->PrefixOffsetInBytes = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
2104     VNetRoot->NamePrefix.Buffer = Add2Ptr(VNetRoot->PrefixEntry.Prefix.Buffer, VNetRoot->PrefixOffsetInBytes);
2105     VNetRoot->NamePrefix.Length = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
2106     VNetRoot->NamePrefix.MaximumLength = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
2107 
2108     InitializeListHead(&VNetRoot->TransitionWaitList);
2109     InitializeListHead(&VNetRoot->ScavengerFinalizationList);
2110 
2111     if (!BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES))
2112     {
2113         USHORT i;
2114 
2115         if (BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
2116         {
2117             CaseInsensitiveLength = NetRoot->PrefixEntry.CaseInsensitiveLength;
2118         }
2119         else
2120         {
2121             CaseInsensitiveLength = NetRoot->SrvCall->PrefixEntry.CaseInsensitiveLength;
2122         }
2123 
2124         for (i = 1; i < CanonicalName->Length / sizeof(WCHAR); ++i)
2125         {
2126             if (CanonicalName->Buffer[i] != OBJ_NAME_PATH_SEPARATOR)
2127             {
2128                 break;
2129             }
2130         }
2131 
2132         CaseInsensitiveLength += (i * sizeof(WCHAR));
2133     }
2134 
2135     /* Insert in prefix table */
2136     RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &VNetRoot->PrefixEntry,
2137                             VNetRoot, (PULONG)&VNetRoot->NodeReferenceCount, CaseInsensitiveLength,
2138                             RxConnectionId);
2139 
2140     RxReferenceNetRoot(NetRoot);
2141     RxAddVirtualNetRootToNetRoot(NetRoot, VNetRoot);
2142 
2143     /* Finish init */
2144     VNetRoot->SerialNumberForEnum = SerialNumber++;
2145     VNetRoot->UpperFinalizationDone = FALSE;
2146     VNetRoot->ConnectionFinalizationDone = FALSE;
2147     VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
2148 
2149     DPRINT("NamePrefix: %wZ\n", &VNetRoot->NamePrefix);
2150     DPRINT("PrefixEntry: %wZ\n", &VNetRoot->PrefixEntry.Prefix);
2151 
2152     return VNetRoot;
2153 }
2154 
2155 /*
2156  * @implemented
2157  */
2158 VOID
2159 RxDereference(
2160     IN OUT PVOID Instance,
2161     IN LOCK_HOLDING_STATE LockHoldingState)
2162 {
2163     LONG RefCount;
2164     NODE_TYPE_CODE NodeType;
2165     PNODE_TYPE_AND_SIZE Node;
2166 
2167     PAGED_CODE();
2168 
2169     RxAcquireScavengerMutex();
2170 
2171     /* Check we have a node we can handle */
2172     NodeType = NodeType(Instance);
2173     ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
2174            (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
2175            (NodeType == RDBSS_NTC_FOBX));
2176 
2177     Node = (PNODE_TYPE_AND_SIZE)Instance;
2178     RefCount = InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
2179     ASSERT(RefCount >= 0);
2180 
2181     /* Trace refcount */
2182     switch (NodeType)
2183     {
2184         case RDBSS_NTC_SRVCALL:
2185             PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
2186             break;
2187 
2188         case RDBSS_NTC_NETROOT:
2189             PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
2190             break;
2191 
2192         case RDBSS_NTC_V_NETROOT:
2193             PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
2194             break;
2195 
2196         case RDBSS_NTC_SRVOPEN:
2197             PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
2198             break;
2199 
2200         case RDBSS_NTC_FOBX:
2201             PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
2202             break;
2203 
2204         default:
2205             ASSERT(FALSE);
2206             break;
2207     }
2208 
2209     /* No need to free - still in use */
2210     if (RefCount > 1)
2211     {
2212         RxReleaseScavengerMutex();
2213         return;
2214     }
2215 
2216     /* We have to be locked exclusively */
2217     if (LockHoldingState != LHS_ExclusiveLockHeld)
2218     {
2219         if ((NodeType == RDBSS_NTC_FOBX && RefCount == 0) ||
2220              (NodeType >= RDBSS_NTC_SRVCALL && NodeType <= RDBSS_NTC_V_NETROOT))
2221         {
2222             RxpMarkInstanceForScavengedFinalization(Instance);
2223         }
2224 
2225         RxReleaseScavengerMutex();
2226         return;
2227     }
2228     else
2229     {
2230         if (BooleanFlagOn(NodeType, RX_SCAVENGER_MASK))
2231         {
2232             RxpUndoScavengerFinalizationMarking(Instance);
2233         }
2234     }
2235 
2236     RxReleaseScavengerMutex();
2237 
2238     /* Now, deallocate the memory */
2239     switch (NodeType)
2240     {
2241         case RDBSS_NTC_SRVCALL:
2242         {
2243             PSRV_CALL SrvCall;
2244 
2245             SrvCall = (PSRV_CALL)Instance;
2246 
2247             ASSERT(SrvCall->RxDeviceObject != NULL);
2248             ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable));
2249             RxFinalizeSrvCall(SrvCall, TRUE, TRUE);
2250             break;
2251         }
2252 
2253         case RDBSS_NTC_NETROOT:
2254         {
2255             PNET_ROOT NetRoot;
2256 
2257             NetRoot = (PNET_ROOT)Instance;
2258 
2259             ASSERT(NetRoot->pSrvCall->RxDeviceObject != NULL);
2260             ASSERT(RxIsPrefixTableLockAcquired(NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
2261             RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
2262             break;
2263         }
2264 
2265         case RDBSS_NTC_V_NETROOT:
2266         {
2267             PV_NET_ROOT VNetRoot;
2268 
2269             VNetRoot = (PV_NET_ROOT)Instance;
2270 
2271             ASSERT(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject != NULL);
2272             ASSERT(RxIsPrefixTableLockAcquired(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
2273             RxFinalizeVNetRoot(VNetRoot, TRUE, TRUE);
2274             break;
2275         }
2276 
2277         case RDBSS_NTC_SRVOPEN:
2278         {
2279             PSRV_OPEN SrvOpen;
2280 
2281             SrvOpen = (PSRV_OPEN)Instance;
2282 
2283             ASSERT(RxIsFcbAcquired(SrvOpen->Fcb));
2284             if (SrvOpen->OpenCount == 0)
2285             {
2286                 RxFinalizeSrvOpen(SrvOpen, FALSE, FALSE);
2287             }
2288             break;
2289         }
2290 
2291         case RDBSS_NTC_FOBX:
2292         {
2293             PFOBX Fobx;
2294 
2295             Fobx = (PFOBX)Instance;
2296 
2297             ASSERT(RxIsFcbAcquired(Fobx->SrvOpen->Fcb));
2298             RxFinalizeNetFobx(Fobx, TRUE, FALSE);
2299             break;
2300         }
2301     }
2302 }
2303 
2304 /*
2305  * @implemented
2306  */
2307 VOID
2308 NTAPI
2309 RxDereferenceAndDeleteRxContext_Real(
2310     IN PRX_CONTEXT RxContext)
2311 {
2312     KIRQL OldIrql;
2313     ULONG RefCount;
2314     BOOLEAN Allocated;
2315     PRX_CONTEXT StopContext = NULL;
2316 
2317     /* Make sure we really have a context */
2318     KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
2319     ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT);
2320     RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount);
2321     /* If refcount is 0, start releasing stuff that needs spinlock held */
2322     if (RefCount == 0)
2323     {
2324         PRDBSS_DEVICE_OBJECT RxDeviceObject;
2325 
2326         Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
2327 
2328         /* If that's stop context from DO, remove it */
2329         RxDeviceObject = RxContext->RxDeviceObject;
2330         if (RxDeviceObject->StartStopContext.pStopContext == RxContext)
2331         {
2332             RxDeviceObject->StartStopContext.pStopContext = NULL;
2333         }
2334         else
2335         {
2336            /* Remove it from the list */
2337             ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
2338                    (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
2339             RemoveEntryList(&RxContext->ContextListEntry);
2340 
2341             /* If that was the last active context, save the stop context */
2342             if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0)
2343             {
2344                 if (RxDeviceObject->StartStopContext.pStopContext != NULL)
2345                 {
2346                     StopContext = RxDeviceObject->StartStopContext.pStopContext;
2347                 }
2348             }
2349         }
2350     }
2351     KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
2352 
2353     /* Now, deal with what can be done without spinlock held */
2354     if (RefCount == 0)
2355     {
2356         /* Refcount shouldn't have changed */
2357         ASSERT(RxContext->ReferenceCount == 0);
2358         /* Reset everything that can be */
2359         RxPrepareContextForReuse(RxContext);
2360 
2361 #ifdef RDBSS_TRACKER
2362         ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
2363 #endif
2364         /* If that was the last active, set the event */
2365         if (StopContext != NULL)
2366         {
2367             StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL;
2368             KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE);
2369         }
2370 
2371 #if DBG
2372         /* Is ShadowCrit still owned? Shouldn't happen! */
2373         if (RxContext->ShadowCritOwner != 0)
2374         {
2375             DPRINT1("ShadowCritOwner not null! %lx\n", RxContext->ShadowCritOwner);
2376             ASSERT(FALSE);
2377         }
2378 #endif
2379 
2380         /* If it was allocated, free it */
2381         if (Allocated)
2382         {
2383             ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext);
2384         }
2385     }
2386 }
2387 
2388 VOID
2389 NTAPI
2390 RxDispatchChangeBufferingStateRequests(
2391     PVOID Context)
2392 {
2393     UNIMPLEMENTED;
2394 }
2395 
2396 /*
2397  * @implemented
2398  */
2399 NTSTATUS
2400 NTAPI
2401 RxDispatchToWorkerThread(
2402     IN  PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
2403     IN  WORK_QUEUE_TYPE WorkQueueType,
2404     IN  PRX_WORKERTHREAD_ROUTINE Routine,
2405     IN PVOID pContext)
2406 {
2407     NTSTATUS Status;
2408     PRX_WORK_DISPATCH_ITEM DispatchItem;
2409 
2410     /* Allocate a bit of context */
2411     DispatchItem = RxAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
2412     if (DispatchItem == NULL)
2413     {
2414         return STATUS_INSUFFICIENT_RESOURCES;
2415     }
2416 
2417     /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2418     DispatchItem->DispatchRoutine = Routine;
2419     DispatchItem->DispatchRoutineParameter = pContext;
2420     DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher;
2421     DispatchItem->WorkQueueItem.Parameter = DispatchItem;
2422 
2423     /* Insert item */
2424     Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, &DispatchItem->WorkQueueItem);
2425     if (!NT_SUCCESS(Status))
2426     {
2427         RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
2428         DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
2429     }
2430 
2431     DPRINT("Dispatching: %p, %p\n", Routine, pContext);
2432 
2433     return Status;
2434 }
2435 
2436 /*
2437  * @implemented
2438  */
2439 VOID
2440 RxExclusivePrefixTableLockToShared(
2441     PRX_PREFIX_TABLE Table)
2442 {
2443     PAGED_CODE();
2444 
2445     ExConvertExclusiveToSharedLite(&Table->TableLock);
2446 }
2447 
2448 /*
2449  * @implemented
2450  */
2451 VOID
2452 RxExtractServerName(
2453     IN PUNICODE_STRING FilePathName,
2454     OUT PUNICODE_STRING SrvCallName,
2455     OUT PUNICODE_STRING RestOfName)
2456 {
2457     USHORT i, Length;
2458 
2459     PAGED_CODE();
2460 
2461     ASSERT(SrvCallName != NULL);
2462 
2463     /* SrvCall name will start from the begin up to the first separator */
2464     SrvCallName->Buffer = FilePathName->Buffer;
2465     for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i)
2466     {
2467         if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
2468         {
2469             break;
2470         }
2471     }
2472 
2473     /* Compute length */
2474     Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer);
2475     SrvCallName->MaximumLength = Length;
2476     SrvCallName->Length = Length;
2477 
2478     /* Return the rest if asked */
2479     if (RestOfName != NULL)
2480     {
2481         Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]);
2482         RestOfName->Buffer = &FilePathName->Buffer[i];
2483         RestOfName->MaximumLength = Length;
2484         RestOfName->Length = Length;
2485     }
2486 }
2487 
2488 /*
2489  * @implemented
2490  */
2491 NTSTATUS
2492 RxFcbTableInsertFcb(
2493     IN OUT PRX_FCB_TABLE FcbTable,
2494     IN OUT PFCB Fcb)
2495 {
2496     PAGED_CODE();
2497 
2498     /* We deal with the table, make sure it's locked */
2499     ASSERT(RxIsFcbTableLockExclusive(FcbTable));
2500 
2501     /* Compute the hash */
2502     Fcb->FcbTableEntry.HashValue = RxTableComputePathHashValue(&Fcb->FcbTableEntry.Path);
2503 
2504     RxReferenceNetFcb(Fcb);
2505 
2506     /* If no length, it will be our null entry */
2507     if (Fcb->FcbTableEntry.Path.Length == 0)
2508     {
2509         FcbTable->TableEntryForNull = &Fcb->FcbTableEntry;
2510     }
2511     /* Otherwise, insert in the appropriate bucket */
2512     else
2513     {
2514         InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue),
2515                        &Fcb->FcbTableEntry.HashLinks);
2516     }
2517 
2518     /* Propagate the change by incrementing the version number */
2519     InterlockedIncrement((volatile long *)&FcbTable->Version);
2520 
2521     return STATUS_SUCCESS;
2522 }
2523 
2524 /*
2525  * @implemented
2526  */
2527 PFCB
2528 RxFcbTableLookupFcb(
2529     IN  PRX_FCB_TABLE FcbTable,
2530     IN  PUNICODE_STRING Path)
2531 {
2532     PFCB Fcb;
2533     PRX_FCB_TABLE_ENTRY TableEntry;
2534 
2535     PAGED_CODE();
2536 
2537     /* No path - easy, that's null entry */
2538     if (Path == NULL)
2539     {
2540         TableEntry = FcbTable->TableEntryForNull;
2541     }
2542     else
2543     {
2544         ULONG Hash;
2545         PLIST_ENTRY HashBucket, ListEntry;
2546 
2547         /* Otherwise, compute the hash value and find the associated bucket */
2548         Hash = RxTableComputePathHashValue(Path);
2549         HashBucket = FCB_HASH_BUCKET(FcbTable, Hash);
2550         /* If the bucket is empty, it means there's no entry yet */
2551         if (IsListEmpty(HashBucket))
2552         {
2553             TableEntry = NULL;
2554         }
2555         else
2556         {
2557             /* Otherwise, browse all the entry */
2558             for (ListEntry = HashBucket->Flink;
2559                  ListEntry != HashBucket;
2560                  ListEntry = ListEntry->Flink)
2561             {
2562                 TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks);
2563                 InterlockedIncrement(&FcbTable->Compares);
2564 
2565                 /* If entry hash and string are equal, thatt's the one! */
2566                 if (TableEntry->HashValue == Hash &&
2567                     TableEntry->Path.Length == Path->Length &&
2568                     RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch))
2569                 {
2570                     break;
2571                 }
2572             }
2573 
2574             /* We reached the end? Not found */
2575             if (ListEntry == HashBucket)
2576             {
2577                 TableEntry = NULL;
2578             }
2579         }
2580     }
2581 
2582     InterlockedIncrement(&FcbTable->Lookups);
2583 
2584     /* If table entry isn't null, return the FCB */
2585     if (TableEntry != NULL)
2586     {
2587         Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry);
2588         RxReferenceNetFcb(Fcb);
2589     }
2590     else
2591     {
2592         Fcb = NULL;
2593         InterlockedIncrement(&FcbTable->FailedLookups);
2594     }
2595 
2596     return Fcb;
2597 }
2598 
2599 /*
2600  * @implemented
2601  */
2602 NTSTATUS
2603 RxFcbTableRemoveFcb(
2604     IN OUT PRX_FCB_TABLE FcbTable,
2605     IN OUT PFCB Fcb)
2606 {
2607     PAGED_CODE();
2608 
2609     ASSERT(RxIsPrefixTableLockExclusive(FcbTable));
2610 
2611     /* If no path, then remove entry for null */
2612     if (Fcb->FcbTableEntry.Path.Length == 0)
2613     {
2614         FcbTable->TableEntryForNull = NULL;
2615     }
2616     /* Otherwise, remove from the bucket */
2617     else
2618     {
2619         RemoveEntryList(&Fcb->FcbTableEntry.HashLinks);
2620     }
2621 
2622     /* Reset its list entry */
2623     InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
2624 
2625     /* Propagate the change by incrementing the version number */
2626     InterlockedIncrement((volatile long *)&FcbTable->Version);
2627 
2628     return STATUS_SUCCESS;
2629 }
2630 
2631 /*
2632  * @implemented
2633  */
2634 NTSTATUS
2635 NTAPI
2636 RxFinalizeConnection(
2637     IN OUT PNET_ROOT NetRoot,
2638     IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
2639     IN LOGICAL ForceFilesClosed)
2640 {
2641     NTSTATUS Status;
2642     PRX_PREFIX_TABLE PrefixTable;
2643     ULONG UncleanAny, UncleanDir;
2644     LONG FilesOpen, AdditionalRef;
2645     BOOLEAN PrefixLocked, FcbTableLocked, ForceClose;
2646 
2647     PAGED_CODE();
2648 
2649     ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
2650 
2651     /* Get a BOOLEAN out of LOGICAL
2652      * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2653      */
2654     ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE);
2655 
2656     /* First, delete any notification change */
2657     Status = RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot, ForceClose);
2658     /* If it failed, continue if forced */
2659     if (Status != STATUS_SUCCESS && !ForceFilesClosed)
2660     {
2661         return Status;
2662     }
2663     /* Reset status, in case notification deletion failed */
2664     Status = STATUS_SUCCESS;
2665 
2666     PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
2667 
2668     PrefixLocked = FALSE;
2669     FcbTableLocked = FALSE;
2670     FilesOpen = 0;
2671     AdditionalRef = 0;
2672     UncleanAny = 0;
2673     UncleanDir = 0;
2674     _SEH2_TRY
2675     {
2676         RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2677         PrefixLocked = TRUE;
2678 
2679         RxReferenceNetRoot(NetRoot);
2680 
2681         RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2682         FcbTableLocked = TRUE;
2683 
2684         /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2685         if (!VNetRoot->ConnectionFinalizationDone)
2686         {
2687             USHORT Bucket;
2688             PRX_FCB_TABLE FcbTable;
2689 
2690             DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix);
2691 
2692             /* We'll browse all its associated FCB to check whether they're open/orphaned */
2693             FcbTable = &NetRoot->FcbTable;
2694             for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2695             {
2696                 PLIST_ENTRY BucketList, Entry;
2697 
2698                 BucketList = &FcbTable->HashBuckets[Bucket];
2699                 Entry = BucketList->Flink;
2700                 while (Entry != BucketList)
2701                 {
2702                     PFCB Fcb;
2703 
2704                     Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
2705                     Entry = Entry->Flink;
2706 
2707                     /* FCB for this connection, go ahead */
2708                     if (Fcb->VNetRoot == VNetRoot)
2709                     {
2710                         /* It's still open, and no force? Fail and keep track */
2711                         if (Fcb->UncleanCount > 0 && !ForceClose)
2712                         {
2713                             Status = STATUS_CONNECTION_IN_USE;
2714                             if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2715                             {
2716                                 ++UncleanDir;
2717                             }
2718                             else
2719                             {
2720                                 ++UncleanAny;
2721                             }
2722                         }
2723                         else
2724                         {
2725                             /* Else, force purge */
2726                             ASSERT(NodeTypeIsFcb(Fcb));
2727 
2728                             Status = RxAcquireExclusiveFcb(NULL, Fcb);
2729                             ASSERT(Status == STATUS_SUCCESS);
2730 
2731                             ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
2732 
2733                             RxScavengeRelatedFobxs(Fcb);
2734                             RxPurgeFcb(Fcb);
2735 
2736                             /* We don't need to release FCB lock, FCB finalize will take care of it */
2737                         }
2738                     }
2739                 }
2740             }
2741 
2742             /* No files left, our V_NET_ROOT is finalized */
2743             if (VNetRoot->NumberOfFobxs == 0)
2744             {
2745                 VNetRoot->ConnectionFinalizationDone = TRUE;
2746             }
2747         }
2748 
2749         /* Keep Number of open files and track of the extra reference */
2750         FilesOpen = VNetRoot->NumberOfFobxs;
2751         AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken;
2752         /* If force close, caller doesn't want to keep connection alive
2753          * and wants it totally close, so drop the V_NET_ROOT too
2754          */
2755         if (ForceClose)
2756         {
2757             RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE);
2758         }
2759     }
2760     _SEH2_FINALLY
2761     {
2762         /* Release what was acquired */
2763         if (FcbTableLocked)
2764         {
2765             RxReleaseFcbTableLock(&NetRoot->FcbTable);
2766         }
2767 
2768         /* If close is forced, only fix status if there are open files */
2769         if (ForceClose)
2770         {
2771             if (Status != STATUS_SUCCESS && UncleanAny != 0)
2772             {
2773                 Status = STATUS_FILES_OPEN;
2774             }
2775         }
2776         /* Else, fix status and fail closing if there are open files */
2777         else
2778         {
2779             if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0)
2780             {
2781                 Status = STATUS_FILES_OPEN;
2782             }
2783         }
2784 
2785         DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen);
2786 
2787         /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2788          * only if it was still referenced!
2789          */
2790         if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0)
2791         {
2792             VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
2793             RxDereferenceVNetRoot(VNetRoot, LHS_ExclusiveLockHeld);
2794         }
2795 
2796         if (PrefixLocked)
2797         {
2798             RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2799             RxReleasePrefixTableLock(PrefixTable);
2800         }
2801     }
2802     _SEH2_END;
2803 
2804     return Status;
2805 }
2806 
2807 /*
2808  * @implemented
2809  */
2810 VOID
2811 RxFinalizeFcbTable(
2812     IN OUT PRX_FCB_TABLE FcbTable)
2813 {
2814     USHORT Bucket;
2815 
2816     PAGED_CODE();
2817 
2818     /* Just delete the lock */
2819     ExDeleteResourceLite(&FcbTable->TableLock);
2820 
2821     /* And make sure (checked) that the table is really empty... */
2822     for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2823     {
2824         ASSERT(IsListEmpty(&FcbTable->HashBuckets[Bucket]));
2825     }
2826 }
2827 
2828 /*
2829  * @implemented
2830  */
2831 BOOLEAN
2832 RxFinalizeNetFcb(
2833     OUT PFCB ThisFcb,
2834     IN BOOLEAN RecursiveFinalize,
2835     IN BOOLEAN ForceFinalize,
2836     IN LONG ReferenceCount)
2837 {
2838     PAGED_CODE();
2839 
2840     DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
2841     DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
2842 
2843     /* Make sure we have an exclusively acquired FCB */
2844     ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
2845     ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
2846 
2847     /* We shouldn't force finalization... */
2848     ASSERT(!ForceFinalize);
2849 
2850     /* If recurisve, finalize all the associated SRV_OPEN */
2851     if (RecursiveFinalize)
2852     {
2853         PLIST_ENTRY ListEntry;
2854 
2855         for (ListEntry = ThisFcb->SrvOpenList.Flink;
2856              ListEntry != &ThisFcb->SrvOpenList;
2857              ListEntry = ListEntry->Flink)
2858         {
2859             PSRV_OPEN SrvOpen;
2860 
2861             SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
2862             RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
2863         }
2864     }
2865     /* If FCB is still in use, that's over */
2866     else
2867     {
2868         if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
2869         {
2870             ASSERT(ReferenceCount > 0);
2871 
2872             return FALSE;
2873         }
2874     }
2875 
2876     ASSERT(ReferenceCount >= 1);
2877 
2878     /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2879     if (ReferenceCount != 1 && !ForceFinalize)
2880     {
2881         return FALSE;
2882     }
2883 
2884     ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
2885 
2886     DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb->OpenCount, ForceFinalize);
2887 
2888     /* If finalization was not already initiated, go ahead */
2889     if (!ThisFcb->UpperFinalizationDone)
2890     {
2891         /* Free any FCB_LOCK */
2892         if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
2893         {
2894             FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
2895 
2896             while (ThisFcb->BufferedLocks.List != NULL)
2897             {
2898                 PFCB_LOCK Entry;
2899 
2900                 Entry = ThisFcb->BufferedLocks.List;
2901                 ThisFcb->BufferedLocks.List = Entry->Next;
2902 
2903                 RxFreePool(Entry);
2904             }
2905         }
2906 
2907         /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2908         if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
2909         {
2910             PNET_ROOT NetRoot;
2911 
2912             NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
2913 
2914             ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
2915             /* So, remove it */
2916             if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
2917             {
2918                 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
2919             }
2920         }
2921 
2922         ThisFcb->UpperFinalizationDone = TRUE;
2923     }
2924 
2925     ASSERT(ReferenceCount >= 1);
2926 
2927     /* Even if forced, don't allow broken free */
2928     if (ReferenceCount != 1)
2929     {
2930         return FALSE;
2931     }
2932 
2933     /* Now, release everything */
2934     if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
2935     {
2936         RxFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
2937     }
2938 
2939     if (ThisFcb->MRxDispatch != NULL)
2940     {
2941         ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
2942     }
2943 
2944     ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
2945     ExDeleteResourceLite(ThisFcb->Header.Resource);
2946     ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
2947 
2948     InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
2949     RxDereferenceVNetRoot(ThisFcb->VNetRoot, LHS_LockNotHeld);
2950 
2951     ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
2952     ASSERT(!ThisFcb->fMiniInited);
2953 
2954     /* And free the object */
2955     RxFreeFcbObject(ThisFcb);
2956 
2957     return TRUE;
2958 }
2959 
2960 /*
2961  * @implemented
2962  */
2963 BOOLEAN
2964 RxFinalizeNetFobx(
2965     _Out_ PFOBX ThisFobx,
2966     _In_ BOOLEAN RecursiveFinalize,
2967     _In_ BOOLEAN ForceFinalize)
2968 {
2969     PFCB Fcb;
2970     PSRV_OPEN SrvOpen;
2971 
2972     PAGED_CODE();
2973 
2974     ASSERT(NodeType(ThisFobx) == RDBSS_NTC_FOBX);
2975 
2976     /* Only finalize if forced or if there's no ref left */
2977     if (ThisFobx->NodeReferenceCount != 0 &&
2978         !ForceFinalize)
2979     {
2980         return FALSE;
2981     }
2982 
2983     DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx, ThisFobx->NodeReferenceCount, ForceFinalize);
2984 
2985     SrvOpen = ThisFobx->SrvOpen;
2986     Fcb = SrvOpen->Fcb;
2987     /* If it wasn't finalized yet, do it */
2988     if (!ThisFobx->UpperFinalizationDone)
2989     {
2990         ASSERT(NodeType(SrvOpen->Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
2991         ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
2992 
2993         /* Remove it from the SRV_OPEN */
2994         RemoveEntryList(&ThisFobx->FobxQLinks);
2995 
2996         /* If we were used to browse a directory, free the query buffer */
2997         if (BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_FREE_UNICODE))
2998         {
2999             RxFreePoolWithTag(ThisFobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
3000         }
3001 
3002         /* Notify the mini-rdr */
3003         if (Fcb->MRxDispatch != NULL && Fcb->MRxDispatch->MRxDeallocateForFobx != NULL)
3004         {
3005             Fcb->MRxDispatch->MRxDeallocateForFobx((PMRX_FOBX)ThisFobx);
3006         }
3007 
3008         /* If the SRV_OPEN wasn't closed yet, do it */
3009         if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
3010         {
3011             NTSTATUS Status;
3012 
3013             Status = RxCloseAssociatedSrvOpen(ThisFobx, FALSE);
3014             DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen, ThisFobx, Status);
3015         }
3016 
3017         /* Finalization done */
3018         ThisFobx->UpperFinalizationDone = TRUE;
3019     }
3020 
3021     /* If we're still referenced, don't go any further! */
3022     if (ThisFobx->NodeReferenceCount != 0)
3023     {
3024         return FALSE;
3025     }
3026 
3027     /* At that point, everything should be closed */
3028     ASSERT(IsListEmpty(&ThisFobx->ClosePendingList));
3029 
3030     /* Was the FOBX allocated with another object?
3031      * If so, mark the buffer free in said object
3032      */
3033     if (ThisFobx == Fcb->InternalFobx)
3034     {
3035         ClearFlag(Fcb->FcbState, FCB_STATE_FOBX_USED);
3036     }
3037     else if (ThisFobx == SrvOpen->InternalFobx)
3038     {
3039         ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED);
3040     }
3041 
3042     ThisFobx->pSrvOpen = NULL;
3043 
3044     /* A FOBX less */
3045     InterlockedDecrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
3046 
3047     RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
3048 
3049     /* If it wasn't allocated with another object, free the FOBX */
3050     if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_ENCLOSED_ALLOCATED))
3051     {
3052         RxFreeFcbObject(ThisFobx);
3053     }
3054 
3055     return TRUE;
3056 }
3057 
3058 /*
3059  * @implemented
3060  */
3061 BOOLEAN
3062 RxFinalizeNetRoot(
3063     OUT PNET_ROOT ThisNetRoot,
3064     IN BOOLEAN RecursiveFinalize,
3065     IN BOOLEAN ForceFinalize)
3066 {
3067     PSRV_CALL SrvCall;
3068     PRX_FCB_TABLE FcbTable;
3069     PRX_PREFIX_TABLE PrefixTable;
3070 
3071     PAGED_CODE();
3072 
3073     ASSERT(NodeType(ThisNetRoot) == RDBSS_NTC_NETROOT);
3074 
3075     PrefixTable = ThisNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3076     ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3077 
3078     /* If sme finalization is already ongoing, leave */
3079     if (BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS))
3080     {
3081         return FALSE;
3082     }
3083 
3084     /* Mark we're finalizing */
3085     SetFlag(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS);
3086 
3087     FcbTable = &ThisNetRoot->FcbTable;
3088     /* Did caller asked us to finalize any associated FCB? */
3089     if (RecursiveFinalize)
3090     {
3091         USHORT Bucket;
3092 
3093         /* Browse all the FCBs in our FCB table */
3094         RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
3095         for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
3096         {
3097             PLIST_ENTRY HashBucket, ListEntry;
3098 
3099             HashBucket = &FcbTable->HashBuckets[Bucket];
3100             ListEntry = HashBucket->Flink;
3101             while (ListEntry != HashBucket)
3102             {
3103                 PFCB Fcb;
3104 
3105                 Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
3106                 ASSERT(NodeTypeIsFcb(Fcb));
3107 
3108                 ListEntry = ListEntry->Flink;
3109 
3110                 /* If the FCB isn't orphaned, then, it's time to purge it */
3111                 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
3112                 {
3113                     NTSTATUS Status;
3114 
3115                     Status = RxAcquireExclusiveFcb(NULL, Fcb);
3116                     ASSERT(Status == STATUS_SUCCESS);
3117                     RxPurgeFcb(Fcb);
3118                 }
3119             }
3120         }
3121         RxReleaseFcbTableLock(FcbTable);
3122     }
3123 
3124     /* Only finalize if forced or if there's a single ref left */
3125     if (ThisNetRoot->NodeReferenceCount != 1 && !ForceFinalize)
3126     {
3127         return FALSE;
3128     }
3129 
3130     DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot, &ThisNetRoot->PrefixEntry.Prefix);
3131 
3132     /* If we're still referenced, don't go any further! */
3133     if (ThisNetRoot->NodeReferenceCount != 1)
3134     {
3135         return FALSE;
3136     }
3137 
3138     /* Finalize the FCB table (and make sure it's empty!) */
3139     RxFinalizeFcbTable(FcbTable);
3140 
3141     /* If name wasn't remove already, do it now */
3142     if (!BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
3143     {
3144         RxRemovePrefixTableEntry(PrefixTable, &ThisNetRoot->PrefixEntry);
3145     }
3146 
3147     /* Delete the object */
3148     SrvCall = (PSRV_CALL)ThisNetRoot->pSrvCall;
3149     RxFreeObject(ThisNetRoot);
3150 
3151     /* And dereference the associated SRV_CALL */
3152     if (SrvCall != NULL)
3153     {
3154         RxDereferenceSrvCall(SrvCall, LHS_ExclusiveLockHeld);
3155     }
3156 
3157     return TRUE;
3158 }
3159 
3160 /*
3161  * @implemented
3162  */
3163 BOOLEAN
3164 RxFinalizeSrvCall(
3165     OUT PSRV_CALL ThisSrvCall,
3166     IN BOOLEAN RecursiveFinalize,
3167     IN BOOLEAN ForceFinalize)
3168 {
3169     PRX_PREFIX_TABLE PrefixTable;
3170 
3171     PAGED_CODE();
3172 
3173     ASSERT(NodeType(ThisSrvCall) == RDBSS_NTC_SRVCALL);
3174 
3175     PrefixTable = ThisSrvCall->RxDeviceObject->pRxNetNameTable;
3176     ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3177 
3178     /* Only finalize if forced or if there's a single ref left */
3179     if (ThisSrvCall->NodeReferenceCount != 1 &&
3180         !ForceFinalize)
3181     {
3182         return FALSE;
3183     }
3184 
3185     DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall, &ThisSrvCall->PrefixEntry.Prefix);
3186 
3187     /* If it wasn't finalized yet, do it */
3188     if (!ThisSrvCall->UpperFinalizationDone)
3189     {
3190         BOOLEAN WillFree;
3191 
3192         /* Remove ourselves from prefix table */
3193         RxRemovePrefixTableEntry(PrefixTable, &ThisSrvCall->PrefixEntry);
3194 
3195         /* Remember our third arg, in case we get queued for later execution */
3196         if (ForceFinalize)
3197         {
3198             SetFlag(ThisSrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
3199         }
3200 
3201         /* And done */
3202         ThisSrvCall->UpperFinalizationDone = TRUE;
3203 
3204         /* Would defered execution free the object? */
3205         WillFree = (ThisSrvCall->NodeReferenceCount == 1);
3206 
3207         /* If we have a device object */
3208         if (ThisSrvCall->RxDeviceObject != NULL)
3209         {
3210             NTSTATUS Status;
3211 
3212             /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3213             if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3214             {
3215                 /* Extra ref, as usual */
3216                 InterlockedIncrement((volatile long *)&ThisSrvCall->NodeReferenceCount);
3217                 /* And dispatch */
3218                 RxDispatchToWorkerThread(ThisSrvCall->RxDeviceObject, DelayedWorkQueue, RxpDestroySrvCall, ThisSrvCall);
3219 
3220                 /* Return to the caller, in advance, whether we're freeing the object or not */
3221                 return WillFree;
3222             }
3223 
3224             /* If in the right thread already, call the mini-rdr */
3225             MINIRDR_CALL_THROUGH(Status, ThisSrvCall->RxDeviceObject->Dispatch,
3226                                  MRxFinalizeSrvCall, ((PMRX_SRV_CALL)ThisSrvCall, ForceFinalize));
3227             (void)Status;
3228         }
3229     }
3230 
3231     /* If we're still referenced, don't go any further! */
3232     if (ThisSrvCall->NodeReferenceCount != 1)
3233     {
3234         return FALSE;
3235     }
3236 
3237     /* Don't leak */
3238     if (ThisSrvCall->pDomainName != NULL)
3239     {
3240         RxFreePool(ThisSrvCall->pDomainName);
3241     }
3242 
3243     /* And free! */
3244     RxTearDownBufferingManager(ThisSrvCall);
3245     RxFreeObject(ThisSrvCall);
3246 
3247     return TRUE;
3248 }
3249 
3250 /*
3251  * @implemented
3252  */
3253 BOOLEAN
3254 RxFinalizeSrvOpen(
3255     OUT PSRV_OPEN ThisSrvOpen,
3256     IN BOOLEAN RecursiveFinalize,
3257     IN BOOLEAN ForceFinalize)
3258 {
3259     PFCB Fcb;
3260 
3261     PAGED_CODE();
3262 
3263     /* We have to have a SRV_OPEN */
3264     ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN);
3265 
3266     /* If that's a recursive finalization, finalize any related FOBX */
3267     if (RecursiveFinalize)
3268     {
3269         PLIST_ENTRY ListEntry;
3270 
3271         ListEntry = ThisSrvOpen->FobxList.Flink;
3272         while (ListEntry != &ThisSrvOpen->FobxList)
3273         {
3274             PFOBX Fobx;
3275 
3276             Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
3277             ListEntry = ListEntry->Flink;
3278             RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
3279         }
3280     }
3281 
3282     /* If we have still references, don't finalize unless forced */
3283     if (ThisSrvOpen->NodeReferenceCount != 0 &&
3284         !ForceFinalize)
3285     {
3286         return FALSE;
3287     }
3288 
3289     DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize);
3290 
3291     /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3292     Fcb = (PFCB)ThisSrvOpen->pFcb;
3293     if ((!ThisSrvOpen->UpperFinalizationDone && ThisSrvOpen->Condition != Condition_Good) ||
3294         BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
3295     {
3296         PV_NET_ROOT VNetRoot;
3297 
3298         /* Associated FCB can't be fake one */
3299         ASSERT(NodeType(Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
3300         ASSERT(RxIsFcbAcquiredExclusive (Fcb));
3301 
3302         /* Purge any pending operation */
3303         RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen);
3304 
3305         /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3306         if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
3307         {
3308             NTSTATUS Status;
3309 
3310             MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen));
3311             (void)Status;
3312         }
3313 
3314         /* Remove ourselves from the FCB */
3315         RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3316         InitializeListHead(&ThisSrvOpen->SrvOpenQLinks);
3317         ++Fcb->SrvOpenListVersion;
3318 
3319         /* If we have a V_NET_ROOT, dereference it */
3320         VNetRoot = (PV_NET_ROOT)ThisSrvOpen->pVNetRoot;
3321         if (VNetRoot != NULL)
3322         {
3323             InterlockedDecrement((volatile long *)&VNetRoot->pNetRoot->NumberOfSrvOpens);
3324             RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3325             ThisSrvOpen->pVNetRoot = NULL;
3326         }
3327 
3328         /* Finalization done */
3329         ThisSrvOpen->UpperFinalizationDone = TRUE;
3330     }
3331 
3332     /* Don't free memory if still referenced */
3333     if (ThisSrvOpen->NodeReferenceCount != 0)
3334     {
3335         return FALSE;
3336     }
3337 
3338     /* No key association left */
3339     ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList));
3340 
3341     /* If we're still in some FCB, remove us */
3342     if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks))
3343     {
3344         RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3345     }
3346 
3347     /* If enclosed allocation, mark the memory zone free */
3348     if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
3349     {
3350         ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED);
3351     }
3352     /* Otherwise, free the memory */
3353     else
3354     {
3355         RxFreeFcbObject(ThisSrvOpen);
3356     }
3357 
3358     RxDereferenceNetFcb(Fcb);
3359 
3360     return TRUE;
3361 }
3362 
3363 /*
3364  * @implemented
3365  */
3366 BOOLEAN
3367 RxFinalizeVNetRoot(
3368     OUT PV_NET_ROOT ThisVNetRoot,
3369     IN BOOLEAN RecursiveFinalize,
3370     IN BOOLEAN ForceFinalize)
3371 {
3372     PNET_ROOT NetRoot;
3373     PRX_PREFIX_TABLE PrefixTable;
3374 
3375     PAGED_CODE();
3376 
3377     ASSERT(NodeType(ThisVNetRoot) == RDBSS_NTC_V_NETROOT);
3378 
3379     PrefixTable = ThisVNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3380     ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3381 
3382     /* Only finalize if forced or if there's a single ref left */
3383     if (ThisVNetRoot->NodeReferenceCount != 1 &&
3384         !ForceFinalize)
3385     {
3386         return FALSE;
3387     }
3388 
3389     DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot, &ThisVNetRoot->PrefixEntry.Prefix);
3390 
3391     NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
3392     /* If it wasn't finalized yet, do it */
3393     if (!ThisVNetRoot->UpperFinalizationDone)
3394     {
3395         ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
3396 
3397         /* Reference the NetRoot so that it doesn't disappear */
3398         RxReferenceNetRoot(NetRoot);
3399         RxOrphanSrvOpens(ThisVNetRoot);
3400         /* Remove us from the available VNetRoot for NetRoot */
3401         RxRemoveVirtualNetRootFromNetRoot(NetRoot, ThisVNetRoot);
3402         /* Remove extra ref */
3403         RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
3404 
3405         /* Remove ourselves from prefix table */
3406         RxRemovePrefixTableEntry(PrefixTable, &ThisVNetRoot->PrefixEntry);
3407 
3408         /* Finalization done */
3409         ThisVNetRoot->UpperFinalizationDone = TRUE;
3410     }
3411 
3412     /* If we're still referenced, don't go any further! */
3413     if (ThisVNetRoot->NodeReferenceCount != 1)
3414     {
3415         return FALSE;
3416     }
3417 
3418     /* If there's an associated device, notify mini-rdr */
3419     if (NetRoot->pSrvCall->RxDeviceObject != NULL)
3420     {
3421         NTSTATUS Status;
3422 
3423         MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
3424                              MRxFinalizeVNetRoot, ((PMRX_V_NET_ROOT)ThisVNetRoot, FALSE));
3425         (void)Status;
3426     }
3427 
3428     /* Free parameters */
3429     RxUninitializeVNetRootParameters(ThisVNetRoot->pUserName, ThisVNetRoot->pUserDomainName,
3430                                      ThisVNetRoot->pPassword, &ThisVNetRoot->Flags);
3431     /* Dereference our NetRoot, we won't reference it anymore */
3432     RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
3433 
3434     /* And free the object! */
3435     RxFreePoolWithTag(ThisVNetRoot, RX_V_NETROOT_POOLTAG);
3436 
3437     return TRUE;
3438 }
3439 
3440 NTSTATUS
3441 RxFindOrConstructVirtualNetRoot(
3442     IN PRX_CONTEXT RxContext,
3443     IN PUNICODE_STRING CanonicalName,
3444     IN NET_ROOT_TYPE NetRootType,
3445     IN PUNICODE_STRING RemainingName)
3446 {
3447     ULONG Flags;
3448     NTSTATUS Status;
3449     PVOID Container;
3450     BOOLEAN Construct;
3451     PV_NET_ROOT VNetRoot;
3452     RX_CONNECTION_ID ConnectionID;
3453     PRDBSS_DEVICE_OBJECT RxDeviceObject;
3454     LOCK_HOLDING_STATE LockHoldingState;
3455 
3456     PAGED_CODE();
3457 
3458     RxDeviceObject = RxContext->RxDeviceObject;
3459     ASSERT(RxDeviceObject->Dispatch != NULL);
3460     ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
3461 
3462     /* Ask the mini-rdr for connection ID */
3463     ConnectionID.SessionID = 0;
3464     if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
3465     {
3466         Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
3467         if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
3468         {
3469             /* mini-rdr is expected not to fail - unless it's not implemented */
3470             DPRINT1("Failed to initialize connection ID\n");
3471             ASSERT(FALSE);
3472         }
3473     }
3474 
3475     RxContext->Create.NetNamePrefixEntry = NULL;
3476 
3477     Status = STATUS_MORE_PROCESSING_REQUIRED;
3478     RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
3479     LockHoldingState = LHS_SharedLockHeld;
3480     Construct = TRUE;
3481     Flags = 0;
3482 
3483     /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3484     while (TRUE)
3485     {
3486         PNET_ROOT NetRoot;
3487         PV_NET_ROOT SavedVNetRoot;
3488 
3489         /* Look in prefix table */
3490         Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
3491         if (Container != NULL)
3492         {
3493             /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3494             if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
3495             {
3496                 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3497                 RxDereferenceSrvCall(Container, LockHoldingState);
3498             }
3499             else
3500             {
3501                 VNetRoot = Container;
3502                 NetRoot = VNetRoot->NetRoot;
3503 
3504                 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3505                 if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
3506                     NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3507                 {
3508                     Status = STATUS_BAD_NETWORK_PATH;
3509                     SavedVNetRoot = NULL;
3510                 }
3511                 else
3512                 {
3513                     LUID LogonId;
3514                     ULONG SessionId;
3515                     PUNICODE_STRING UserName, UserDomain, Password;
3516 
3517                     /* We can reuse if we use same credentials */
3518                     Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
3519                                                             &SessionId, &UserName,
3520                                                             &UserDomain, &Password,
3521                                                             &Flags);
3522                     if (NT_SUCCESS(Status))
3523                     {
3524                         SavedVNetRoot = VNetRoot;
3525                         Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
3526                                                             &LogonId, UserName,
3527                                                             UserDomain, Password,
3528                                                             Flags);
3529                         if (Status == STATUS_MORE_PROCESSING_REQUIRED)
3530                         {
3531                             PLIST_ENTRY ListEntry;
3532 
3533                             for (ListEntry = NetRoot->VirtualNetRoots.Flink;
3534                                  ListEntry != &NetRoot->VirtualNetRoots;
3535                                  ListEntry = ListEntry->Flink)
3536                             {
3537                                 SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
3538                                 Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
3539                                                                     &LogonId, UserName,
3540                                                                     UserDomain, Password,
3541                                                                     Flags);
3542                                 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
3543                                 {
3544                                     break;
3545                                 }
3546                             }
3547 
3548                             if (ListEntry == &NetRoot->VirtualNetRoots)
3549                             {
3550                                 SavedVNetRoot = NULL;
3551                             }
3552                         }
3553 
3554                         if (!NT_SUCCESS(Status))
3555                         {
3556                             SavedVNetRoot = NULL;
3557                         }
3558 
3559                         RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
3560                     }
3561                 }
3562 
3563                 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3564                 if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
3565                 {
3566                     if (SavedVNetRoot == NULL)
3567                     {
3568                         RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3569                     }
3570                 }
3571                 /* Reference VNetRoot we'll keep, and dereference current */
3572                 else if (SavedVNetRoot != VNetRoot)
3573                 {
3574                     RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3575                     if (SavedVNetRoot != NULL)
3576                     {
3577                         RxReferenceVNetRoot(SavedVNetRoot);
3578                     }
3579                 }
3580             }
3581 
3582             /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3583             if (Status != STATUS_MORE_PROCESSING_REQUIRED)
3584             {
3585                 Construct = FALSE;
3586                 break;
3587             }
3588         }
3589 
3590         /* If we're locked exclusive, we won't loop again, it was the second pass */
3591         if (LockHoldingState != LHS_SharedLockHeld)
3592         {
3593             break;
3594         }
3595 
3596         /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3597         if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
3598         {
3599             RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3600             LockHoldingState = LHS_ExclusiveLockHeld;
3601             break;
3602         }
3603 
3604         RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3605         RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
3606         LockHoldingState = LHS_ExclusiveLockHeld;
3607     }
3608 
3609     /* We didn't fail, and didn't find any VNetRoot, construct one */
3610     if (Construct)
3611     {
3612         ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
3613 
3614         Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
3615         ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
3616 
3617         if (Status == STATUS_SUCCESS)
3618         {
3619             DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
3620             DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
3621             ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
3622 
3623             RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
3624             RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
3625             RemainingName->MaximumLength = RemainingName->Length;
3626 
3627             if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
3628             {
3629                 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
3630             }
3631             VNetRoot->Flags |= Flags;
3632         }
3633     }
3634 
3635     /* Release the prefix table - caller expects it to be released */
3636     if (LockHoldingState != LHS_LockNotHeld)
3637     {
3638         RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3639     }
3640 
3641     /* If we failed creating, quit */
3642     if (Status != STATUS_SUCCESS)
3643     {
3644         DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
3645         return Status;
3646     }
3647 
3648     /* Otherwise, wait until the VNetRoot is stable */
3649     DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
3650     RxWaitForStableVNetRoot(VNetRoot, RxContext);
3651     /* It's all good, update the RX_CONTEXT with all our structs */
3652     if (VNetRoot->Condition == Condition_Good)
3653     {
3654         PNET_ROOT NetRoot;
3655 
3656         NetRoot = VNetRoot->NetRoot;
3657         RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3658         RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3659         RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
3660     }
3661     else
3662     {
3663         RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3664         RxContext->Create.pVNetRoot = NULL;
3665         Status = STATUS_BAD_NETWORK_PATH;
3666     }
3667 
3668     return Status;
3669 }
3670 
3671 /*
3672  * @implemented
3673  */
3674 NTSTATUS
3675 RxFindOrCreateConnections(
3676     _In_ PRX_CONTEXT RxContext,
3677     _In_ PUNICODE_STRING CanonicalName,
3678     _In_ NET_ROOT_TYPE NetRootType,
3679     _Out_ PUNICODE_STRING LocalNetRootName,
3680     _Out_ PUNICODE_STRING FilePathName,
3681     _Inout_ PLOCK_HOLDING_STATE LockState,
3682     _In_ PRX_CONNECTION_ID RxConnectionId)
3683 {
3684     PVOID Container;
3685     PSRV_CALL SrvCall;
3686     PNET_ROOT NetRoot;
3687     PV_NET_ROOT VNetRoot;
3688     NTSTATUS Status = STATUS_UNSUCCESSFUL;
3689     PRX_PREFIX_TABLE PrefixTable;
3690     UNICODE_STRING RemainingName, NetRootName;
3691 
3692     PAGED_CODE();
3693 
3694     DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3695            RxContext, CanonicalName, NetRootType, LocalNetRootName,
3696            FilePathName, LockState, RxConnectionId);
3697 
3698     *FilePathName = *CanonicalName;
3699     LocalNetRootName->Length = 0;
3700     LocalNetRootName->MaximumLength = 0;
3701     LocalNetRootName->Buffer = CanonicalName->Buffer;
3702 
3703     /* UNC path, split it */
3704     if (FilePathName->Buffer[1] == ';')
3705     {
3706         BOOLEAN Slash;
3707         USHORT i, Length;
3708 
3709         Slash = FALSE;
3710         for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
3711         {
3712             if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
3713             {
3714                 Slash = TRUE;
3715                 break;
3716             }
3717         }
3718 
3719         if (!Slash)
3720         {
3721             return STATUS_OBJECT_NAME_INVALID;
3722         }
3723 
3724         FilePathName->Buffer = &FilePathName->Buffer[i];
3725         Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
3726         LocalNetRootName->Length = Length;
3727         LocalNetRootName->MaximumLength = Length;
3728         FilePathName->Length -= Length;
3729 
3730         DPRINT("CanonicalName: %wZ\n", CanonicalName);
3731         DPRINT(" -> FilePathName: %wZ\n", FilePathName);
3732         DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
3733     }
3734 
3735     Container = NULL;
3736     PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
3737 
3738     _SEH2_TRY
3739     {
3740 RetryLookup:
3741         ASSERT(*LockState != LHS_LockNotHeld);
3742 
3743         /* If previous lookup left something, dereference it */
3744         if (Container != NULL)
3745         {
3746             switch (NodeType(Container))
3747             {
3748                 case RDBSS_NTC_SRVCALL:
3749                     RxDereferenceSrvCall(Container, *LockState);
3750                     break;
3751 
3752                 case RDBSS_NTC_NETROOT:
3753                     RxDereferenceNetRoot(Container, *LockState);
3754                     break;
3755 
3756                 case RDBSS_NTC_V_NETROOT:
3757                     RxDereferenceVNetRoot(Container, *LockState);
3758                     break;
3759 
3760                 default:
3761                     /* Should never happen */
3762                     ASSERT(FALSE);
3763                     break;
3764             }
3765         }
3766 
3767         /* Look for our NetRoot in prefix table */
3768         Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
3769         DPRINT("Container %p for path %wZ\n", Container, FilePathName);
3770 
3771         while (TRUE)
3772         {
3773             UNICODE_STRING SrvCallName;
3774 
3775             SrvCall = NULL;
3776             NetRoot = NULL;
3777             VNetRoot = NULL;
3778 
3779             /* Assume we didn't succeed */
3780             RxContext->Create.pVNetRoot = NULL;
3781             RxContext->Create.pNetRoot = NULL;
3782             RxContext->Create.pSrvCall = NULL;
3783             RxContext->Create.Type = NetRootType;
3784 
3785             /* If we found something */
3786             if (Container != NULL)
3787             {
3788                 /* A VNetRoot */
3789                 if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
3790                 {
3791                     VNetRoot = Container;
3792                     /* Use its NetRoot */
3793                     NetRoot = VNetRoot->NetRoot;
3794 
3795                     /* If it's not stable, wait for it to be stable */
3796                     if (NetRoot->Condition == Condition_InTransition)
3797                     {
3798                         RxReleasePrefixTableLock(PrefixTable);
3799                         DPRINT("Waiting for stable condition for: %p\n", NetRoot);
3800                         RxWaitForStableNetRoot(NetRoot, RxContext);
3801                         RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3802                         *LockState = LHS_ExclusiveLockHeld;
3803 
3804                         /* Now that's it's ok, retry lookup to find what we want */
3805                         if (NetRoot->Condition == Condition_Good)
3806                         {
3807                             goto RetryLookup;
3808                         }
3809                     }
3810 
3811                     /* Is the associated netroot good? */
3812                     if (NetRoot->Condition == Condition_Good)
3813                     {
3814                         SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
3815 
3816                         /* If it is, and SrvCall as well, then, we have our active connection */
3817                         if (SrvCall->Condition == Condition_Good &&
3818                             SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
3819                         {
3820                             RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3821                             RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3822                             RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3823 
3824                             Status = STATUS_CONNECTION_ACTIVE;
3825                             _SEH2_LEAVE;
3826                         }
3827                     }
3828 
3829                     /* If VNetRoot was well constructed, it means the connection is active */
3830                     if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
3831                     {
3832                         Status = STATUS_CONNECTION_ACTIVE;
3833                     }
3834                     else
3835                     {
3836                         Status = VNetRoot->ConstructionStatus;
3837                     }
3838 
3839                     RxDereferenceVNetRoot(VNetRoot, *LockState);
3840                     _SEH2_LEAVE;
3841                 }
3842                 /* Can only be a SrvCall */
3843                 else
3844                 {
3845                     ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3846                     SrvCall = Container;
3847 
3848                     /* Wait for the SRV_CALL to be stable */
3849                     if (SrvCall->Condition == Condition_InTransition)
3850                     {
3851                         RxReleasePrefixTableLock(PrefixTable);
3852                         DPRINT("Waiting for stable condition for: %p\n", SrvCall);
3853                         RxWaitForStableSrvCall(SrvCall, RxContext);
3854                         RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3855                         *LockState = LHS_ExclusiveLockHeld;
3856 
3857                         /* It went good, loop again to find what we look for */
3858                         if (SrvCall->Condition == Condition_Good)
3859                         {
3860                             goto RetryLookup;
3861                         }
3862                     }
3863 
3864                     /* If it's not good... */
3865                     if (SrvCall->Condition != Condition_Good)
3866                     {
3867                         /* But SRV_CALL was well constructed, assume a connection was active */
3868                         if (SrvCall->Status == STATUS_SUCCESS)
3869                         {
3870                             Status = STATUS_CONNECTION_ACTIVE;
3871                         }
3872                         else
3873                         {
3874                             Status = SrvCall->Status;
3875                         }
3876 
3877                         RxDereferenceSrvCall(SrvCall, *LockState);
3878                         _SEH2_LEAVE;
3879                     }
3880                 }
3881             }
3882 
3883             /* If we found a SRV_CALL not matching our DO, quit */
3884             if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
3885                 SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3886             {
3887                 RxDereferenceSrvCall(SrvCall, *LockState);
3888                 Status = STATUS_BAD_NETWORK_NAME;
3889                 _SEH2_LEAVE;
3890             }
3891 
3892             /* Now, we want exclusive lock */
3893             if (*LockState == LHS_SharedLockHeld)
3894             {
3895                 if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
3896                 {
3897                     RxReleasePrefixTableLock(PrefixTable);
3898                     RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3899                     *LockState = LHS_ExclusiveLockHeld;
3900                     goto RetryLookup;
3901                 }
3902 
3903                 RxReleasePrefixTableLock(PrefixTable);
3904                 *LockState = LHS_ExclusiveLockHeld;
3905             }
3906 
3907             ASSERT(*LockState == LHS_ExclusiveLockHeld);
3908 
3909             /* If we reach that point, we found something, no need to create something */
3910             if (Container != NULL)
3911             {
3912                 break;
3913             }
3914 
3915             /* Get the name for the SRV_CALL */
3916             RxExtractServerName(FilePathName, &SrvCallName, NULL);
3917             DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
3918             /* And create the SRV_CALL */
3919             SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
3920             if (SrvCall == NULL)
3921             {
3922                 Status = STATUS_INSUFFICIENT_RESOURCES;
3923                 _SEH2_LEAVE;
3924             }
3925 
3926             /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3927             RxReferenceSrvCall(SrvCall);
3928             RxContext->Create.pVNetRoot = NULL;
3929             RxContext->Create.pNetRoot = NULL;
3930             RxContext->Create.pSrvCall = NULL;
3931             RxContext->Create.Type = NetRootType;
3932             Container = SrvCall;
3933 
3934             /* Construct SRV_CALL, ie, use mini-rdr */
3935             Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
3936             ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
3937             if (Status != STATUS_SUCCESS)
3938             {
3939                 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
3940                 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3941                 RxDereferenceSrvCall(SrvCall, *LockState);
3942                 RxReleasePrefixTableLock(PrefixTable);
3943                 _SEH2_LEAVE;
3944             }
3945 
3946             /* Loop again to make use of SRV_CALL stable condition wait */
3947         }
3948 
3949         /* At that point, we have a stable SRV_CALL (either found or constructed) */
3950         ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
3951         ASSERT(NetRoot == NULL && VNetRoot == NULL);
3952         ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
3953 
3954         /* Call mini-rdr to get NetRoot name */
3955         SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
3956         /* And create the NetRoot with that name */
3957         NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
3958         if (NetRoot == NULL)
3959         {
3960             Status = STATUS_INSUFFICIENT_RESOURCES;
3961             _SEH2_LEAVE;
3962         }
3963         NetRoot->Type = NetRootType;
3964 
3965         RxDereferenceSrvCall(SrvCall, *LockState);
3966 
3967         /* Finally, create the associated VNetRoot */
3968         VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
3969         if (VNetRoot == NULL)
3970         {
3971             RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
3972             Status = STATUS_INSUFFICIENT_RESOURCES;
3973             _SEH2_LEAVE;
3974         }
3975         RxReferenceVNetRoot(VNetRoot);
3976 
3977         /* We're get closer! */
3978         NetRoot->Condition = Condition_InTransition;
3979         RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3980         RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3981         RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3982 
3983         /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3984         Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
3985         if (!NT_SUCCESS(Status))
3986         {
3987             RxTransitionVNetRoot(VNetRoot, Condition_Bad);
3988             DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
3989             RxDereferenceVNetRoot(VNetRoot, *LockState);
3990 
3991             RxContext->Create.pNetRoot = NULL;
3992             RxContext->Create.pVNetRoot = NULL;
3993         }
3994         else
3995         {
3996             PIO_STACK_LOCATION Stack;
3997 
3998             ASSERT(*LockState == LHS_ExclusiveLockHeld);
3999 
4000             Stack = RxContext->CurrentIrpSp;
4001             if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
4002             {
4003                 RxExclusivePrefixTableLockToShared(PrefixTable);
4004                 *LockState = LHS_SharedLockHeld;
4005             }
4006         }
4007     }
4008     _SEH2_FINALLY
4009     {
4010         if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
4011         {
4012             if (*LockState != LHS_LockNotHeld)
4013             {
4014                 RxReleasePrefixTableLock(PrefixTable);
4015                 *LockState = LHS_LockNotHeld;
4016             }
4017         }
4018     }
4019     _SEH2_END;
4020 
4021     DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
4022     return Status;
4023 }
4024 
4025 /*
4026  * @implemented
4027  */
4028 VOID
4029 NTAPI
4030 RxFinishFcbInitialization(
4031     IN OUT PMRX_FCB Fcb,
4032     IN RX_FILE_TYPE FileType,
4033     IN PFCB_INIT_PACKET InitPacket OPTIONAL)
4034 {
4035     RX_FILE_TYPE OldType;
4036 
4037     PAGED_CODE();
4038 
4039     DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
4040 
4041     OldType = NodeType(Fcb);
4042     NodeType(Fcb) = FileType;
4043     /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
4044     if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
4045     {
4046         FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
4047     }
4048     /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
4049     else if (InitPacket != NULL)
4050     {
4051         FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
4052                     InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
4053                     InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
4054                     InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
4055                     InitPacket->pValidDataLength->QuadPart);
4056     }
4057 
4058     if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
4059         FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
4060     {
4061         /* If our FCB newly points to a file, initiliaze everything related */
4062         if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE)
4063 
4064         {
4065             if (OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
4066             {
4067                 RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
4068                 FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, RxLockOperationCompletion,
4069                                         RxUnlockOperation);
4070 
4071                 ((PFCB)Fcb)->BufferedLocks.List = NULL;
4072                 ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
4073 
4074                 Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
4075             }
4076         }
4077         /* If not a file, validate type */
4078         else
4079         {
4080             ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
4081         }
4082     }
4083 }
4084 
4085 /*
4086  * @implemented
4087  */
4088 NTSTATUS
4089 RxFinishSrvCallConstruction(
4090     PMRX_SRVCALLDOWN_STRUCTURE Calldown)
4091 {
4092     NTSTATUS Status;
4093     PSRV_CALL SrvCall;
4094     PRX_CONTEXT Context;
4095     RX_BLOCK_CONDITION Condition;
4096     PRX_PREFIX_TABLE PrefixTable;
4097 
4098     DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
4099 
4100     SrvCall = (PSRV_CALL)Calldown->SrvCall;
4101     Context = Calldown->RxContext;
4102     PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
4103 
4104     /* We have a winner, notify him */
4105     if (Calldown->BestFinisher != NULL)
4106     {
4107         DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
4108 
4109         ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
4110 
4111         MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
4112                              MRxSrvCallWinnerNotify,
4113                              ((PMRX_SRV_CALL)SrvCall, TRUE,
4114                               Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
4115         if (Status != STATUS_SUCCESS)
4116         {
4117             Condition = Condition_Bad;
4118         }
4119         else
4120         {
4121             Condition = Condition_Good;
4122         }
4123     }
4124     /* Otherwise, just fail our SRV_CALL */
4125     else
4126     {
4127         Status = Calldown->CallbackContexts[0].Status;
4128         Condition = Condition_Bad;
4129     }
4130 
4131     RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
4132     RxTransitionSrvCall(SrvCall, Condition);
4133     RxFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
4134 
4135     /* If async, finish it here, otherwise, caller has already finished the stuff */
4136     if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
4137     {
4138         DPRINT("Finishing async call\n");
4139 
4140         RxReleasePrefixTableLock(PrefixTable);
4141 
4142         /* Make sure we weren't cancelled in-between */
4143         if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
4144         {
4145             Status = STATUS_CANCELLED;
4146         }
4147 
4148         /* In case that was a create, context can be reused */
4149         if (Context->MajorFunction == IRP_MJ_CREATE)
4150         {
4151             RxpPrepareCreateContextForReuse(Context);
4152         }
4153 
4154         /* If that's a failure, reset everything and return failure */
4155         if (Status != STATUS_SUCCESS)
4156         {
4157             Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
4158             if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
4159             {
4160                 if (Context->Info.Buffer != NULL)
4161                 {
4162                     RxFreePool(Context->Info.Buffer);
4163                     Context->Info.Buffer = NULL;
4164                 }
4165             }
4166             Context->CurrentIrp->IoStatus.Information = 0;
4167             Context->CurrentIrp->IoStatus.Status = Status;
4168             RxCompleteRequest(Context, Status);
4169         }
4170         /* Otherwise, call resume routine and done! */
4171         else
4172         {
4173             Status = Context->ResumeRoutine(Context);
4174             if (Status != STATUS_PENDING)
4175             {
4176                 RxCompleteRequest(Context, Status);
4177             }
4178 
4179             DPRINT("Not completing, pending\n");
4180         }
4181     }
4182 
4183     RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
4184     return Status;
4185 }
4186 
4187 /*
4188  * @implemented
4189  */
4190 VOID
4191 NTAPI
4192 RxFinishSrvCallConstructionDispatcher(
4193     IN PVOID Context)
4194 {
4195     KIRQL OldIrql;
4196     BOOLEAN Direct, KeepLoop;
4197 
4198     DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
4199 
4200     /* In case of failure of starting dispatcher, context is not set
4201      * We keep track of it to fail associated SRV_CALL
4202      */
4203     Direct = (Context == NULL);
4204 
4205     /* Separated thread, loop forever */
4206     while (TRUE)
4207     {
4208         PLIST_ENTRY ListEntry;
4209         PMRX_SRVCALLDOWN_STRUCTURE Calldown;
4210 
4211         /* If there are no SRV_CALL to finalize left, just finish thread */
4212         KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
4213         if (IsListEmpty(&RxSrvCalldownList))
4214         {
4215             KeepLoop =  FALSE;
4216             RxSrvCallConstructionDispatcherActive = FALSE;
4217         }
4218         /* Otherwise, get the SRV_CALL to finish construction */
4219         else
4220         {
4221             ListEntry = RemoveHeadList(&RxSrvCalldownList);
4222             KeepLoop =  TRUE;
4223         }
4224         KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
4225 
4226         /* Nothing to do */
4227         if (!KeepLoop)
4228         {
4229             break;
4230         }
4231 
4232         /* If direct is set, reset the finisher to avoid electing a winner
4233          * and fail SRV_CALL (see upper comment)
4234          */
4235         Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
4236         if (Direct)
4237         {
4238             Calldown->BestFinisher = NULL;
4239         }
4240         /* Finish SRV_CALL construction */
4241         RxFinishSrvCallConstruction(Calldown);
4242     }
4243 }
4244 
4245 /*
4246  * @implemented
4247  */
4248 NTSTATUS
4249 RxFlushFcbInSystemCache(
4250     IN PFCB Fcb,
4251     IN BOOLEAN SynchronizeWithLazyWriter)
4252 {
4253     IO_STATUS_BLOCK IoStatus;
4254 
4255     PAGED_CODE();
4256 
4257     /* Deal with Cc */
4258     CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, &IoStatus);
4259     /* If we're asked to sync with LW, do it in case of success */
4260     if (SynchronizeWithLazyWriter && NT_SUCCESS(IoStatus.Status))
4261     {
4262         RxAcquirePagingIoResource((PRX_CONTEXT)NULL, Fcb);
4263         RxReleasePagingIoResource((PRX_CONTEXT)NULL, Fcb);
4264     }
4265 
4266     DPRINT("Flushing for FCB %p returns %lx\n", Fcb, IoStatus.Status);
4267     return IoStatus.Status;
4268 }
4269 
4270 /*
4271  * @implemented
4272  */
4273 VOID
4274 RxFreeFcbObject(
4275     PVOID Object)
4276 {
4277     PAGED_CODE();
4278 
4279     DPRINT("Freeing %p\n", Object);
4280 
4281     /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4282     if (NodeType(Object) == RDBSS_NTC_FOBX || NodeType(Object) == RDBSS_NTC_SRVOPEN)
4283     {
4284         RxFreePoolWithTag(Object, RX_FCB_POOLTAG);
4285     }
4286     /* If that's a FCB... */
4287     else if (NodeTypeIsFcb(Object))
4288     {
4289         PFCB Fcb;
4290         PRDBSS_DEVICE_OBJECT DeviceObject;
4291 
4292         Fcb = (PFCB)Object;
4293         DeviceObject = Fcb->RxDeviceObject;
4294 
4295         /* Delete per stream contexts */
4296         FsRtlTeardownPerStreamContexts(&Fcb->Header);
4297 
4298         SetFlag(Fcb->Header.Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH);
4299 
4300         /* If there was a non-paged FCB allocated, free it */
4301         if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
4302         {
4303             RxFreePoolWithTag(Fcb->NonPaged, RX_NONPAGEDFCB_POOLTAG);
4304         }
4305 
4306         /* Free the FCB */
4307         RxFreePool(Fcb);
4308 
4309         /* Update statistics */
4310         InterlockedDecrement(&RxNumberOfActiveFcbs);
4311         InterlockedDecrement((volatile long *)&DeviceObject->NumberOfActiveFcbs);
4312     }
4313 }
4314 
4315 /*
4316  * @implemented
4317  */
4318 VOID
4319 RxFreeObject(
4320     PVOID pObject)
4321 {
4322     PAGED_CODE();
4323 
4324     /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4325     if (NodeType(pObject) == RDBSS_NTC_SRVCALL)
4326     {
4327         PSRV_CALL SrvCall;
4328         PRDBSS_DEVICE_OBJECT DeviceObject;
4329 
4330         SrvCall = (PSRV_CALL)pObject;
4331         DeviceObject = SrvCall->RxDeviceObject;
4332         if (DeviceObject != NULL)
4333         {
4334             if (!BooleanFlagOn(DeviceObject->Dispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
4335             {
4336                 ASSERT(SrvCall->Context == NULL);
4337             }
4338 
4339             ASSERT(SrvCall->Context2 == NULL);
4340 
4341             SrvCall->RxDeviceObject = NULL;
4342         }
4343     }
4344     else if (NodeType(pObject) == RDBSS_NTC_NETROOT)
4345     {
4346         PNET_ROOT NetRoot;
4347 
4348         NetRoot = (PNET_ROOT)pObject;
4349         NetRoot->pSrvCall = NULL;
4350         NetRoot->NodeTypeCode = NodeType(pObject) | 0xF000;
4351     }
4352 
4353     /* And just free the object */
4354     RxFreePool(pObject);
4355 }
4356 
4357 /*
4358  * @implemented
4359  */
4360 VOID
4361 RxGatherRequestsForSrvOpen(
4362     IN OUT PSRV_CALL SrvCall,
4363     IN PSRV_OPEN SrvOpen,
4364     IN OUT PLIST_ENTRY RequestsListHead)
4365 {
4366     KIRQL OldIrql;
4367     LIST_ENTRY Discarded, *Entry;
4368     PCHANGE_BUFFERING_STATE_REQUEST Request;
4369 
4370     /* Dispatch any pending operation first */
4371     RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &Discarded);
4372 
4373     /* Then, get any entry related to our key and SRV_OPEN */
4374     KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
4375     Entry = SrvCall->BufferingManager.HandlerList.Flink;
4376     while (Entry != &SrvCall->BufferingManager.HandlerList)
4377     {
4378         Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
4379         Entry = Entry->Flink;
4380         if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
4381         {
4382             RemoveEntryList(&Request->ListEntry);
4383             InsertTailList(RequestsListHead, &Request->ListEntry);
4384         }
4385     }
4386     KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
4387 
4388     /* Perform the same search in the last change list */
4389     Entry = SrvCall->BufferingManager.LastChanceHandlerList.Flink;
4390     while (Entry != &SrvCall->BufferingManager.LastChanceHandlerList)
4391     {
4392         Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
4393         Entry = Entry->Flink;
4394         if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
4395         {
4396             RemoveEntryList(&Request->ListEntry);
4397             InsertTailList(RequestsListHead, &Request->ListEntry);
4398         }
4399     }
4400 
4401     /* Discard the discarded requests */
4402     RxpDiscardChangeBufferingStateRequests(&Discarded);
4403 }
4404 
4405 /*
4406  * @implemented
4407  */
4408 PRDBSS_DEVICE_OBJECT
4409 RxGetDeviceObjectOfInstance(
4410     PVOID Instance)
4411 {
4412     NODE_TYPE_CODE NodeType;
4413     PRDBSS_DEVICE_OBJECT DeviceObject;
4414 
4415     PAGED_CODE();
4416 
4417     /* We only handle a few object types */
4418     NodeType = NodeType(Instance);
4419     ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
4420            (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) || (NodeType == RDBSS_NTC_FOBX));
4421 
4422     /* Get the device object depending on the object */
4423     switch (NodeType)
4424     {
4425         case RDBSS_NTC_FOBX:
4426         {
4427             PFOBX Fobx;
4428 
4429             Fobx = (PFOBX)Instance;
4430             DeviceObject = Fobx->RxDeviceObject;
4431             break;
4432         }
4433 
4434         case RDBSS_NTC_SRVCALL:
4435         {
4436             PSRV_CALL SrvCall;
4437 
4438             SrvCall = (PSRV_CALL)Instance;
4439             DeviceObject = SrvCall->RxDeviceObject;
4440             break;
4441         }
4442 
4443         case RDBSS_NTC_NETROOT:
4444         {
4445             PNET_ROOT NetRoot;
4446 
4447             NetRoot = (PNET_ROOT)Instance;
4448             DeviceObject = NetRoot->pSrvCall->RxDeviceObject;
4449             break;
4450         }
4451 
4452         case RDBSS_NTC_V_NETROOT:
4453         {
4454             PV_NET_ROOT VNetRoot;
4455 
4456             VNetRoot = (PV_NET_ROOT)Instance;
4457             DeviceObject = VNetRoot->pNetRoot->pSrvCall->RxDeviceObject;
4458             break;
4459         }
4460 
4461         case RDBSS_NTC_SRVOPEN:
4462         {
4463             PSRV_OPEN SrvOpen;
4464 
4465             SrvOpen = (PSRV_OPEN)Instance;
4466             DeviceObject = ((PFCB)SrvOpen->pFcb)->RxDeviceObject;
4467             break;
4468         }
4469 
4470         default:
4471             DeviceObject = NULL;
4472             break;
4473     }
4474 
4475     /* Job done */
4476     return DeviceObject;
4477 }
4478 
4479 /*
4480  * @implemented
4481  */
4482 VOID
4483 RxGetFileSizeWithLock(
4484     IN PFCB Fcb,
4485     OUT PLONGLONG FileSize)
4486 {
4487     PAGED_CODE();
4488 
4489     *FileSize = Fcb->Header.FileSize.QuadPart;
4490 }
4491 
4492 /*
4493  * @implemented
4494  */
4495 PEPROCESS
4496 NTAPI
4497 RxGetRDBSSProcess(
4498     VOID)
4499 {
4500     return RxData.OurProcess;
4501 }
4502 
4503 /*
4504  * @implemented
4505  */
4506 NTSTATUS
4507 RxInitializeBufferingManager(
4508    PSRV_CALL SrvCall)
4509 {
4510     KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
4511     InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
4512     InitializeListHead(&SrvCall->BufferingManager.HandlerList);
4513     InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
4514     SrvCall->BufferingManager.DispatcherActive = FALSE;
4515     SrvCall->BufferingManager.HandlerInactive = FALSE;
4516     SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
4517     SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
4518     InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
4519     ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
4520 
4521     return STATUS_SUCCESS;
4522 }
4523 
4524 /*
4525  * @implemented
4526  */
4527 VOID
4528 NTAPI
4529 RxInitializeContext(
4530     IN PIRP Irp,
4531     IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
4532     IN ULONG InitialContextFlags,
4533     IN OUT PRX_CONTEXT RxContext)
4534 {
4535     PIO_STACK_LOCATION Stack;
4536 
4537     /* Initialize our various fields */
4538     RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
4539     RxContext->NodeByteSize = sizeof(RX_CONTEXT);
4540     RxContext->ReferenceCount = 1;
4541     RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
4542     RxContext->RxDeviceObject = RxDeviceObject;
4543     KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
4544     RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
4545     InitializeListHead(&RxContext->BlockedOperations);
4546     RxContext->MRxCancelRoutine = NULL;
4547     RxContext->ResumeRoutine = NULL;
4548     RxContext->Flags |= InitialContextFlags;
4549     RxContext->CurrentIrp = Irp;
4550     RxContext->LastExecutionThread = PsGetCurrentThread();
4551     RxContext->OriginalThread = RxContext->LastExecutionThread;
4552 
4553     /* If've got no IRP, mark RX_CONTEXT */
4554     if (Irp == NULL)
4555     {
4556         RxContext->CurrentIrpSp = NULL;
4557         RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
4558         RxContext->MinorFunction = 0;
4559     }
4560     else
4561     {
4562         /* Otherwise, first determine whether we are performing async operation */
4563         Stack = IoGetCurrentIrpStackLocation(Irp);
4564         if (Stack->FileObject != NULL)
4565         {
4566             PFCB Fcb;
4567 
4568             Fcb = Stack->FileObject->FsContext;
4569             if (!IoIsOperationSynchronous(Irp) ||
4570                 ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
4571                  (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
4572                  (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
4573             {
4574                 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4575             }
4576         }
4577 
4578         if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
4579         {
4580             RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4581         }
4582         if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
4583         {
4584             RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4585         }
4586 
4587         /* Set proper flags if TopLevl IRP/Device */
4588         if (!RxIsThisTheTopLevelIrp(Irp))
4589         {
4590             RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
4591         }
4592         if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
4593         {
4594             RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
4595         }
4596 
4597         /* Copy stack information */
4598         RxContext->MajorFunction = Stack->MajorFunction;
4599         RxContext->MinorFunction = Stack->MinorFunction;
4600         ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
4601         RxContext->CurrentIrpSp = Stack;
4602 
4603         /* If we have a FO associated, learn for more */
4604         if (Stack->FileObject != NULL)
4605         {
4606             PFCB Fcb;
4607             PFOBX Fobx;
4608 
4609             /* Get the FCB and CCB (FOBX) */
4610             Fcb = Stack->FileObject->FsContext;
4611             Fobx = Stack->FileObject->FsContext2;
4612             RxContext->pFcb = (PMRX_FCB)Fcb;
4613             if (Fcb != NULL && NodeTypeIsFcb(Fcb))
4614             {
4615                 RxContext->NonPagedFcb = Fcb->NonPaged;
4616             }
4617 
4618             /* We have a FOBX, this not a DFS opening, keep track of it */
4619             if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
4620             {
4621                 RxContext->pFobx = (PMRX_FOBX)Fobx;
4622                 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
4623                 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
4624                 {
4625                     RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
4626                 }
4627             }
4628             else
4629             {
4630                 RxContext->pFobx = NULL;
4631             }
4632 
4633             /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4634             if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
4635                 Fobx != NULL)
4636             {
4637                 PV_NET_ROOT VNetRoot = NULL;
4638 
4639                 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
4640                 {
4641                     VNetRoot = Fcb->VNetRoot;
4642                 }
4643                 else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
4644                 {
4645                     VNetRoot = (PV_NET_ROOT)Fobx;
4646                 }
4647 
4648                 if (VNetRoot != NULL)
4649                 {
4650                     RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
4651                 }
4652             }
4653 
4654             /* Remember if that's a write through file */
4655             RxContext->RealDevice = Stack->FileObject->DeviceObject;
4656             if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
4657             {
4658                 RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
4659             }
4660         }
4661     }
4662 
4663     if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
4664     {
4665         DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4666                RxContext, RxContext->MinorFunction, Irp,
4667                PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
4668                RxContext->SerialNumber);
4669     }
4670 }
4671 
4672 /*
4673  * @implemented
4674  */
4675 VOID
4676 NTAPI
4677 RxInitializeDebugSupport(
4678     VOID)
4679 {
4680     /* Nothing to do */
4681 }
4682 
4683 /*
4684  * @implemented
4685  */
4686 NTSTATUS
4687 NTAPI
4688 RxInitializeDispatcher(
4689     VOID)
4690 {
4691     NTSTATUS Status;
4692     HANDLE ThreadHandle;
4693 
4694     PAGED_CODE();
4695 
4696     RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
4697     RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL;
4698 
4699     /* Set appropriate timeouts: 10s & 60s */
4700     RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4701     RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4702     RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4703     RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
4704 
4705     RxDispatcher.NumberOfProcessors = 1;
4706     RxDispatcher.OwnerProcess = IoGetCurrentProcess();
4707     RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues;
4708 
4709     /* Initialize our dispatchers */
4710     Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher);
4711     if (!NT_SUCCESS(Status))
4712     {
4713         return Status;
4714     }
4715 
4716     Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject);
4717     if (!NT_SUCCESS(Status))
4718     {
4719         return Status;
4720     }
4721 
4722     /* And start them */
4723     RxDispatcher.State = RxDispatcherActive;
4724     InitializeListHead(&RxDispatcher.SpinUpRequests);
4725     KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock);
4726     KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0);
4727     KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0);
4728     Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL,
4729                                   NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher);
4730     if (NT_SUCCESS(Status))
4731     {
4732         ZwClose(ThreadHandle);
4733     }
4734 
4735     return Status;
4736 }
4737 
4738 /*
4739  * @implemented
4740  */
4741 VOID
4742 RxInitializeFcbTable(
4743     IN OUT PRX_FCB_TABLE FcbTable,
4744     IN BOOLEAN CaseInsensitiveMatch)
4745 {
4746     USHORT i;
4747 
4748     PAGED_CODE();
4749 
4750     FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
4751     FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
4752 
4753     ExInitializeResourceLite(&FcbTable->TableLock);
4754     FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
4755     FcbTable->Version = 0;
4756     FcbTable->TableEntryForNull = NULL;
4757 
4758     FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
4759     for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
4760     {
4761         InitializeListHead(&FcbTable->HashBuckets[i]);
4762     }
4763 
4764     FcbTable->Lookups = 0;
4765     FcbTable->FailedLookups = 0;
4766     FcbTable->Compares = 0;
4767 }
4768 
4769 /*
4770  * @implemented
4771  */
4772 VOID
4773 NTAPI
4774 RxInitializeLowIoContext(
4775     OUT PLOWIO_CONTEXT LowIoContext,
4776     IN ULONG Operation)
4777 {
4778     PRX_CONTEXT RxContext;
4779     PIO_STACK_LOCATION Stack;
4780 
4781     PAGED_CODE();
4782 
4783     RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
4784     ASSERT(LowIoContext == &RxContext->LowIoContext);
4785 
4786     Stack = RxContext->CurrentIrpSp;
4787 
4788     KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
4789     RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread();
4790     RxContext->LowIoContext.Operation = Operation;
4791 
4792     switch (Operation)
4793     {
4794         case LOWIO_OP_READ:
4795         case LOWIO_OP_WRITE:
4796             /* In case of RW, set a canary, to make sure these fields are properly set
4797              * they will be asserted when lowio request will be submit to mini-rdr
4798              * See LowIoSubmit()
4799              */
4800             RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
4801             RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
4802             RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
4803 
4804             /* Keep track of paging IOs */
4805             if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
4806             {
4807                 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO;
4808             }
4809             else
4810             {
4811                 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
4812             }
4813 
4814             break;
4815 
4816         case LOWIO_OP_FSCTL:
4817         case LOWIO_OP_IOCTL:
4818             /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4819             RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
4820             RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0;
4821             RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL;
4822             RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0;
4823             RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
4824             RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
4825             break;
4826 
4827         /* Nothing to do for these */
4828         case LOWIO_OP_SHAREDLOCK:
4829         case LOWIO_OP_EXCLUSIVELOCK:
4830         case LOWIO_OP_UNLOCK:
4831         case LOWIO_OP_UNLOCK_MULTIPLE:
4832         case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
4833         case LOWIO_OP_CLEAROUT:
4834             break;
4835 
4836         default:
4837             /* Should never happen */
4838             ASSERT(FALSE);
4839             break;
4840     }
4841 }
4842 
4843 /*
4844  * @implemented
4845  */
4846 VOID
4847 RxInitializeLowIoPerFcbInfo(
4848     PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
4849 {
4850     PAGED_CODE();
4851 
4852     InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
4853     InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
4854 }
4855 
4856 /*
4857  * @implemented
4858  */
4859 NTSTATUS
4860 RxInitializeMRxDispatcher(
4861      IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
4862 {
4863     PAGED_CODE();
4864 
4865     pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
4866     pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
4867 
4868     return STATUS_SUCCESS;
4869 }
4870 
4871 /*
4872  * @implemented
4873  */
4874 VOID
4875 RxInitializePrefixTable(
4876     IN OUT PRX_PREFIX_TABLE ThisTable,
4877     IN ULONG TableSize OPTIONAL,
4878     IN BOOLEAN CaseInsensitiveMatch)
4879 {
4880     PAGED_CODE();
4881 
4882     if (TableSize == 0)
4883     {
4884         TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH;
4885     }
4886 
4887     ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
4888     ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
4889     InitializeListHead(&ThisTable->MemberQueue);
4890     ThisTable->Version = 0;
4891     ThisTable->TableEntryForNull = NULL;
4892     ThisTable->IsNetNameTable = FALSE;
4893     ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
4894     ThisTable->TableSize = TableSize;
4895 
4896     if (TableSize > 0)
4897     {
4898         USHORT i;
4899 
4900         for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
4901         {
4902             InitializeListHead(&ThisTable->HashBuckets[i]);
4903         }
4904     }
4905 }
4906 
4907 /*
4908  * @implemented
4909  */
4910 VOID
4911 RxInitializePurgeSyncronizationContext(
4912     PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
4913 {
4914     PAGED_CODE();
4915 
4916     InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
4917     PurgeSyncronizationContext->PurgeInProgress = FALSE;
4918 }
4919 
4920 NTSTATUS
4921 RxInitializeSrvCallParameters(
4922     IN PRX_CONTEXT RxContext,
4923     IN OUT PSRV_CALL SrvCall)
4924 {
4925     PAGED_CODE();
4926 
4927     SrvCall->pPrincipalName = NULL;
4928 
4929     /* We only have stuff to initialize for file opening from DFS */
4930     if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
4931     {
4932         return STATUS_SUCCESS;
4933     }
4934 
4935     ASSERT(RxContext->Create.EaBuffer != NULL);
4936 
4937     UNIMPLEMENTED;
4938     return STATUS_NOT_IMPLEMENTED;
4939 }
4940 
4941 /*
4942  * @implemented
4943  */
4944 NTSTATUS
4945 NTAPI
4946 RxInitializeRxTimer(
4947     VOID)
4948 {
4949     PAGED_CODE();
4950 
4951     RxTimerInterval.QuadPart = -550000;
4952     KeInitializeSpinLock(&RxTimerLock);
4953     InitializeListHead(&RxTimerQueueHead);
4954     InitializeListHead(&RxRecurrentWorkItemsList);
4955     KeInitializeDpc(&RxTimerDpc, RxTimerDispatch, NULL);
4956     KeInitializeTimer(&RxTimer);
4957     RxTimerTickCount = 0;
4958 
4959     return STATUS_SUCCESS;
4960 }
4961 
4962 NTSTATUS
4963 RxInitializeVNetRootParameters(
4964    PRX_CONTEXT RxContext,
4965    OUT LUID *LogonId,
4966    OUT PULONG SessionId,
4967    OUT PUNICODE_STRING *UserNamePtr,
4968    OUT PUNICODE_STRING *UserDomainNamePtr,
4969    OUT PUNICODE_STRING *PasswordPtr,
4970    OUT PULONG Flags)
4971 {
4972     NTSTATUS Status;
4973     PACCESS_TOKEN Token;
4974 
4975     PAGED_CODE();
4976 
4977     DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
4978            LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
4979 
4980     *UserNamePtr = NULL;
4981     *UserDomainNamePtr = NULL;
4982     *PasswordPtr = NULL;
4983     /* By default, that's not CSC instance */
4984     *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
4985 
4986     Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
4987     if (SeTokenIsRestricted(Token))
4988     {
4989         return STATUS_ACCESS_DENIED;
4990     }
4991 
4992     /* Get LogonId */
4993     Status = SeQueryAuthenticationIdToken(Token, LogonId);
4994     if (!NT_SUCCESS(Status))
4995     {
4996         return Status;
4997     }
4998 
4999     /* And SessionId */
5000     Status = SeQuerySessionIdToken(Token, SessionId);
5001     if (!NT_SUCCESS(Status))
5002     {
5003         return Status;
5004     }
5005 
5006     if (RxContext->Create.UserName.Buffer != NULL)
5007     {
5008         UNIMPLEMENTED;
5009         Status = STATUS_NOT_IMPLEMENTED;
5010         goto Leave;
5011     }
5012 
5013     /* Deal with connection credentials */
5014     if (RxContext->Create.UserDomainName.Buffer != NULL)
5015     {
5016         UNIMPLEMENTED;
5017         Status = STATUS_NOT_IMPLEMENTED;
5018         goto Leave;
5019     }
5020 
5021     if (RxContext->Create.Password.Buffer != NULL)
5022     {
5023         UNIMPLEMENTED;
5024         Status = STATUS_NOT_IMPLEMENTED;
5025         goto Leave;
5026     }
5027 
5028 Leave:
5029     if (NT_SUCCESS(Status))
5030     {
5031         /* If that's a CSC instance, mark it as such */
5032         if (RxIsThisACscAgentOpen(RxContext))
5033         {
5034             *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE;
5035         }
5036         return Status;
5037     }
5038 
5039     return Status;
5040 }
5041 
5042 /*
5043  * @implemented
5044  */
5045 VOID
5046 RxInitializeWorkQueue(
5047    PRX_WORK_QUEUE WorkQueue,
5048    WORK_QUEUE_TYPE WorkQueueType,
5049    ULONG MaximumNumberOfWorkerThreads,
5050    ULONG MinimumNumberOfWorkerThreads)
5051 {
5052     PAGED_CODE();
5053 
5054     WorkQueue->Type = WorkQueueType;
5055     WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
5056     WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
5057 
5058     WorkQueue->State = RxWorkQueueActive;
5059     WorkQueue->SpinUpRequestPending = FALSE;
5060     WorkQueue->pRundownContext = NULL;
5061     WorkQueue->NumberOfWorkItemsDispatched = 0;
5062     WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
5063     WorkQueue->CumulativeQueueLength = 0;
5064     WorkQueue->NumberOfSpinUpRequests = 0;
5065     WorkQueue->NumberOfActiveWorkerThreads = 0;
5066     WorkQueue->NumberOfIdleWorkerThreads = 0;
5067     WorkQueue->NumberOfFailedSpinUpRequests = 0;
5068     WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
5069     WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
5070     WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
5071     WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
5072     WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
5073     WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
5074     WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
5075     WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
5076     WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
5077     WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
5078     WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
5079     WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
5080     WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
5081 
5082     KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
5083     KeInitializeSpinLock(&WorkQueue->SpinLock);
5084 }
5085 
5086 /*
5087  * @implemented
5088  */
5089 NTSTATUS
5090 RxInitializeWorkQueueDispatcher(
5091    PRX_WORK_QUEUE_DISPATCHER Dispatcher)
5092 {
5093     NTSTATUS Status;
5094     ULONG MaximumNumberOfWorkerThreads;
5095 
5096     PAGED_CODE();
5097 
5098     /* Number of threads will depend on system capacity */
5099     if (MmQuerySystemSize() != MmLargeSystem)
5100     {
5101         MaximumNumberOfWorkerThreads = 5;
5102     }
5103     else
5104     {
5105         MaximumNumberOfWorkerThreads = 10;
5106     }
5107 
5108     /* Initialize the work queues */
5109     RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue,
5110                           MaximumNumberOfWorkerThreads, 1);
5111     RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1);
5112     RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1);
5113 
5114     /* And start the worker threads */
5115     Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue],
5116                                   RxBootstrapWorkerThreadDispatcher,
5117                                   &Dispatcher->WorkQueue[HyperCriticalWorkQueue]);
5118     if (!NT_SUCCESS(Status))
5119     {
5120         return Status;
5121     }
5122 
5123     Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue],
5124                                   RxBootstrapWorkerThreadDispatcher,
5125                                   &Dispatcher->WorkQueue[CriticalWorkQueue]);
5126     if (!NT_SUCCESS(Status))
5127     {
5128         return Status;
5129     }
5130 
5131     Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue],
5132                                   RxBootstrapWorkerThreadDispatcher,
5133                                   &Dispatcher->WorkQueue[DelayedWorkQueue]);
5134     return Status;
5135 }
5136 
5137 /*
5138  * @implemented
5139  */
5140 VOID
5141 RxInitiateSrvOpenKeyAssociation(
5142    IN OUT PSRV_OPEN SrvOpen)
5143 {
5144     PRX_BUFFERING_MANAGER BufferingManager;
5145 
5146     PAGED_CODE();
5147 
5148     SrvOpen->Key = NULL;
5149 
5150     /* Just keep track of the opening request */
5151     BufferingManager = &((PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall)->BufferingManager;
5152     InterlockedIncrement(&BufferingManager->NumberOfOutstandingOpens);
5153 
5154     InitializeListHead(&SrvOpen->SrvOpenKeyList);
5155 }
5156 
5157 /*
5158  * @implemented
5159  */
5160 NTSTATUS
5161 RxInsertWorkQueueItem(
5162     PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
5163     WORK_QUEUE_TYPE WorkQueueType,
5164     PRX_WORK_QUEUE_ITEM WorkQueueItem)
5165 {
5166     KIRQL OldIrql;
5167     NTSTATUS Status;
5168     BOOLEAN SpinUpThreads;
5169     PRX_WORK_QUEUE WorkQueue;
5170 
5171     /* No dispatcher, nothing to insert */
5172     if (RxDispatcher.State != RxDispatcherActive)
5173     {
5174         return STATUS_UNSUCCESSFUL;
5175     }
5176 
5177     /* Get the work queue */
5178     WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType];
5179 
5180     KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
5181     /* Only insert if the work queue is in decent state */
5182     if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL)
5183     {
5184         Status = STATUS_UNSUCCESSFUL;
5185     }
5186     else
5187     {
5188         SpinUpThreads = FALSE;
5189         WorkQueueItem->pDeviceObject = pMRxDeviceObject;
5190         InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
5191         WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
5192         InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
5193 
5194         /* If required (and possible!), spin up a new worker thread */
5195         if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched &&
5196             WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads &&
5197             !WorkQueue->SpinUpRequestPending)
5198         {
5199             WorkQueue->SpinUpRequestPending = TRUE;
5200             SpinUpThreads = TRUE;
5201         }
5202 
5203         Status = STATUS_SUCCESS;
5204     }
5205     KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
5206 
5207     /* If we failed, return and still not insert item */
5208     if (!NT_SUCCESS(Status))
5209     {
5210         return Status;
5211     }
5212 
5213     /* All fine, insert the item */
5214     KeInsertQueue(&WorkQueue->Queue, &WorkQueueItem->List);
5215 
5216     /* And start a new worker thread if needed */
5217     if (SpinUpThreads)
5218     {
5219         RxSpinUpWorkerThreads(WorkQueue);
5220     }
5221 
5222     return Status;
5223 }
5224 
5225 BOOLEAN
5226 RxIsThisACscAgentOpen(
5227     IN PRX_CONTEXT RxContext)
5228 {
5229     BOOLEAN CscAgent;
5230 
5231     CscAgent = FALSE;
5232 
5233     /* Client Side Caching is DFS stuff - we don't support it */
5234     if (RxContext->Create.EaLength != 0)
5235     {
5236         UNIMPLEMENTED;
5237     }
5238 
5239     if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL &&
5240         ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA)
5241     {
5242         CscAgent = TRUE;
5243     }
5244 
5245     return CscAgent;
5246 }
5247 
5248 VOID
5249 RxLockUserBuffer(
5250     IN PRX_CONTEXT RxContext,
5251     IN LOCK_OPERATION Operation,
5252     IN ULONG BufferLength)
5253 {
5254     PIRP Irp;
5255     PMDL Mdl = NULL;
5256 
5257     PAGED_CODE();
5258 
5259     _SEH2_TRY
5260     {
5261         Irp = RxContext->CurrentIrp;
5262         /* If we already have a MDL, make sure it's locked */
5263         if (Irp->MdlAddress != NULL)
5264         {
5265             ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress));
5266         }
5267         else
5268         {
5269             /* That likely means the driver asks for buffered IOs - we don't support it! */
5270             ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION));
5271 
5272             /* If we have a real length */
5273             if (BufferLength > 0)
5274             {
5275                 /* Allocate a MDL and lock it */
5276                 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
5277                 if (Mdl == NULL)
5278                 {
5279                     RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES;
5280                     ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
5281                 }
5282 
5283                 MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
5284             }
5285         }
5286     }
5287     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5288     {
5289         NTSTATUS Status;
5290 
5291         Status = _SEH2_GetExceptionCode();
5292 
5293         /* Free the possible MDL we have allocated */
5294         IoFreeMdl(Mdl);
5295         Irp->MdlAddress = NULL;
5296 
5297         RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT;
5298 
5299         /* Fix status */
5300         if (!FsRtlIsNtstatusExpected(Status))
5301         {
5302             Status = STATUS_INVALID_USER_BUFFER;
5303         }
5304 
5305         RxContext->IoStatusBlock.Status = Status;
5306         ExRaiseStatus(Status);
5307     }
5308     _SEH2_END;
5309 }
5310 
5311 /*
5312  * @implemented
5313  */
5314 NTSTATUS
5315 RxLowIoCompletionTail(
5316     IN PRX_CONTEXT RxContext)
5317 {
5318     NTSTATUS Status;
5319     USHORT Operation;
5320 
5321     PAGED_CODE();
5322 
5323     DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
5324 
5325     /* Only continue if we're at APC_LEVEL or lower */
5326     if (RxShouldPostCompletion() &&
5327         !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
5328     {
5329         return STATUS_MORE_PROCESSING_REQUIRED;
5330     }
5331 
5332     /* Call the completion routine */
5333     DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine);
5334     Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
5335     if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY)
5336     {
5337         return Status;
5338     }
5339 
5340     /* If it was a RW operation, for a paging file ... */
5341     Operation = RxContext->LowIoContext.Operation;
5342     if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
5343     {
5344         /* Remove ourselves from the list and resume operations */
5345         if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
5346         {
5347             ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5348             RemoveEntryList(&RxContext->RxContextSerializationQLinks);
5349             RxContext->RxContextSerializationQLinks.Flink = NULL;
5350             RxContext->RxContextSerializationQLinks.Blink = NULL;
5351             ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5352             RxResumeBlockedOperations_ALL(RxContext);
5353         }
5354     }
5355     else
5356     {
5357         /* Sanity check: we had known operation */
5358         ASSERT(Operation < LOWIO_OP_MAXIMUM);
5359     }
5360 
5361     /* If not sync operation, complete now. Otherwise, caller has already completed */
5362     if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
5363     {
5364         RxCompleteRequest(RxContext, Status);
5365     }
5366 
5367     DPRINT("Status: %x\n", Status);
5368     return Status;
5369 }
5370 
5371 /*
5372  * @implemented
5373  */
5374 NTSTATUS
5375 NTAPI
5376 RxLowIoPopulateFsctlInfo(
5377     IN PRX_CONTEXT RxContext)
5378 {
5379     PMDL Mdl;
5380     PIRP Irp;
5381     UCHAR Method;
5382     PIO_STACK_LOCATION Stack;
5383 
5384     PAGED_CODE();
5385 
5386     DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext);
5387 
5388     Irp = RxContext->CurrentIrp;
5389     Stack = RxContext->CurrentIrpSp;
5390 
5391     /* Copy stack parameters */
5392     RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
5393     RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength;
5394     RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength;
5395     RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction;
5396     Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
5397 
5398     /* Same buffer in case of buffered */
5399     if (Method == METHOD_BUFFERED)
5400     {
5401         RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
5402         RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
5403 
5404         return STATUS_SUCCESS;
5405     }
5406 
5407     /* Two buffers for neither */
5408     if (Method == METHOD_NEITHER)
5409     {
5410         RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer;
5411         RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
5412 
5413         return STATUS_SUCCESS;
5414     }
5415 
5416     /* Only IN/OUT remain */
5417     ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT);
5418 
5419     /* Use system buffer for input */
5420     RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
5421     /* And MDL for output */
5422     Mdl = Irp->MdlAddress;
5423     if (Mdl != NULL)
5424     {
5425         RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
5426         if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)
5427         {
5428             return STATUS_INSUFFICIENT_RESOURCES;
5429         }
5430     }
5431     else
5432     {
5433         RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
5434     }
5435 
5436     return STATUS_SUCCESS;
5437 }
5438 
5439 NTSTATUS
5440 NTAPI
5441 RxLowIoSubmit(
5442     IN PRX_CONTEXT RxContext,
5443     IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine)
5444 {
5445     NTSTATUS Status;
5446     USHORT Operation;
5447     BOOLEAN Synchronous;
5448     PLOWIO_CONTEXT LowIoContext;
5449 
5450     DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine);
5451 
5452     PAGED_CODE();
5453 
5454     LowIoContext = &RxContext->LowIoContext;
5455     Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
5456 
5457     LowIoContext->CompletionRoutine = CompletionRoutine;
5458 
5459     Status = STATUS_SUCCESS;
5460     Operation = LowIoContext->Operation;
5461     switch (Operation)
5462     {
5463         case LOWIO_OP_READ:
5464         case LOWIO_OP_WRITE:
5465             /* Check that the parameters were properly set by caller
5466              * See comment in RxInitializeLowIoContext()
5467              */
5468             ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE);
5469             ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE);
5470 
5471             /* Lock the buffer */
5472             RxLockUserBuffer(RxContext,
5473                              (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess),
5474                              LowIoContext->ParamsFor.ReadWrite.ByteCount);
5475             if (RxNewMapUserBuffer(RxContext) == NULL)
5476             {
5477                 return STATUS_INSUFFICIENT_RESOURCES;
5478             }
5479             LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress;
5480 
5481             /* If that's a paging IO, initialize serial operation */
5482             if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
5483             {
5484                 PFCB Fcb;
5485 
5486                 Fcb = (PFCB)RxContext->pFcb;
5487 
5488                 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5489                 RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
5490                 if (Operation == LOWIO_OP_READ)
5491                 {
5492                     InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks);
5493                 }
5494                 else
5495                 {
5496                     InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks);
5497                 }
5498 
5499                 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5500             }
5501 
5502             break;
5503 
5504         case LOWIO_OP_FSCTL:
5505         case LOWIO_OP_IOCTL:
5506             /* Set FSCTL/IOCTL parameters */
5507             Status = RxLowIoPopulateFsctlInfo(RxContext);
5508             /* Check whether we're consistent: a length means a buffer */
5509             if (NT_SUCCESS(Status))
5510             {
5511                 if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 &&
5512                      LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
5513                     (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 &&
5514                      LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL))
5515                 {
5516                     Status = STATUS_INVALID_PARAMETER;
5517                 }
5518             }
5519             break;
5520 
5521         /* Nothing to do */
5522         case LOWIO_OP_SHAREDLOCK:
5523         case LOWIO_OP_EXCLUSIVELOCK:
5524         case LOWIO_OP_UNLOCK:
5525         case LOWIO_OP_UNLOCK_MULTIPLE:
5526         case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
5527         case LOWIO_OP_CLEAROUT:
5528             break;
5529 
5530         default:
5531             ASSERT(FALSE);
5532             Status = STATUS_INVALID_PARAMETER;
5533             break;
5534     }
5535 
5536     /* No need to perform extra init in case of posting */
5537     RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED;
5538 
5539     /* Preflight checks were OK, time to submit */
5540     if (NT_SUCCESS(Status))
5541     {
5542         PMINIRDR_DISPATCH Dispatch;
5543 
5544         if (!Synchronous)
5545         {
5546             InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
5547             /* If not synchronous, we're likely to return before the operation is finished */
5548             if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
5549             {
5550                 IoMarkIrpPending(RxContext->CurrentIrp);
5551             }
5552         }
5553 
5554         Dispatch = RxContext->RxDeviceObject->Dispatch;
5555         if (Dispatch != NULL)
5556         {
5557             /* We'll try to execute until the mini-rdr doesn't return pending */
5558             do
5559             {
5560                 RxContext->IoStatusBlock.Information = 0;
5561 
5562                 MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext));
5563                 if (Status == STATUS_PENDING)
5564                 {
5565                     /* Unless it's not synchronous, caller will be happy with pending op */
5566                     if (!Synchronous)
5567                     {
5568                         return Status;
5569                     }
5570 
5571                     RxWaitSync(RxContext);
5572                     Status = RxContext->IoStatusBlock.Status;
5573                 }
5574                 else
5575                 {
5576                     if (!Synchronous)
5577                     {
5578                         /* We had marked the IRP pending, whereas the operation finished, drop that */
5579                         if (Status != STATUS_RETRY)
5580                         {
5581                             if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
5582                             {
5583                                 RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED;
5584                             }
5585 
5586                             InterlockedDecrement((volatile long *)&RxContext->ReferenceCount);
5587                         }
5588                     }
5589                 }
5590             } while (Status == STATUS_PENDING);
5591         }
5592         else
5593         {
5594             Status = STATUS_INVALID_PARAMETER;
5595         }
5596     }
5597 
5598     /* Call completion and return */
5599     RxContext->IoStatusBlock.Status = Status;
5600     LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL;
5601     return RxLowIoCompletionTail(RxContext);
5602 }
5603 
5604 /*
5605  * @implemented
5606  */
5607 PVOID
5608 RxMapSystemBuffer(
5609     IN PRX_CONTEXT RxContext)
5610 {
5611     PIRP Irp;
5612 
5613     PAGED_CODE();
5614 
5615     Irp = RxContext->CurrentIrp;
5616     /* We should have a MDL (buffered IOs are not supported!) */
5617     if (Irp->MdlAddress != NULL)
5618     {
5619         ASSERT(FALSE);
5620         return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
5621     }
5622 
5623     /* Just return system buffer */
5624     return Irp->AssociatedIrp.SystemBuffer;
5625 }
5626 
5627 /*
5628  * @implemented
5629  */
5630 VOID
5631 RxMarkFobxOnCleanup(
5632     PFOBX pFobx,
5633     PBOOLEAN NeedPurge)
5634 {
5635     PFCB Fcb;
5636     PFOBX ScavengerFobx;
5637     LARGE_INTEGER TickCount;
5638     PRDBSS_SCAVENGER Scavenger;
5639 
5640     PAGED_CODE();
5641 
5642     /* No FOBX, nothing to mark */
5643     if (pFobx == NULL)
5644     {
5645         return;
5646     }
5647 
5648     /* Query time for close */
5649     KeQueryTickCount(&TickCount);
5650 
5651     Fcb = (PFCB)pFobx->pSrvOpen->pFcb;
5652     ASSERT(NodeTypeIsFcb(Fcb));
5653 
5654     Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
5655     RxAcquireScavengerMutex();
5656 
5657     ScavengerFobx = NULL;
5658     /* If that's not a file, or even not a disk resource, just mark as dormant */
5659     if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE || Fcb->VNetRoot->pNetRoot->DeviceType != FILE_DEVICE_DISK)
5660     {
5661         SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5662         InitializeListHead(&pFobx->ClosePendingList);
5663         ++Scavenger->NumberOfDormantFiles;
5664     }
5665     else
5666     {
5667         ASSERT(Scavenger->NumberOfDormantFiles >= 0);
5668         /* If we're about to reach the maximum dormant of FOBX */
5669         if (Scavenger->NumberOfDormantFiles >= Scavenger->MaximumNumberOfDormantFiles)
5670         {
5671             /* This should never be wrong... */
5672             if (!IsListEmpty(&Scavenger->ClosePendingFobxsList))
5673             {
5674                 /* Then, take the first from the list (oldest) and save it for later purge */
5675                 ScavengerFobx = CONTAINING_RECORD(Scavenger->ClosePendingFobxsList.Flink, FOBX, ClosePendingList);
5676                 if (ScavengerFobx->pSrvOpen != NULL && ScavengerFobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
5677                 {
5678                     *NeedPurge = TRUE;
5679                     ScavengerFobx = NULL;
5680                 }
5681                 else
5682                 {
5683                     RxReferenceNetFobx(ScavengerFobx);
5684                 }
5685             }
5686         }
5687 
5688         /* Mark ourselves as dormant */
5689         SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5690         pFobx->CloseTime.QuadPart = TickCount.QuadPart;
5691 
5692         /* And insert us in the list of dormant files */
5693         InsertTailList(&Scavenger->ClosePendingFobxsList, &pFobx->ClosePendingList);
5694         /* If scavenger was inactive, start it */
5695         if (Scavenger->NumberOfDormantFiles++ == 0 && Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
5696         {
5697             Scavenger->State = RDBSS_SCAVENGER_DORMANT;
5698             RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem, RxScavengerTimerRoutine,
5699                                       Fcb->RxDeviceObject, Scavenger->TimeLimit);
5700         }
5701     }
5702 
5703     RxReleaseScavengerMutex();
5704 
5705     /* If we had reached max */
5706     if (ScavengerFobx != NULL)
5707     {
5708         NTSTATUS Status;
5709 
5710         /* Purge the oldest FOBX */
5711         Status = RxPurgeFobxFromCache(ScavengerFobx);
5712         if (Status != STATUS_SUCCESS)
5713         {
5714             *NeedPurge = TRUE;
5715         }
5716     }
5717 }
5718 
5719 /*
5720  * @implemented
5721  */
5722 VOID
5723 RxMarkFobxOnClose(
5724     PFOBX Fobx)
5725 {
5726     PFCB Fcb;
5727     PRDBSS_SCAVENGER Scavenger;
5728 
5729     PAGED_CODE();
5730 
5731     /* No FOBX, nothing to mark */
5732     if (Fobx == NULL)
5733     {
5734         return;
5735     }
5736 
5737     Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
5738     ASSERT(NodeTypeIsFcb(Fcb));
5739 
5740     Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
5741 
5742     RxAcquireScavengerMutex();
5743     /* Only mark it if it was already marked as dormant */
5744     if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT))
5745     {
5746         /* If FCB wasn't already decrement, do it now */
5747         if (!Fobx->fOpenCountDecremented)
5748         {
5749             Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
5750             ASSERT(NodeTypeIsFcb(Fcb));
5751             InterlockedDecrement((volatile long *)&Fcb->OpenCount);
5752 
5753             Fobx->fOpenCountDecremented = TRUE;
5754         }
5755 
5756         /* We're no longer dormant */
5757         InterlockedDecrement(&Scavenger->NumberOfDormantFiles);
5758         ClearFlag(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5759     }
5760 
5761     /* If we were inserted in the scavenger, drop ourselves out */
5762     if (!IsListEmpty(&Fobx->ClosePendingList))
5763     {
5764         RemoveEntryList(&Fobx->ClosePendingList);
5765         InitializeListHead(&Fobx->ClosePendingList);
5766     }
5767 
5768     RxReleaseScavengerMutex();
5769 }
5770 
5771 /*
5772  * @implemented
5773  */
5774 PVOID
5775 RxNewMapUserBuffer(
5776     PRX_CONTEXT RxContext)
5777 {
5778     PIRP Irp;
5779 
5780     PAGED_CODE();
5781 
5782     Irp = RxContext->CurrentIrp;
5783     if (Irp->MdlAddress != NULL)
5784     {
5785         return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
5786     }
5787 
5788     return Irp->UserBuffer;
5789 }
5790 
5791 BOOLEAN
5792 NTAPI
5793 RxNoOpAcquire(
5794     IN PVOID Fcb,
5795     IN BOOLEAN Wait)
5796 {
5797     UNIMPLEMENTED;
5798     return FALSE;
5799 }
5800 
5801 VOID
5802 NTAPI
5803 RxNoOpRelease(
5804     IN PVOID Fcb)
5805 {
5806     UNIMPLEMENTED;
5807 }
5808 
5809 VOID
5810 RxOrphanThisFcb(
5811     PFCB Fcb)
5812 {
5813     UNIMPLEMENTED;
5814 }
5815 
5816 VOID
5817 RxOrphanSrvOpens(
5818     IN PV_NET_ROOT ThisVNetRoot)
5819 {
5820     PFCB Fcb;
5821     USHORT Bucket;
5822     PNET_ROOT NetRoot;
5823     PRX_FCB_TABLE FcbTable;
5824     PRX_PREFIX_TABLE PrefixTable;
5825 
5826     PAGED_CODE();
5827 
5828     /* Mailslot won't have any SRV_OPEN (to orphan) */
5829     NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
5830     if (NetRoot->Type == NET_ROOT_MAILSLOT)
5831     {
5832         return;
5833     }
5834 
5835     PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
5836     ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
5837 
5838     FcbTable = &NetRoot->FcbTable;
5839     RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
5840 
5841     _SEH2_TRY
5842     {
5843         /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
5844         for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
5845         {
5846             PLIST_ENTRY BucketList, Entry;
5847 
5848             BucketList = &FcbTable->HashBuckets[Bucket];
5849             Entry = BucketList->Flink;
5850             while (Entry != BucketList)
5851             {
5852                 Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
5853                 Entry = Entry->Flink;
5854 
5855                 ASSERT(NodeTypeIsFcb(Fcb));
5856                 RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
5857             }
5858         }
5859 
5860         /* Of course, don't forget about NULL-entry */
5861         if (FcbTable->TableEntryForNull != NULL)
5862         {
5863             Fcb = CONTAINING_RECORD(FcbTable->TableEntryForNull, FCB, FcbTableEntry.HashLinks);
5864             ASSERT(NodeTypeIsFcb(Fcb));
5865             RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
5866         }
5867     }
5868     _SEH2_FINALLY
5869     {
5870         RxReleaseFcbTableLock(FcbTable);
5871     }
5872     _SEH2_END;
5873 }
5874 
5875 VOID
5876 RxOrphanSrvOpensForThisFcb(
5877     IN PFCB Fcb,
5878     IN PV_NET_ROOT ThisVNetRoot,
5879     IN BOOLEAN OrphanAll)
5880 {
5881     UNIMPLEMENTED;
5882 }
5883 
5884 /*
5885  * @implemented
5886  */
5887 BOOLEAN
5888 RxpAcquirePrefixTableLockShared(
5889    PRX_PREFIX_TABLE pTable,
5890    BOOLEAN Wait,
5891    BOOLEAN ProcessBufferingStateChangeRequests)
5892 {
5893     PAGED_CODE();
5894 
5895     DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
5896            pTable->TableLock.ActiveEntries);
5897 
5898     return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
5899 }
5900 
5901 /*
5902  * @implemented
5903  */
5904 BOOLEAN
5905 RxpAcquirePrefixTableLockExclusive(
5906    PRX_PREFIX_TABLE pTable,
5907    BOOLEAN Wait,
5908    BOOLEAN ProcessBufferingStateChangeRequests)
5909 {
5910     PAGED_CODE();
5911 
5912     DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
5913            pTable->TableLock.ActiveEntries);
5914 
5915     return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait);
5916 }
5917 
5918 /*
5919  * @implemented
5920  */
5921 BOOLEAN
5922 RxpDereferenceAndFinalizeNetFcb(
5923     OUT PFCB ThisFcb,
5924     IN PRX_CONTEXT RxContext,
5925     IN BOOLEAN RecursiveFinalize,
5926     IN BOOLEAN ForceFinalize)
5927 {
5928     NTSTATUS Status;
5929     ULONG References;
5930     PNET_ROOT NetRoot;
5931     BOOLEAN ResourceAcquired, NetRootReferenced, Freed;
5932 
5933     PAGED_CODE();
5934 
5935     ASSERT(!ForceFinalize);
5936     ASSERT(NodeTypeIsFcb(ThisFcb));
5937     ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
5938 
5939     /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5940     References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount);
5941     if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1))
5942     {
5943         return FALSE;
5944     }
5945 
5946     Freed = FALSE;
5947     Status = STATUS_SUCCESS;
5948     NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
5949     ResourceAcquired = FALSE;
5950     NetRootReferenced = FALSE;
5951     /* If FCB isn't orphaned, it still have context attached */
5952     if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
5953     {
5954         /* Don't let NetRoot go away before we're done */
5955         RxReferenceNetRoot(NetRoot);
5956         NetRootReferenced = TRUE;
5957 
5958         /* Try to acquire the table lock exclusively */
5959         if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable))
5960         {
5961             RxReferenceNetFcb(ThisFcb);
5962 
5963             if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
5964             {
5965                 if (RxContext != NULL && RxContext != CHANGE_BUFFERING_STATE_CONTEXT &&
5966                     RxContext != CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
5967                 {
5968                     RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
5969                 }
5970 
5971                 RxReleaseFcb(RxContext, ThisFcb);
5972 
5973                 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
5974 
5975                 Status = RxAcquireExclusiveFcb(RxContext, ThisFcb);
5976             }
5977 
5978             References = RxDereferenceNetFcb(ThisFcb);
5979 
5980             ResourceAcquired = TRUE;
5981         }
5982     }
5983 
5984     /* If locking was OK (or not needed!), attempt finalization */
5985     if (Status == STATUS_SUCCESS)
5986     {
5987         Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
5988     }
5989 
5990     /* Release table lock if acquired */
5991     if (ResourceAcquired)
5992     {
5993         RxReleaseFcbTableLock(&NetRoot->FcbTable);
5994     }
5995 
5996     /* We don't need the NetRoot anylonger */
5997     if (NetRootReferenced)
5998     {
5999         RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld);
6000     }
6001 
6002     return Freed;
6003 }
6004 
6005 /*
6006  * @implemented
6007  */
6008 LONG
6009 RxpDereferenceNetFcb(
6010    PFCB Fcb)
6011 {
6012     LONG NewCount;
6013 
6014     PAGED_CODE();
6015 
6016     ASSERT(NodeTypeIsFcb(Fcb));
6017 
6018     NewCount = InterlockedDecrement((volatile long *)&Fcb->NodeReferenceCount);
6019     ASSERT(NewCount >= 0);
6020 
6021     PRINT_REF_COUNT(NETFCB, NewCount);
6022 
6023     return NewCount;
6024 }
6025 
6026 /*
6027  * @implemented
6028  */
6029 VOID
6030 NTAPI
6031 RxpDestroySrvCall(
6032     IN PVOID Context)
6033 {
6034     NTSTATUS Status;
6035     PSRV_CALL SrvCall;
6036     BOOLEAN ForceFinalize;
6037     PRX_PREFIX_TABLE PrefixTable;
6038 
6039     SrvCall = (PSRV_CALL)Context;
6040     /* At this step, RxFinalizeSrvCall already cleaned some fields */
6041     ASSERT(SrvCall->UpperFinalizationDone);
6042 
6043     PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
6044     /* Were we called with ForceFinalize? */
6045     ForceFinalize = BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
6046 
6047     /* Notify mini-rdr */
6048     MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch,
6049                          MRxFinalizeSrvCall, ((PMRX_SRV_CALL)SrvCall,
6050                          ForceFinalize));
6051     (void)Status;
6052 
6053     /* Dereference our extra reference (set before queueing) */
6054     RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
6055     InterlockedDecrement((volatile long *)&SrvCall->NodeReferenceCount);
6056     /* And finalize for real, with the right context */
6057     RxFinalizeSrvCall(SrvCall, FALSE, ForceFinalize);
6058     RxReleasePrefixTableLock(PrefixTable);
6059 }
6060 
6061 /*
6062  * @implemented
6063  */
6064 VOID
6065 RxpDiscardChangeBufferingStateRequests(
6066     _Inout_ PLIST_ENTRY DiscardedRequests)
6067 {
6068     PLIST_ENTRY Entry;
6069 
6070     PAGED_CODE();
6071 
6072     /* No requests to discard */
6073     if (IsListEmpty(DiscardedRequests))
6074     {
6075         return;
6076     }
6077 
6078     /* Free all the discarded requests */
6079     Entry = DiscardedRequests->Flink;
6080     while (Entry != DiscardedRequests)
6081     {
6082         PCHANGE_BUFFERING_STATE_REQUEST Request;
6083 
6084         Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
6085         Entry = Entry->Flink;
6086 
6087         DPRINT("Req %p for %p (%p) discarded\n", Request, Request->SrvOpenKey, Request->SrvOpen);
6088 
6089         RxPrepareRequestForReuse(Request);
6090         RxFreePool(Request);
6091     }
6092 }
6093 
6094 /*
6095  * @implemented
6096  */
6097 VOID
6098 RxpDispatchChangeBufferingStateRequests(
6099     PSRV_CALL SrvCall,
6100     PSRV_OPEN SrvOpen,
6101     PLIST_ENTRY DiscardedRequests)
6102 {
6103     KIRQL OldIrql;
6104     NTSTATUS Status;
6105     BOOLEAN StartDispatcher;
6106     LIST_ENTRY AcceptedReqs;
6107     LIST_ENTRY DispatcherList;
6108     PRX_BUFFERING_MANAGER BufferingManager;
6109 
6110     /* Initialize our lists */
6111     InitializeListHead(&AcceptedReqs);
6112     InitializeListHead(DiscardedRequests);
6113 
6114     /* Transfer the requests to dispatch locally */
6115     BufferingManager = &SrvCall->BufferingManager;
6116     KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
6117     RxTransferList(&DispatcherList, &BufferingManager->DispatcherList);
6118     KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
6119 
6120     /* If there were requests */
6121     if (!IsListEmpty(&DispatcherList))
6122     {
6123         PLIST_ENTRY Entry;
6124 
6125         /* For each of the entries... */
6126         Entry = DispatcherList.Flink;
6127         while (Entry != &DispatcherList)
6128         {
6129             PCHANGE_BUFFERING_STATE_REQUEST Request;
6130 
6131             Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
6132             Entry = Entry->Flink;
6133 
6134             /* If we have been provided a SRV_OPEN, see whether it matches */
6135             if (SrvOpen != NULL)
6136             {
6137                 /* Match, the request is accepted */
6138                 if (Request->SrvOpenKey == SrvOpen->Key)
6139                 {
6140                     Request->SrvOpen = SrvOpen;
6141                     RxReferenceSrvOpen(SrvOpen);
6142 
6143                     RemoveEntryList(&Request->ListEntry);
6144                     InsertTailList(&AcceptedReqs, &Request->ListEntry);
6145 
6146                     /* Move to the next entry */
6147                     continue;
6148                 }
6149                 else
6150                 {
6151                     Status = STATUS_PENDING;
6152                 }
6153             }
6154             else
6155             {
6156                 /* No SRV_OPEN provided, try to find one */
6157                 Status = RxpLookupSrvOpenForRequestLite(SrvCall, Request);
6158             }
6159 
6160             /* We found a matching SRV_OPEN, accept the request */
6161             if (Status == STATUS_SUCCESS)
6162             {
6163                 RemoveEntryList(&Request->ListEntry);
6164                 InsertTailList(&AcceptedReqs, &Request->ListEntry);
6165             }
6166             /* Another run might help handling it, don't discard it */
6167             else if (Status == STATUS_PENDING)
6168             {
6169                 continue;
6170             }
6171             /* Otherwise, discard the request */
6172             else
6173             {
6174                 ASSERT(Status == STATUS_NOT_FOUND);
6175 
6176                 RemoveEntryList(&Request->ListEntry);
6177                 InsertTailList(DiscardedRequests, &Request->ListEntry);
6178             }
6179         }
6180     }
6181 
6182     KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
6183     /* Nothing to dispatch, no need to start dispatcher */
6184     if (IsListEmpty(&DispatcherList))
6185     {
6186         StartDispatcher = FALSE;
6187     }
6188     else
6189     {
6190         /* Transfer back the list of the not treated entries to the buffering manager */
6191         RxTransferList(&BufferingManager->DispatcherList, &DispatcherList);
6192         StartDispatcher = (BufferingManager->DispatcherActive == FALSE);
6193         /* If the dispatcher isn't active, start it */
6194         if (StartDispatcher)
6195         {
6196             BufferingManager->DispatcherActive = TRUE;
6197         }
6198     }
6199 
6200     /* If there were accepted requests, move them to the buffering manager */
6201     if (!IsListEmpty(&AcceptedReqs))
6202     {
6203         RxTransferList(&BufferingManager->HandlerList, &AcceptedReqs);
6204     }
6205     KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
6206 
6207     /* If we're to start the dispatcher, do it */
6208     if (StartDispatcher)
6209     {
6210         RxReferenceSrvCall(SrvCall);
6211         DPRINT("Starting dispatcher\n");
6212         RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
6213                              &BufferingManager->DispatcherWorkItem,
6214                              RxDispatchChangeBufferingStateRequests, SrvCall);
6215     }
6216 }
6217 
6218 /*
6219  * @implemented
6220  */
6221 NTSTATUS
6222 RxpLookupSrvOpenForRequestLite(
6223     IN PSRV_CALL SrvCall,
6224     IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request)
6225 {
6226     NTSTATUS Status;
6227     PLIST_ENTRY Entry;
6228     PSRV_OPEN SrvOpen;
6229 
6230     PAGED_CODE();
6231 
6232     Status = STATUS_SUCCESS;
6233     /* Browse all our associated SRV_OPENs to find the one! */
6234     for (Entry = SrvCall->BufferingManager.SrvOpenLists[0].Flink;
6235          Entry != &SrvCall->BufferingManager.SrvOpenLists[0];
6236          Entry = Entry->Flink)
6237     {
6238         /* Same key, not orphaned, this is ours */
6239         SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenKeyList);
6240         if (SrvOpen->Key == Request->SrvOpenKey)
6241         {
6242             if (!BooleanFlagOn(SrvOpen->pFcb->FcbState, FCB_STATE_ORPHANED))
6243             {
6244                 RxReferenceSrvOpen(SrvOpen);
6245                 break;
6246             }
6247         }
6248     }
6249 
6250     /* We didn't manage to find a SRV_OPEN */
6251     if (Entry == &SrvCall->BufferingManager.SrvOpenLists[0])
6252     {
6253         SrvOpen = NULL;
6254 
6255         /* The coming open might help, mark as pending for later retry */
6256         if (SrvCall->BufferingManager.NumberOfOutstandingOpens != 0)
6257         {
6258             Status = STATUS_PENDING;
6259         }
6260         /* Else, it's a complete failure */
6261         else
6262         {
6263             Status = STATUS_NOT_FOUND;
6264         }
6265     }
6266 
6267     /* Return the (not) found SRV_OPEN */
6268     Request->SrvOpen = SrvOpen;
6269 
6270     return Status;
6271 }
6272 
6273 /*
6274  * @implemented
6275  */
6276 VOID
6277 RxpMarkInstanceForScavengedFinalization(
6278    PVOID Instance)
6279 {
6280     NODE_TYPE_CODE NodeType;
6281     PNODE_TYPE_AND_SIZE Node;
6282     PRDBSS_SCAVENGER Scavenger;
6283     PRDBSS_DEVICE_OBJECT DeviceObject;
6284     PLIST_ENTRY ScavengerHead, InstEntry;
6285 
6286     PAGED_CODE();
6287 
6288     /* If still referenced, don't mark it (broken caller) */
6289     Node = (PNODE_TYPE_AND_SIZE)Instance;
6290     if (Node->NodeReferenceCount > 1)
6291     {
6292         return;
6293     }
6294 
6295     DeviceObject = RxGetDeviceObjectOfInstance(Instance);
6296     Scavenger = DeviceObject->pRdbssScavenger;
6297 
6298     /* Mark the node */
6299     NodeType = NodeType(Instance);
6300     SetFlag(NodeType(Node), RX_SCAVENGER_MASK);
6301     DPRINT("Node %p has now the scavenger mark!\n", Instance);
6302 
6303     /* Increase the count in the scavenger, and queue it */
6304     ScavengerHead = NULL;
6305     switch (NodeType)
6306     {
6307         case RDBSS_NTC_FOBX:
6308             ++Scavenger->FobxsToBeFinalized;
6309             ScavengerHead = &Scavenger->FobxFinalizationList;
6310             InstEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
6311             break;
6312 
6313         case RDBSS_NTC_SRVCALL:
6314             ++Scavenger->SrvCallsToBeFinalized;
6315             ScavengerHead = &Scavenger->SrvCallFinalizationList;
6316             InstEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
6317             break;
6318 
6319         case RDBSS_NTC_NETROOT:
6320             ++Scavenger->NetRootsToBeFinalized;
6321             ScavengerHead = &Scavenger->NetRootFinalizationList;
6322             InstEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
6323             break;
6324 
6325         case RDBSS_NTC_V_NETROOT:
6326             ++Scavenger->VNetRootsToBeFinalized;
6327             ScavengerHead = &Scavenger->VNetRootFinalizationList;
6328             InstEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
6329             break;
6330 
6331         case RDBSS_NTC_SRVOPEN:
6332             ++Scavenger->SrvOpensToBeFinalized;
6333             ScavengerHead = &Scavenger->SrvOpenFinalizationList;
6334             InstEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
6335             break;
6336     }
6337 
6338     /* Extra ref for scavenger */
6339     InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
6340 
6341     /* If matching type */
6342     if (ScavengerHead != NULL)
6343     {
6344         /* Insert in the scavenger list */
6345         InsertTailList(ScavengerHead, InstEntry);
6346 
6347         /* And if it wasn't started, start it */
6348         if (Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
6349         {
6350             Scavenger->State = RDBSS_SCAVENGER_DORMANT;
6351             RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
6352                                       RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
6353         }
6354     }
6355 }
6356 
6357 /*
6358  * @implemented
6359  */
6360 NTSTATUS
6361 NTAPI
6362 RxPostOneShotTimerRequest(
6363     IN PRDBSS_DEVICE_OBJECT pDeviceObject,
6364     IN PRX_WORK_ITEM pWorkItem,
6365     IN PRX_WORKERTHREAD_ROUTINE Routine,
6366     IN PVOID pContext,
6367     IN LARGE_INTEGER TimeInterval)
6368 {
6369     KIRQL OldIrql;
6370 
6371     ASSERT(pWorkItem != NULL);
6372 
6373     /* Prepare the work item */
6374     ExInitializeWorkItem(&pWorkItem->WorkQueueItem, Routine, pContext);
6375     pWorkItem->WorkQueueItem.pDeviceObject = pDeviceObject;
6376 
6377     /* Last tick can be computed with the number of times it was caller (timertickcount)
6378      * and the interval between calls
6379      */
6380     KeAcquireSpinLock(&RxTimerLock, &OldIrql);
6381     pWorkItem->LastTick = (TimeInterval.QuadPart / 550000) + RxTimerTickCount + 1;
6382     /* Insert in work queue */
6383     InsertTailList(&RxTimerQueueHead, &pWorkItem->WorkQueueItem.List);
6384     KeReleaseSpinLock(&RxTimerLock, OldIrql);
6385 
6386     /* If there are queued events, queue an execution */
6387     if (IsListEmpty(&RxTimerQueueHead))
6388     {
6389         KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
6390     }
6391 
6392     return STATUS_SUCCESS;
6393 }
6394 
6395 /*
6396  * @implemented
6397  */
6398 NTSTATUS
6399 NTAPI
6400 RxPostToWorkerThread(
6401     _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
6402     _In_ WORK_QUEUE_TYPE WorkQueueType,
6403     _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem,
6404     _In_ PRX_WORKERTHREAD_ROUTINE Routine,
6405     _In_ PVOID pContext)
6406 {
6407     /* Initialize work queue item */
6408     pWorkQueueItem->List.Flink = NULL;
6409     pWorkQueueItem->WorkerRoutine = Routine;
6410     pWorkQueueItem->Parameter = pContext;
6411 
6412     /* And insert it in the work queue */
6413     return RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, pWorkQueueItem);
6414 }
6415 
6416 VOID
6417 RxpProcessChangeBufferingStateRequests(
6418     PSRV_CALL SrvCall,
6419     BOOLEAN UpdateHandlerState)
6420 {
6421     UNIMPLEMENTED;
6422 }
6423 
6424 /*
6425  * @implemented
6426  */
6427 PRX_PREFIX_ENTRY
6428 RxPrefixTableInsertName(
6429     IN OUT PRX_PREFIX_TABLE ThisTable,
6430     IN OUT PRX_PREFIX_ENTRY ThisEntry,
6431     IN PVOID Container,
6432     IN PULONG ContainerRefCount,
6433     IN USHORT CaseInsensitiveLength,
6434     IN PRX_CONNECTION_ID ConnectionId
6435     )
6436 {
6437     PAGED_CODE();
6438 
6439     DPRINT("Insert: %wZ\n", &ThisEntry->Prefix);
6440 
6441     ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
6442     ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length);
6443 
6444     /* Copy parameters and compute hash */
6445     ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength;
6446     ThisEntry->ContainingRecord = Container;
6447     ThisEntry->ContainerRefCount = ContainerRefCount;
6448     InterlockedIncrement((volatile long *)ContainerRefCount);
6449     ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix);
6450     DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue);
6451 
6452     /* If no path length: this is entry for null path */
6453     if (ThisEntry->Prefix.Length == 0)
6454     {
6455         ThisTable->TableEntryForNull = ThisEntry;
6456     }
6457     /* Otherwise, insert in the appropriate bucket */
6458     else
6459     {
6460         InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks);
6461     }
6462 
6463     /* If we had a connection ID, keep track of it */
6464     if (ConnectionId != NULL)
6465     {
6466         ThisEntry->ConnectionId.Luid = ConnectionId->Luid;
6467     }
6468     else
6469     {
6470         ThisEntry->ConnectionId.Luid.LowPart = 0;
6471         ThisEntry->ConnectionId.Luid.HighPart = 0;
6472     }
6473 
6474     InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks);
6475     /* Reflect the changes */
6476     ++ThisTable->Version;
6477 
6478     DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue));
6479 
6480     return ThisEntry;
6481 }
6482 
6483 /*
6484  * @implemented
6485  */
6486 PVOID
6487 RxPrefixTableLookupName(
6488     IN PRX_PREFIX_TABLE ThisTable,
6489     IN PUNICODE_STRING CanonicalName,
6490     OUT PUNICODE_STRING RemainingName,
6491     IN PRX_CONNECTION_ID ConnectionId)
6492 {
6493     PVOID Container;
6494 
6495     PAGED_CODE();
6496 
6497     ASSERT(RxIsPrefixTableLockAcquired(ThisTable));
6498     ASSERT(CanonicalName->Length > 0);
6499 
6500     /* Call the internal helper */
6501     Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId);
6502     if (Container == NULL)
6503     {
6504         return NULL;
6505     }
6506 
6507     /* Reference our container before returning it */
6508     if (RdbssReferenceTracingValue != 0)
6509     {
6510         NODE_TYPE_CODE Type;
6511 
6512         Type = (NodeType(Container) & ~RX_SCAVENGER_MASK);
6513         switch (Type)
6514         {
6515             case RDBSS_NTC_SRVCALL:
6516                 RxReferenceSrvCall(Container);
6517                 break;
6518 
6519             case RDBSS_NTC_NETROOT:
6520                 RxReferenceNetRoot(Container);
6521                 break;
6522 
6523             case RDBSS_NTC_V_NETROOT:
6524                 RxReferenceVNetRoot(Container);
6525                 break;
6526 
6527             default:
6528                 DPRINT1("Invalid node type: %x\n", Type);
6529                 ASSERT(FALSE);
6530                 RxReference(Container);
6531                 break;
6532         }
6533     }
6534     else
6535     {
6536         RxReference(Container);
6537     }
6538 
6539     return Container;
6540 }
6541 
6542 /*
6543  * @implemented
6544  */
6545 LONG
6546 RxpReferenceNetFcb(
6547    PFCB Fcb)
6548 {
6549     LONG NewCount;
6550 
6551     PAGED_CODE();
6552 
6553     ASSERT(NodeTypeIsFcb(Fcb));
6554 
6555     NewCount = InterlockedIncrement((volatile long *)&Fcb->NodeReferenceCount);
6556 
6557     PRINT_REF_COUNT(NETFCB, Fcb->NodeReferenceCount);
6558 
6559     return NewCount;
6560 }
6561 
6562 /*
6563  * @implemented
6564  */
6565 VOID
6566 RxpReleasePrefixTableLock(
6567    PRX_PREFIX_TABLE pTable,
6568    BOOLEAN ProcessBufferingStateChangeRequests)
6569 {
6570     PAGED_CODE();
6571 
6572     DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
6573            pTable->TableLock.ActiveEntries);
6574 
6575     ExReleaseResourceLite(&pTable->TableLock);
6576 }
6577 
6578 /*
6579  * @implemented
6580  */
6581 VOID
6582 NTAPI
6583 RxPrepareContextForReuse(
6584    IN OUT PRX_CONTEXT RxContext)
6585 {
6586     PAGED_CODE();
6587 
6588     /* When we reach that point, make sure mandatory parts are null-ed */
6589     if (RxContext->MajorFunction == IRP_MJ_CREATE)
6590     {
6591         ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
6592         RxContext->Create.RdrFlags = 0;
6593     }
6594     else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
6595     {
6596         ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
6597         ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
6598     }
6599 
6600     RxContext->ReferenceCount = 0;
6601 }
6602 
6603 /*
6604  * @implemented
6605  */
6606 VOID
6607 RxPrepareRequestForReuse(
6608     PCHANGE_BUFFERING_STATE_REQUEST Request)
6609 {
6610     PSRV_OPEN SrvOpen;
6611 
6612     PAGED_CODE();
6613 
6614     SrvOpen = Request->SrvOpen;
6615 
6616     /* If the request was already prepared for service */
6617     if (BooleanFlagOn(Request->Flags, RX_REQUEST_PREPARED_FOR_HANDLING))
6618     {
6619         /* We have to dereference the associated SRV_OPEN depending on the lock */
6620         if (RxIsFcbAcquiredExclusive(SrvOpen->pFcb))
6621         {
6622             RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
6623         }
6624         else
6625         {
6626             RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
6627         }
6628     }
6629     /* Otherwise, just dereference */
6630     else if (SrvOpen != NULL)
6631     {
6632         RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
6633     }
6634 
6635     Request->SrvOpen = NULL;
6636 }
6637 
6638 /*
6639  * @implemented
6640  */
6641 VOID
6642 NTAPI
6643 RxProcessChangeBufferingStateRequests(
6644     _In_ PVOID SrvCall)
6645 {
6646     /* Call internal routine */
6647     RxUndoScavengerFinalizationMarking(SrvCall);
6648     RxpProcessChangeBufferingStateRequests(SrvCall, TRUE);
6649 }
6650 
6651 /*
6652  * @implemented
6653  */
6654 VOID
6655 RxProcessChangeBufferingStateRequestsForSrvOpen(
6656     PSRV_OPEN SrvOpen)
6657 {
6658     LONG NumberOfBufferingChangeRequests, LockedOldBufferingToken, OldBufferingToken;
6659 
6660     /* Get the current number of change requests */
6661     NumberOfBufferingChangeRequests = ((PSRV_CALL)SrvOpen->pVNetRoot->pNetRoot->pSrvCall)->BufferingManager.CumulativeNumberOfBufferingChangeRequests;
6662     /* Get our old token */
6663     OldBufferingToken = SrvOpen->BufferingToken;
6664     LockedOldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken,
6665                                                          NumberOfBufferingChangeRequests,
6666                                                          NumberOfBufferingChangeRequests);
6667     /* If buffering state changed in between, process changes */
6668     if (OldBufferingToken != LockedOldBufferingToken)
6669     {
6670         PFCB Fcb;
6671         NTSTATUS Status;
6672 
6673         /* Acquire the FCB and start processing */
6674         Fcb = (PFCB)SrvOpen->pFcb;
6675         Status = RxAcquireExclusiveFcb(NULL, Fcb);
6676         if (Status == STATUS_SUCCESS)
6677         {
6678             RxProcessFcbChangeBufferingStateRequest(Fcb);
6679             RxReleaseFcb(NULL, Fcb);
6680         }
6681     }
6682 }
6683 
6684 VOID
6685 RxProcessFcbChangeBufferingStateRequest(
6686     PFCB Fcb)
6687 {
6688     UNIMPLEMENTED;
6689 }
6690 
6691 /*
6692  * @implemented
6693  */
6694 VOID
6695 RxpScavengeFobxs(
6696     PRDBSS_SCAVENGER Scavenger,
6697     PLIST_ENTRY FobxToScavenge)
6698 {
6699     /* Explore the whole list of FOBX to scavenge */
6700     while (!IsListEmpty(FobxToScavenge))
6701     {
6702         PFCB Fcb;
6703         PFOBX Fobx;
6704         PLIST_ENTRY Entry;
6705 
6706         Entry = RemoveHeadList(FobxToScavenge);
6707         Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
6708         Fcb = (PFCB)Fobx->SrvOpen->pFcb;
6709 
6710         /* Try to acquire the lock exclusively to perform finalization */
6711         if (RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS)
6712         {
6713             RxDereferenceNetRoot(Fobx, LHS_LockNotHeld);
6714         }
6715         else
6716         {
6717             RxReferenceNetFcb(Fcb);
6718             RxDereferenceNetRoot(Fobx, LHS_ExclusiveLockHeld);
6719 
6720             if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
6721             {
6722                 RxReleaseFcb(NULL, Fcb);
6723             }
6724         }
6725     }
6726 }
6727 
6728 BOOLEAN
6729 RxpTrackDereference(
6730     _In_ ULONG TraceType,
6731     _In_ PCSTR FileName,
6732     _In_ ULONG Line,
6733     _In_ PVOID Instance)
6734 {
6735     PCSTR InstanceType;
6736     ULONG ReferenceCount;
6737 
6738     PAGED_CODE();
6739 
6740     if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
6741     {
6742         return TRUE;
6743     }
6744 
6745     switch (TraceType)
6746     {
6747         case RDBSS_REF_TRACK_SRVCALL:
6748             InstanceType = "SrvCall";
6749             ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount;
6750             break;
6751 
6752         case RDBSS_REF_TRACK_NETROOT:
6753             InstanceType = "NetRoot";
6754             ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount;
6755             break;
6756 
6757         case RDBSS_REF_TRACK_VNETROOT:
6758             InstanceType = "VNetRoot";
6759             ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount;
6760             break;
6761 
6762         case RDBSS_REF_TRACK_NETFOBX:
6763             InstanceType = "NetFobx";
6764             ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount;
6765             break;
6766 
6767         case RDBSS_REF_TRACK_NETFCB:
6768             InstanceType = "NetFcb";
6769             ReferenceCount = ((PFCB)Instance)->NodeReferenceCount;
6770             break;
6771 
6772         case RDBSS_REF_TRACK_SRVOPEN:
6773             InstanceType = "SrvOpen";
6774             ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount;
6775             break;
6776 
6777         default:
6778             DPRINT1("Invalid node type!\n");
6779             return TRUE;
6780     }
6781 
6782     if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING))
6783     {
6784         UNIMPLEMENTED;
6785     }
6786 
6787     if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING))
6788     {
6789         DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount);
6790     }
6791 
6792     return TRUE;
6793 }
6794 
6795 VOID
6796 RxpTrackReference(
6797     _In_ ULONG TraceType,
6798     _In_ PCSTR FileName,
6799     _In_ ULONG Line,
6800     _In_ PVOID Instance)
6801 {
6802     PCSTR InstanceType;
6803     ULONG ReferenceCount;
6804 
6805     if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
6806     {
6807         return;
6808     }
6809 
6810     switch (TraceType)
6811     {
6812         case RDBSS_REF_TRACK_SRVCALL:
6813             InstanceType = "SrvCall";
6814             ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount;
6815             break;
6816 
6817         case RDBSS_REF_TRACK_NETROOT:
6818             InstanceType = "NetRoot";
6819             ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount;
6820             break;
6821 
6822         case RDBSS_REF_TRACK_VNETROOT:
6823             InstanceType = "VNetRoot";
6824             ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount;
6825             break;
6826 
6827         case RDBSS_REF_TRACK_NETFOBX:
6828             InstanceType = "NetFobx";
6829             ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount;
6830             break;
6831 
6832         case RDBSS_REF_TRACK_NETFCB:
6833             InstanceType = "NetFcb";
6834             ReferenceCount = ((PFCB)Instance)->NodeReferenceCount;
6835             break;
6836 
6837         case RDBSS_REF_TRACK_SRVOPEN:
6838             InstanceType = "SrvOpen";
6839             ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount;
6840             break;
6841 
6842         default:
6843             DPRINT1("Invalid node type!\n");
6844             return;
6845     }
6846 
6847     if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING))
6848     {
6849         UNIMPLEMENTED;
6850     }
6851 
6852     if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING))
6853     {
6854         DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount);
6855     }
6856 }
6857 
6858 /*
6859  * @implemented
6860  */
6861 VOID
6862 RxpUndoScavengerFinalizationMarking(
6863    PVOID Instance)
6864 {
6865     PLIST_ENTRY ListEntry;
6866     PNODE_TYPE_AND_SIZE Node;
6867     PRDBSS_SCAVENGER Scavenger;
6868 
6869     PAGED_CODE();
6870 
6871     Node = (PNODE_TYPE_AND_SIZE)Instance;
6872     /* There's no marking - nothing to do */
6873     if (!BooleanFlagOn(NodeType(Node), RX_SCAVENGER_MASK))
6874     {
6875         return;
6876     }
6877 
6878     /* First of all, remove the mark */
6879     ClearFlag(NodeType(Node), RX_SCAVENGER_MASK);
6880     DPRINT("Node %p no longer has the scavenger mark\n");
6881 
6882     /* And now, remove from the scavenger */
6883     Scavenger = RxGetDeviceObjectOfInstance(Instance)->pRdbssScavenger;
6884     switch (NodeType(Node))
6885     {
6886         case RDBSS_NTC_FOBX:
6887             --Scavenger->FobxsToBeFinalized;
6888             ListEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
6889             break;
6890 
6891         case RDBSS_NTC_SRVCALL:
6892             --Scavenger->SrvCallsToBeFinalized;
6893             ListEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
6894             break;
6895 
6896         case RDBSS_NTC_NETROOT:
6897             --Scavenger->NetRootsToBeFinalized;
6898             ListEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
6899             break;
6900 
6901         case RDBSS_NTC_V_NETROOT:
6902             --Scavenger->VNetRootsToBeFinalized;
6903             ListEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
6904             break;
6905 
6906         case RDBSS_NTC_SRVOPEN:
6907             --Scavenger->SrvOpensToBeFinalized;
6908             ListEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
6909             break;
6910 
6911         default:
6912             return;
6913     }
6914 
6915     /* Also, remove the extra ref from the scavenger */
6916     RemoveEntryList(ListEntry);
6917     InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
6918 }
6919 
6920 /*
6921  * @implemented
6922  */
6923 VOID
6924 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6925     PSRV_OPEN SrvOpen)
6926 {
6927     PSRV_CALL SrvCall;
6928     LIST_ENTRY Discarded;
6929 
6930     PAGED_CODE();
6931 
6932     ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
6933 
6934     /* Initialize our discarded list */
6935     InitializeListHead(&Discarded);
6936 
6937     SrvCall = (PSRV_CALL)SrvOpen->Fcb->VNetRoot->pNetRoot->pSrvCall;
6938     RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
6939 
6940     /* Set the flag, and get the requests */
6941     InitializeListHead(&SrvOpen->SrvOpenKeyList);
6942     SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED);
6943     RxGatherRequestsForSrvOpen(SrvCall, SrvOpen, &Discarded);
6944 
6945     RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
6946 
6947     /* If there were discarded requests */
6948     if (!IsListEmpty(&Discarded))
6949     {
6950         /* And a pending buffering state change */
6951         if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
6952         {
6953             /* Clear the flag, and set the associated event - job done */
6954             RxAcquireSerializationMutex();
6955             ClearFlag(SrvOpen->Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
6956             if (SrvOpen->Fcb->pBufferingStateChangeCompletedEvent != NULL)
6957             {
6958                 KeSetEvent(SrvOpen->Fcb->pBufferingStateChangeCompletedEvent, IO_NETWORK_INCREMENT, FALSE);
6959             }
6960             RxReleaseSerializationMutex();
6961         }
6962 
6963         /* Drop the discarded requests */
6964         RxpDiscardChangeBufferingStateRequests(&Discarded);
6965     }
6966 }
6967 
6968 /*
6969  * @implemented
6970  */
6971 VOID
6972 RxPurgeFcb(
6973     IN  PFCB Fcb)
6974 {
6975     PAGED_CODE();
6976 
6977     ASSERT(RxIsFcbAcquiredExclusive(Fcb));
6978 
6979     /* Reference our FCB so that it doesn't disappear */
6980     RxReferenceNetFcb(Fcb);
6981     /* Purge Cc if required */
6982     if (Fcb->OpenCount != 0)
6983     {
6984         RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE);
6985     }
6986 
6987     /* If it wasn't freed, release the lock */
6988     if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
6989     {
6990         RxReleaseFcb(NULL, Fcb);
6991     }
6992 }
6993 
6994 /*
6995  * @implemented
6996  */
6997 NTSTATUS
6998 RxPurgeFcbInSystemCache(
6999     IN PFCB Fcb,
7000     IN PLARGE_INTEGER FileOffset OPTIONAL,
7001     IN ULONG Length,
7002     IN BOOLEAN UninitializeCacheMaps,
7003     IN BOOLEAN FlushFile)
7004 {
7005     BOOLEAN Purged;
7006     NTSTATUS Status;
7007 
7008     PAGED_CODE();
7009 
7010     ASSERT(RxIsFcbAcquiredExclusive(Fcb));
7011 
7012     /* Try to flush first, if asked */
7013     if (FlushFile)
7014     {
7015         /* If flushing failed, just make some noise */
7016         Status = RxFlushFcbInSystemCache(Fcb, TRUE);
7017         if (!NT_SUCCESS(Status))
7018         {
7019             PVOID CallersAddress, CallersCaller;
7020 
7021             RtlGetCallersAddress(&CallersAddress, &CallersCaller);
7022             DPRINT1("Flush failed with status %lx for FCB %p\n", Status, Fcb);
7023             DPRINT1("Caller was %p %p\n", CallersAddress, CallersCaller);
7024         }
7025     }
7026 
7027     /* Deal with Cc for purge */
7028     Purged = CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, FileOffset,
7029                                  Length, UninitializeCacheMaps);
7030     /* If purge failed, force section closing */
7031     if (!Purged)
7032     {
7033         MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
7034 
7035         RxReleaseFcb(NULL, Fcb);
7036         Purged = MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
7037         RxAcquireExclusiveFcb(NULL, Fcb);
7038     }
7039 
7040     /* Return appropriate status */
7041     Status = (Purged ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
7042     DPRINT("Purge for FCB %p returns %lx\n", Fcb, Status);
7043 
7044     return Status;
7045 }
7046 
7047 /*
7048  * @implemented
7049  */
7050 BOOLEAN
7051 RxPurgeFobx(
7052     PFOBX pFobx)
7053 {
7054     NTSTATUS Status;
7055     PFCB FcbToBePurged;
7056 
7057     PAGED_CODE();
7058 
7059     /* Get the associated FCB */
7060     FcbToBePurged = (PFCB)pFobx->pSrvOpen->pFcb;
7061     Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
7062     ASSERT(Status == STATUS_SUCCESS);
7063 
7064     /* Purge it */
7065     Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
7066     if (Status != STATUS_SUCCESS)
7067     {
7068         DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged, pFobx);
7069         return FALSE;
7070     }
7071 
7072     /* And flush */
7073     if (!MmFlushImageSection(&FcbToBePurged->NonPaged->SectionObjectPointers, MmFlushForWrite))
7074     {
7075         DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged, pFobx);
7076         return FALSE;
7077     }
7078 
7079     DPRINT("Purge OK for %p (%p)\n", FcbToBePurged, pFobx);
7080     return TRUE;
7081 }
7082 
7083 /*
7084  * @implemented
7085  */
7086 NTSTATUS
7087 RxPurgeFobxFromCache(
7088     PFOBX FobxToBePurged)
7089 {
7090     NTSTATUS Status;
7091     PFCB FcbToBePurged;
7092 
7093     PAGED_CODE();
7094 
7095     FcbToBePurged = (PFCB)FobxToBePurged->pSrvOpen->pFcb;
7096     ASSERT(FcbToBePurged != NULL);
7097 
7098     /* If we cannot have our FCB exclusively, give up */
7099     Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
7100     if (Status != STATUS_SUCCESS)
7101     {
7102         RxDereferenceNetFobx(FobxToBePurged, LHS_LockNotHeld);
7103         return Status;
7104     }
7105 
7106     /* Don't let the FCB disappear */
7107     RxReferenceNetFcb(FcbToBePurged);
7108 
7109     /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
7110     if (BooleanFlagOn(FobxToBePurged->Flags, FOBX_FLAG_SRVOPEN_CLOSED) || FobxToBePurged->pSrvOpen->UncleanFobxCount != 0)
7111     {
7112         DPRINT("FCB purge skipped\n");
7113     }
7114     else
7115     {
7116         Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
7117     }
7118 
7119     RxDereferenceNetFobx(FobxToBePurged, LHS_ExclusiveLockHeld);
7120     /* Drop our extra reference */
7121     if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged, NULL, FALSE, FALSE))
7122     {
7123         RxReleaseFcb(NULL, FcbToBePurged);
7124     }
7125 
7126     return Status;
7127 }
7128 
7129 /*
7130  * @implemented
7131  */
7132 NTSTATUS
7133 RxPurgeRelatedFobxs(
7134     PNET_ROOT NetRoot,
7135     PRX_CONTEXT RxContext,
7136     BOOLEAN AttemptFinalization,
7137     PFCB PurgingFcb)
7138 {
7139     PLIST_ENTRY Entry;
7140     ULONG SuccessfullPurge;
7141     PRDBSS_SCAVENGER Scavenger;
7142     PRDBSS_DEVICE_OBJECT RxDeviceObject;
7143     PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx;
7144 
7145     PAGED_CODE();
7146 
7147     RxDeviceObject = RxContext->RxDeviceObject;
7148     Scavenger = RxDeviceObject->pRdbssScavenger;
7149     PurgeSyncCtx = &NetRoot->PurgeSyncronizationContext;
7150 
7151     RxAcquireScavengerMutex();
7152 
7153     /* If there's already a purge in progress */
7154     if (PurgeSyncCtx->PurgeInProgress)
7155     {
7156         /* Add our RX_CONTEXT to the current run */
7157         InsertTailList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion,
7158                        &RxContext->RxContextSerializationQLinks);
7159 
7160         /* And wait until it's done */
7161         RxReleaseScavengerMutex();
7162         RxWaitSync(RxContext);
7163         RxAcquireScavengerMutex();
7164     }
7165 
7166     /* Start the purge */
7167     PurgeSyncCtx->PurgeInProgress = TRUE;
7168 
7169     /* While the purge is still handling our NET_ROOT, do nothing but wait */
7170     while (Scavenger->CurrentNetRootForClosePendingProcessing == NetRoot)
7171     {
7172         RxReleaseScavengerMutex();
7173         KeWaitForSingleObject(&Scavenger->ClosePendingProcessingSyncEvent, Executive,
7174                               KernelMode, TRUE, NULL);
7175         RxAcquireScavengerMutex();
7176     }
7177 
7178     /* Now, for all the entries */
7179     SuccessfullPurge = 0;
7180     Entry = Scavenger->ClosePendingFobxsList.Flink;
7181     while (Entry != &Scavenger->ClosePendingFobxsList)
7182     {
7183         PFCB Fcb;
7184         PFOBX Fobx;
7185         BOOLEAN Success;
7186 
7187         Fobx = CONTAINING_RECORD(Entry, FOBX, ClosePendingList);
7188         DPRINT("Dealing with FOBX: %p\n", Fobx);
7189 
7190         Entry = Entry->Flink;
7191 
7192         /* If it's not matching our NET_ROOT, ignore */
7193         if (Fobx->pSrvOpen == NULL ||
7194             Fobx->pSrvOpen->pFcb == NULL ||
7195             ((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot == NULL ||
7196             (PNET_ROOT)((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot->pNetRoot != NetRoot)
7197         {
7198             continue;
7199         }
7200 
7201         /* Determine if it matches our FCB */
7202         Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
7203         if (PurgingFcb != NULL && NodeType(PurgingFcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
7204             PurgingFcb != Fcb)
7205         {
7206             NTSTATUS Status;
7207 
7208             MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
7209             if (Status == STATUS_SUCCESS)
7210             {
7211                 continue;
7212             }
7213         }
7214 
7215         /* Matching, we'll purge it */
7216         RemoveEntryList(&Fobx->ClosePendingList);
7217 
7218         /* Reference it so that it doesn't disappear */
7219         RxReferenceNetFobx(Fobx);
7220 
7221         RxReleaseScavengerMutex();
7222 
7223         /* And purge */
7224         Success = RxPurgeFobx(Fobx);
7225         if (Success)
7226         {
7227             ++SuccessfullPurge;
7228         }
7229 
7230         /* If we don't have to finalize it (or if we cannot acquire lock exclusively
7231          * Just normally dereference
7232          */
7233         if ((AttemptFinalization == DONT_ATTEMPT_FINALIZE_ON_PURGE) ||
7234             RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS)
7235         {
7236             RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
7237         }
7238         /* Otherwise, finalize */
7239         else
7240         {
7241             RxReferenceNetFcb(Fcb);
7242             RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
7243             if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
7244             {
7245                 RxReleaseFcb(NULL, Fcb);
7246             }
7247         }
7248 
7249         if (!Success)
7250         {
7251             DPRINT1("Failed purging %p (%p)\n", Fcb, Fobx);
7252         }
7253 
7254         RxAcquireScavengerMutex();
7255     }
7256 
7257     /* If no contexts left, purge is not running */
7258     if (IsListEmpty(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion))
7259     {
7260         PurgeSyncCtx->PurgeInProgress = FALSE;
7261     }
7262     /* Otherwise, notify a waiter it can start */
7263     else
7264     {
7265         PRX_CONTEXT Context;
7266 
7267         Entry = RemoveHeadList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion);
7268         Context = CONTAINING_RECORD(Entry, RX_CONTEXT, RxContextSerializationQLinks);
7269 
7270         RxSignalSynchronousWaiter(Context);
7271     }
7272 
7273     RxReleaseScavengerMutex();
7274 
7275     return (SuccessfullPurge > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
7276 }
7277 
7278 /*
7279  * @implemented
7280  */
7281 VOID
7282 RxpWorkerThreadDispatcher(
7283    IN PRX_WORK_QUEUE WorkQueue,
7284    IN PLARGE_INTEGER WaitInterval)
7285 {
7286     NTSTATUS Status;
7287     PVOID Parameter;
7288     PETHREAD CurrentThread;
7289     BOOLEAN KillThread, Dereference;
7290     PRX_WORK_QUEUE_ITEM WorkQueueItem;
7291     PWORKER_THREAD_ROUTINE WorkerRoutine;
7292 
7293     InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
7294 
7295     /* Reference ourselves */
7296     CurrentThread = PsGetCurrentThread();
7297     Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
7298     ASSERT(NT_SUCCESS(Status));
7299 
7300     /* Infinite loop for worker */
7301     KillThread = FALSE;
7302     Dereference = FALSE;
7303     do
7304     {
7305         KIRQL OldIrql;
7306         PLIST_ENTRY ListEntry;
7307 
7308         /* Remove an entry from the work queue */
7309         ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval);
7310         if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT)
7311         {
7312             PRDBSS_DEVICE_OBJECT DeviceObject;
7313 
7314             WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List);
7315 
7316             InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched);
7317             InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
7318             InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
7319 
7320             /* Get the parameters, and null-them in the struct */
7321             WorkerRoutine = WorkQueueItem->WorkerRoutine;
7322             Parameter = WorkQueueItem->Parameter;
7323             DeviceObject = WorkQueueItem->pDeviceObject;
7324 
7325             WorkQueueItem->List.Flink = NULL;
7326             WorkQueueItem->WorkerRoutine = NULL;
7327             WorkQueueItem->Parameter = NULL;
7328             WorkQueueItem->pDeviceObject = NULL;
7329 
7330             /* Call the routine */
7331             DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter);
7332             WorkerRoutine(Parameter);
7333 
7334             /* Are we going down now? */
7335             if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0)
7336             {
7337                 PKEVENT TearDownEvent;
7338 
7339                 TearDownEvent = InterlockedExchangePointer((void * volatile*)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
7340                 if (TearDownEvent != NULL)
7341                 {
7342                     KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
7343                 }
7344             }
7345 
7346             InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
7347         }
7348 
7349         /* Shall we shutdown... */
7350         KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
7351         switch (WorkQueue->State)
7352         {
7353             /* Our queue is active, kill it if we have no more items to dispatch
7354              * and more threads than the required minimum
7355              */
7356             case RxWorkQueueActive:
7357                 if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0)
7358                 {
7359                     ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
7360                     if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
7361                     {
7362                         KillThread = TRUE;
7363                         Dereference = TRUE;
7364                         InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
7365                     }
7366 
7367                     if (KillThread)
7368                     {
7369                         InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
7370                     }
7371                 }
7372                 break;
7373 
7374             /* The queue is inactive: kill it we have more threads than the required minimum */
7375             case RxWorkQueueInactive:
7376                 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
7377                 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
7378                 {
7379                     KillThread = TRUE;
7380                     Dereference = TRUE;
7381                     InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
7382                 }
7383 
7384                 if (KillThread)
7385                 {
7386                     InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
7387                 }
7388                 break;
7389 
7390             /* Rundown in progress..., kill it for sure! */
7391             case RxWorkQueueRundownInProgress:
7392                 {
7393                     PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext;
7394 
7395                     ASSERT(WorkQueue->pRundownContext != NULL);
7396 
7397                     RundownContext = WorkQueue->pRundownContext;
7398                     RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread;
7399 
7400                     InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
7401                     KillThread = TRUE;
7402                     Dereference = FALSE;
7403 
7404                     if (WorkQueue->NumberOfActiveWorkerThreads == 0)
7405                     {
7406                         KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
7407                     }
7408 
7409                     InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
7410                 }
7411                 break;
7412 
7413             default:
7414                 break;
7415         }
7416         KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
7417     } while (!KillThread);
7418 
7419     DPRINT("Killed worker thread\n");
7420 
7421     /* Do we have to dereference ourselves? */
7422     if (Dereference)
7423     {
7424         ObDereferenceObject(CurrentThread);
7425     }
7426 
7427     /* Dump last executed routine */
7428     if (DumpDispatchRoutine)
7429     {
7430         DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
7431     }
7432 
7433     PsTerminateSystemThread(STATUS_SUCCESS);
7434 }
7435 
7436 VOID
7437 RxReference(
7438     IN OUT PVOID Instance)
7439 {
7440     NODE_TYPE_CODE NodeType;
7441     PNODE_TYPE_AND_SIZE Node;
7442 
7443     PAGED_CODE();
7444 
7445     RxAcquireScavengerMutex();
7446 
7447     /* We can only reference a few structs */
7448     NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK;
7449     ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
7450            (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
7451            (NodeType == RDBSS_NTC_FOBX));
7452 
7453     Node = (PNODE_TYPE_AND_SIZE)Instance;
7454     InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
7455 
7456     /* Trace refcount if asked */
7457     switch (NodeType)
7458     {
7459         case RDBSS_NTC_SRVCALL:
7460             PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
7461             break;
7462 
7463         case RDBSS_NTC_NETROOT:
7464             PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
7465             break;
7466 
7467         case RDBSS_NTC_V_NETROOT:
7468             PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
7469             break;
7470 
7471         case RDBSS_NTC_SRVOPEN:
7472             PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
7473             break;
7474 
7475         case RDBSS_NTC_FOBX:
7476             PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
7477             break;
7478 
7479         default:
7480             ASSERT(FALSE);
7481             break;
7482     }
7483 
7484     RxpUndoScavengerFinalizationMarking(Instance);
7485     RxReleaseScavengerMutex();
7486 }
7487 
7488 /*
7489  * @implemented
7490  */
7491 VOID
7492 NTAPI
7493 RxReinitializeContext(
7494    IN OUT PRX_CONTEXT RxContext)
7495 {
7496     PIRP Irp;
7497     PRDBSS_DEVICE_OBJECT RxDeviceObject;
7498     ULONG InitialContextFlags, SavedFlags;
7499 
7500     PAGED_CODE();
7501 
7502     /* Backup a few flags */
7503     Irp = RxContext->CurrentIrp;
7504     RxDeviceObject = RxContext->RxDeviceObject;
7505     SavedFlags = RxContext->Flags & RX_CONTEXT_PRESERVED_FLAGS;
7506     InitialContextFlags = RxContext->Flags & RX_CONTEXT_INITIALIZATION_FLAGS;
7507 
7508     /* Reset our context */
7509     RxPrepareContextForReuse(RxContext);
7510 
7511     /* Zero everything */
7512     RtlZeroMemory(&RxContext->MajorFunction, sizeof(RX_CONTEXT) - FIELD_OFFSET(RX_CONTEXT, MajorFunction));
7513 
7514     /* Restore saved flags */
7515     RxContext->Flags = SavedFlags;
7516     /* And reinit the context */
7517     RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, RxContext);
7518 }
7519 
7520 /*
7521  * @implemented
7522  */
7523 VOID
7524 NTAPI
7525 RxReleaseFcbFromLazyWrite(
7526     PVOID Context)
7527 {
7528     PFCB Fcb;
7529 
7530     PAGED_CODE();
7531 
7532     Fcb = Context;
7533     /* The received context is a FCB */
7534     ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
7535     ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
7536 
7537     /* Lazy writer is releasing lock, so forget about it */
7538     Fcb->Specific.Fcb.LazyWriteThread = NULL;
7539 
7540     /* If we were top level IRP, unwind */
7541     if (RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP)
7542     {
7543         RxUnwindTopLevelIrp(NULL);
7544     }
7545 
7546     /* And finally, release the lock */
7547     Fcb->PagingIoResourceFile = NULL;
7548     Fcb->PagingIoResourceLine = 0;
7549     ExReleaseResourceLite(Fcb->Header.PagingIoResource);
7550 }
7551 
7552 /*
7553  * @implemented
7554  */
7555 VOID
7556 NTAPI
7557 RxReleaseFcbFromReadAhead(
7558     PVOID Context)
7559 {
7560     PFCB Fcb;
7561 
7562     PAGED_CODE();
7563 
7564     Fcb = Context;
7565     /* The received context is a FCB */
7566     ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
7567     ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
7568 
7569     /* Top Level IRP is CC */
7570     ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
7571     RxUnwindTopLevelIrp(NULL);
7572 
7573     ExReleaseResourceLite(Fcb->Header.Resource);
7574 }
7575 
7576 VOID
7577 NTAPI
7578 RxReleaseFileForNtCreateSection(
7579     PFILE_OBJECT FileObject)
7580 {
7581     UNIMPLEMENTED;
7582 }
7583 
7584 NTSTATUS
7585 NTAPI
7586 RxReleaseForCcFlush(
7587     PFILE_OBJECT FileObject,
7588     PDEVICE_OBJECT DeviceObject)
7589 {
7590     UNIMPLEMENTED;
7591     return STATUS_NOT_IMPLEMENTED;
7592 }
7593 
7594 /*
7595  * @implemented
7596  */
7597 VOID
7598 RxRemoveNameNetFcb(
7599     OUT PFCB ThisFcb)
7600 {
7601     PNET_ROOT NetRoot;
7602 
7603     PAGED_CODE();
7604 
7605     ASSERT(NodeTypeIsFcb(ThisFcb));
7606 
7607     /* Just remove the entry from the FCB_TABLE */
7608     NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
7609     ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
7610     ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
7611 
7612 #ifdef __REACTOS__
7613     if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
7614     {
7615 #endif
7616         RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
7617         DPRINT("FCB (%p) %wZ removed\n", ThisFcb, &ThisFcb->FcbTableEntry.Path);
7618         /* Mark, so that we don't try to do it twice */
7619         SetFlag(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED);
7620 #ifdef __REACTOS__
7621     }
7622 #endif
7623 }
7624 
7625 /*
7626  * @implemented
7627  */
7628 VOID
7629 RxRemoveOperationFromBlockingQueue(
7630     IN OUT PRX_CONTEXT RxContext)
7631 {
7632     /* Acquire the pipe mutex */
7633     ExAcquireFastMutex(&RxContextPerFileSerializationMutex);
7634 
7635     /* Is that a blocking serial operation? */
7636     if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7637     {
7638         /* Clear it! */
7639         ClearFlag(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
7640 
7641         /* Drop it off the list */
7642         RemoveEntryList(&RxContext->RxContextSerializationQLinks);
7643         RxContext->RxContextSerializationQLinks.Flink = NULL;
7644         RxContext->RxContextSerializationQLinks.Blink = NULL;
7645     }
7646 
7647     /* Done */
7648     ExReleaseFastMutex(&RxContextPerFileSerializationMutex);
7649 }
7650 
7651 /*
7652  * @implemented
7653  */
7654 VOID
7655 RxRemovePrefixTableEntry(
7656     IN OUT PRX_PREFIX_TABLE ThisTable,
7657     IN OUT PRX_PREFIX_ENTRY Entry)
7658 {
7659     PAGED_CODE();
7660 
7661     ASSERT(NodeType(Entry) == RDBSS_NTC_PREFIX_ENTRY);
7662     ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
7663 
7664     /* Check whether we're asked to remove null entry */
7665     if (Entry->Prefix.Length == 0)
7666     {
7667         ThisTable->TableEntryForNull = NULL;
7668     }
7669     else
7670     {
7671         RemoveEntryList(&Entry->HashLinks);
7672     }
7673 
7674     Entry->ContainingRecord = NULL;
7675 
7676     /* Also remove it from global list */
7677     RemoveEntryList(&Entry->MemberQLinks);
7678 
7679     ++ThisTable->Version;
7680 }
7681 
7682 /*
7683  * @implemented
7684  */
7685 VOID
7686 RxRemoveVirtualNetRootFromNetRoot(
7687     PNET_ROOT NetRoot,
7688     PV_NET_ROOT VNetRoot)
7689 {
7690     PRX_PREFIX_TABLE PrefixTable;
7691 
7692     PAGED_CODE();
7693 
7694     PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
7695     ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
7696 
7697     /* Remove the VNetRoot from the list in the NetRoot */
7698     --NetRoot->NumberOfVirtualNetRoots;
7699     RemoveEntryList(&VNetRoot->NetRootListEntry);
7700 
7701     /* Fix the NetRoot if we were the default VNetRoot */
7702     if (NetRoot->DefaultVNetRoot == VNetRoot)
7703     {
7704         /* Put the first one available */
7705         if (!IsListEmpty(&NetRoot->VirtualNetRoots))
7706         {
7707             NetRoot->DefaultVNetRoot = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry);
7708         }
7709         /* Otherwise, none */
7710         else
7711         {
7712             NetRoot->DefaultVNetRoot = NULL;
7713         }
7714     }
7715 
7716     /* If there are still other VNetRoot available, we're done */
7717     if (!IsListEmpty(&NetRoot->VirtualNetRoots))
7718     {
7719         return;
7720     }
7721 
7722     /* Otherwise, initiate NetRoot finalization */
7723     if (!BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
7724     {
7725         RxRemovePrefixTableEntry(PrefixTable, &NetRoot->PrefixEntry);
7726         SetFlag(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED);
7727     }
7728 
7729     /* Notify mini-rdr */
7730     if (NetRoot->pSrvCall != NULL && NetRoot->pSrvCall->RxDeviceObject != NULL)
7731     {
7732         NTSTATUS Status;
7733 
7734         MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
7735                              MRxFinalizeNetRoot, ((PMRX_NET_ROOT)NetRoot, FALSE));
7736         (void)Status;
7737     }
7738 }
7739 
7740 VOID
7741 RxResumeBlockedOperations_ALL(
7742     IN OUT PRX_CONTEXT RxContext)
7743 {
7744     LIST_ENTRY BlockedOps;
7745 
7746     PAGED_CODE();
7747 
7748     /* Get the blocked operations */
7749     RxTransferListWithMutex(&BlockedOps, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex);
7750 
7751     if (!IsListEmpty(&BlockedOps))
7752     {
7753         UNIMPLEMENTED;
7754     }
7755 }
7756 
7757 VOID
7758 NTAPI
7759 RxResumeBlockedOperations_Serially(
7760     IN OUT PRX_CONTEXT RxContext,
7761     IN OUT PLIST_ENTRY BlockingIoQ)
7762 {
7763     PAGED_CODE();
7764 
7765     RxAcquireSerializationMutex();
7766 
7767     /* This can only happen on pipes */
7768     if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7769     {
7770         RxReleaseSerializationMutex();
7771         return;
7772     }
7773 
7774     UNIMPLEMENTED;
7775 
7776     RxReleaseSerializationMutex();
7777 }
7778 
7779 /*
7780  * @implemented
7781  */
7782 VOID
7783 RxSetFileSizeWithLock(
7784     IN OUT PFCB Fcb,
7785     IN PLONGLONG FileSize)
7786 {
7787     PAGED_CODE();
7788 
7789     /* Set attribute and increase version */
7790     Fcb->Header.FileSize.QuadPart = *FileSize;
7791     ++Fcb->ulFileSizeVersion;
7792 }
7793 
7794 /*
7795  * @implemented
7796  */
7797 VOID
7798 RxScavengeFobxsForNetRoot(
7799     PNET_ROOT NetRoot,
7800     PFCB PurgingFcb,
7801     BOOLEAN SynchronizeWithScavenger)
7802 {
7803     PRDBSS_SCAVENGER Scavenger;
7804     PRDBSS_DEVICE_OBJECT RxDeviceObject;
7805 
7806     PAGED_CODE();
7807 
7808     RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
7809     Scavenger = RxDeviceObject->pRdbssScavenger;
7810 
7811     /* Wait for the scavenger, if asked to */
7812     if (SynchronizeWithScavenger)
7813     {
7814         KeWaitForSingleObject(&Scavenger->ScavengeEvent, Executive, KernelMode, FALSE, NULL);
7815     }
7816 
7817     RxAcquireScavengerMutex();
7818 
7819     /* If there's nothing left to do... */
7820     if (Scavenger->FobxsToBeFinalized <= 0)
7821     {
7822         RxReleaseScavengerMutex();
7823     }
7824     else
7825     {
7826         PLIST_ENTRY Entry;
7827         LIST_ENTRY FobxToScavenge;
7828 
7829         InitializeListHead(&FobxToScavenge);
7830 
7831         /* Browse all the FOBXs to finalize */
7832         Entry = Scavenger->FobxFinalizationList.Flink;
7833         while (Entry != &Scavenger->FobxFinalizationList)
7834         {
7835             PFOBX Fobx;
7836 
7837             Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
7838             Entry = Entry->Flink;
7839 
7840             if (Fobx->SrvOpen != NULL)
7841             {
7842                 PFCB Fcb;
7843 
7844                 Fcb = (PFCB)Fobx->SrvOpen->pFcb;
7845 
7846                 /* If it matches our NET_ROOT */
7847                 if ((PNET_ROOT)Fcb->pNetRoot == NetRoot)
7848                 {
7849                     NTSTATUS Status;
7850 
7851                     /* Check whether it matches our FCB */
7852                     Status = STATUS_MORE_PROCESSING_REQUIRED;
7853                     if (PurgingFcb != NULL && PurgingFcb != Fcb)
7854                     {
7855                         MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
7856                     }
7857 
7858                     /* If so, add it to the list of the FOBXs to scavenge */
7859                     if (Status != STATUS_SUCCESS)
7860                     {
7861                         RxReferenceNetFobx(Fobx);
7862                         ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
7863 
7864                         RemoveEntryList(&Fobx->ScavengerFinalizationList);
7865                         InsertTailList(&FobxToScavenge, &Fobx->ScavengerFinalizationList);
7866                     }
7867                 }
7868             }
7869         }
7870 
7871         RxReleaseScavengerMutex();
7872 
7873         /* Now, scavenge all the extracted FOBX */
7874         RxpScavengeFobxs(Scavenger, &FobxToScavenge);
7875     }
7876 
7877     if (SynchronizeWithScavenger)
7878     {
7879         KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE);
7880     }
7881 }
7882 
7883 /*
7884  * @implemented
7885  */
7886 BOOLEAN
7887 RxScavengeRelatedFobxs(
7888     PFCB Fcb)
7889 {
7890     PFOBX Fobx;
7891     LIST_ENTRY LocalList;
7892     PLIST_ENTRY NextEntry;
7893     PRDBSS_SCAVENGER Scavenger;
7894 
7895     PAGED_CODE();
7896 
7897     /* First of all, check whether there are FOBX to scavenge */
7898     Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
7899     RxAcquireScavengerMutex();
7900     if (Scavenger->FobxsToBeFinalized <= 0)
7901     {
7902         RxReleaseScavengerMutex();
7903         return FALSE;
7904     }
7905 
7906     /* Initialize our local list which will hold all the FOBX to scavenge so
7907      * that we don't acquire the scavenger mutex too long
7908      */
7909     InitializeListHead(&LocalList);
7910 
7911     /* Technically, that condition should all be true... */
7912     if (!IsListEmpty(&Scavenger->FobxFinalizationList))
7913     {
7914         PLIST_ENTRY NextEntry, LastEntry;
7915 
7916         /* Browse all the FCBs to find the matching ones */
7917         NextEntry = Scavenger->FobxFinalizationList.Flink;
7918         LastEntry = &Scavenger->FobxFinalizationList;
7919         while (NextEntry != LastEntry)
7920         {
7921             Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList);
7922             NextEntry = NextEntry->Flink;
7923             /* Matching our FCB? Let's finalize it */
7924             if (Fobx->pSrvOpen != NULL && Fobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
7925             {
7926                 RxpUndoScavengerFinalizationMarking(Fobx);
7927                 ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
7928                 InsertTailList(&LocalList, &Fobx->ScavengerFinalizationList);
7929             }
7930         }
7931     }
7932 
7933     RxReleaseScavengerMutex();
7934 
7935     /* Nothing to scavenge? Quit */
7936     if (IsListEmpty(&LocalList))
7937     {
7938         return FALSE;
7939     }
7940 
7941     /* Now, finalize all the extracted FOBX */
7942     while (!IsListEmpty(&LocalList))
7943     {
7944         NextEntry = RemoveHeadList(&LocalList);
7945         Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList);
7946         RxFinalizeNetFobx(Fobx, TRUE, TRUE);
7947     }
7948 
7949     return TRUE;
7950 }
7951 
7952 VOID
7953 RxScavengerFinalizeEntries(
7954     PRDBSS_DEVICE_OBJECT DeviceObject)
7955 {
7956     UNIMPLEMENTED;
7957 }
7958 
7959 /*
7960  * @implemented
7961  */
7962 VOID
7963 NTAPI
7964 RxScavengerTimerRoutine(
7965     PVOID Context)
7966 {
7967     BOOLEAN Requeue;
7968     PRDBSS_DEVICE_OBJECT DeviceObject;
7969     PRDBSS_SCAVENGER Scavenger;
7970 
7971     PAGED_CODE();
7972 
7973     DeviceObject = Context;
7974     Scavenger = DeviceObject->pRdbssScavenger;
7975 
7976     Requeue = FALSE;
7977     RxAcquireScavengerMutex();
7978     /* If the scavenger was dormant, wake it up! */
7979     if (Scavenger->State == RDBSS_SCAVENGER_DORMANT)
7980     {
7981         /* Done */
7982         Scavenger->State = RDBSS_SCAVENGER_ACTIVE;
7983         KeClearEvent(&Scavenger->ScavengeEvent);
7984 
7985         /* Scavenger the entries */
7986         RxReleaseScavengerMutex();
7987         RxScavengerFinalizeEntries(DeviceObject);
7988         RxAcquireScavengerMutex();
7989 
7990         /* If we're still active (race) */
7991         if (Scavenger->State == RDBSS_SCAVENGER_ACTIVE)
7992         {
7993             /* If there are new entries to scavenge, stay dormant and requeue a run */
7994             if (Scavenger->NumberOfDormantFiles + Scavenger->SrvCallsToBeFinalized +
7995                 Scavenger->NetRootsToBeFinalized + Scavenger->VNetRootsToBeFinalized +
7996                 Scavenger->FcbsToBeFinalized + Scavenger->SrvOpensToBeFinalized +
7997                 Scavenger->FobxsToBeFinalized != 0)
7998             {
7999                 Requeue = TRUE;
8000                 Scavenger->State = RDBSS_SCAVENGER_DORMANT;
8001             }
8002             /* Otherwise, we're inactive again */
8003             else
8004             {
8005                 Scavenger->State = RDBSS_SCAVENGER_INACTIVE;
8006             }
8007         }
8008 
8009         RxReleaseScavengerMutex();
8010 
8011         /* Requeue an execution */
8012         if (Requeue)
8013         {
8014             RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
8015                                       RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
8016         }
8017     }
8018     else
8019     {
8020         RxReleaseScavengerMutex();
8021     }
8022 
8023     KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE);
8024 }
8025 
8026 BOOLEAN
8027 RxScavengeVNetRoots(
8028     PRDBSS_DEVICE_OBJECT RxDeviceObject)
8029 {
8030     UNIMPLEMENTED;
8031     return FALSE;
8032 }
8033 
8034 /*
8035  * @implemented
8036  */
8037 VOID
8038 NTAPI
8039 RxSpinUpRequestsDispatcher(
8040     PVOID Dispatcher)
8041 {
8042     NTSTATUS Status;
8043     PRX_DISPATCHER RxDispatcher;
8044 
8045     Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
8046     if (!NT_SUCCESS(Status))
8047     {
8048         PsTerminateSystemThread(STATUS_SUCCESS);
8049     }
8050 
8051     RxDispatcher = Dispatcher;
8052 
8053     do
8054     {
8055         KIRQL OldIrql;
8056         PLIST_ENTRY ListEntry;
8057 
8058         Status = KeWaitForSingleObject(&RxDispatcher->SpinUpRequestsEvent, Executive,
8059                                        KernelMode, FALSE, &RxSpinUpDispatcherWaitInterval);
8060         ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_TIMEOUT));
8061 
8062         KeAcquireSpinLock(&RxDispatcher->SpinUpRequestsLock, &OldIrql);
8063         if (!IsListEmpty(&RxDispatcher->SpinUpRequests))
8064         {
8065             ListEntry = RemoveHeadList(&RxDispatcher->SpinUpRequests);
8066         }
8067         else
8068         {
8069             ListEntry = &RxDispatcher->SpinUpRequests;
8070         }
8071         KeClearEvent(&RxDispatcher->SpinUpRequestsEvent);
8072         KeReleaseSpinLock(&RxDispatcher->SpinUpRequestsLock, OldIrql);
8073 
8074         while (ListEntry != &RxDispatcher->SpinUpRequests)
8075         {
8076             PWORK_QUEUE_ITEM WorkItem;
8077             PRX_WORK_QUEUE WorkQueue;
8078 
8079             WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List);
8080             WorkQueue = WorkItem->Parameter;
8081 
8082             InterlockedDecrement(&WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse);
8083 
8084             DPRINT("Workqueue: calling %p(%p)\n", WorkItem->WorkerRoutine, WorkItem->Parameter);
8085             WorkItem->WorkerRoutine(WorkItem->Parameter);
8086         }
8087     } while (RxDispatcher->State == RxDispatcherActive);
8088 
8089     KeSetEvent(&RxDispatcher->SpinUpRequestsTearDownEvent, IO_NO_INCREMENT, FALSE);
8090     PsTerminateSystemThread(STATUS_SUCCESS);
8091 }
8092 
8093 /*
8094  * @implemented
8095  */
8096 NTSTATUS
8097 RxSpinUpWorkerThread(
8098    PRX_WORK_QUEUE WorkQueue,
8099    PRX_WORKERTHREAD_ROUTINE Routine,
8100    PVOID Parameter)
8101 {
8102     KIRQL OldIrql;
8103     NTSTATUS Status;
8104     HANDLE ThreadHandle;
8105 
8106     PAGED_CODE();
8107 
8108     /* If work queue is inactive, that cannot work */
8109     KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
8110     if (WorkQueue->State != RxWorkQueueActive)
8111     {
8112         Status = STATUS_UNSUCCESSFUL;
8113         DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
8114     }
8115     else
8116     {
8117         ++WorkQueue->NumberOfActiveWorkerThreads;
8118         Status = STATUS_SUCCESS;
8119     }
8120     KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
8121 
8122     /* Quit on failure */
8123     if (!NT_SUCCESS(Status))
8124     {
8125         return Status;
8126     }
8127 
8128     /* Spin up the worker thread */
8129     Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, Routine, Parameter);
8130     if (NT_SUCCESS(Status))
8131     {
8132         ZwClose(ThreadHandle);
8133         return Status;
8134     }
8135     /* Read well: we reached that point because it failed! */
8136     DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue, Status);
8137 
8138     KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
8139     --WorkQueue->NumberOfActiveWorkerThreads;
8140     ++WorkQueue->NumberOfFailedSpinUpRequests;
8141 
8142     /* Rundown, no more active threads, set the event! */
8143     if (WorkQueue->NumberOfActiveWorkerThreads == 0 &&
8144         WorkQueue->State == RxWorkQueueRundownInProgress)
8145     {
8146         KeSetEvent(&WorkQueue->pRundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
8147     }
8148 
8149     DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
8150 
8151     KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
8152 
8153     return Status;
8154 }
8155 
8156 VOID
8157 RxSpinUpWorkerThreads(
8158    PRX_WORK_QUEUE WorkQueue)
8159 {
8160     UNIMPLEMENTED;
8161 }
8162 
8163 VOID
8164 RxSynchronizeWithScavenger(
8165     IN PRX_CONTEXT RxContext)
8166 {
8167     UNIMPLEMENTED;
8168 }
8169 
8170 /*
8171  * @implemented
8172  */
8173 ULONG
8174 RxTableComputeHashValue(
8175     IN PUNICODE_STRING Name)
8176 {
8177     ULONG Hash;
8178     SHORT Loops[8];
8179     USHORT MaxChar, i;
8180 
8181     PAGED_CODE();
8182 
8183     MaxChar = Name->Length / sizeof(WCHAR);
8184 
8185     Loops[0] = 1;
8186     Loops[1] = MaxChar - 1;
8187     Loops[2] = MaxChar - 2;
8188     Loops[3] = MaxChar - 3;
8189     Loops[4] = MaxChar - 4;
8190     Loops[5] = MaxChar / 4;
8191     Loops[6] = 2 * MaxChar / 4;
8192     Loops[7] = 3 * MaxChar / 4;
8193 
8194     Hash = 0;
8195     for (i = 0; i < 8; ++i)
8196     {
8197         SHORT Idx;
8198 
8199         Idx = Loops[i];
8200         if (Idx >= 0 && Idx < MaxChar)
8201         {
8202             Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
8203         }
8204     }
8205 
8206     return Hash;
8207 }
8208 
8209 /*
8210  * @implemented
8211  */
8212 ULONG
8213 RxTableComputePathHashValue(
8214     IN PUNICODE_STRING Name)
8215 {
8216     ULONG Hash;
8217     SHORT Loops[8];
8218     USHORT MaxChar, i;
8219 
8220     PAGED_CODE();
8221 
8222     MaxChar = Name->Length / sizeof(WCHAR);
8223 
8224     Loops[0] = 1;
8225     Loops[1] = MaxChar - 1;
8226     Loops[2] = MaxChar - 2;
8227     Loops[3] = MaxChar - 3;
8228     Loops[4] = MaxChar - 4;
8229     Loops[5] = MaxChar / 4;
8230     Loops[6] = 2 * MaxChar / 4;
8231     Loops[7] = 3 * MaxChar / 4;
8232 
8233     Hash = 0;
8234     for (i = 0; i < 8; ++i)
8235     {
8236         SHORT Idx;
8237 
8238         Idx = Loops[i];
8239         if (Idx >= 0 && Idx < MaxChar)
8240         {
8241             Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
8242         }
8243     }
8244 
8245     return Hash;
8246 }
8247 
8248 /*
8249  * @implemented
8250  */
8251 PVOID
8252 RxTableLookupName(
8253     IN PRX_PREFIX_TABLE ThisTable,
8254     IN PUNICODE_STRING Name,
8255     OUT PUNICODE_STRING RemainingName,
8256     IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
8257 {
8258     PVOID Container;
8259     USHORT i, MaxChar;
8260     PRX_PREFIX_ENTRY Entry;
8261     RX_CONNECTION_ID NullId;
8262     UNICODE_STRING LookupString;
8263 
8264     PAGED_CODE();
8265 
8266     /* If caller didn't provide a connection ID, setup one */
8267     if (ThisTable->IsNetNameTable && RxConnectionId == NULL)
8268     {
8269         NullId.Luid.LowPart = 0;
8270         NullId.Luid.HighPart = 0;
8271         RxConnectionId = &NullId;
8272     }
8273 
8274     /* Validate name */
8275     ASSERT(Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR);
8276 
8277     Entry = NULL;
8278     Container = NULL;
8279     LookupString.Buffer = Name->Buffer;
8280     MaxChar = Name->Length / sizeof(WCHAR);
8281     /* We'll perform the lookup, path component after another */
8282     for (i = 1; i < MaxChar; ++i)
8283     {
8284         ULONG Hash;
8285         PRX_PREFIX_ENTRY CurEntry;
8286 
8287         /* Don't cut in the middle of a path element */
8288         if (Name->Buffer[i] != OBJ_NAME_PATH_SEPARATOR && Name->Buffer[i] != ':')
8289         {
8290             continue;
8291         }
8292 
8293         /* Perform lookup in the table */
8294         LookupString.Length = i * sizeof(WCHAR);
8295         Hash = RxTableComputeHashValue(&LookupString);
8296         CurEntry = RxTableLookupName_ExactLengthMatch(ThisTable, &LookupString, Hash, RxConnectionId);
8297 #if DBG
8298         ++ThisTable->Lookups;
8299 #endif
8300         /* Entry not found, move to the next component */
8301         if (CurEntry == NULL)
8302         {
8303 #if DBG
8304             ++ThisTable->FailedLookups;
8305 #endif
8306             continue;
8307         }
8308 
8309         Entry = CurEntry;
8310         ASSERT(Entry->ContainingRecord != NULL);
8311         Container = Entry->ContainingRecord;
8312 
8313         /* If we have a NET_ROOT, let's return a V_NET_ROOT */
8314         if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_NETROOT)
8315         {
8316             PNET_ROOT NetRoot;
8317 
8318             NetRoot = (PNET_ROOT)Entry->ContainingRecord;
8319             /* If there's a default one, perfect, that's a match */
8320             if (NetRoot->DefaultVNetRoot != NULL)
8321             {
8322                 Container = NetRoot->DefaultVNetRoot;
8323             }
8324             /* If none (that shouldn't happen!), try to find one */
8325             else
8326             {
8327                 /* Use the first one in the list */
8328                 if (!IsListEmpty(&NetRoot->VirtualNetRoots))
8329                 {
8330                     Container = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry);
8331                 }
8332                 /* Really, really, shouldn't happen */
8333                 else
8334                 {
8335                     ASSERT(FALSE);
8336                     Entry = NULL;
8337                     Container = NULL;
8338                 }
8339             }
8340 
8341             break;
8342         }
8343         else if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_V_NETROOT)
8344         {
8345             break;
8346         }
8347         else
8348         {
8349             ASSERT((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_SRVCALL);
8350         }
8351     }
8352 
8353     /* Entry was found */
8354     if (Entry != NULL)
8355     {
8356         DPRINT("Found\n");
8357 
8358         ASSERT(Name->Length >= Entry->Prefix.Length);
8359 
8360         /* Setup remaining name */
8361         RemainingName->Buffer = Add2Ptr(Name->Buffer, Entry->Prefix.Length);
8362         RemainingName->Length = Name->Length - Entry->Prefix.Length;
8363         RemainingName->MaximumLength = Name->Length - Entry->Prefix.Length;
8364     }
8365     else
8366     {
8367         /* Otherwise, that's the whole name */
8368         RemainingName = Name;
8369     }
8370 
8371     return Container;
8372 }
8373 
8374 /*
8375  * @implemented
8376  */
8377 PRX_PREFIX_ENTRY
8378 RxTableLookupName_ExactLengthMatch(
8379     IN PRX_PREFIX_TABLE ThisTable,
8380     IN PUNICODE_STRING  Name,
8381     IN ULONG HashValue,
8382     IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
8383 {
8384     PLIST_ENTRY ListEntry, HashBucket;
8385 
8386     PAGED_CODE();
8387 
8388     ASSERT(RxConnectionId != NULL);
8389 
8390     /* Select the right bucket */
8391     HashBucket = HASH_BUCKET(ThisTable, HashValue);
8392     DPRINT("Looking in bucket: %p for %x\n", HashBucket, HashValue);
8393     /* If bucket is empty, no match */
8394     if (IsListEmpty(HashBucket))
8395     {
8396         return NULL;
8397     }
8398 
8399     /* Browse all the entries in the bucket */
8400     for (ListEntry = HashBucket->Flink;
8401          ListEntry != HashBucket;
8402          ListEntry = ListEntry->Flink)
8403     {
8404         PVOID Container;
8405         PRX_PREFIX_ENTRY Entry;
8406         BOOLEAN CaseInsensitive;
8407         PUNICODE_STRING CmpName, CmpPrefix;
8408         UNICODE_STRING InsensitiveName, InsensitivePrefix;
8409 
8410         Entry = CONTAINING_RECORD(ListEntry, RX_PREFIX_ENTRY, HashLinks);
8411 #if DBG
8412         ++ThisTable->Considers;
8413 #endif
8414         ASSERT(HashBucket == HASH_BUCKET(ThisTable, Entry->SavedHashValue));
8415 
8416         Container = Entry->ContainingRecord;
8417         ASSERT(Container != NULL);
8418 
8419         /* Not the same hash, not the same length, move on */
8420         if (Entry->SavedHashValue != HashValue || Entry->Prefix.Length != Name->Length)
8421         {
8422             continue;
8423         }
8424 
8425 #if DBG
8426         ++ThisTable->Compares;
8427 #endif
8428         /* If we have to perform a case insensitive compare on a portion... */
8429         if (Entry->CaseInsensitiveLength != 0)
8430         {
8431             ASSERT(Entry->CaseInsensitiveLength <= Name->Length);
8432 
8433             /* Perform the case insensitive check on the asked length */
8434             InsensitiveName.Buffer = Name->Buffer;
8435             InsensitivePrefix.Buffer = Entry->Prefix.Buffer;
8436             InsensitiveName.Length = Entry->CaseInsensitiveLength;
8437             InsensitivePrefix.Length = Entry->CaseInsensitiveLength;
8438             /* No match, move to the next entry */
8439             if (!RtlEqualUnicodeString(&InsensitiveName, &InsensitivePrefix, TRUE))
8440             {
8441                 continue;
8442             }
8443 
8444             /* Was the case insensitive covering the whole name? */
8445             if (Name->Length == Entry->CaseInsensitiveLength)
8446             {
8447                 /* If connection ID also matches, that a complete match! */
8448                 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
8449                 {
8450                     return Entry;
8451                 }
8452             }
8453 
8454             /* Otherwise, we have to continue with the sensitive match.... */
8455             InsensitiveName.Buffer = Add2Ptr(InsensitiveName.Buffer, Entry->CaseInsensitiveLength);
8456             InsensitivePrefix.Buffer = Add2Ptr(InsensitivePrefix.Buffer, Entry->CaseInsensitiveLength);
8457             InsensitiveName.Length = Name->Length - Entry->CaseInsensitiveLength;
8458             InsensitivePrefix.Length = Entry->Prefix.Length - Entry->CaseInsensitiveLength;
8459 
8460             CmpName = &InsensitiveName;
8461             CmpPrefix = &InsensitivePrefix;
8462             CaseInsensitive = FALSE;
8463         }
8464         else
8465         {
8466             CmpName = Name;
8467             CmpPrefix = &Entry->Prefix;
8468             CaseInsensitive = ThisTable->CaseInsensitiveMatch;
8469         }
8470 
8471         /* Perform the compare, if there's a match, also check for connection ID */
8472         if (RtlEqualUnicodeString(CmpName, CmpPrefix, CaseInsensitive))
8473         {
8474             if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
8475             {
8476                 return Entry;
8477             }
8478         }
8479     }
8480 
8481     return NULL;
8482 }
8483 
8484 /*
8485  * @implemented
8486  */
8487 NTSTATUS
8488 RxTearDownBufferingManager(
8489    PSRV_CALL SrvCall)
8490 {
8491     PAGED_CODE();
8492 
8493     /* Nothing to do */
8494     return STATUS_SUCCESS;
8495 }
8496 
8497 /*
8498  * @implemented
8499  */
8500 VOID
8501 NTAPI
8502 RxTimerDispatch(
8503     _In_ struct _KDPC *Dpc,
8504     _In_opt_ PVOID DeferredContext,
8505     _In_opt_ PVOID SystemArgument1,
8506     _In_opt_ PVOID SystemArgument2)
8507 {
8508     BOOLEAN Set;
8509     LIST_ENTRY LocalList;
8510     PLIST_ENTRY ListEntry;
8511     PRX_WORK_ITEM WorkItem;
8512 
8513     InitializeListHead(&LocalList);
8514 
8515     KeAcquireSpinLockAtDpcLevel(&RxTimerLock);
8516     ++RxTimerTickCount;
8517 
8518     /* Find any entry matching */
8519     if (!IsListEmpty(&RxTimerQueueHead))
8520     {
8521         ListEntry = RxTimerQueueHead.Flink;
8522         do
8523         {
8524             WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
8525             if (WorkItem->LastTick == RxTimerTickCount)
8526             {
8527                 ListEntry = ListEntry->Flink;
8528 
8529                 RemoveEntryList(&WorkItem->WorkQueueItem.List);
8530                 InsertTailList(&LocalList, &WorkItem->WorkQueueItem.List);
8531             }
8532             else
8533             {
8534                 ListEntry = ListEntry->Flink;
8535             }
8536         } while (ListEntry != &RxTimerQueueHead);
8537     }
8538     /* Do we have to requeue a later execution? */
8539     Set = !IsListEmpty(&RxTimerQueueHead);
8540 
8541     KeReleaseSpinLockFromDpcLevel(&RxTimerLock);
8542 
8543     /* Requeue if list wasn't empty */
8544     if (Set)
8545     {
8546         KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
8547     }
8548 
8549     /* If we had matching entries */
8550     if (!IsListEmpty(&LocalList))
8551     {
8552         /* Post them, one after another */
8553         ListEntry = LocalList.Flink;
8554         do
8555         {
8556             WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
8557             ListEntry = ListEntry->Flink;
8558 
8559             WorkItem->WorkQueueItem.List.Flink = NULL;
8560             WorkItem->WorkQueueItem.List.Blink = NULL;
8561             RxPostToWorkerThread(WorkItem->WorkQueueItem.pDeviceObject, CriticalWorkQueue,
8562                                  &WorkItem->WorkQueueItem, WorkItem->WorkQueueItem.WorkerRoutine,
8563                                  WorkItem->WorkQueueItem.Parameter);
8564         }
8565         while (ListEntry != &LocalList);
8566     }
8567 }
8568 
8569 #ifdef RDBSS_TRACKER
8570 /*
8571  * @implemented
8572  */
8573 VOID
8574 RxTrackerUpdateHistory(
8575     _Inout_opt_ PRX_CONTEXT RxContext,
8576     _Inout_ PMRX_FCB MrxFcb,
8577     _In_ ULONG Operation,
8578     _In_ ULONG LineNumber,
8579     _In_ PCSTR FileName,
8580     _In_ ULONG SerialNumber)
8581 {
8582     PFCB Fcb;
8583     RX_FCBTRACKER_CASES Case;
8584 
8585     /* Check for null or special context */
8586     if (RxContext == NULL)
8587     {
8588         Case = RX_FCBTRACKER_CASE_NULLCONTEXT;
8589     }
8590     else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT)
8591     {
8592         Case = RX_FCBTRACKER_CASE_CBS_CONTEXT;
8593     }
8594     else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
8595     {
8596         Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT;
8597     }
8598     else
8599     {
8600         ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT);
8601         Case = RX_FCBTRACKER_CASE_NORMAL;
8602     }
8603 
8604     /* If caller provided a FCB, update its history */
8605     if (MrxFcb != NULL)
8606     {
8607         Fcb = (PFCB)MrxFcb;
8608         ASSERT(NodeTypeIsFcb(Fcb));
8609 
8610         /* Only one acquire operation, so many release operations... */
8611         if (Operation == TRACKER_ACQUIRE_FCB)
8612         {
8613             ++Fcb->FcbAcquires[Case];
8614         }
8615         else
8616         {
8617             ++Fcb->FcbReleases[Case];
8618         }
8619     }
8620 
8621     /* If we have a normal context, update its history about this function calls */
8622     if (Case == RX_FCBTRACKER_CASE_NORMAL)
8623     {
8624         ULONG TrackerHistoryPointer;
8625 
8626         /* Only one acquire operation, so many release operations... */
8627         if (Operation == TRACKER_ACQUIRE_FCB)
8628         {
8629             InterlockedIncrement(&RxContext->AcquireReleaseFcbTrackerX);
8630         }
8631         else
8632         {
8633             InterlockedDecrement(&RxContext->AcquireReleaseFcbTrackerX);
8634         }
8635 
8636         /* We only keep track of the 32 first calls */
8637         TrackerHistoryPointer = InterlockedExchangeAdd((volatile long *)&RxContext->TrackerHistoryPointer, 1);
8638         if (TrackerHistoryPointer < RDBSS_TRACKER_HISTORY_SIZE)
8639         {
8640             RxContext->TrackerHistory[TrackerHistoryPointer].AcquireRelease = Operation;
8641             RxContext->TrackerHistory[TrackerHistoryPointer].LineNumber = LineNumber;
8642             RxContext->TrackerHistory[TrackerHistoryPointer].FileName = (PSZ)FileName;
8643             RxContext->TrackerHistory[TrackerHistoryPointer].SavedTrackerValue = RxContext->AcquireReleaseFcbTrackerX;
8644             RxContext->TrackerHistory[TrackerHistoryPointer].Flags = RxContext->Flags;
8645         }
8646 
8647         /* If it's negative, then we released once more than we acquired it?! */
8648         ASSERT(RxContext->AcquireReleaseFcbTrackerX >= 0);
8649     }
8650 }
8651 #endif
8652 
8653 VOID
8654 RxTrackPagingIoResource(
8655     _Inout_ PVOID Instance,
8656     _In_ ULONG Type,
8657     _In_ ULONG Line,
8658     _In_ PCSTR File)
8659 {
8660     UNIMPLEMENTED;
8661 }
8662 
8663 /*
8664  * @implemented
8665  */
8666 VOID
8667 RxUndoScavengerFinalizationMarking(
8668     PVOID Instance)
8669 {
8670     /* Just call internal routine with mutex held */
8671     RxAcquireScavengerMutex();
8672     RxpUndoScavengerFinalizationMarking(Instance);
8673     RxReleaseScavengerMutex();
8674 }
8675 
8676 /*
8677  * @implemented
8678  */
8679 VOID
8680 RxUninitializeVNetRootParameters(
8681    IN PUNICODE_STRING UserName,
8682    IN PUNICODE_STRING UserDomainName,
8683    IN PUNICODE_STRING Password,
8684    OUT PULONG Flags)
8685 {
8686     PAGED_CODE();
8687 
8688     /* Only free what could have been allocated */
8689     if (UserName != NULL)
8690     {
8691         RxFreePool(UserName);
8692     }
8693 
8694     if (UserDomainName != NULL)
8695     {
8696         RxFreePool(UserDomainName);
8697     }
8698 
8699     if (Password != NULL)
8700     {
8701         RxFreePool(Password);
8702     }
8703 
8704     /* And remove the possibly set CSC agent flag */
8705     if (Flags != NULL)
8706     {
8707         (*Flags) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
8708     }
8709 }
8710 
8711 /*
8712  * @implemented
8713  */
8714 VOID
8715 RxUpdateCondition(
8716     IN RX_BLOCK_CONDITION NewConditionValue,
8717     OUT PRX_BLOCK_CONDITION Condition,
8718     IN OUT PLIST_ENTRY TransitionWaitList)
8719 {
8720     PRX_CONTEXT Context;
8721     LIST_ENTRY SerializationQueue;
8722 
8723     PAGED_CODE();
8724 
8725     DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue, Condition, TransitionWaitList);
8726 
8727     /* Set the new condition */
8728     RxAcquireSerializationMutex();
8729     ASSERT(NewConditionValue != Condition_InTransition);
8730     *Condition = NewConditionValue;
8731     /* And get the serialization queue for treatment */
8732     RxTransferList(&SerializationQueue, TransitionWaitList);
8733     RxReleaseSerializationMutex();
8734 
8735     /* Handle the serialization queue */
8736     Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
8737     while (Context != NULL)
8738     {
8739         /* If the caller asked for post, post the request */
8740         if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
8741         {
8742             Context->Flags &= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION;
8743             RxFsdPostRequest(Context);
8744         }
8745         /* Otherwise, wake up sleeping waiters */
8746         else
8747         {
8748             RxSignalSynchronousWaiter(Context);
8749         }
8750 
8751         Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
8752     }
8753 }
8754 
8755 /*
8756  * @implemented
8757  */
8758 VOID
8759 RxVerifyOperationIsLegal(
8760     IN PRX_CONTEXT RxContext)
8761 {
8762     PIRP Irp;
8763     PMRX_FOBX Fobx;
8764     BOOLEAN FlagSet;
8765     PFILE_OBJECT FileObject;
8766     PIO_STACK_LOCATION Stack;
8767 
8768     PAGED_CODE();
8769 
8770     Irp = RxContext->CurrentIrp;
8771     Stack = RxContext->CurrentIrpSp;
8772     FileObject = Stack->FileObject;
8773 
8774     /* We'll only check stuff on opened files, this requires an IRP and a FO */
8775     if (Irp == NULL || FileObject == NULL)
8776     {
8777         return;
8778     }
8779 
8780     /* Set no exception for breakpoint - remember whether is was already set */
8781     FlagSet = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8782     SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8783 
8784     /* If we have a CCB, perform a few checks on opened file */
8785     Fobx = RxContext->pFobx;
8786     if (Fobx != NULL)
8787     {
8788         PMRX_SRV_OPEN SrvOpen;
8789 
8790         SrvOpen = Fobx->pSrvOpen;
8791         if (SrvOpen != NULL)
8792         {
8793             UCHAR MajorFunction;
8794 
8795             MajorFunction = RxContext->MajorFunction;
8796             /* Only allow closing/cleanup operations on renamed files */
8797             if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE &&
8798                 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
8799             {
8800                 RxContext->IoStatusBlock.Status = STATUS_FILE_RENAMED;
8801                 ExRaiseStatus(STATUS_FILE_RENAMED);
8802             }
8803 
8804             /* Only allow closing/cleanup operations on deleted files */
8805             if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE &&
8806                 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED))
8807             {
8808                 RxContext->IoStatusBlock.Status = STATUS_FILE_DELETED;
8809                 ExRaiseStatus(STATUS_FILE_DELETED);
8810             }
8811         }
8812     }
8813 
8814     /* If that's an open operation */
8815     if (RxContext->MajorFunction == IRP_MJ_CREATE)
8816     {
8817         PFILE_OBJECT RelatedFileObject;
8818 
8819         /* We won't allow an open operation relative to a file to be deleted */
8820         RelatedFileObject = FileObject->RelatedFileObject;
8821         if (RelatedFileObject != NULL)
8822         {
8823             PMRX_FCB Fcb;
8824 
8825             Fcb = RelatedFileObject->FsContext;
8826             if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
8827             {
8828                 RxContext->IoStatusBlock.Status = STATUS_DELETE_PENDING;
8829                 ExRaiseStatus(STATUS_DELETE_PENDING);
8830             }
8831         }
8832     }
8833 
8834     /* If cleanup was completed */
8835     if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
8836     {
8837         if (!BooleanFlagOn(Irp->Flags, IRP_PAGING_IO))
8838         {
8839             UCHAR MajorFunction;
8840 
8841             /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
8842             MajorFunction = Stack->MajorFunction;
8843             if (MajorFunction != IRP_MJ_CLOSE && MajorFunction != IRP_MJ_QUERY_INFORMATION &&
8844                 MajorFunction != IRP_MJ_SET_INFORMATION)
8845             {
8846                 if ((MajorFunction != IRP_MJ_READ && MajorFunction != IRP_MJ_WRITE) ||
8847                     !BooleanFlagOn(Stack->MinorFunction, IRP_MN_COMPLETE))
8848                 {
8849                     RxContext->IoStatusBlock.Status = STATUS_FILE_CLOSED;
8850                     ExRaiseStatus(STATUS_FILE_CLOSED);
8851                 }
8852             }
8853         }
8854     }
8855 
8856     /* If flag was already set, don't clear it */
8857     if (!FlagSet)
8858     {
8859         ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8860     }
8861 }
8862 
8863 /*
8864  * @implemented
8865  */
8866 VOID
8867 RxWaitForStableCondition(
8868     IN PRX_BLOCK_CONDITION Condition,
8869     IN OUT PLIST_ENTRY TransitionWaitList,
8870     IN OUT PRX_CONTEXT RxContext,
8871     OUT NTSTATUS *AsyncStatus OPTIONAL)
8872 {
8873     BOOLEAN Wait;
8874     NTSTATUS LocalStatus;
8875 
8876     PAGED_CODE();
8877 
8878     /* Make sure to always get status */
8879     if (AsyncStatus == NULL)
8880     {
8881         AsyncStatus = &LocalStatus;
8882     }
8883 
8884     /* By default, it's a success */
8885     *AsyncStatus = STATUS_SUCCESS;
8886 
8887     Wait = FALSE;
8888     /* If it's not stable, we've to wait */
8889     if (!StableCondition(*Condition))
8890     {
8891         /* Lock the mutex */
8892         RxAcquireSerializationMutex();
8893         /* Still not stable? */
8894         if (!StableCondition(*Condition))
8895         {
8896             /* Insert us in the wait list for processing on stable condition */
8897             RxInsertContextInSerializationQueue(TransitionWaitList, RxContext);
8898 
8899             /* If we're asked to post on stable, don't wait, and just return pending */
8900             if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
8901             {
8902                 *AsyncStatus = STATUS_PENDING;
8903             }
8904             else
8905             {
8906                 Wait = TRUE;
8907             }
8908         }
8909         RxReleaseSerializationMutex();
8910 
8911         /* We don't post on stable, so, just wait... */
8912         if (Wait)
8913         {
8914             RxWaitSync(RxContext);
8915         }
8916     }
8917 }
8918 
8919 /*
8920  * @implemented
8921  */
8922 VOID
8923 NTAPI
8924 RxWorkItemDispatcher(
8925     PVOID Context)
8926 {
8927     PRX_WORK_DISPATCH_ITEM DispatchItem = Context;
8928 
8929     DPRINT("Calling: %p, %p\n", DispatchItem->DispatchRoutine, DispatchItem->DispatchRoutineParameter);
8930 
8931     DispatchItem->DispatchRoutine(DispatchItem->DispatchRoutineParameter);
8932 
8933     RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
8934 }
8935 
8936 /*
8937  * @implemented
8938  */
8939 PVOID
8940 NTAPI
8941 _RxAllocatePoolWithTag(
8942     _In_ POOL_TYPE PoolType,
8943     _In_ SIZE_T NumberOfBytes,
8944     _In_ ULONG Tag)
8945 {
8946     return ExAllocatePoolWithTagPriority(PoolType, NumberOfBytes, Tag, LowPoolPriority);
8947 }
8948 
8949 /*
8950  * @implemented
8951  */
8952 VOID
8953 NTAPI
8954 _RxFreePool(
8955     _In_ PVOID Buffer)
8956 {
8957     ExFreePoolWithTag(Buffer, 0);
8958 }
8959 
8960 /*
8961  * @implemented
8962  */
8963 VOID
8964 NTAPI
8965 _RxFreePoolWithTag(
8966     _In_ PVOID Buffer,
8967     _In_ ULONG Tag)
8968 {
8969     ExFreePoolWithTag(Buffer, Tag);
8970 }
8971 
8972 NTSTATUS
8973 __RxAcquireFcb(
8974     _Inout_ PFCB Fcb,
8975     _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL,
8976     _In_ ULONG Mode
8977 #ifdef RDBSS_TRACKER
8978     ,
8979     _In_ ULONG LineNumber,
8980     _In_ PCSTR FileName,
8981     _In_ ULONG SerialNumber
8982 #endif
8983     )
8984 {
8985     NTSTATUS Status;
8986     BOOLEAN SpecialContext, CanWait, Acquired, ContextIsPresent;
8987 
8988     PAGED_CODE();
8989 
8990     DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb, RxContext, Mode, LineNumber, FileName, SerialNumber);
8991 
8992     SpecialContext = FALSE;
8993     ContextIsPresent = FALSE;
8994     /* Check for special context */
8995     if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT || RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
8996     {
8997         SpecialContext = TRUE;
8998     }
8999 
9000     /* We don't handle buffering state change yet... */
9001     if (!RxIsFcbAcquired(Fcb) && !SpecialContext &&
9002         BooleanFlagOn(Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING))
9003     {
9004         UNIMPLEMENTED;
9005     }
9006 
9007     /* Nor special contexts */
9008     if (SpecialContext)
9009     {
9010         UNIMPLEMENTED;
9011     }
9012 
9013     /* If we don't have a context, assume we can wait! */
9014     if (RxContext == NULL)
9015     {
9016         CanWait = TRUE;
9017     }
9018     else
9019     {
9020         /* That said: we have a real context! */
9021         ContextIsPresent = TRUE;
9022 
9023         /* If we've been cancelled in between, give up */
9024         Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
9025         if (!NT_SUCCESS(Status))
9026         {
9027             return Status;
9028         }
9029 
9030         /* Can we wait? */
9031         CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
9032     }
9033 
9034     while (TRUE)
9035     {
9036         /* Assume we cannot lock */
9037         Status = STATUS_LOCK_NOT_GRANTED;
9038 
9039         /* Lock according to what the caller asked */
9040         switch (Mode)
9041         {
9042             case FCB_MODE_EXCLUSIVE:
9043                 Acquired = ExAcquireResourceExclusiveLite(Fcb->Header.Resource, CanWait);
9044                 break;
9045 
9046             case FCB_MODE_SHARED:
9047                 Acquired = ExAcquireResourceSharedLite(Fcb->Header.Resource, CanWait);
9048                 break;
9049 
9050             case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE:
9051                 Acquired = ExAcquireSharedWaitForExclusive(Fcb->Header.Resource, CanWait);
9052                 break;
9053 
9054             default:
9055                 ASSERT(Mode == FCB_MODE_SHARED_STARVE_EXCLUSIVE);
9056                 Acquired = ExAcquireSharedStarveExclusive(Fcb->Header.Resource, CanWait);
9057                 break;
9058         }
9059 
9060         /* Lock granted! */
9061         if (Acquired)
9062         {
9063             Status = STATUS_SUCCESS;
9064             ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
9065 
9066             /* Handle paging write - not implemented */
9067             if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
9068             {
9069                 UNIMPLEMENTED;
9070             }
9071         }
9072 
9073         /* And break, that cool! */
9074         if (Acquired)
9075         {
9076             break;
9077         }
9078 
9079         /* If it failed, return immediately */
9080         if (!NT_SUCCESS(Status))
9081         {
9082             return Status;
9083         }
9084     }
9085 
9086     /* If we don't have to check for valid operation, job done, nothing more to do */
9087     if (!ContextIsPresent || BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK))
9088     {
9089         if (NT_SUCCESS(Status))
9090         {
9091             RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
9092         }
9093 
9094         return Status;
9095     }
9096 
9097     /* Verify operation */
9098     _SEH2_TRY
9099     {
9100         RxVerifyOperationIsLegal(RxContext);
9101     }
9102     _SEH2_FINALLY
9103     {
9104         /* If it failed, release lock and fail */
9105         if (_SEH2_AbnormalTermination())
9106         {
9107             ExReleaseResourceLite(Fcb->Header.Resource);
9108             Status = STATUS_LOCK_NOT_GRANTED;
9109         }
9110     }
9111     _SEH2_END;
9112 
9113     if (NT_SUCCESS(Status))
9114     {
9115         RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
9116     }
9117 
9118     DPRINT("Status: %x\n", Status);
9119     return Status;
9120 }
9121 
9122 /*
9123  * @implemented
9124  */
9125 VOID
9126 __RxItsTheSameContext(
9127     _In_ PRX_CONTEXT RxContext,
9128     _In_ ULONG CapturedRxContextSerialNumber,
9129     _In_ ULONG Line,
9130     _In_ PCSTR File)
9131 {
9132     /* Check we have a context with the same serial number */
9133     if (NodeType(RxContext) != RDBSS_NTC_RX_CONTEXT ||
9134         RxContext->SerialNumber != CapturedRxContextSerialNumber)
9135     {
9136         /* Just be noisy */
9137         DPRINT1("Context %p has changed at line %d in file %s\n", RxContext, Line, File);
9138     }
9139 }
9140 
9141 VOID
9142 __RxReleaseFcb(
9143     _Inout_opt_ PRX_CONTEXT RxContext,
9144     _Inout_ PMRX_FCB MrxFcb
9145 #ifdef RDBSS_TRACKER
9146     ,
9147     _In_ ULONG LineNumber,
9148     _In_ PCSTR FileName,
9149     _In_ ULONG SerialNumber
9150 #endif
9151     )
9152 {
9153     BOOLEAN IsExclusive, BufferingPending;
9154 
9155     RxAcquireSerializationMutex();
9156 
9157     BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
9158     IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
9159 
9160     /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9161      * then just release the FCB
9162      */
9163     if (!BufferingPending || !IsExclusive)
9164     {
9165         RxTrackerUpdateHistory(RxContext, MrxFcb, (!BufferingPending ? TRACKER_RELEASE_FCB_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING),
9166                                LineNumber, FileName, SerialNumber);
9167         ExReleaseResourceLite(MrxFcb->Header.Resource);
9168     }
9169 
9170     RxReleaseSerializationMutex();
9171 
9172     /* And finally leave */
9173     if (!BufferingPending || !IsExclusive)
9174     {
9175         return;
9176     }
9177 
9178     ASSERT(RxIsFcbAcquiredExclusive(MrxFcb));
9179 
9180     /* Otherwise, handle buffering state and release */
9181     RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
9182 
9183     RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING, LineNumber, FileName, SerialNumber);
9184     ExReleaseResourceLite(MrxFcb->Header.Resource);
9185 }
9186 
9187 VOID
9188 __RxReleaseFcbForThread(
9189     _Inout_opt_ PRX_CONTEXT RxContext,
9190     _Inout_ PMRX_FCB MrxFcb,
9191     _In_ ERESOURCE_THREAD ResourceThreadId
9192 #ifdef RDBSS_TRACKER
9193     ,
9194     _In_ ULONG LineNumber,
9195     _In_ PCSTR FileName,
9196     _In_ ULONG SerialNumber
9197 #endif
9198     )
9199 {
9200     BOOLEAN IsExclusive, BufferingPending;
9201 
9202     RxAcquireSerializationMutex();
9203 
9204     BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
9205     IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
9206 
9207     /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9208      * then just release the FCB
9209      */
9210     if (!BufferingPending || !IsExclusive)
9211     {
9212         RxTrackerUpdateHistory(RxContext, MrxFcb,
9213                                (!BufferingPending ? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING),
9214                                LineNumber, FileName, SerialNumber);
9215         ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
9216     }
9217 
9218     RxReleaseSerializationMutex();
9219 
9220     /* And finally leave */
9221     if (!BufferingPending || !IsExclusive)
9222     {
9223         return;
9224     }
9225 
9226     /* Otherwise, handle buffering state and release */
9227     RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING, LineNumber, FileName, SerialNumber);
9228     RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
9229     ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
9230 }
9231