[RXCE]
[reactos.git] / reactos / sdk / lib / drivers / rxce / rxce.c
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 #if DBG
147 BOOLEAN DumpDispatchRoutine = TRUE;
148 #else
149 BOOLEAN DumpDispatchRoutine = FALSE;
150 #endif
151
152 #if RDBSS_ASSERTS
153 #ifdef ASSERT
154 #undef ASSERT
155 #endif
156
157 #define ASSERT(exp) \
158 if (!(exp)) \
159 { \
160 RxAssert(#exp, __FILE__, __LINE__, NULL); \
161 }
162 #endif
163
164 #if RX_POOL_WRAPPER
165 #undef RxAllocatePool
166 #undef RxAllocatePoolWithTag
167 #undef RxFreePool
168
169 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
170 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
171 #define RxFreePool _RxFreePool
172 #define RxFreePoolWithTag _RxFreePoolWithTag
173 #endif
174
175 /* FUNCTIONS ****************************************************************/
176
177 NTSTATUS
178 NTAPI
179 RxAcquireExclusiveFcbResourceInMRx(
180 _Inout_ PMRX_FCB Fcb)
181 {
182 UNIMPLEMENTED;
183 return STATUS_NOT_IMPLEMENTED;
184 }
185
186 /*
187 * @implemented
188 */
189 BOOLEAN
190 NTAPI
191 RxAcquireFcbForLazyWrite(
192 PVOID Context,
193 BOOLEAN Wait)
194 {
195 PFCB Fcb;
196 BOOLEAN Ret;
197
198 PAGED_CODE();
199
200 Fcb = Context;
201 /* The received context is a FCB */
202 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
203 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
204 ASSERT(Fcb->Specific.Fcb.LazyWriteThread == NULL);
205
206 /* Acquire the paging resource (shared) */
207 Ret = ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, Wait);
208 if (Ret)
209 {
210 /* Update tracker information */
211 Fcb->PagingIoResourceFile = __FILE__;
212 Fcb->PagingIoResourceLine = __LINE__;
213 /* Lazy writer thread is the current one */
214 Fcb->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
215
216 /* There is no top level IRP */
217 ASSERT(RxIsThisTheTopLevelIrp(NULL));
218 /* Now, there will be! */
219 Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
220 Fcb->RxDeviceObject, TRUE);
221 /* In case of failure, release the lock and reset everything */
222 if (!Ret)
223 {
224 Fcb->PagingIoResourceFile = NULL;
225 Fcb->PagingIoResourceLine = 0;
226 ExReleaseResourceLite(Fcb->Header.PagingIoResource);
227 Fcb->Specific.Fcb.LazyWriteThread = NULL;
228 }
229 }
230
231 return Ret;
232 }
233
234 /*
235 * @implemented
236 */
237 BOOLEAN
238 NTAPI
239 RxAcquireFcbForReadAhead(
240 PVOID Context,
241 BOOLEAN Wait)
242 {
243 PFCB Fcb;
244 BOOLEAN Ret;
245
246 PAGED_CODE();
247
248 Fcb = Context;
249 /* The received context is a FCB */
250 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
251 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
252
253 Ret = ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait);
254 if (Ret)
255 {
256 /* There is no top level IRP */
257 ASSERT(RxIsThisTheTopLevelIrp(NULL));
258 /* Now, there will be! */
259 Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP,
260 Fcb->RxDeviceObject, TRUE);
261 /* In case of failure, release the lock and reset everything */
262 if (!Ret)
263 {
264 ExReleaseResourceLite(Fcb->Header.Resource);
265 }
266 }
267
268 return Ret;
269 }
270
271 VOID
272 NTAPI
273 RxAcquireFileForNtCreateSection(
274 PFILE_OBJECT FileObject)
275 {
276 UNIMPLEMENTED;
277 }
278
279 NTSTATUS
280 NTAPI
281 RxAcquireForCcFlush(
282 PFILE_OBJECT FileObject,
283 PDEVICE_OBJECT DeviceObject)
284 {
285 UNIMPLEMENTED;
286 return STATUS_NOT_IMPLEMENTED;
287 }
288
289 /*
290 * @implemented
291 */
292 VOID
293 RxAddVirtualNetRootToNetRoot(
294 PNET_ROOT NetRoot,
295 PV_NET_ROOT VNetRoot)
296 {
297 PAGED_CODE();
298
299 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot, VNetRoot);
300
301 /* Insert in the VNetRoot list - make sure lock is held */
302 ASSERT(RxIsPrefixTableLockExclusive(NetRoot->SrvCall->RxDeviceObject->pRxNetNameTable));
303
304 VNetRoot->pNetRoot = (PMRX_NET_ROOT)NetRoot;
305 ++NetRoot->NumberOfVirtualNetRoots;
306 InsertTailList(&NetRoot->VirtualNetRoots, &VNetRoot->NetRootListEntry);
307 }
308
309 /*
310 * @implemented
311 */
312 PVOID
313 RxAllocateFcbObject(
314 PRDBSS_DEVICE_OBJECT RxDeviceObject,
315 NODE_TYPE_CODE NodeType,
316 POOL_TYPE PoolType,
317 ULONG NameSize,
318 PVOID AlreadyAllocatedObject)
319 {
320 PFCB Fcb;
321 PFOBX Fobx;
322 PSRV_OPEN SrvOpen;
323 PVOID Buffer, PAPNBuffer;
324 PNON_PAGED_FCB NonPagedFcb;
325 PMINIRDR_DISPATCH Dispatch;
326 ULONG NonPagedSize, FobxSize, SrvOpenSize, FcbSize;
327
328 PAGED_CODE();
329
330 Dispatch = RxDeviceObject->Dispatch;
331
332 NonPagedSize = 0;
333 FobxSize = 0;
334 SrvOpenSize = 0;
335 FcbSize = 0;
336
337 Fcb = NULL;
338 Fobx = NULL;
339 SrvOpen = NULL;
340 NonPagedFcb = NULL;
341 PAPNBuffer = NULL;
342
343 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
344 if (NodeType == RDBSS_NTC_FOBX)
345 {
346 FobxSize = sizeof(FOBX);
347 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
348 {
349 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
350 }
351 }
352 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
353 else if (NodeType == RDBSS_NTC_SRVOPEN || NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
354 {
355 SrvOpenSize = sizeof(SRV_OPEN);
356 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
357 {
358 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
359 }
360
361 FobxSize = sizeof(FOBX);
362 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
363 {
364 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
365 }
366 }
367 /* Otherwise, we're asked to allocate a FCB */
368 else
369 {
370 /* So, allocate the FCB and its extension if asked */
371 FcbSize = sizeof(FCB);
372 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
373 {
374 FcbSize += QuadAlign(Dispatch->MRxFcbSize);
375 }
376
377 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
378 * Otherwise, it will be allocated later on, specifically
379 */
380 if (PoolType == NonPagedPool)
381 {
382 NonPagedSize = sizeof(NON_PAGED_FCB);
383 }
384
385 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
386 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
387 {
388 SrvOpenSize = sizeof(SRV_OPEN);
389 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
390 {
391 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize);
392 }
393
394 FobxSize = sizeof(FOBX);
395 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
396 {
397 FobxSize += QuadAlign(Dispatch->MRxFobxSize);
398 }
399 }
400 }
401
402 /* If we already have a buffer, go ahead */
403 if (AlreadyAllocatedObject != NULL)
404 {
405 Buffer = AlreadyAllocatedObject;
406 }
407 /* Otherwise, allocate it */
408 else
409 {
410 Buffer = RxAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG);
411 if (Buffer == NULL)
412 {
413 return NULL;
414 }
415 }
416
417 /* Now, get the pointers - FOBX is easy */
418 if (NodeType == RDBSS_NTC_FOBX)
419 {
420 Fobx = Buffer;
421 }
422 /* SRV_OPEN first, FOBX next */
423 else if (NodeType == RDBSS_NTC_SRVOPEN)
424 {
425 SrvOpen = Buffer;
426 Fobx = Add2Ptr(Buffer, SrvOpenSize);
427 }
428 else if (NodeType == RDBSS_NTC_INTERNAL_SRVOPEN)
429 {
430 SrvOpen = Buffer;
431 }
432 else
433 {
434 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
435 Fcb = Buffer;
436 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB)
437 {
438 SrvOpen = Add2Ptr(Buffer, FcbSize);
439 Fobx = Add2Ptr(Buffer, FcbSize + SrvOpenSize);
440 }
441
442 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
443 if (PoolType != NonPagedPool)
444 {
445 NonPagedFcb = RxAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG);
446 if (NonPagedFcb == NULL)
447 {
448 RxFreePoolWithTag(Buffer, RX_FCB_POOLTAG);
449 return NULL;
450 }
451
452 PAPNBuffer = Add2Ptr(Buffer, FcbSize + SrvOpenSize + FobxSize);
453 }
454 /* Otherwise, just point at the right place in what has been allocated previously */
455 else
456 {
457 NonPagedFcb = Add2Ptr(Fobx, FobxSize);
458 PAPNBuffer = Add2Ptr(Fobx, FobxSize + NonPagedSize);
459 }
460 }
461
462 /* If we have allocated a SRV_OPEN, initialize it */
463 if (SrvOpen != NULL)
464 {
465 ZeroAndInitializeNodeType(SrvOpen, RDBSS_NTC_SRVOPEN, SrvOpenSize);
466
467 if (NodeType == RDBSS_NTC_SRVOPEN)
468 {
469 SrvOpen->InternalFobx = Fobx;
470 }
471 else
472 {
473 SrvOpen->InternalFobx = NULL;
474 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
475 }
476
477 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION))
478 {
479 SrvOpen->Context = Add2Ptr(SrvOpen, sizeof(SRV_OPEN));
480 }
481
482 InitializeListHead(&SrvOpen->SrvOpenQLinks);
483 }
484
485 /* If we have allocated a FOBX, initialize it */
486 if (Fobx != NULL)
487 {
488 ZeroAndInitializeNodeType(Fobx, RDBSS_NTC_FOBX, FobxSize);
489
490 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION))
491 {
492 Fobx->Context = Add2Ptr(Fobx, sizeof(FOBX));
493 }
494 }
495
496 /* If we have allocated a FCB, initialize it */
497 if (Fcb != NULL)
498 {
499 ZeroAndInitializeNodeType(Fcb, RDBSS_STORAGE_NTC(FileTypeNotYetKnown), FcbSize);
500
501 Fcb->NonPaged = NonPagedFcb;
502 ZeroAndInitializeNodeType(Fcb->NonPaged, RDBSS_NTC_NONPAGED_FCB, sizeof(NON_PAGED_FCB));
503 Fcb->CopyOfNonPaged = NonPagedFcb;
504 NonPagedFcb->FcbBackPointer = Fcb;
505
506 Fcb->InternalSrvOpen = SrvOpen;
507 Fcb->InternalFobx = Fobx;
508
509 Fcb->PrivateAlreadyPrefixedName.Length = NameSize;
510 Fcb->PrivateAlreadyPrefixedName.MaximumLength = NameSize;
511 Fcb->PrivateAlreadyPrefixedName.Buffer = PAPNBuffer;
512
513 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION))
514 {
515 Fcb->Context = Add2Ptr(Fcb, sizeof(FCB));
516 }
517
518 ZeroAndInitializeNodeType(&Fcb->FcbTableEntry, RDBSS_NTC_FCB_TABLE_ENTRY, sizeof(RX_FCB_TABLE_ENTRY));
519
520 InterlockedIncrement(&RxNumberOfActiveFcbs);
521 InterlockedIncrement((volatile long *)&RxDeviceObject->NumberOfActiveFcbs);
522
523 ExInitializeFastMutex(&NonPagedFcb->AdvancedFcbHeaderMutex);
524 FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex);
525 }
526
527 DPRINT("Allocated %p\n", Buffer);
528
529 return Buffer;
530 }
531
532 /*
533 * @implemented
534 */
535 PVOID
536 RxAllocateObject(
537 NODE_TYPE_CODE NodeType,
538 PMINIRDR_DISPATCH MRxDispatch,
539 ULONG NameLength)
540 {
541 ULONG Tag, ObjectSize;
542 PVOID Object, *Extension;
543 PRX_PREFIX_ENTRY PrefixEntry;
544 USHORT StructSize, ExtensionSize;
545
546 PAGED_CODE();
547
548 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
549 ExtensionSize = 0;
550 switch (NodeType)
551 {
552 case RDBSS_NTC_SRVCALL:
553 Tag = RX_SRVCALL_POOLTAG;
554 StructSize = sizeof(SRV_CALL);
555 if (MRxDispatch != NULL && BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
556 {
557 ExtensionSize = QuadAlign(MRxDispatch->MRxSrvCallSize);
558 }
559 break;
560
561 case RDBSS_NTC_NETROOT:
562 Tag = RX_NETROOT_POOLTAG;
563 StructSize = sizeof(NET_ROOT);
564 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_NET_ROOT_EXTENSION))
565 {
566 ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize);
567 }
568 break;
569
570 case RDBSS_NTC_V_NETROOT:
571 Tag = RX_V_NETROOT_POOLTAG;
572 StructSize = sizeof(V_NET_ROOT);
573 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_V_NET_ROOT_EXTENSION))
574 {
575 ExtensionSize = QuadAlign(MRxDispatch->MRxVNetRootSize);
576 }
577 break;
578
579 default:
580 ASSERT(FALSE);
581 break;
582 }
583
584 /* Now, allocate the object */
585 ObjectSize = ExtensionSize + StructSize + NameLength;
586 Object = RxAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag);
587 if (Object == NULL)
588 {
589 return NULL;
590 }
591 /* Initialize it */
592 ZeroAndInitializeNodeType(Object, NodeType, ObjectSize);
593
594 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
595 switch (NodeType)
596 {
597 case RDBSS_NTC_SRVCALL:
598 PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry;
599 Extension = &((PSRV_CALL)Object)->Context;
600 ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix;
601 break;
602
603 case RDBSS_NTC_NETROOT:
604 PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry;
605 Extension = &((PNET_ROOT)Object)->Context;
606 ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix;
607 break;
608
609 case RDBSS_NTC_V_NETROOT:
610 PrefixEntry = &((PV_NET_ROOT)Object)->PrefixEntry;
611 Extension = &((PV_NET_ROOT)Object)->Context;
612 break;
613
614 default:
615 ASSERT(FALSE);
616 break;
617 }
618
619 /* Set the prefix table unicode string */
620 RtlZeroMemory(PrefixEntry, sizeof(RX_PREFIX_ENTRY));
621 PrefixEntry->NodeTypeCode = RDBSS_NTC_PREFIX_ENTRY;
622 PrefixEntry->NodeByteSize = sizeof(RX_PREFIX_ENTRY);
623 PrefixEntry->Prefix.Length = NameLength;
624 PrefixEntry->Prefix.MaximumLength = NameLength;
625 PrefixEntry->Prefix.Buffer = Add2Ptr(Object, ExtensionSize + StructSize);
626
627 /* Return the extension if we are asked to manage it */
628 if (ExtensionSize != 0)
629 {
630 *Extension = Add2Ptr(Object, StructSize);
631 }
632
633 return Object;
634 }
635
636 /*
637 * @implemented
638 */
639 VOID
640 RxAssert(
641 PVOID Assert,
642 PVOID File,
643 ULONG Line,
644 PVOID Message)
645 {
646 CHAR Response[2];
647 CONTEXT Context;
648
649 /* If we're not asked to continue, just stop the system */
650 if (!RxContinueFromAssert)
651 {
652 KeBugCheckEx(RDBSS_FILE_SYSTEM, RDBSS_BUG_CHECK_ASSERT | Line, 0, 0, 0);
653 }
654
655 /* Otherwise, capture context to offer the user to dump it */
656 RtlCaptureContext(&Context);
657
658 /* Loop until the user hits 'i' */
659 while (TRUE)
660 {
661 /* If no file provided, use empty name */
662 if (File == NULL)
663 {
664 File = "";
665 }
666
667 /* If no message provided, use empty one */
668 if (Message == NULL)
669 {
670 Message = "";
671 }
672
673 /* Display the message */
674 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message, Assert, File, Line);
675 /* And ask the user */
676 DbgPrompt("Break, Ignore (bi)? ", Response, sizeof(Response));
677 /* If he asks for ignore, quit
678 * In case of invalid input, ask again
679 */
680 if (Response[0] != 'B' && Response[0] != 'b')
681 {
682 if (Response[0] == 'I' || Response[0] == 'i')
683 {
684 return;
685 }
686
687 continue;
688 }
689
690 /* Break: offer the user to dump the context and break */
691 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context);
692 DbgBreakPoint();
693
694 /* Continue looping, so that after dump, execution can continue (with ignore) */
695 }
696 }
697
698 /*
699 * @implemented
700 */
701 VOID
702 NTAPI
703 RxBootstrapWorkerThreadDispatcher(
704 IN PVOID WorkQueue)
705 {
706 PRX_WORK_QUEUE RxWorkQueue;
707
708 PAGED_CODE();
709
710 RxWorkQueue = WorkQueue;
711 RxpWorkerThreadDispatcher(RxWorkQueue, NULL);
712 }
713
714 /*
715 * @implemented
716 */
717 NTSTATUS
718 NTAPI
719 RxChangeBufferingState(
720 PSRV_OPEN SrvOpen,
721 PVOID Context,
722 BOOLEAN ComputeNewState)
723 {
724 PFCB Fcb;
725 NTSTATUS Status, MiniStatus;
726 ULONG NewBufferingState, OldBufferingState;
727
728 PAGED_CODE();
729
730 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen, Context, ComputeNewState);
731
732 Fcb = (PFCB)SrvOpen->pFcb;
733 ASSERT(NodeTypeIsFcb(Fcb));
734 /* First of all, mark that buffering state is changing */
735 SetFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
736
737 /* Assume success */
738 Status = STATUS_SUCCESS;
739 _SEH2_TRY
740 {
741 /* If we're asked to compute a new state, ask the mini-rdr for it */
742 if (ComputeNewState)
743 {
744 MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxComputeNewBufferingState,
745 ((PMRX_SRV_OPEN)SrvOpen, Context, &NewBufferingState));
746 if (MiniStatus != STATUS_SUCCESS)
747 {
748 NewBufferingState = 0;
749 }
750 }
751 else
752 {
753 /* If not, use SRV_OPEN state */
754 NewBufferingState = SrvOpen->BufferingFlags;
755 }
756
757 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
758 if ((Fcb->ShareAccess.SharedRead + Fcb->ShareAccess.SharedWrite + Fcb->ShareAccess.SharedDelete) == 0 && !ComputeNewState)
759 {
760 SetFlag(NewBufferingState, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES);
761 }
762
763 /* If there's a lock operation to complete, clear that flag */
764 if (Fcb->OutstandingLockOperationsCount != 0)
765 {
766 ClearFlag(NewBufferingState, FCB_STATE_LOCK_BUFFERING_ENABLED);
767 }
768
769 /* Get the old state */
770 OldBufferingState = Fcb->FcbState & FCB_STATE_BUFFERING_STATE_MASK;
771 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags);
772
773 /* If we're dropping write cache, then flush the FCB */
774 if (BooleanFlagOn(OldBufferingState, FCB_STATE_WRITECACHING_ENABLED) &&
775 !BooleanFlagOn(NewBufferingState, FCB_STATE_WRITECACHING_ENABLED))
776 {
777 DPRINT("Flushing\n");
778
779 Status = RxFlushFcbInSystemCache(Fcb, TRUE);
780 }
781
782 /* If we're dropping read cache, then purge */
783 if (Fcb->UncleanCount == 0 ||
784 (BooleanFlagOn(OldBufferingState, FCB_STATE_READCACHING_ENABLED) &&
785 !BooleanFlagOn(NewBufferingState, FCB_STATE_READCACHING_ENABLED)) ||
786 BooleanFlagOn(NewBufferingState, FCB_STATE_DELETE_ON_CLOSE))
787 {
788 DPRINT("Purging\n");
789
790 if (!NT_SUCCESS(Status))
791 {
792 DPRINT("Previous flush failed with status: %lx\n", Status);
793 }
794
795 CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, TRUE);
796 }
797
798 /* If there's already a change pending in SRV_OPEN */
799 if (ComputeNewState && BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
800 {
801 /* If there's a FOBX at least */
802 if (!IsListEmpty(&SrvOpen->FobxList))
803 {
804 PRX_CONTEXT RxContext;
805
806 /* Create a fake context to pass to the mini-rdr */
807 RxContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
808 if (RxContext != NULL)
809 {
810 PFOBX Fobx;
811
812 RxContext->pFcb = RX_GET_MRX_FCB(Fcb);
813
814 /* Give the first FOBX */
815 Fobx = CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks);
816 RxContext->pFobx = (PMRX_FOBX)Fobx;
817 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
818
819 /* If there was a delayed close, perform it */
820 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
821 {
822 DPRINT("Oplock break close for %p\n", SrvOpen);
823
824 RxCloseAssociatedSrvOpen(Fobx, RxContext);
825 }
826 /* Otherwise, inform the mini-rdr about completion */
827 else
828 {
829 MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxCompleteBufferingStateChangeRequest,
830 (RxContext, (PMRX_SRV_OPEN)SrvOpen, Context));
831 (void)MiniStatus;
832 }
833
834 RxDereferenceAndDeleteRxContext(RxContext);
835 }
836 }
837 }
838
839 /* Set the new state */
840 Fcb->FcbState ^= (NewBufferingState ^ Fcb->FcbState) & FCB_STATE_BUFFERING_STATE_MASK;
841 }
842 _SEH2_FINALLY
843 {
844 /* Job done, clear the flag */
845 ClearFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING);
846
847 if (!BooleanFlagOn(NewBufferingState, FCB_STATE_FILETIMECACHEING_ENABLED))
848 {
849 ClearFlag(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET);
850 }
851 }
852 _SEH2_END;
853
854 return Status;
855 }
856
857 NTSTATUS
858 RxCheckVNetRootCredentials(
859 PRX_CONTEXT RxContext,
860 PV_NET_ROOT VNetRoot,
861 PLUID LogonId,
862 PUNICODE_STRING UserName,
863 PUNICODE_STRING UserDomain,
864 PUNICODE_STRING Password,
865 ULONG Flags)
866 {
867 PAGED_CODE();
868
869 /* If that's a UNC name, there's nothing to process */
870 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME) &&
871 (BooleanFlagOn(VNetRoot->Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE) ||
872 Flags != 0))
873 {
874 return STATUS_MORE_PROCESSING_REQUIRED;
875 }
876
877 /* Compare the logon ID in the VNetRoot with the one provided */
878 if (RtlCompareMemory(&VNetRoot->LogonId, LogonId, sizeof(LUID)) != sizeof(LUID))
879 {
880 return STATUS_MORE_PROCESSING_REQUIRED;
881 }
882
883 /* No credential provided? That's OK */
884 if (UserName == NULL && UserDomain == NULL && Password == NULL)
885 {
886 return STATUS_SUCCESS;
887 }
888
889 /* Left to do! */
890 UNIMPLEMENTED;
891 return STATUS_NOT_IMPLEMENTED;
892 }
893
894 NTSTATUS
895 RxCompleteRequest(
896 PRX_CONTEXT Context,
897 NTSTATUS Status)
898 {
899 PIRP Irp;
900
901 PAGED_CODE();
902
903 DPRINT("RxCompleteRequest(%p, %lx)\n", Context, Status);
904
905 ASSERT(Context != NULL);
906 ASSERT(Context->CurrentIrp != NULL);
907 Irp = Context->CurrentIrp;
908
909 /* Debug what the caller asks for */
910 if (Context->LoudCompletionString != NULL)
911 {
912 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
913 /* Does the user asks to stop on failed completion */
914 if (!NT_SUCCESS(Status) && RxStopOnLoudCompletion)
915 {
916 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString);
917 }
918 }
919
920 /* Complete for real */
921 Context->CurrentIrp = NULL;
922 RxCompleteRequest_Real(Context, Irp, Status);
923
924 DPRINT("Status: %lx\n", Status);
925 return Status;
926 }
927
928 /*
929 * @implemented
930 */
931 VOID
932 RxCompleteRequest_Real(
933 IN PRX_CONTEXT RxContext,
934 IN PIRP Irp,
935 IN NTSTATUS Status)
936 {
937 CCHAR Boost;
938 KIRQL OldIrql;
939 PIO_STACK_LOCATION Stack;
940
941 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext, Irp, Status);
942
943 /* Nothing to complete, just free context */
944 if (Irp == NULL)
945 {
946 DPRINT("NULL IRP for %p\n", RxContext);
947 if (RxContext != NULL)
948 {
949 RxDereferenceAndDeleteRxContext_Real(RxContext);
950 }
951
952 return;
953 }
954
955 /* Remove cancel routine */
956 IoAcquireCancelSpinLock(&OldIrql);
957 IoSetCancelRoutine(Irp, NULL);
958 IoReleaseCancelSpinLock(OldIrql);
959
960 /* Select the boost, given the success/paging operation */
961 if (NT_SUCCESS(Status) || !BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO))
962 {
963 Boost = IO_DISK_INCREMENT;
964 }
965 else
966 {
967 Irp->IoStatus.Information = 0;
968 Boost = IO_NO_INCREMENT;
969 }
970 Irp->IoStatus.Status = Status;
971
972 if (RxContext != NULL)
973 {
974 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
975 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
976 {
977 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
978 RxContext->MinorFunction, RxContext, Irp,
979 Status, Irp->IoStatus.Information, RxContext->SerialNumber);
980 }
981 }
982
983 /* If that's an opening, there might be a canonical name allocated,
984 * if completion isn't pending, release it
985 */
986 Stack = IoGetCurrentIrpStackLocation(Irp);
987 if (Stack->MajorFunction == IRP_MJ_CREATE && Status != STATUS_PENDING &&
988 RxContext != NULL)
989 {
990 if (BooleanFlagOn(RxContext->Create.Flags, 2))
991 {
992 Stack->FileObject->FileName.Length += sizeof(WCHAR);
993 }
994
995 RxpPrepareCreateContextForReuse(RxContext);
996 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
997 }
998
999 /* If it's a write, validate the correct behavior of the operation */
1000 if (Stack->MajorFunction == IRP_MJ_WRITE)
1001 {
1002 if (NT_SUCCESS(Irp->IoStatus.Status))
1003 {
1004 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
1005 }
1006 }
1007
1008 /* If it's pending, make sure IRP is marked as such */
1009 if (RxContext != NULL)
1010 {
1011 if (RxContext->PendingReturned)
1012 {
1013 ASSERT(BooleanFlagOn(Stack->Control, SL_PENDING_RETURNED));
1014 }
1015 }
1016
1017 /* Complete now */
1018 DPRINT("Completing IRP with %x/%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information);
1019 IoCompleteRequest(Irp, Boost);
1020
1021 /* If there's a context, dereference it */
1022 if (RxContext != NULL)
1023 {
1024 RxDereferenceAndDeleteRxContext_Real(RxContext);
1025 }
1026 }
1027
1028 /*
1029 * @implemented
1030 */
1031 VOID
1032 RxCompleteSrvOpenKeyAssociation(
1033 IN OUT PSRV_OPEN SrvOpen)
1034 {
1035 PSRV_CALL SrvCall;
1036
1037 SrvCall = (PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall;
1038 /* Only handle requests if opening was a success */
1039 if (SrvOpen->Condition == Condition_Good)
1040 {
1041 KIRQL OldIrql;
1042 BOOLEAN ProcessChange;
1043 LIST_ENTRY DiscardedRequests;
1044
1045 /* Initialize our discarded requests list */
1046 InitializeListHead(&DiscardedRequests);
1047
1048 RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
1049
1050 /* Transfer our requests in the SRV_CALL */
1051 RxTransferList(&SrvCall->BufferingManager.SrvOpenLists[0], &SrvOpen->SrvOpenKeyList);
1052
1053 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
1054 InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens);
1055
1056 /* Dispatch requests and get the discarded ones */
1057 RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &DiscardedRequests);
1058
1059 RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
1060
1061 /* Is there still anything to process? */
1062 KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
1063 if (IsListEmpty(&SrvCall->BufferingManager.HandlerList))
1064 {
1065 ProcessChange = FALSE;
1066 }
1067 else
1068 {
1069 ProcessChange = (SrvCall->BufferingManager.HandlerInactive == FALSE);
1070 if (ProcessChange)
1071 {
1072 SrvCall->BufferingManager.HandlerInactive = TRUE;
1073 }
1074 }
1075 KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
1076
1077 /* Yes? Go ahead! */
1078 if (ProcessChange)
1079 {
1080 RxReferenceSrvCall(SrvCall);
1081 RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
1082 &SrvCall->BufferingManager.HandlerWorkItem,
1083 RxProcessChangeBufferingStateRequests, SrvCall);
1084 }
1085
1086 /* And discard left requests */
1087 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests);
1088 }
1089 else
1090 {
1091 InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens);
1092 }
1093 }
1094
1095 /*
1096 * @implemented
1097 */
1098 NTSTATUS
1099 RxConstructNetRoot(
1100 IN PRX_CONTEXT RxContext,
1101 IN PSRV_CALL SrvCall,
1102 IN PNET_ROOT NetRoot,
1103 IN PV_NET_ROOT VirtualNetRoot,
1104 OUT PLOCK_HOLDING_STATE LockHoldingState)
1105 {
1106 NTSTATUS Status;
1107 PRX_PREFIX_TABLE PrefixTable;
1108 PMRX_CREATENETROOT_CONTEXT Context;
1109 RX_BLOCK_CONDITION RootCondition, VRootCondition;
1110
1111 PAGED_CODE();
1112
1113 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext, SrvCall, NetRoot,
1114 VirtualNetRoot, LockHoldingState);
1115
1116 /* Validate the lock is exclusively held */
1117 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
1118 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
1119
1120 /* Allocate the context */
1121 Context = RxAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG);
1122 if (Context == NULL)
1123 {
1124 return STATUS_INSUFFICIENT_RESOURCES;
1125 }
1126
1127 /* We can release lock now */
1128 RxReleasePrefixTableLock(PrefixTable);
1129 *LockHoldingState = LHS_LockNotHeld;
1130
1131 RootCondition = Condition_Bad;
1132 VRootCondition = Condition_Bad;
1133
1134 /* Initialize the context */
1135 RtlZeroMemory(Context, sizeof(MRX_CREATENETROOT_CONTEXT));
1136 KeInitializeEvent(&Context->FinishEvent, SynchronizationEvent, FALSE);
1137 Context->RxContext = RxContext;
1138 Context->pVNetRoot = VirtualNetRoot;
1139 Context->Callback = RxCreateNetRootCallBack;
1140
1141 /* And call the mini-rdr */
1142 MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot, (Context));
1143 if (Status == STATUS_PENDING)
1144 {
1145 /* Wait for the mini-rdr to be done */
1146 KeWaitForSingleObject(&Context->FinishEvent, Executive, KernelMode, FALSE, NULL);
1147 /* Update the structures condition according to mini-rdr return */
1148 if (NT_SUCCESS(Context->NetRootStatus))
1149 {
1150 if (NT_SUCCESS(Context->VirtualNetRootStatus))
1151 {
1152 RootCondition = Condition_Good;
1153 VRootCondition = Condition_Good;
1154 Status = STATUS_SUCCESS;
1155 }
1156 else
1157 {
1158 RootCondition = Condition_Good;
1159 Status = Context->VirtualNetRootStatus;
1160 }
1161 }
1162 else
1163 {
1164 Status = Context->VirtualNetRootStatus;
1165 if (NT_SUCCESS(Status))
1166 {
1167 Status = Context->NetRootStatus;
1168 }
1169 }
1170 }
1171 else
1172 {
1173 /* It has to return STATUS_PENDING! */
1174 ASSERT(FALSE);
1175 }
1176
1177 /* Acquire lock again - for caller lock status will remain unchanged */
1178 ASSERT(*LockHoldingState == LHS_LockNotHeld);
1179 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
1180 *LockHoldingState = LHS_ExclusiveLockHeld;
1181
1182 /* Do the transition to the condition got from mini-rdr */
1183 RxTransitionNetRoot(NetRoot, RootCondition);
1184 RxTransitionVNetRoot(VirtualNetRoot, VRootCondition);
1185
1186 /* Context is not longer needed */
1187 RxFreePoolWithTag(Context, RX_SRVCALL_POOLTAG);
1188
1189 DPRINT("Status: %x\n", Status);
1190
1191 return Status;
1192 }
1193
1194 /*
1195 * @implemented
1196 */
1197 NTSTATUS
1198 RxConstructSrvCall(
1199 IN PRX_CONTEXT RxContext,
1200 IN PSRV_CALL SrvCall,
1201 OUT PLOCK_HOLDING_STATE LockHoldingState)
1202 {
1203 NTSTATUS Status;
1204 PRX_PREFIX_TABLE PrefixTable;
1205 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1206 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1207 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext;
1208
1209 PAGED_CODE();
1210
1211 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext, SrvCall, LockHoldingState);
1212
1213 /* Validate the lock is exclusively held */
1214 RxDeviceObject = RxContext->RxDeviceObject;
1215 PrefixTable = RxDeviceObject->pRxNetNameTable;
1216 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld);
1217
1218 /* Allocate the context for mini-rdr */
1219 Calldown = RxAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG);
1220 if (Calldown == NULL)
1221 {
1222 SrvCall->Context = NULL;
1223 SrvCall->Condition = Condition_Bad;
1224 RxReleasePrefixTableLock(PrefixTable);
1225 *LockHoldingState = LHS_LockNotHeld;
1226 return STATUS_INSUFFICIENT_RESOURCES;
1227 }
1228
1229 /* Initialize it */
1230 RtlZeroMemory(Calldown, sizeof(MRX_SRVCALLDOWN_STRUCTURE));
1231
1232 SrvCall->Context = NULL;
1233 SrvCall->Condition = Condition_InTransition;
1234
1235 RxReleasePrefixTableLock(PrefixTable);
1236 *LockHoldingState = LHS_LockNotHeld;
1237
1238 CallbackContext = &Calldown->CallbackContexts[0];
1239 DPRINT("CalldownContext %p for %wZ\n", CallbackContext, &RxDeviceObject->DeviceName);
1240 DPRINT("With calldown %p and SrvCall %p\n", Calldown, SrvCall);
1241 CallbackContext->SrvCalldownStructure = Calldown;
1242 CallbackContext->CallbackContextOrdinal = 0;
1243 CallbackContext->RxDeviceObject = RxDeviceObject;
1244
1245 RxReferenceSrvCall(SrvCall);
1246
1247 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1248 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1249 {
1250 RxPrePostIrp(RxContext, RxContext->CurrentIrp);
1251 }
1252 else
1253 {
1254 KeInitializeEvent(&Calldown->FinishEvent, SynchronizationEvent, FALSE);
1255 }
1256
1257 Calldown->NumberToWait = 1;
1258 Calldown->NumberRemaining = 1;
1259 Calldown->RxContext = RxContext;
1260 Calldown->SrvCall = (PMRX_SRV_CALL)SrvCall;
1261 Calldown->CallBack = RxCreateSrvCallCallBack;
1262 Calldown->BestFinisher = NULL;
1263 CallbackContext->Status = STATUS_BAD_NETWORK_PATH;
1264 InitializeListHead(&Calldown->SrvCalldownList);
1265
1266 /* Call the mini-rdr */
1267 ASSERT(RxDeviceObject->Dispatch != NULL);
1268 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
1269 ASSERT(RxDeviceObject->Dispatch->MRxCreateSrvCall != NULL);
1270 Status = RxDeviceObject->Dispatch->MRxCreateSrvCall((PMRX_SRV_CALL)SrvCall, CallbackContext);
1271 /* It has to return STATUS_PENDING! */
1272 ASSERT(Status == STATUS_PENDING);
1273
1274 /* No async, start completion */
1275 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1276 {
1277 KeWaitForSingleObject(&Calldown->FinishEvent, Executive, KernelMode, FALSE, NULL);
1278
1279 /* Finish construction - we'll notify mini-rdr it's the winner */
1280 Status = RxFinishSrvCallConstruction(Calldown);
1281 if (!NT_SUCCESS(Status))
1282 {
1283 RxReleasePrefixTableLock(PrefixTable);
1284 *LockHoldingState = LHS_LockNotHeld;
1285 }
1286 else
1287 {
1288 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
1289 *LockHoldingState = LHS_ExclusiveLockHeld;
1290 }
1291 }
1292
1293 DPRINT("RxConstructSrvCall() = Status: %x\n", Status);
1294 return Status;
1295 }
1296
1297 /*
1298 * @implemented
1299 */
1300 NTSTATUS
1301 RxConstructVirtualNetRoot(
1302 IN PRX_CONTEXT RxContext,
1303 IN PUNICODE_STRING CanonicalName,
1304 IN NET_ROOT_TYPE NetRootType,
1305 OUT PV_NET_ROOT *VirtualNetRootPointer,
1306 OUT PLOCK_HOLDING_STATE LockHoldingState,
1307 OUT PRX_CONNECTION_ID RxConnectionId)
1308 {
1309 NTSTATUS Status;
1310 PV_NET_ROOT VNetRoot;
1311 RX_BLOCK_CONDITION Condition;
1312 UNICODE_STRING LocalNetRootName, FilePathName;
1313
1314 PAGED_CODE();
1315
1316 ASSERT(*LockHoldingState != LHS_LockNotHeld);
1317
1318 VNetRoot = NULL;
1319 Condition = Condition_Bad;
1320 /* Before creating the VNetRoot, try to find the appropriate connection */
1321 Status = RxFindOrCreateConnections(RxContext, CanonicalName, NetRootType,
1322 &LocalNetRootName, &FilePathName,
1323 LockHoldingState, RxConnectionId);
1324 /* Found and active */
1325 if (Status == STATUS_CONNECTION_ACTIVE)
1326 {
1327 /* We need a new VNetRoot */
1328 VNetRoot = RxCreateVNetRoot(RxContext, (PNET_ROOT)RxContext->Create.pVNetRoot->pNetRoot,
1329 CanonicalName, &LocalNetRootName, &FilePathName, RxConnectionId);
1330 if (VNetRoot != NULL)
1331 {
1332 RxReferenceVNetRoot(VNetRoot);
1333 }
1334
1335 /* Dereference previous VNetRoot */
1336 RxDereferenceVNetRoot(RxContext->Create.pVNetRoot->pNetRoot, *LockHoldingState);
1337 /* Reset and start construct (new structures will replace old ones) */
1338 RxContext->Create.pSrvCall = NULL;
1339 RxContext->Create.pNetRoot = NULL;
1340 RxContext->Create.pVNetRoot = NULL;
1341
1342 /* Construct new NetRoot */
1343 if (VNetRoot != NULL)
1344 {
1345 Status = RxConstructNetRoot(RxContext, (PSRV_CALL)VNetRoot->pNetRoot->pSrvCall,
1346 (PNET_ROOT)VNetRoot->pNetRoot, VNetRoot, LockHoldingState);
1347 if (NT_SUCCESS(Status))
1348 {
1349 Condition = Condition_Good;
1350 }
1351 }
1352 else
1353 {
1354 Status = STATUS_INSUFFICIENT_RESOURCES;
1355 }
1356 }
1357 else
1358 {
1359 /* If it failed creating the connection, leave */
1360 if (Status != STATUS_SUCCESS)
1361 {
1362 if (*LockHoldingState != LHS_LockNotHeld)
1363 {
1364 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1365 *LockHoldingState = LHS_LockNotHeld;
1366 }
1367
1368 *VirtualNetRootPointer = VNetRoot;
1369 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status);
1370 return Status;
1371 }
1372
1373 *LockHoldingState = LHS_ExclusiveLockHeld;
1374
1375 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
1376 Condition = Condition_Good;
1377 }
1378
1379 /* We have a non stable VNetRoot - transition it */
1380 if (VNetRoot != NULL && !StableCondition(VNetRoot->Condition))
1381 {
1382 RxTransitionVNetRoot(VNetRoot, Condition);
1383 }
1384
1385 /* If recreation failed */
1386 if (Status != STATUS_SUCCESS)
1387 {
1388 /* Dereference potential VNetRoot */
1389 if (VNetRoot != NULL)
1390 {
1391 ASSERT(*LockHoldingState != LHS_LockNotHeld);
1392 RxDereferenceVNetRoot(VNetRoot, *LockHoldingState);
1393 VNetRoot = NULL;
1394 }
1395
1396 /* Release lock */
1397 if (*LockHoldingState != LHS_LockNotHeld)
1398 {
1399 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable);
1400 *LockHoldingState = LHS_LockNotHeld;
1401 }
1402
1403 /* Set NULL ptr */
1404 *VirtualNetRootPointer = VNetRoot;
1405 return Status;
1406 }
1407
1408 /* Return the allocated VNetRoot */
1409 *VirtualNetRootPointer = VNetRoot;
1410 return Status;
1411 }
1412
1413 /*
1414 * @implemented
1415 */
1416 PFCB
1417 RxCreateNetFcb(
1418 IN PRX_CONTEXT RxContext,
1419 IN PV_NET_ROOT VNetRoot,
1420 IN PUNICODE_STRING Name)
1421 {
1422 PFCB Fcb;
1423 BOOLEAN FakeFcb;
1424 PNET_ROOT NetRoot;
1425 POOL_TYPE PoolType;
1426 NODE_TYPE_CODE NodeType;
1427 PIO_STACK_LOCATION Stack;
1428 PRDBSS_DEVICE_OBJECT RxDeviceObject;
1429
1430 PAGED_CODE();
1431
1432 /* We need a decent VNetRoot */
1433 ASSERT(VNetRoot != NULL && NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT);
1434
1435 NetRoot = (PNET_ROOT)VNetRoot->pNetRoot;
1436 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
1437 ASSERT((PMRX_NET_ROOT)NetRoot == RxContext->Create.pNetRoot);
1438
1439 RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
1440 ASSERT(RxDeviceObject == RxContext->RxDeviceObject);
1441
1442 Stack = RxContext->CurrentIrpSp;
1443
1444 /* Do we need to create a fake FCB? Like for renaming */
1445 FakeFcb = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY) &&
1446 !BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS);
1447 ASSERT(FakeFcb || RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
1448
1449 PoolType = (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE) ? NonPagedPool : PagedPool);
1450 NodeType = (FakeFcb) ? RDBSS_NTC_OPENTARGETDIR_FCB : RDBSS_STORAGE_NTC(FileTypeNotYetKnown);
1451
1452 /* Allocate the FCB */
1453 Fcb = RxAllocateFcbObject(RxDeviceObject, NodeType, PoolType,
1454 NetRoot->InnerNamePrefix.Length + Name->Length, NULL);
1455 if (Fcb == NULL)
1456 {
1457 return NULL;
1458 }
1459
1460 /* Initialize the FCB */
1461 Fcb->CachedNetRootType = NetRoot->Type;
1462 Fcb->RxDeviceObject = RxDeviceObject;
1463 Fcb->MRxDispatch = RxDeviceObject->Dispatch;
1464 Fcb->VNetRoot = VNetRoot;
1465 Fcb->pNetRoot = VNetRoot->pNetRoot;
1466
1467 InitializeListHead(&Fcb->SrvOpenList);
1468 Fcb->SrvOpenListVersion = 0;
1469
1470 Fcb->FcbTableEntry.Path.Length = Name->Length;
1471 Fcb->FcbTableEntry.Path.MaximumLength = Name->Length;
1472 Fcb->FcbTableEntry.Path.Buffer = Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Length);
1473 RtlMoveMemory(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Buffer,
1474 NetRoot->InnerNamePrefix.Length);
1475 RtlMoveMemory(Fcb->FcbTableEntry.Path.Buffer, Name->Buffer, Name->Length);
1476
1477 /* Copy back parameters from RxContext */
1478 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH))
1479 {
1480 Fcb->FcbState |= FCB_STATE_ADDEDBACKSLASH;
1481 }
1482
1483 InitializeListHead(&Fcb->NonPaged->TransitionWaitList);
1484
1485 if (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE))
1486 {
1487 Fcb->FcbState |= FCB_STATE_PAGING_FILE;
1488 }
1489
1490 if (RxContext->MajorFunction == IRP_MJ_CREATE && BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH))
1491 {
1492 Fcb->FcbState |= FCB_STATE_SPECIAL_PATH;
1493 }
1494
1495 Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource;
1496 ExInitializeResourceLite(Fcb->Header.Resource);
1497
1498 Fcb->Header.PagingIoResource = &Fcb->NonPaged->PagingIoResource;
1499 ExInitializeResourceLite(Fcb->Header.PagingIoResource);
1500
1501 Fcb->BufferedLocks.Resource = &Fcb->NonPaged->BufferedLocksResource;
1502 ExInitializeResourceLite(Fcb->BufferedLocks.Resource);
1503
1504 /* Fake FCB doesn't go in prefix table */
1505 if (FakeFcb)
1506 {
1507 Fcb->FcbState |= (FCB_STATE_FAKEFCB | FCB_STATE_NAME_ALREADY_REMOVED);
1508 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
1509 DPRINT("Fake FCB: %p\n", Fcb);
1510 }
1511 else
1512 {
1513 RxFcbTableInsertFcb(&NetRoot->FcbTable, Fcb);
1514 }
1515
1516 RxReferenceVNetRoot(VNetRoot);
1517 InterlockedIncrement((volatile long *)&Fcb->pNetRoot->NumberOfFcbs);
1518
1519 Fcb->ulFileSizeVersion = 0;
1520
1521 DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path);
1522 RxReferenceNetFcb(Fcb);
1523
1524 return Fcb;
1525 }
1526
1527 /*
1528 * @implemented
1529 */
1530 PMRX_FOBX
1531 NTAPI
1532 RxCreateNetFobx(
1533 OUT PRX_CONTEXT RxContext,
1534 IN PMRX_SRV_OPEN MrxSrvOpen)
1535 {
1536 PFCB Fcb;
1537 PFOBX Fobx;
1538 ULONG Flags;
1539 PNET_ROOT NetRoot;
1540 PSRV_OPEN SrvOpen;
1541 POOL_TYPE PoolType;
1542
1543 PAGED_CODE();
1544
1545 SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1546 ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN);
1547 ASSERT(NodeTypeIsFcb(SrvOpen->Fcb));
1548 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
1549
1550 Fcb = SrvOpen->Fcb;
1551 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1552 /* Can we use pre-allocated FOBX? */
1553 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FOBX_USED) && Fcb->InternalSrvOpen == (PSRV_OPEN)MrxSrvOpen)
1554 {
1555 Fobx = Fcb->InternalFobx;
1556 /* Call allocate to initialize the FOBX */
1557 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1558 /* Mark it used now */
1559 Fcb->FcbState |= FCB_STATE_FOBX_USED;
1560 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1561 }
1562 else if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED))
1563 {
1564 Fobx = SrvOpen->InternalFobx;
1565 /* Call allocate to initialize the FOBX */
1566 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx);
1567 /* Mark it used now */
1568 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED;
1569 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED;
1570 }
1571 else
1572 {
1573 /* Last case, we cannot, allocate a FOBX */
1574 Fobx = RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, NULL);
1575 Flags = 0;
1576 }
1577
1578 /* Allocation failed! */
1579 if (Fobx == NULL)
1580 {
1581 return NULL;
1582 }
1583
1584 /* Set flags */
1585 Fobx->Flags = Flags;
1586
1587 /* Initialize throttling */
1588 NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot;
1589 if (NetRoot != NULL)
1590 {
1591 if (NetRoot->DeviceType == FILE_DEVICE_DISK)
1592 {
1593 RxInitializeThrottlingState(&Fobx->Specific.DiskFile.LockThrottlingState,
1594 NetRoot->DiskParameters.LockThrottlingParameters.Increment,
1595 NetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay);
1596 }
1597 else if (NetRoot->DeviceType == FILE_DEVICE_NAMED_PIPE)
1598 {
1599 RxInitializeThrottlingState(&Fobx->Specific.NamedPipe.ThrottlingState,
1600 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.Increment,
1601 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.MaximumDelay);
1602 }
1603 }
1604
1605 /* Propagate flags fron RxContext */
1606 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME))
1607 {
1608 Fobx->Flags |= FOBX_FLAG_UNC_NAME;
1609 }
1610
1611 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT))
1612 {
1613 Fobx->Flags |= FOBX_FLAG_BACKUP_INTENT;
1614 }
1615
1616 /* Continue init */
1617 Fobx->FobxSerialNumber = 0;
1618 Fobx->SrvOpen = (PSRV_OPEN)MrxSrvOpen;
1619 Fobx->NodeReferenceCount = 1;
1620 Fobx->RxDeviceObject = Fcb->RxDeviceObject;
1621
1622 RxReferenceSrvOpen(SrvOpen);
1623 InterlockedIncrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
1624
1625 InsertTailList(&SrvOpen->FobxList, &Fobx->FobxQLinks);
1626 InitializeListHead(&Fobx->ScavengerFinalizationList);
1627 InitializeListHead(&Fobx->ClosePendingList);
1628
1629 Fobx->CloseTime.QuadPart = 0;
1630 Fobx->fOpenCountDecremented = FALSE;
1631
1632 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx, Fobx->SrvOpen, Fobx->SrvOpen->pFcb);
1633
1634 return (PMRX_FOBX)Fobx;
1635 }
1636
1637 /*
1638 * @implemented
1639 */
1640 PNET_ROOT
1641 RxCreateNetRoot(
1642 IN PSRV_CALL SrvCall,
1643 IN PUNICODE_STRING Name,
1644 IN ULONG NetRootFlags,
1645 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
1646 {
1647 PNET_ROOT NetRoot;
1648 USHORT CaseInsensitiveLength;
1649 PRX_PREFIX_TABLE PrefixTable;
1650
1651 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall, Name, NetRootFlags, RxConnectionId);
1652
1653 PAGED_CODE();
1654
1655 /* We need a SRV_CALL */
1656 ASSERT(SrvCall != NULL);
1657
1658 PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
1659 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
1660
1661 /* Get name length */
1662 CaseInsensitiveLength = SrvCall->PrefixEntry.Prefix.Length + Name->Length;
1663 if (CaseInsensitiveLength > MAXUSHORT)
1664 {
1665 return NULL;
1666 }
1667
1668 /* Allocate the NetRoot */
1669 NetRoot = RxAllocateObject(RDBSS_NTC_NETROOT, SrvCall->RxDeviceObject->Dispatch,
1670 CaseInsensitiveLength);
1671 if (NetRoot == NULL)
1672 {
1673 return NULL;
1674 }
1675
1676 /* Construct name */
1677 RtlMoveMemory(Add2Ptr(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Length),
1678 Name->Buffer, Name->Length);
1679 if (SrvCall->PrefixEntry.Prefix.Length != 0)
1680 {
1681 RtlMoveMemory(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Buffer,
1682 SrvCall->PrefixEntry.Prefix.Length);
1683 }
1684
1685 if (!BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
1686 {
1687 CaseInsensitiveLength = SrvCall->PrefixEntry.CaseInsensitiveLength;
1688 }
1689 /* Inisert in prefix table */
1690 RxPrefixTableInsertName(PrefixTable, &NetRoot->PrefixEntry, NetRoot,
1691 (PULONG)&NetRoot->NodeReferenceCount, CaseInsensitiveLength,
1692 RxConnectionId);
1693
1694 /* Prepare the FCB table */
1695 RxInitializeFcbTable(&NetRoot->FcbTable, TRUE);
1696
1697 InitializeListHead(&NetRoot->TransitionWaitList);
1698 InitializeListHead(&NetRoot->ScavengerFinalizationList);
1699 InitializeListHead(&NetRoot->VirtualNetRoots);
1700
1701 RxInitializePurgeSyncronizationContext(&NetRoot->PurgeSyncronizationContext);
1702
1703 NetRoot->SerialNumberForEnum = SerialNumber++;
1704 NetRoot->Flags |= NetRootFlags;
1705 NetRoot->DiskParameters.ClusterSize = 1;
1706 NetRoot->DiskParameters.ReadAheadGranularity = ReadAheadGranularity;
1707 NetRoot->SrvCall = SrvCall;
1708
1709 RxReferenceSrvCall(SrvCall);
1710
1711 DPRINT("NetRootName: %wZ (%p)\n", NetRoot->pNetRootName, NetRoot);
1712 return NetRoot;
1713 }
1714
1715 /*
1716 * @implemented
1717 */
1718 VOID
1719 NTAPI
1720 RxCreateNetRootCallBack(
1721 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext)
1722 {
1723 PAGED_CODE();
1724
1725 KeSetEvent(&CreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1726 }
1727
1728 /*
1729 * @implemented
1730 */
1731 PRX_CONTEXT
1732 NTAPI
1733 RxCreateRxContext(
1734 IN PIRP Irp,
1735 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
1736 IN ULONG InitialContextFlags)
1737 {
1738 KIRQL OldIrql;
1739 PRX_CONTEXT Context;
1740
1741 ASSERT(RxDeviceObject != NULL);
1742
1743 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp, RxDeviceObject, InitialContextFlags);
1744
1745 InterlockedIncrement((volatile LONG *)&RxFsdEntryCount);
1746 InterlockedIncrement((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts);
1747
1748 /* Allocate the context from our lookaside list */
1749 Context = ExAllocateFromNPagedLookasideList(&RxContextLookasideList);
1750 if (Context == NULL)
1751 {
1752 return NULL;
1753 }
1754
1755 /* Zero it */
1756 RtlZeroMemory(Context, sizeof(RX_CONTEXT));
1757
1758 /* It was allocated on NP pool, keep track of it! */
1759 SetFlag(Context->Flags, RX_CONTEXT_FLAG_FROM_POOL);
1760 /* And initialize it */
1761 RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context);
1762 ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED));
1763
1764 /* Add it to our global list */
1765 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1766 InsertTailList(&RxActiveContexts, &Context->ContextListEntry);
1767 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1768
1769 DPRINT("Context: %p\n", Context);
1770 return Context;
1771 }
1772
1773 /*
1774 * @implemented
1775 */
1776 PSRV_CALL
1777 RxCreateSrvCall(
1778 IN PRX_CONTEXT RxContext,
1779 IN PUNICODE_STRING Name,
1780 IN PUNICODE_STRING InnerNamePrefix OPTIONAL,
1781 IN PRX_CONNECTION_ID RxConnectionId)
1782 {
1783 ULONG NameLength;
1784 PSRV_CALL SrvCall;
1785
1786 PAGED_CODE();
1787
1788 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext, Name, InnerNamePrefix, RxConnectionId);
1789
1790 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
1791
1792 /* Get the name length */
1793 NameLength = Name->Length + 2 * sizeof(WCHAR);
1794 if (InnerNamePrefix != NULL)
1795 {
1796 NameLength += InnerNamePrefix->Length;
1797 }
1798
1799 /* Allocate the object */
1800 SrvCall = RxAllocateObject(RDBSS_NTC_SRVCALL, NULL, NameLength);
1801 if (SrvCall == NULL)
1802 {
1803 return NULL;
1804 }
1805
1806 /* Initialize it */
1807 SrvCall->SerialNumberForEnum = SerialNumber++;
1808 SrvCall->RxDeviceObject = RxContext->RxDeviceObject;
1809 RxInitializeBufferingManager(SrvCall);
1810 InitializeListHead(&SrvCall->TransitionWaitList);
1811 InitializeListHead(&SrvCall->ScavengerFinalizationList);
1812 RxInitializePurgeSyncronizationContext(&SrvCall->PurgeSyncronizationContext);
1813 RxInitializeSrvCallParameters(RxContext, SrvCall);
1814 RtlMoveMemory(SrvCall->PrefixEntry.Prefix.Buffer, Name->Buffer, Name->Length);
1815 SrvCall->PrefixEntry.Prefix.MaximumLength = Name->Length + 2 * sizeof(WCHAR);
1816 SrvCall->PrefixEntry.Prefix.Length = Name->Length;
1817 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &SrvCall->PrefixEntry,
1818 SrvCall, (PULONG)&SrvCall->NodeReferenceCount, Name->Length, RxConnectionId);
1819
1820 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall->pSrvCallName, SrvCall);
1821 return SrvCall;
1822 }
1823
1824 /*
1825 * @implemented
1826 */
1827 VOID
1828 NTAPI
1829 RxCreateSrvCallCallBack(
1830 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context)
1831 {
1832 KIRQL OldIrql;
1833 PSRV_CALL SrvCall;
1834 PRX_CONTEXT RxContext;
1835 ULONG NumberRemaining;
1836 BOOLEAN StartDispatcher;
1837 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
1838
1839 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context);
1840
1841 /* Get our context structures */
1842 Calldown = Context->SrvCalldownStructure;
1843 SrvCall = (PSRV_CALL)Calldown->SrvCall;
1844
1845 /* If it is a success, that's the winner */
1846 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1847 if (Context->Status == STATUS_SUCCESS)
1848 {
1849 Calldown->BestFinisherOrdinal = Context->CallbackContextOrdinal;
1850 Calldown->BestFinisher = Context->RxDeviceObject;
1851 }
1852 NumberRemaining = --Calldown->NumberRemaining;
1853 SrvCall->Status = Context->Status;
1854 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1855
1856 /* Still some to ask, keep going */
1857 if (NumberRemaining != 0)
1858 {
1859 return;
1860 }
1861
1862 /* If that's not async, signal we're done */
1863 RxContext = Calldown->RxContext;
1864 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
1865 {
1866 KeSetEvent(&Calldown->FinishEvent, IO_NETWORK_INCREMENT, FALSE);
1867 return;
1868 }
1869 /* If that's a mailslot, finish construction, no more to do */
1870 else if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT))
1871 {
1872 RxFinishSrvCallConstruction(Calldown);
1873 return;
1874 }
1875
1876 /* Queue our finish call for delayed completion */
1877 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1878 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
1879 InsertTailList(&RxSrvCalldownList, &Calldown->SrvCalldownList);
1880 StartDispatcher = !RxSrvCallConstructionDispatcherActive;
1881 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
1882
1883 /* If we have to start dispatcher, go ahead */
1884 if (StartDispatcher)
1885 {
1886 NTSTATUS Status;
1887
1888 Status = RxDispatchToWorkerThread(RxFileSystemDeviceObject, CriticalWorkQueue,
1889 RxFinishSrvCallConstructionDispatcher, &RxSrvCalldownList);
1890 if (!NT_SUCCESS(Status))
1891 {
1892 /* It failed - run it manually.... */
1893 RxFinishSrvCallConstructionDispatcher(NULL);
1894 }
1895 }
1896 }
1897
1898 /*
1899 * @implemented
1900 */
1901 PSRV_OPEN
1902 RxCreateSrvOpen(
1903 IN PV_NET_ROOT VNetRoot,
1904 IN OUT PFCB Fcb)
1905 {
1906 ULONG Flags;
1907 PSRV_OPEN SrvOpen;
1908 POOL_TYPE PoolType;
1909
1910 PAGED_CODE();
1911
1912 ASSERT(NodeTypeIsFcb(Fcb));
1913 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
1914
1915 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool);
1916
1917 _SEH2_TRY
1918 {
1919 SrvOpen = Fcb->InternalSrvOpen;
1920 /* Check whethet we have to allocate a new SRV_OPEN */
1921 if (Fcb->InternalSrvOpen == NULL || BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED) ||
1922 BooleanFlagOn(Fcb->InternalSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED) ||
1923 !IsListEmpty(&Fcb->InternalSrvOpen->SrvOpenQLinks))
1924 {
1925 /* Proceed */
1926 SrvOpen = RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1927 RDBSS_NTC_SRVOPEN, PoolType, 0, NULL);
1928 Flags = 0;
1929 }
1930 else
1931 {
1932 /* Otherwise, just use internal one and initialize it */
1933 RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject,
1934 RDBSS_NTC_INTERNAL_SRVOPEN, PoolType, 0,
1935 Fcb->InternalSrvOpen);
1936 Fcb->FcbState |= FCB_STATE_SRVOPEN_USED;
1937 Flags = SRVOPEN_FLAG_ENCLOSED_ALLOCATED | SRVOPEN_FLAG_FOBX_USED;
1938 }
1939
1940 /* If SrvOpen was properly allocated, initialize it */
1941 if (SrvOpen != NULL)
1942 {
1943 SrvOpen->Flags = Flags;
1944 SrvOpen->pFcb = RX_GET_MRX_FCB(Fcb);
1945 SrvOpen->pAlreadyPrefixedName = &Fcb->PrivateAlreadyPrefixedName;
1946 SrvOpen->pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
1947 SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion;
1948 SrvOpen->NodeReferenceCount = 1;
1949
1950 RxReferenceVNetRoot(VNetRoot);
1951 RxReferenceNetFcb(Fcb);
1952
1953 InsertTailList(&Fcb->SrvOpenList, &SrvOpen->SrvOpenQLinks);
1954 ++Fcb->SrvOpenListVersion;
1955
1956 InitializeListHead(&SrvOpen->ScavengerFinalizationList);
1957 InitializeListHead(&SrvOpen->TransitionWaitList);
1958 InitializeListHead(&SrvOpen->FobxList);
1959 InitializeListHead(&SrvOpen->SrvOpenKeyList);
1960 }
1961 }
1962 _SEH2_FINALLY
1963 {
1964 if (_SEH2_AbnormalTermination())
1965 {
1966 if (SrvOpen != NULL)
1967 {
1968 RxFinalizeSrvOpen(SrvOpen, TRUE, TRUE);
1969 SrvOpen = NULL;
1970 }
1971 }
1972 else
1973 {
1974 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen, SrvOpen->pFcb);
1975 }
1976 }
1977 _SEH2_END;
1978
1979 return SrvOpen;
1980 }
1981
1982 /*
1983 * @implemented
1984 */
1985 PV_NET_ROOT
1986 RxCreateVNetRoot(
1987 IN PRX_CONTEXT RxContext,
1988 IN PNET_ROOT NetRoot,
1989 IN PUNICODE_STRING CanonicalName,
1990 IN PUNICODE_STRING LocalNetRootName,
1991 IN PUNICODE_STRING FilePath,
1992 IN PRX_CONNECTION_ID RxConnectionId)
1993 {
1994 NTSTATUS Status;
1995 PV_NET_ROOT VNetRoot;
1996 USHORT CaseInsensitiveLength;
1997
1998 PAGED_CODE();
1999
2000 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext, NetRoot, CanonicalName,
2001 LocalNetRootName, FilePath, RxConnectionId);
2002
2003 /* Lock must be held exclusively */
2004 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable));
2005
2006 /* Check for overflow */
2007 if (LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length > MAXUSHORT)
2008 {
2009 return NULL;
2010 }
2011
2012 /* Get name length and allocate VNetRoot */
2013 CaseInsensitiveLength = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
2014 VNetRoot = RxAllocateObject(RDBSS_NTC_V_NETROOT, NetRoot->SrvCall->RxDeviceObject->Dispatch,
2015 CaseInsensitiveLength);
2016 if (VNetRoot == NULL)
2017 {
2018 return NULL;
2019 }
2020
2021 /* Initialize its connection parameters */
2022 Status = RxInitializeVNetRootParameters(RxContext, &VNetRoot->LogonId, &VNetRoot->SessionId,
2023 &VNetRoot->pUserName, &VNetRoot->pUserDomainName,
2024 &VNetRoot->pPassword, &VNetRoot->Flags);
2025 if (!NT_SUCCESS(Status))
2026 {
2027 RxUninitializeVNetRootParameters(VNetRoot->pUserName, VNetRoot->pUserDomainName,
2028 VNetRoot->pPassword, &VNetRoot->Flags);
2029 RxFreeObject(VNetRoot);
2030
2031 return NULL;
2032 }
2033
2034 /* Set name */
2035 RtlMoveMemory(VNetRoot->PrefixEntry.Prefix.Buffer, CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
2036
2037 VNetRoot->PrefixOffsetInBytes = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length;
2038 VNetRoot->NamePrefix.Buffer = Add2Ptr(VNetRoot->PrefixEntry.Prefix.Buffer, VNetRoot->PrefixOffsetInBytes);
2039 VNetRoot->NamePrefix.Length = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
2040 VNetRoot->NamePrefix.MaximumLength = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes;
2041
2042 InitializeListHead(&VNetRoot->TransitionWaitList);
2043 InitializeListHead(&VNetRoot->ScavengerFinalizationList);
2044
2045 if (!BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES))
2046 {
2047 USHORT i;
2048
2049 if (BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS))
2050 {
2051 CaseInsensitiveLength = NetRoot->PrefixEntry.CaseInsensitiveLength;
2052 }
2053 else
2054 {
2055 CaseInsensitiveLength = NetRoot->SrvCall->PrefixEntry.CaseInsensitiveLength;
2056 }
2057
2058 for (i = 1; i < CanonicalName->Length / sizeof(WCHAR); ++i)
2059 {
2060 if (CanonicalName->Buffer[i] != OBJ_NAME_PATH_SEPARATOR)
2061 {
2062 break;
2063 }
2064 }
2065
2066 CaseInsensitiveLength += (i * sizeof(WCHAR));
2067 }
2068
2069 /* Insert in prefix table */
2070 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &VNetRoot->PrefixEntry,
2071 VNetRoot, (PULONG)&VNetRoot->NodeReferenceCount, CaseInsensitiveLength,
2072 RxConnectionId);
2073
2074 RxReferenceNetRoot(NetRoot);
2075 RxAddVirtualNetRootToNetRoot(NetRoot, VNetRoot);
2076
2077 /* Finish init */
2078 VNetRoot->SerialNumberForEnum = SerialNumber++;
2079 VNetRoot->UpperFinalizationDone = FALSE;
2080 VNetRoot->ConnectionFinalizationDone = FALSE;
2081 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
2082
2083 DPRINT("NamePrefix: %wZ\n", &VNetRoot->NamePrefix);
2084 DPRINT("PrefixEntry: %wZ\n", &VNetRoot->PrefixEntry.Prefix);
2085
2086 return VNetRoot;
2087 }
2088
2089 /*
2090 * @implemented
2091 */
2092 VOID
2093 RxDereference(
2094 IN OUT PVOID Instance,
2095 IN LOCK_HOLDING_STATE LockHoldingState)
2096 {
2097 LONG RefCount;
2098 NODE_TYPE_CODE NodeType;
2099 PNODE_TYPE_AND_SIZE Node;
2100
2101 PAGED_CODE();
2102
2103 RxAcquireScavengerMutex();
2104
2105 /* Check we have a node we can handle */
2106 NodeType = NodeType(Instance);
2107 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
2108 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
2109 (NodeType == RDBSS_NTC_FOBX));
2110
2111 Node = (PNODE_TYPE_AND_SIZE)Instance;
2112 RefCount = InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
2113 ASSERT(RefCount >= 0);
2114
2115 /* Trace refcount */
2116 switch (NodeType)
2117 {
2118 case RDBSS_NTC_SRVCALL:
2119 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
2120 break;
2121
2122 case RDBSS_NTC_NETROOT:
2123 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
2124 break;
2125
2126 case RDBSS_NTC_V_NETROOT:
2127 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
2128 break;
2129
2130 case RDBSS_NTC_SRVOPEN:
2131 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
2132 break;
2133
2134 case RDBSS_NTC_FOBX:
2135 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
2136 break;
2137
2138 default:
2139 ASSERT(FALSE);
2140 break;
2141 }
2142
2143 /* No need to free - still in use */
2144 if (RefCount > 1)
2145 {
2146 RxReleaseScavengerMutex();
2147 return;
2148 }
2149
2150 /* We have to be locked exclusively */
2151 if (LockHoldingState != LHS_ExclusiveLockHeld)
2152 {
2153 if ((NodeType == RDBSS_NTC_FOBX && RefCount == 0) ||
2154 (NodeType >= RDBSS_NTC_SRVCALL && NodeType <= RDBSS_NTC_V_NETROOT))
2155 {
2156 RxpMarkInstanceForScavengedFinalization(Instance);
2157 }
2158
2159 RxReleaseScavengerMutex();
2160 return;
2161 }
2162 else
2163 {
2164 if (BooleanFlagOn(NodeType, RX_SCAVENGER_MASK))
2165 {
2166 RxpUndoScavengerFinalizationMarking(Instance);
2167 }
2168 }
2169
2170 RxReleaseScavengerMutex();
2171
2172 /* Now, deallocate the memory */
2173 switch (NodeType)
2174 {
2175 case RDBSS_NTC_SRVCALL:
2176 {
2177 PSRV_CALL SrvCall;
2178
2179 SrvCall = (PSRV_CALL)Instance;
2180
2181 ASSERT(SrvCall->RxDeviceObject != NULL);
2182 ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable));
2183 RxFinalizeSrvCall(SrvCall, TRUE, TRUE);
2184 break;
2185 }
2186
2187 case RDBSS_NTC_NETROOT:
2188 {
2189 PNET_ROOT NetRoot;
2190
2191 NetRoot = (PNET_ROOT)Instance;
2192
2193 ASSERT(NetRoot->pSrvCall->RxDeviceObject != NULL);
2194 ASSERT(RxIsPrefixTableLockAcquired(NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
2195 RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
2196 break;
2197 }
2198
2199 case RDBSS_NTC_V_NETROOT:
2200 {
2201 PV_NET_ROOT VNetRoot;
2202
2203 VNetRoot = (PV_NET_ROOT)Instance;
2204
2205 ASSERT(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject != NULL);
2206 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable));
2207 RxFinalizeVNetRoot(VNetRoot, TRUE, TRUE);
2208 break;
2209 }
2210
2211 case RDBSS_NTC_SRVOPEN:
2212 {
2213 PSRV_OPEN SrvOpen;
2214
2215 SrvOpen = (PSRV_OPEN)Instance;
2216
2217 ASSERT(RxIsFcbAcquired(SrvOpen->Fcb));
2218 if (SrvOpen->OpenCount == 0)
2219 {
2220 RxFinalizeSrvOpen(SrvOpen, FALSE, FALSE);
2221 }
2222 break;
2223 }
2224
2225 case RDBSS_NTC_FOBX:
2226 {
2227 PFOBX Fobx;
2228
2229 Fobx = (PFOBX)Instance;
2230
2231 ASSERT(RxIsFcbAcquired(Fobx->SrvOpen->Fcb));
2232 RxFinalizeNetFobx(Fobx, TRUE, FALSE);
2233 break;
2234 }
2235 }
2236 }
2237
2238 /*
2239 * @implemented
2240 */
2241 VOID
2242 NTAPI
2243 RxDereferenceAndDeleteRxContext_Real(
2244 IN PRX_CONTEXT RxContext)
2245 {
2246 KIRQL OldIrql;
2247 ULONG RefCount;
2248 BOOLEAN Allocated;
2249 PRX_CONTEXT StopContext = NULL;
2250
2251 /* Make sure we really have a context */
2252 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
2253 ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT);
2254 RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount);
2255 /* If refcount is 0, start releasing stuff that needs spinlock held */
2256 if (RefCount == 0)
2257 {
2258 PRDBSS_DEVICE_OBJECT RxDeviceObject;
2259
2260 Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
2261
2262 /* If that's stop context from DO, remove it */
2263 RxDeviceObject = RxContext->RxDeviceObject;
2264 if (RxDeviceObject->StartStopContext.pStopContext == RxContext)
2265 {
2266 RxDeviceObject->StartStopContext.pStopContext = NULL;
2267 }
2268 else
2269 {
2270 /* Remove it from the list */
2271 ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
2272 (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
2273 RemoveEntryList(&RxContext->ContextListEntry);
2274
2275 /* If that was the last active context, save the stop context */
2276 if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0)
2277 {
2278 if (RxDeviceObject->StartStopContext.pStopContext != NULL)
2279 {
2280 StopContext = RxDeviceObject->StartStopContext.pStopContext;
2281 }
2282 }
2283 }
2284 }
2285 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
2286
2287 /* Now, deal with what can be done without spinlock held */
2288 if (RefCount == 0)
2289 {
2290 /* Refcount shouldn't have changed */
2291 ASSERT(RxContext->ReferenceCount == 0);
2292 /* Reset everything that can be */
2293 RxPrepareContextForReuse(RxContext);
2294
2295 #ifdef RDBSS_TRACKER
2296 ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
2297 #endif
2298 /* If that was the last active, set the event */
2299 if (StopContext != NULL)
2300 {
2301 StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL;
2302 KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE);
2303 }
2304
2305 /* Is ShadowCrit still owned? Shouldn't happen! */
2306 if (RxContext->ShadowCritOwner != 0)
2307 {
2308 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID)RxContext->ShadowCritOwner);
2309 ASSERT(FALSE);
2310 }
2311
2312 /* If it was allocated, free it */
2313 if (Allocated)
2314 {
2315 ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext);
2316 }
2317 }
2318 }
2319
2320 VOID
2321 NTAPI
2322 RxDispatchChangeBufferingStateRequests(
2323 PVOID Context)
2324 {
2325 UNIMPLEMENTED;
2326 }
2327
2328 /*
2329 * @implemented
2330 */
2331 NTSTATUS
2332 NTAPI
2333 RxDispatchToWorkerThread(
2334 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
2335 IN WORK_QUEUE_TYPE WorkQueueType,
2336 IN PRX_WORKERTHREAD_ROUTINE Routine,
2337 IN PVOID pContext)
2338 {
2339 NTSTATUS Status;
2340 PRX_WORK_DISPATCH_ITEM DispatchItem;
2341
2342 /* Allocate a bit of context */
2343 DispatchItem = RxAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG);
2344 if (DispatchItem == NULL)
2345 {
2346 return STATUS_INSUFFICIENT_RESOURCES;
2347 }
2348
2349 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2350 DispatchItem->DispatchRoutine = Routine;
2351 DispatchItem->DispatchRoutineParameter = pContext;
2352 DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher;
2353 DispatchItem->WorkQueueItem.Parameter = DispatchItem;
2354
2355 /* Insert item */
2356 Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, &DispatchItem->WorkQueueItem);
2357 if (!NT_SUCCESS(Status))
2358 {
2359 RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
2360 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status);
2361 }
2362
2363 DPRINT("Dispatching: %p, %p\n", Routine, pContext);
2364
2365 return Status;
2366 }
2367
2368 /*
2369 * @implemented
2370 */
2371 VOID
2372 RxExclusivePrefixTableLockToShared(
2373 PRX_PREFIX_TABLE Table)
2374 {
2375 PAGED_CODE();
2376
2377 ExConvertExclusiveToSharedLite(&Table->TableLock);
2378 }
2379
2380 /*
2381 * @implemented
2382 */
2383 VOID
2384 RxExtractServerName(
2385 IN PUNICODE_STRING FilePathName,
2386 OUT PUNICODE_STRING SrvCallName,
2387 OUT PUNICODE_STRING RestOfName)
2388 {
2389 USHORT i, Length;
2390
2391 PAGED_CODE();
2392
2393 ASSERT(SrvCallName != NULL);
2394
2395 /* SrvCall name will start from the begin up to the first separator */
2396 SrvCallName->Buffer = FilePathName->Buffer;
2397 for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i)
2398 {
2399 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
2400 {
2401 break;
2402 }
2403 }
2404
2405 /* Compute length */
2406 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer);
2407 SrvCallName->MaximumLength = Length;
2408 SrvCallName->Length = Length;
2409
2410 /* Return the rest if asked */
2411 if (RestOfName != NULL)
2412 {
2413 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]);
2414 RestOfName->Buffer = &FilePathName->Buffer[i];
2415 RestOfName->MaximumLength = Length;
2416 RestOfName->Length = Length;
2417 }
2418 }
2419
2420 /*
2421 * @implemented
2422 */
2423 NTSTATUS
2424 RxFcbTableInsertFcb(
2425 IN OUT PRX_FCB_TABLE FcbTable,
2426 IN OUT PFCB Fcb)
2427 {
2428 PAGED_CODE();
2429
2430 /* We deal with the table, make sure it's locked */
2431 ASSERT(RxIsFcbTableLockExclusive(FcbTable));
2432
2433 /* Compute the hash */
2434 Fcb->FcbTableEntry.HashValue = RxTableComputePathHashValue(&Fcb->FcbTableEntry.Path);
2435
2436 RxReferenceNetFcb(Fcb);
2437
2438 /* If no length, it will be our null entry */
2439 if (Fcb->FcbTableEntry.Path.Length == 0)
2440 {
2441 FcbTable->TableEntryForNull = &Fcb->FcbTableEntry;
2442 }
2443 /* Otherwise, insert in the appropriate bucket */
2444 else
2445 {
2446 InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue),
2447 &Fcb->FcbTableEntry.HashLinks);
2448 }
2449
2450 /* Propagate the change by incrementing the version number */
2451 InterlockedIncrement((volatile long *)&FcbTable->Version);
2452
2453 return STATUS_SUCCESS;
2454 }
2455
2456 /*
2457 * @implemented
2458 */
2459 PFCB
2460 RxFcbTableLookupFcb(
2461 IN PRX_FCB_TABLE FcbTable,
2462 IN PUNICODE_STRING Path)
2463 {
2464 PFCB Fcb;
2465 PRX_FCB_TABLE_ENTRY TableEntry;
2466
2467 PAGED_CODE();
2468
2469 /* No path - easy, that's null entry */
2470 if (Path == NULL)
2471 {
2472 TableEntry = FcbTable->TableEntryForNull;
2473 }
2474 else
2475 {
2476 ULONG Hash;
2477 PLIST_ENTRY HashBucket, ListEntry;
2478
2479 /* Otherwise, compute the hash value and find the associated bucket */
2480 Hash = RxTableComputePathHashValue(Path);
2481 HashBucket = FCB_HASH_BUCKET(FcbTable, Hash);
2482 /* If the bucket is empty, it means there's no entry yet */
2483 if (IsListEmpty(HashBucket))
2484 {
2485 TableEntry = NULL;
2486 }
2487 else
2488 {
2489 /* Otherwise, browse all the entry */
2490 for (ListEntry = HashBucket->Flink;
2491 ListEntry != HashBucket;
2492 ListEntry = ListEntry->Flink)
2493 {
2494 TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks);
2495 InterlockedIncrement(&FcbTable->Compares);
2496
2497 /* If entry hash and string are equal, thatt's the one! */
2498 if (TableEntry->HashValue == Hash &&
2499 TableEntry->Path.Length == Path->Length &&
2500 RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch))
2501 {
2502 break;
2503 }
2504 }
2505
2506 /* We reached the end? Not found */
2507 if (ListEntry == HashBucket)
2508 {
2509 TableEntry = NULL;
2510 }
2511 }
2512 }
2513
2514 InterlockedIncrement(&FcbTable->Lookups);
2515
2516 /* If table entry isn't null, return the FCB */
2517 if (TableEntry != NULL)
2518 {
2519 Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry);
2520 RxReferenceNetFcb(Fcb);
2521 }
2522 else
2523 {
2524 Fcb = NULL;
2525 InterlockedIncrement(&FcbTable->FailedLookups);
2526 }
2527
2528 return Fcb;
2529 }
2530
2531 /*
2532 * @implemented
2533 */
2534 NTSTATUS
2535 RxFcbTableRemoveFcb(
2536 IN OUT PRX_FCB_TABLE FcbTable,
2537 IN OUT PFCB Fcb)
2538 {
2539 PAGED_CODE();
2540
2541 ASSERT(RxIsPrefixTableLockExclusive(FcbTable));
2542
2543 /* If no path, then remove entry for null */
2544 if (Fcb->FcbTableEntry.Path.Length == 0)
2545 {
2546 FcbTable->TableEntryForNull = NULL;
2547 }
2548 /* Otherwise, remove from the bucket */
2549 else
2550 {
2551 RemoveEntryList(&Fcb->FcbTableEntry.HashLinks);
2552 }
2553
2554 /* Reset its list entry */
2555 InitializeListHead(&Fcb->FcbTableEntry.HashLinks);
2556
2557 /* Propagate the change by incrementing the version number */
2558 InterlockedIncrement((volatile long *)&FcbTable->Version);
2559
2560 return STATUS_SUCCESS;
2561 }
2562
2563 /*
2564 * @implemented
2565 */
2566 NTSTATUS
2567 NTAPI
2568 RxFinalizeConnection(
2569 IN OUT PNET_ROOT NetRoot,
2570 IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
2571 IN LOGICAL ForceFilesClosed)
2572 {
2573 NTSTATUS Status;
2574 PRX_PREFIX_TABLE PrefixTable;
2575 ULONG UncleanAny, UncleanDir;
2576 LONG FilesOpen, AdditionalRef;
2577 BOOLEAN PrefixLocked, FcbTableLocked, ForceClose;
2578
2579 PAGED_CODE();
2580
2581 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
2582
2583 /* Get a BOOLEAN out of LOGICAL
2584 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2585 */
2586 ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE);
2587
2588 /* First, delete any notification change */
2589 Status = RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot, ForceClose);
2590 /* If it failed, continue if forced */
2591 if (Status != STATUS_SUCCESS && !ForceFilesClosed)
2592 {
2593 return Status;
2594 }
2595 /* Reset status, in case notification deletion failed */
2596 Status = STATUS_SUCCESS;
2597
2598 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
2599
2600 PrefixLocked = FALSE;
2601 FcbTableLocked = FALSE;
2602 FilesOpen = 0;
2603 AdditionalRef = 0;
2604 UncleanAny = 0;
2605 UncleanDir = 0;
2606 _SEH2_TRY
2607 {
2608 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2609 PrefixLocked = TRUE;
2610
2611 RxReferenceNetRoot(NetRoot);
2612
2613 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2614 FcbTableLocked = TRUE;
2615
2616 /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2617 if (!VNetRoot->ConnectionFinalizationDone)
2618 {
2619 USHORT Bucket;
2620 PRX_FCB_TABLE FcbTable;
2621
2622 DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix);
2623
2624 /* We'll browse all its associated FCB to check whether they're open/orphaned */
2625 FcbTable = &NetRoot->FcbTable;
2626 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2627 {
2628 PLIST_ENTRY BucketList, Entry;
2629
2630 BucketList = &FcbTable->HashBuckets[Bucket];
2631 Entry = BucketList->Flink;
2632 while (Entry != BucketList)
2633 {
2634 PFCB Fcb;
2635
2636 Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
2637 Entry = Entry->Flink;
2638
2639 /* FCB for this connection, go ahead */
2640 if (Fcb->VNetRoot == VNetRoot)
2641 {
2642 /* It's still open, and no force? Fail and keep track */
2643 if (Fcb->UncleanCount > 0 && !ForceClose)
2644 {
2645 Status = STATUS_CONNECTION_IN_USE;
2646 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2647 {
2648 ++UncleanDir;
2649 }
2650 else
2651 {
2652 ++UncleanAny;
2653 }
2654 }
2655 else
2656 {
2657 /* Else, force purge */
2658 ASSERT(NodeTypeIsFcb(Fcb));
2659
2660 Status = RxAcquireExclusiveFcb(NULL, Fcb);
2661 ASSERT(Status == STATUS_SUCCESS);
2662
2663 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
2664
2665 RxScavengeRelatedFobxs(Fcb);
2666 RxPurgeFcb(Fcb);
2667
2668 /* We don't need to release FCB lock, FCB finalize will take care of it */
2669 }
2670 }
2671 }
2672 }
2673
2674 /* No files left, our V_NET_ROOT is finalized */
2675 if (VNetRoot->NumberOfFobxs == 0)
2676 {
2677 VNetRoot->ConnectionFinalizationDone = TRUE;
2678 }
2679 }
2680
2681 /* Keep Number of open files and track of the extra reference */
2682 FilesOpen = VNetRoot->NumberOfFobxs;
2683 AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken;
2684 /* If force close, caller doesn't want to keep connection alive
2685 * and wants it totally close, so drop the V_NET_ROOT too
2686 */
2687 if (ForceClose)
2688 {
2689 RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE);
2690 }
2691 }
2692 _SEH2_FINALLY
2693 {
2694 /* Release what was acquired */
2695 if (FcbTableLocked)
2696 {
2697 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2698 }
2699
2700 /* If close is forced, only fix status if there are open files */
2701 if (ForceClose)
2702 {
2703 if (Status != STATUS_SUCCESS && UncleanAny != 0)
2704 {
2705 Status = STATUS_FILES_OPEN;
2706 }
2707 }
2708 /* Else, fix status and fail closing if there are open files */
2709 else
2710 {
2711 if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0)
2712 {
2713 Status = STATUS_FILES_OPEN;
2714 }
2715 }
2716
2717 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen);
2718
2719 /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2720 * only if it was still referenced!
2721 */
2722 if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0)
2723 {
2724 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
2725 RxDereferenceVNetRoot(VNetRoot, LHS_ExclusiveLockHeld);
2726 }
2727
2728 if (PrefixLocked)
2729 {
2730 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2731 RxReleasePrefixTableLock(PrefixTable);
2732 }
2733 }
2734 _SEH2_END;
2735
2736 return Status;
2737 }
2738
2739 /*
2740 * @implemented
2741 */
2742 VOID
2743 RxFinalizeFcbTable(
2744 IN OUT PRX_FCB_TABLE FcbTable)
2745 {
2746 USHORT Bucket;
2747
2748 PAGED_CODE();
2749
2750 /* Just delete the lock */
2751 ExDeleteResourceLite(&FcbTable->TableLock);
2752
2753 /* And make sure (checked) that the table is really empty... */
2754 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2755 {
2756 ASSERT(IsListEmpty(&FcbTable->HashBuckets[Bucket]));
2757 }
2758 }
2759
2760 /*
2761 * @implemented
2762 */
2763 BOOLEAN
2764 RxFinalizeNetFcb(
2765 OUT PFCB ThisFcb,
2766 IN BOOLEAN RecursiveFinalize,
2767 IN BOOLEAN ForceFinalize,
2768 IN LONG ReferenceCount)
2769 {
2770 PAGED_CODE();
2771
2772 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
2773 DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
2774
2775 /* Make sure we have an exclusively acquired FCB */
2776 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
2777 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
2778
2779 /* We shouldn't force finalization... */
2780 ASSERT(!ForceFinalize);
2781
2782 /* If recurisve, finalize all the associated SRV_OPEN */
2783 if (RecursiveFinalize)
2784 {
2785 PLIST_ENTRY ListEntry;
2786
2787 for (ListEntry = ThisFcb->SrvOpenList.Flink;
2788 ListEntry != &ThisFcb->SrvOpenList;
2789 ListEntry = ListEntry->Flink)
2790 {
2791 PSRV_OPEN SrvOpen;
2792
2793 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
2794 RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
2795 }
2796 }
2797 /* If FCB is still in use, that's over */
2798 else
2799 {
2800 if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
2801 {
2802 ASSERT(ReferenceCount > 0);
2803
2804 return FALSE;
2805 }
2806 }
2807
2808 ASSERT(ReferenceCount >= 1);
2809
2810 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2811 if (ReferenceCount != 1 && !ForceFinalize)
2812 {
2813 return FALSE;
2814 }
2815
2816 ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
2817
2818 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb->OpenCount, ForceFinalize);
2819
2820 /* If finalization was not already initiated, go ahead */
2821 if (!ThisFcb->UpperFinalizationDone)
2822 {
2823 /* Free any FCB_LOCK */
2824 if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
2825 {
2826 FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
2827
2828 while (ThisFcb->BufferedLocks.List != NULL)
2829 {
2830 PFCB_LOCK Entry;
2831
2832 Entry = ThisFcb->BufferedLocks.List;
2833 ThisFcb->BufferedLocks.List = Entry->Next;
2834
2835 RxFreePool(Entry);
2836 }
2837 }
2838
2839 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2840 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
2841 {
2842 PNET_ROOT NetRoot;
2843
2844 NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
2845
2846 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
2847 /* So, remove it */
2848 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
2849 {
2850 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
2851 }
2852 }
2853
2854 ThisFcb->UpperFinalizationDone = TRUE;
2855 }
2856
2857 ASSERT(ReferenceCount >= 1);
2858
2859 /* Even if forced, don't allow broken free */
2860 if (ReferenceCount != 1)
2861 {
2862 return FALSE;
2863 }
2864
2865 /* Now, release everything */
2866 if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
2867 {
2868 RxFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
2869 }
2870
2871 if (ThisFcb->MRxDispatch != NULL)
2872 {
2873 ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
2874 }
2875
2876 ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
2877 ExDeleteResourceLite(ThisFcb->Header.Resource);
2878 ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
2879
2880 InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
2881 RxDereferenceVNetRoot(ThisFcb->VNetRoot, LHS_LockNotHeld);
2882
2883 ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
2884 ASSERT(!ThisFcb->fMiniInited);
2885
2886 /* And free the object */
2887 RxFreeFcbObject(ThisFcb);
2888
2889 return TRUE;
2890 }
2891
2892 /*
2893 * @implemented
2894 */
2895 BOOLEAN
2896 RxFinalizeNetFobx(
2897 _Out_ PFOBX ThisFobx,
2898 _In_ BOOLEAN RecursiveFinalize,
2899 _In_ BOOLEAN ForceFinalize)
2900 {
2901 PFCB Fcb;
2902 PSRV_OPEN SrvOpen;
2903
2904 PAGED_CODE();
2905
2906 ASSERT(NodeType(ThisFobx) == RDBSS_NTC_FOBX);
2907
2908 /* Only finalize if forced or if there's no ref left */
2909 if (ThisFobx->NodeReferenceCount != 0 &&
2910 !ForceFinalize)
2911 {
2912 return FALSE;
2913 }
2914
2915 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx, ThisFobx->NodeReferenceCount, ForceFinalize);
2916
2917 SrvOpen = ThisFobx->SrvOpen;
2918 Fcb = SrvOpen->Fcb;
2919 /* If it wasn't finalized yet, do it */
2920 if (!ThisFobx->UpperFinalizationDone)
2921 {
2922 ASSERT(NodeType(SrvOpen->Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
2923 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
2924
2925 /* Remove it from the SRV_OPEN */
2926 RemoveEntryList(&ThisFobx->FobxQLinks);
2927
2928 /* If we were used to browse a directory, free the query buffer */
2929 if (BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_FREE_UNICODE))
2930 {
2931 RxFreePoolWithTag(ThisFobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
2932 }
2933
2934 /* Notify the mini-rdr */
2935 if (Fcb->MRxDispatch != NULL && Fcb->MRxDispatch->MRxDeallocateForFobx != NULL)
2936 {
2937 Fcb->MRxDispatch->MRxDeallocateForFobx((PMRX_FOBX)ThisFobx);
2938 }
2939
2940 /* If the SRV_OPEN wasn't closed yet, do it */
2941 if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
2942 {
2943 NTSTATUS Status;
2944
2945 Status = RxCloseAssociatedSrvOpen(ThisFobx, FALSE);
2946 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen, ThisFobx, Status);
2947 }
2948
2949 /* Finalization done */
2950 ThisFobx->UpperFinalizationDone = TRUE;
2951 }
2952
2953 /* If we're still referenced, don't go any further! */
2954 if (ThisFobx->NodeReferenceCount != 0)
2955 {
2956 return FALSE;
2957 }
2958
2959 /* At that point, everything should be closed */
2960 ASSERT(IsListEmpty(&ThisFobx->ClosePendingList));
2961
2962 /* Was the FOBX allocated with another object?
2963 * If so, mark the buffer free in said object
2964 */
2965 if (ThisFobx == Fcb->InternalFobx)
2966 {
2967 ClearFlag(Fcb->FcbState, FCB_STATE_FOBX_USED);
2968 }
2969 else if (ThisFobx == SrvOpen->InternalFobx)
2970 {
2971 ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED);
2972 }
2973
2974 ThisFobx->pSrvOpen = NULL;
2975
2976 /* A FOBX less */
2977 InterlockedDecrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
2978
2979 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
2980
2981 /* If it wasn't allocated with another object, free the FOBX */
2982 if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_ENCLOSED_ALLOCATED))
2983 {
2984 RxFreeFcbObject(ThisFobx);
2985 }
2986
2987 return TRUE;
2988 }
2989
2990 /*
2991 * @implemented
2992 */
2993 BOOLEAN
2994 RxFinalizeNetRoot(
2995 OUT PNET_ROOT ThisNetRoot,
2996 IN BOOLEAN RecursiveFinalize,
2997 IN BOOLEAN ForceFinalize)
2998 {
2999 PSRV_CALL SrvCall;
3000 PRX_FCB_TABLE FcbTable;
3001 PRX_PREFIX_TABLE PrefixTable;
3002
3003 PAGED_CODE();
3004
3005 ASSERT(NodeType(ThisNetRoot) == RDBSS_NTC_NETROOT);
3006
3007 PrefixTable = ThisNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3008 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3009
3010 /* If sme finalization is already ongoing, leave */
3011 if (BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS))
3012 {
3013 return FALSE;
3014 }
3015
3016 /* Mark we're finalizing */
3017 SetFlag(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS);
3018
3019 FcbTable = &ThisNetRoot->FcbTable;
3020 /* Did caller asked us to finalize any associated FCB? */
3021 if (RecursiveFinalize)
3022 {
3023 USHORT Bucket;
3024
3025 /* Browse all the FCBs in our FCB table */
3026 RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
3027 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
3028 {
3029 PLIST_ENTRY HashBucket, ListEntry;
3030
3031 HashBucket = &FcbTable->HashBuckets[Bucket];
3032 ListEntry = HashBucket->Flink;
3033 while (ListEntry != HashBucket)
3034 {
3035 PFCB Fcb;
3036
3037 Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
3038 ASSERT(NodeTypeIsFcb(Fcb));
3039
3040 ListEntry = ListEntry->Flink;
3041
3042 /* If the FCB isn't orphaned, then, it's time to purge it */
3043 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
3044 {
3045 NTSTATUS Status;
3046
3047 Status = RxAcquireExclusiveFcb(NULL, Fcb);
3048 ASSERT(Status == STATUS_SUCCESS);
3049 RxPurgeFcb(Fcb);
3050 }
3051 }
3052 }
3053 RxReleaseFcbTableLock(FcbTable);
3054 }
3055
3056 /* Only finalize if forced or if there's a single ref left */
3057 if (ThisNetRoot->NodeReferenceCount != 1 && !ForceFinalize)
3058 {
3059 return FALSE;
3060 }
3061
3062 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot, &ThisNetRoot->PrefixEntry.Prefix);
3063
3064 /* If we're still referenced, don't go any further! */
3065 if (ThisNetRoot->NodeReferenceCount != 1)
3066 {
3067 return FALSE;
3068 }
3069
3070 /* Finalize the FCB table (and make sure it's empty!) */
3071 RxFinalizeFcbTable(FcbTable);
3072
3073 /* If name wasn't remove already, do it now */
3074 if (!BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
3075 {
3076 RxRemovePrefixTableEntry(PrefixTable, &ThisNetRoot->PrefixEntry);
3077 }
3078
3079 /* Delete the object */
3080 SrvCall = (PSRV_CALL)ThisNetRoot->pSrvCall;
3081 RxFreeObject(ThisNetRoot);
3082
3083 /* And dereference the associated SRV_CALL */
3084 if (SrvCall != NULL)
3085 {
3086 RxDereferenceSrvCall(SrvCall, LHS_ExclusiveLockHeld);
3087 }
3088
3089 return TRUE;
3090 }
3091
3092 /*
3093 * @implemented
3094 */
3095 BOOLEAN
3096 RxFinalizeSrvCall(
3097 OUT PSRV_CALL ThisSrvCall,
3098 IN BOOLEAN RecursiveFinalize,
3099 IN BOOLEAN ForceFinalize)
3100 {
3101 PRX_PREFIX_TABLE PrefixTable;
3102
3103 PAGED_CODE();
3104
3105 ASSERT(NodeType(ThisSrvCall) == RDBSS_NTC_SRVCALL);
3106
3107 PrefixTable = ThisSrvCall->RxDeviceObject->pRxNetNameTable;
3108 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3109
3110 /* Only finalize if forced or if there's a single ref left */
3111 if (ThisSrvCall->NodeReferenceCount != 1 &&
3112 !ForceFinalize)
3113 {
3114 return FALSE;
3115 }
3116
3117 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall, &ThisSrvCall->PrefixEntry.Prefix);
3118
3119 /* If it wasn't finalized yet, do it */
3120 if (!ThisSrvCall->UpperFinalizationDone)
3121 {
3122 BOOLEAN WillFree;
3123
3124 /* Remove ourselves from prefix table */
3125 RxRemovePrefixTableEntry(PrefixTable, &ThisSrvCall->PrefixEntry);
3126
3127 /* Remember our third arg, in case we get queued for later execution */
3128 if (ForceFinalize)
3129 {
3130 SetFlag(ThisSrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
3131 }
3132
3133 /* And done */
3134 ThisSrvCall->UpperFinalizationDone = TRUE;
3135
3136 /* Would defered execution free the object? */
3137 WillFree = (ThisSrvCall->NodeReferenceCount == 1);
3138
3139 /* If we have a device object */
3140 if (ThisSrvCall->RxDeviceObject != NULL)
3141 {
3142 NTSTATUS Status;
3143
3144 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3145 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3146 {
3147 /* Extra ref, as usual */
3148 InterlockedIncrement((volatile long *)&ThisSrvCall->NodeReferenceCount);
3149 /* And dispatch */
3150 RxDispatchToWorkerThread(ThisSrvCall->RxDeviceObject, DelayedWorkQueue, RxpDestroySrvCall, ThisSrvCall);
3151
3152 /* Return to the caller, in advance, whether we're freeing the object or not */
3153 return WillFree;
3154 }
3155
3156 /* If in the right thread already, call the mini-rdr */
3157 MINIRDR_CALL_THROUGH(Status, ThisSrvCall->RxDeviceObject->Dispatch,
3158 MRxFinalizeSrvCall, ((PMRX_SRV_CALL)ThisSrvCall, ForceFinalize));
3159 (void)Status;
3160 }
3161 }
3162
3163 /* If we're still referenced, don't go any further! */
3164 if (ThisSrvCall->NodeReferenceCount != 1)
3165 {
3166 return FALSE;
3167 }
3168
3169 /* Don't leak */
3170 if (ThisSrvCall->pDomainName != NULL)
3171 {
3172 RxFreePool(ThisSrvCall->pDomainName);
3173 }
3174
3175 /* And free! */
3176 RxTearDownBufferingManager(ThisSrvCall);
3177 RxFreeObject(ThisSrvCall);
3178
3179 return TRUE;
3180 }
3181
3182 /*
3183 * @implemented
3184 */
3185 BOOLEAN
3186 RxFinalizeSrvOpen(
3187 OUT PSRV_OPEN ThisSrvOpen,
3188 IN BOOLEAN RecursiveFinalize,
3189 IN BOOLEAN ForceFinalize)
3190 {
3191 PFCB Fcb;
3192
3193 PAGED_CODE();
3194
3195 /* We have to have a SRV_OPEN */
3196 ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN);
3197
3198 /* If that's a recursive finalization, finalize any related FOBX */
3199 if (RecursiveFinalize)
3200 {
3201 PLIST_ENTRY ListEntry;
3202
3203 ListEntry = ThisSrvOpen->FobxList.Flink;
3204 while (ListEntry != &ThisSrvOpen->FobxList)
3205 {
3206 PFOBX Fobx;
3207
3208 Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
3209 ListEntry = ListEntry->Flink;
3210 RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
3211 }
3212 }
3213
3214 /* If we have still references, don't finalize unless forced */
3215 if (ThisSrvOpen->NodeReferenceCount != 0 &&
3216 !ForceFinalize)
3217 {
3218 return FALSE;
3219 }
3220
3221 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize);
3222
3223 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3224 Fcb = (PFCB)ThisSrvOpen->pFcb;
3225 if ((!ThisSrvOpen->UpperFinalizationDone && ThisSrvOpen->Condition != Condition_Good) ||
3226 BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
3227 {
3228 PV_NET_ROOT VNetRoot;
3229
3230 /* Associated FCB can't be fake one */
3231 ASSERT(NodeType(Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
3232 ASSERT(RxIsFcbAcquiredExclusive (Fcb));
3233
3234 /* Purge any pending operation */
3235 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen);
3236
3237 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3238 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
3239 {
3240 NTSTATUS Status;
3241
3242 MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen));
3243 (void)Status;
3244 }
3245
3246 /* Remove ourselves from the FCB */
3247 RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3248 InitializeListHead(&ThisSrvOpen->SrvOpenQLinks);
3249 ++Fcb->SrvOpenListVersion;
3250
3251 /* If we have a V_NET_ROOT, dereference it */
3252 VNetRoot = (PV_NET_ROOT)ThisSrvOpen->pVNetRoot;
3253 if (VNetRoot != NULL)
3254 {
3255 InterlockedDecrement((volatile long *)&VNetRoot->pNetRoot->NumberOfSrvOpens);
3256 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3257 ThisSrvOpen->pVNetRoot = NULL;
3258 }
3259
3260 /* Finalization done */
3261 ThisSrvOpen->UpperFinalizationDone = TRUE;
3262 }
3263
3264 /* Don't free memory if still referenced */
3265 if (ThisSrvOpen->NodeReferenceCount != 0)
3266 {
3267 return FALSE;
3268 }
3269
3270 /* No key association left */
3271 ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList));
3272
3273 /* If we're still in some FCB, remove us */
3274 if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks))
3275 {
3276 RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3277 }
3278
3279 /* If enclosed allocation, mark the memory zone free */
3280 if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
3281 {
3282 ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED);
3283 }
3284 /* Otherwise, free the memory */
3285 else
3286 {
3287 RxFreeFcbObject(ThisSrvOpen);
3288 }
3289
3290 RxDereferenceNetFcb(Fcb);
3291
3292 return TRUE;
3293 }
3294
3295 /*
3296 * @implemented
3297 */
3298 BOOLEAN
3299 RxFinalizeVNetRoot(
3300 OUT PV_NET_ROOT ThisVNetRoot,
3301 IN BOOLEAN RecursiveFinalize,
3302 IN BOOLEAN ForceFinalize)
3303 {
3304 PNET_ROOT NetRoot;
3305 PRX_PREFIX_TABLE PrefixTable;
3306
3307 PAGED_CODE();
3308
3309 ASSERT(NodeType(ThisVNetRoot) == RDBSS_NTC_V_NETROOT);
3310
3311 PrefixTable = ThisVNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3312 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3313
3314 /* Only finalize if forced or if there's a single ref left */
3315 if (ThisVNetRoot->NodeReferenceCount != 1 &&
3316 !ForceFinalize)
3317 {
3318 return FALSE;
3319 }
3320
3321 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot, &ThisVNetRoot->PrefixEntry.Prefix);
3322
3323 NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
3324 /* If it wasn't finalized yet, do it */
3325 if (!ThisVNetRoot->UpperFinalizationDone)
3326 {
3327 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
3328
3329 /* Reference the NetRoot so that it doesn't disappear */
3330 RxReferenceNetRoot(NetRoot);
3331 RxOrphanSrvOpens(ThisVNetRoot);
3332 /* Remove us from the available VNetRoot for NetRoot */
3333 RxRemoveVirtualNetRootFromNetRoot(NetRoot, ThisVNetRoot);
3334 /* Remove extra ref */
3335 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
3336
3337 /* Remove ourselves from prefix table */
3338 RxRemovePrefixTableEntry(PrefixTable, &ThisVNetRoot->PrefixEntry);
3339
3340 /* Finalization done */
3341 ThisVNetRoot->UpperFinalizationDone = TRUE;
3342 }