82d111ecf48f2bfa9eb4aec89f44358bb8ac2b92
[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 }
3343
3344 /* If we're still referenced, don't go any further! */
3345 if (ThisVNetRoot->NodeReferenceCount != 1)
3346 {
3347 return FALSE;
3348 }
3349
3350 /* If there's an associated device, notify mini-rdr */
3351 if (NetRoot->pSrvCall->RxDeviceObject != NULL)
3352 {
3353 NTSTATUS Status;
3354
3355 MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
3356 MRxFinalizeVNetRoot, ((PMRX_V_NET_ROOT)ThisVNetRoot, FALSE));
3357 (void)Status;
3358 }
3359
3360 /* Free parameters */
3361 RxUninitializeVNetRootParameters(ThisVNetRoot->pUserName, ThisVNetRoot->pUserDomainName,
3362 ThisVNetRoot->pPassword, &ThisVNetRoot->Flags);
3363 /* Dereference our NetRoot, we won't reference it anymore */
3364 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
3365
3366 /* And free the object! */
3367 RxFreePoolWithTag(ThisVNetRoot, RX_V_NETROOT_POOLTAG);
3368
3369 return TRUE;
3370 }
3371
3372 NTSTATUS
3373 RxFindOrConstructVirtualNetRoot(
3374 IN PRX_CONTEXT RxContext,
3375 IN PUNICODE_STRING CanonicalName,
3376 IN NET_ROOT_TYPE NetRootType,
3377 IN PUNICODE_STRING RemainingName)
3378 {
3379 ULONG Flags;
3380 NTSTATUS Status;
3381 PVOID Container;
3382 BOOLEAN Construct;
3383 PV_NET_ROOT VNetRoot;
3384 RX_CONNECTION_ID ConnectionID;
3385 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3386 LOCK_HOLDING_STATE LockHoldingState;
3387
3388 PAGED_CODE();
3389
3390 RxDeviceObject = RxContext->RxDeviceObject;
3391 ASSERT(RxDeviceObject->Dispatch != NULL);
3392 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
3393
3394 /* Ask the mini-rdr for connection ID */
3395 ConnectionID.SessionID = 0;
3396 if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
3397 {
3398 Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
3399 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
3400 {
3401 /* mini-rdr is expected not to fail - unless it's not implemented */
3402 DPRINT1("Failed to initialize connection ID\n");
3403 ASSERT(FALSE);
3404 }
3405 }
3406
3407 RxContext->Create.NetNamePrefixEntry = NULL;
3408
3409 Status = STATUS_MORE_PROCESSING_REQUIRED;
3410 RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
3411 LockHoldingState = LHS_SharedLockHeld;
3412 Construct = TRUE;
3413 Flags = 0;
3414
3415 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3416 while (TRUE)
3417 {
3418 PNET_ROOT NetRoot;
3419 PV_NET_ROOT SavedVNetRoot;
3420
3421 /* Look in prefix table */
3422 Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
3423 if (Container != NULL)
3424 {
3425 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3426 if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
3427 {
3428 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3429 RxDereferenceSrvCall(Container, LockHoldingState);
3430 }
3431 else
3432 {
3433 VNetRoot = Container;
3434 NetRoot = VNetRoot->NetRoot;
3435
3436 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3437 if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
3438 NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3439 {
3440 Status = STATUS_BAD_NETWORK_PATH;
3441 SavedVNetRoot = NULL;
3442 }
3443 else
3444 {
3445 LUID LogonId;
3446 ULONG SessionId;
3447 PUNICODE_STRING UserName, UserDomain, Password;
3448
3449 /* We can reuse if we use same credentials */
3450 Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
3451 &SessionId, &UserName,
3452 &UserDomain, &Password,
3453 &Flags);
3454 if (NT_SUCCESS(Status))
3455 {
3456 SavedVNetRoot = VNetRoot;
3457 Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
3458 &LogonId, UserName,
3459 UserDomain, Password,
3460 Flags);
3461 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
3462 {
3463 PLIST_ENTRY ListEntry;
3464
3465 for (ListEntry = NetRoot->VirtualNetRoots.Flink;
3466 ListEntry != &NetRoot->VirtualNetRoots;
3467 ListEntry = ListEntry->Flink)
3468 {
3469 SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
3470 Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
3471 &LogonId, UserName,
3472 UserDomain, Password,
3473 Flags);
3474 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
3475 {
3476 break;
3477 }
3478 }
3479
3480 if (ListEntry == &NetRoot->VirtualNetRoots)
3481 {
3482 SavedVNetRoot = NULL;
3483 }
3484 }
3485
3486 if (!NT_SUCCESS(Status))
3487 {
3488 SavedVNetRoot = NULL;
3489 }
3490
3491 RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
3492 }
3493 }
3494
3495 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3496 if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
3497 {
3498 if (SavedVNetRoot == NULL)
3499 {
3500 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3501 }
3502 }
3503 /* Reference VNetRoot we'll keep, and dereference current */
3504 else if (SavedVNetRoot != VNetRoot)
3505 {
3506 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3507 if (SavedVNetRoot != NULL)
3508 {
3509 RxReferenceVNetRoot(SavedVNetRoot);
3510 }
3511 }
3512 }
3513
3514 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3515 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
3516 {
3517 Construct = FALSE;
3518 break;
3519 }
3520 }
3521
3522 /* If we're locked exclusive, we won't loop again, it was the second pass */
3523 if (LockHoldingState != LHS_SharedLockHeld)
3524 {
3525 break;
3526 }
3527
3528 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3529 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
3530 {
3531 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3532 LockHoldingState = LHS_ExclusiveLockHeld;
3533 break;
3534 }
3535
3536 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3537 RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
3538 LockHoldingState = LHS_ExclusiveLockHeld;
3539 }
3540
3541 /* We didn't fail, and didn't find any VNetRoot, construct one */
3542 if (Construct)
3543 {
3544 ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
3545
3546 Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
3547 ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
3548
3549 if (Status == STATUS_SUCCESS)
3550 {
3551 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
3552 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
3553 ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
3554
3555 RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
3556 RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
3557 RemainingName->MaximumLength = RemainingName->Length;
3558
3559 if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
3560 {
3561 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
3562 }
3563 VNetRoot->Flags |= Flags;
3564 }
3565 }
3566
3567 /* Release the prefix table - caller expects it to be released */
3568 if (LockHoldingState != LHS_LockNotHeld)
3569 {
3570 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3571 }
3572
3573 /* If we failed creating, quit */
3574 if (Status != STATUS_SUCCESS)
3575 {
3576 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
3577 return Status;
3578 }
3579
3580 /* Otherwise, wait until the VNetRoot is stable */
3581 DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
3582 RxWaitForStableVNetRoot(VNetRoot, RxContext);
3583 /* It's all good, update the RX_CONTEXT with all our structs */
3584 if (VNetRoot->Condition == Condition_Good)
3585 {
3586 PNET_ROOT NetRoot;
3587
3588 NetRoot = VNetRoot->NetRoot;
3589 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3590 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3591 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
3592 }
3593 else
3594 {
3595 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3596 RxContext->Create.pVNetRoot = NULL;
3597 Status = STATUS_BAD_NETWORK_PATH;
3598 }
3599
3600 return Status;
3601 }
3602
3603 /*
3604 * @implemented
3605 */
3606 NTSTATUS
3607 RxFindOrCreateConnections(
3608 _In_ PRX_CONTEXT RxContext,
3609 _In_ PUNICODE_STRING CanonicalName,
3610 _In_ NET_ROOT_TYPE NetRootType,
3611 _Out_ PUNICODE_STRING LocalNetRootName,
3612 _Out_ PUNICODE_STRING FilePathName,
3613 _Inout_ PLOCK_HOLDING_STATE LockState,
3614 _In_ PRX_CONNECTION_ID RxConnectionId)
3615 {
3616 PVOID Container;
3617 PSRV_CALL SrvCall;
3618 PNET_ROOT NetRoot;
3619 PV_NET_ROOT VNetRoot;
3620 NTSTATUS Status = STATUS_UNSUCCESSFUL;
3621 PRX_PREFIX_TABLE PrefixTable;
3622 UNICODE_STRING RemainingName, NetRootName;
3623
3624 PAGED_CODE();
3625
3626 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3627 RxContext, CanonicalName, NetRootType, LocalNetRootName,
3628 FilePathName, LockState, RxConnectionId);
3629
3630 *FilePathName = *CanonicalName;
3631 LocalNetRootName->Length = 0;
3632 LocalNetRootName->MaximumLength = 0;
3633 LocalNetRootName->Buffer = CanonicalName->Buffer;
3634
3635 /* UNC path, split it */
3636 if (FilePathName->Buffer[1] == ';')
3637 {
3638 BOOLEAN Slash;
3639 USHORT i, Length;
3640
3641 Slash = FALSE;
3642 for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
3643 {
3644 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
3645 {
3646 Slash = TRUE;
3647 break;
3648 }
3649 }
3650
3651 if (!Slash)
3652 {
3653 return STATUS_OBJECT_NAME_INVALID;
3654 }
3655
3656 FilePathName->Buffer = &FilePathName->Buffer[i];
3657 Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
3658 LocalNetRootName->Length = Length;
3659 LocalNetRootName->MaximumLength = Length;
3660 FilePathName->Length -= Length;
3661
3662 DPRINT("CanonicalName: %wZ\n", CanonicalName);
3663 DPRINT(" -> FilePathName: %wZ\n", FilePathName);
3664 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
3665 }
3666
3667 Container = NULL;
3668 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
3669
3670 _SEH2_TRY
3671 {
3672 RetryLookup:
3673 ASSERT(*LockState != LHS_LockNotHeld);
3674
3675 /* If previous lookup left something, dereference it */
3676 if (Container != NULL)
3677 {
3678 switch (NodeType(Container))
3679 {
3680 case RDBSS_NTC_SRVCALL:
3681 RxDereferenceSrvCall(Container, *LockState);
3682 break;
3683
3684 case RDBSS_NTC_NETROOT:
3685 RxDereferenceNetRoot(Container, *LockState);
3686 break;
3687
3688 case RDBSS_NTC_V_NETROOT:
3689 RxDereferenceVNetRoot(Container, *LockState);
3690 break;
3691
3692 default:
3693 /* Should never happen */
3694 ASSERT(FALSE);
3695 break;
3696 }
3697 }
3698
3699 /* Look for our NetRoot in prefix table */
3700 Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
3701 DPRINT("Container %p for path %wZ\n", Container, FilePathName);
3702
3703 while (TRUE)
3704 {
3705 UNICODE_STRING SrvCallName;
3706
3707 SrvCall = NULL;
3708 NetRoot = NULL;
3709 VNetRoot = NULL;
3710
3711 /* Assume we didn't succeed */
3712 RxContext->Create.pVNetRoot = NULL;
3713 RxContext->Create.pNetRoot = NULL;
3714 RxContext->Create.pSrvCall = NULL;
3715 RxContext->Create.Type = NetRootType;
3716
3717 /* If we found something */
3718 if (Container != NULL)
3719 {
3720 /* A VNetRoot */
3721 if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
3722 {
3723 VNetRoot = Container;
3724 /* Use its NetRoot */
3725 NetRoot = VNetRoot->NetRoot;
3726
3727 /* If it's not stable, wait for it to be stable */
3728 if (NetRoot->Condition == Condition_InTransition)
3729 {
3730 RxReleasePrefixTableLock(PrefixTable);
3731 DPRINT("Waiting for stable condition for: %p\n", NetRoot);
3732 RxWaitForStableNetRoot(NetRoot, RxContext);
3733 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3734 *LockState = LHS_ExclusiveLockHeld;
3735
3736 /* Now that's it's ok, retry lookup to find what we want */
3737 if (NetRoot->Condition == Condition_Good)
3738 {
3739 goto RetryLookup;
3740 }
3741 }
3742
3743 /* Is the associated netroot good? */
3744 if (NetRoot->Condition == Condition_Good)
3745 {
3746 SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
3747
3748 /* If it is, and SrvCall as well, then, we have our active connection */
3749 if (SrvCall->Condition == Condition_Good &&
3750 SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
3751 {
3752 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3753 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3754 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3755
3756 Status = STATUS_CONNECTION_ACTIVE;
3757 _SEH2_LEAVE;
3758 }
3759 }
3760
3761 /* If VNetRoot was well constructed, it means the connection is active */
3762 if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
3763 {
3764 Status = STATUS_CONNECTION_ACTIVE;
3765 }
3766 else
3767 {
3768 Status = VNetRoot->ConstructionStatus;
3769 }
3770
3771 RxDereferenceVNetRoot(VNetRoot, *LockState);
3772 _SEH2_LEAVE;
3773 }
3774 /* Can only be a SrvCall */
3775 else
3776 {
3777 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3778 SrvCall = Container;
3779
3780 /* Wait for the SRV_CALL to be stable */
3781 if (SrvCall->Condition == Condition_InTransition)
3782 {
3783 RxReleasePrefixTableLock(PrefixTable);
3784 DPRINT("Waiting for stable condition for: %p\n", SrvCall);
3785 RxWaitForStableSrvCall(SrvCall, RxContext);
3786 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3787 *LockState = LHS_ExclusiveLockHeld;
3788
3789 /* It went good, loop again to find what we look for */
3790 if (SrvCall->Condition == Condition_Good)
3791 {
3792 goto RetryLookup;
3793 }
3794 }
3795
3796 /* If it's not good... */
3797 if (SrvCall->Condition != Condition_Good)
3798 {
3799 /* But SRV_CALL was well constructed, assume a connection was active */
3800 if (SrvCall->Status == STATUS_SUCCESS)
3801 {
3802 Status = STATUS_CONNECTION_ACTIVE;
3803 }
3804 else
3805 {
3806 Status = SrvCall->Status;
3807 }
3808
3809 RxDereferenceSrvCall(SrvCall, *LockState);
3810 _SEH2_LEAVE;
3811 }
3812 }
3813 }
3814
3815 /* If we found a SRV_CALL not matching our DO, quit */
3816 if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
3817 SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3818 {
3819 RxDereferenceSrvCall(SrvCall, *LockState);
3820 Status = STATUS_BAD_NETWORK_NAME;
3821 _SEH2_LEAVE;
3822 }
3823
3824 /* Now, we want exclusive lock */
3825 if (*LockState == LHS_SharedLockHeld)
3826 {
3827 if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
3828 {
3829 RxReleasePrefixTableLock(PrefixTable);
3830 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3831 *LockState = LHS_ExclusiveLockHeld;
3832 goto RetryLookup;
3833 }
3834
3835 RxReleasePrefixTableLock(PrefixTable);
3836 *LockState = LHS_ExclusiveLockHeld;
3837 }
3838
3839 ASSERT(*LockState == LHS_ExclusiveLockHeld);
3840
3841 /* If we reach that point, we found something, no need to create something */
3842 if (Container != NULL)
3843 {
3844 break;
3845 }
3846
3847 /* Get the name for the SRV_CALL */
3848 RxExtractServerName(FilePathName, &SrvCallName, NULL);
3849 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
3850 /* And create the SRV_CALL */
3851 SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
3852 if (SrvCall == NULL)
3853 {
3854 Status = STATUS_INSUFFICIENT_RESOURCES;
3855 _SEH2_LEAVE;
3856 }
3857
3858 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3859 RxReferenceSrvCall(SrvCall);
3860 RxContext->Create.pVNetRoot = NULL;
3861 RxContext->Create.pNetRoot = NULL;
3862 RxContext->Create.pSrvCall = NULL;
3863 RxContext->Create.Type = NetRootType;
3864 Container = SrvCall;
3865
3866 /* Construct SRV_CALL, ie, use mini-rdr */
3867 Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
3868 ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
3869 if (Status != STATUS_SUCCESS)
3870 {
3871 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
3872 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3873 RxDereferenceSrvCall(SrvCall, *LockState);
3874 RxReleasePrefixTableLock(PrefixTable);
3875 _SEH2_LEAVE;
3876 }
3877
3878 /* Loop again to make use of SRV_CALL stable condition wait */
3879 }
3880
3881 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3882 ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
3883 ASSERT(NetRoot == NULL && VNetRoot == NULL);
3884 ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
3885
3886 /* Call mini-rdr to get NetRoot name */
3887 SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
3888 /* And create the NetRoot with that name */
3889 NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
3890 if (NetRoot == NULL)
3891 {
3892 Status = STATUS_INSUFFICIENT_RESOURCES;
3893 _SEH2_LEAVE;
3894 }
3895 NetRoot->Type = NetRootType;
3896
3897 RxDereferenceSrvCall(SrvCall, *LockState);
3898
3899 /* Finally, create the associated VNetRoot */
3900 VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
3901 if (VNetRoot == NULL)
3902 {
3903 RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
3904 Status = STATUS_INSUFFICIENT_RESOURCES;
3905 _SEH2_LEAVE;
3906 }
3907 RxReferenceVNetRoot(VNetRoot);
3908
3909 /* We're get closer! */
3910 NetRoot->Condition = Condition_InTransition;
3911 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3912 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3913 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3914
3915 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3916 Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
3917 if (!NT_SUCCESS(Status))
3918 {
3919 RxTransitionVNetRoot(VNetRoot, Condition_Bad);
3920 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
3921 RxDereferenceVNetRoot(VNetRoot, *LockState);
3922
3923 RxContext->Create.pNetRoot = NULL;
3924 RxContext->Create.pVNetRoot = NULL;
3925 }
3926 else
3927 {
3928 PIO_STACK_LOCATION Stack;
3929
3930 ASSERT(*LockState == LHS_ExclusiveLockHeld);
3931
3932 Stack = RxContext->CurrentIrpSp;
3933 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
3934 {
3935 RxExclusivePrefixTableLockToShared(PrefixTable);
3936 *LockState = LHS_SharedLockHeld;
3937 }
3938 }
3939 }
3940 _SEH2_FINALLY
3941 {
3942 if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
3943 {
3944 if (*LockState != LHS_LockNotHeld)
3945 {
3946 RxReleasePrefixTableLock(PrefixTable);
3947 *LockState = LHS_LockNotHeld;
3948 }
3949 }
3950 }
3951 _SEH2_END;
3952
3953 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
3954 return Status;
3955 }
3956
3957 /*
3958 * @implemented
3959 */
3960 VOID
3961 NTAPI
3962 RxFinishFcbInitialization(
3963 IN OUT PMRX_FCB Fcb,
3964 IN RX_FILE_TYPE FileType,
3965 IN PFCB_INIT_PACKET InitPacket OPTIONAL)
3966 {
3967 RX_FILE_TYPE OldType;
3968
3969 PAGED_CODE();
3970
3971 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
3972
3973 OldType = NodeType(Fcb);
3974 NodeType(Fcb) = FileType;
3975 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
3976 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
3977 {
3978 FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3979 }
3980 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
3981 else if (InitPacket != NULL)
3982 {
3983 FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
3984 InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
3985 InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
3986 InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
3987 InitPacket->pValidDataLength->QuadPart);
3988 }
3989
3990 if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
3991 FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
3992 {
3993 /* If our FCB newly points to a file, initiliaze everything related */
3994 if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE)
3995
3996 {
3997 if (OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
3998 {
3999 RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
4000 FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, RxLockOperationCompletion,
4001 RxUnlockOperation);
4002
4003 ((PFCB)Fcb)->BufferedLocks.List = NULL;
4004 ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
4005
4006 Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
4007 }
4008 }
4009 /* If not a file, validate type */
4010 else
4011 {
4012 ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
4013 }
4014 }
4015 }
4016
4017 /*
4018 * @implemented
4019 */
4020 NTSTATUS
4021 RxFinishSrvCallConstruction(
4022 PMRX_SRVCALLDOWN_STRUCTURE Calldown)
4023 {
4024 NTSTATUS Status;
4025 PSRV_CALL SrvCall;
4026 PRX_CONTEXT Context;
4027 RX_BLOCK_CONDITION Condition;
4028 PRX_PREFIX_TABLE PrefixTable;
4029
4030 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
4031
4032 SrvCall = (PSRV_CALL)Calldown->SrvCall;
4033 Context = Calldown->RxContext;
4034 PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
4035
4036 /* We have a winner, notify him */
4037 if (Calldown->BestFinisher != NULL)
4038 {
4039 DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
4040
4041 ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
4042
4043 MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
4044 MRxSrvCallWinnerNotify,
4045 ((PMRX_SRV_CALL)SrvCall, TRUE,
4046 Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
4047 if (Status != STATUS_SUCCESS)
4048 {
4049 Condition = Condition_Bad;
4050 }
4051 else
4052 {
4053 Condition = Condition_Good;
4054 }
4055 }
4056 /* Otherwise, just fail our SRV_CALL */
4057 else
4058 {
4059 Status = Calldown->CallbackContexts[0].Status;
4060 Condition = Condition_Bad;
4061 }
4062
4063 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
4064 RxTransitionSrvCall(SrvCall, Condition);
4065 RxFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
4066
4067 /* If async, finish it here, otherwise, caller has already finished the stuff */
4068 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
4069 {
4070 DPRINT("Finishing async call\n");
4071
4072 RxReleasePrefixTableLock(PrefixTable);
4073
4074 /* Make sure we weren't cancelled in-between */
4075 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
4076 {
4077 Status = STATUS_CANCELLED;
4078 }
4079
4080 /* In case that was a create, context can be reused */
4081 if (Context->MajorFunction == IRP_MJ_CREATE)
4082 {
4083 RxpPrepareCreateContextForReuse(Context);
4084 }
4085
4086 /* If that's a failure, reset everything and return failure */
4087 if (Status != STATUS_SUCCESS)
4088 {
4089 Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
4090 if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
4091 {
4092 if (Context->Info.Buffer != NULL)
4093 {
4094 RxFreePool(Context->Info.Buffer);
4095 Context->Info.Buffer = NULL;
4096 }
4097 }
4098 Context->CurrentIrp->IoStatus.Information = 0;
4099 Context->CurrentIrp->IoStatus.Status = Status;
4100 RxCompleteRequest(Context, Status);
4101 }
4102 /* Otherwise, call resume routine and done! */
4103 else
4104 {
4105 Status = Context->ResumeRoutine(Context);
4106 if (Status != STATUS_PENDING)
4107 {
4108 RxCompleteRequest(Context, Status);
4109 }
4110
4111 DPRINT("Not completing, pending\n");
4112 }
4113 }
4114
4115 RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
4116 return Status;
4117 }
4118
4119 /*
4120 * @implemented
4121 */
4122 VOID
4123 NTAPI
4124 RxFinishSrvCallConstructionDispatcher(
4125 IN PVOID Context)
4126 {
4127 KIRQL OldIrql;
4128 BOOLEAN Direct, KeepLoop;
4129
4130 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
4131
4132 /* In case of failure of starting dispatcher, context is not set
4133 * We keep track of it to fail associated SRV_CALL
4134 */
4135 Direct = (Context == NULL);
4136
4137 /* Separated thread, loop forever */
4138 while (TRUE)
4139 {
4140 PLIST_ENTRY ListEntry;
4141 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
4142
4143 /* If there are no SRV_CALL to finalize left, just finish thread */
4144 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
4145 if (IsListEmpty(&RxSrvCalldownList))
4146 {
4147 KeepLoop = FALSE;
4148 RxSrvCallConstructionDispatcherActive = FALSE;
4149 }
4150 /* Otherwise, get the SRV_CALL to finish construction */
4151 else
4152 {
4153 ListEntry = RemoveHeadList(&RxSrvCalldownList);
4154 KeepLoop = TRUE;
4155 }
4156 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
4157
4158 /* Nothing to do */
4159 if (!KeepLoop)
4160 {
4161 break;
4162 }
4163
4164 /* If direct is set, reset the finisher to avoid electing a winner
4165 * and fail SRV_CALL (see upper comment)
4166 */
4167 Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
4168 if (Direct)
4169 {
4170 Calldown->BestFinisher = NULL;
4171 }
4172 /* Finish SRV_CALL construction */
4173 RxFinishSrvCallConstruction(Calldown);
4174 }
4175 }
4176
4177 /*
4178 * @implemented
4179 */
4180 NTSTATUS
4181 RxFlushFcbInSystemCache(
4182 IN PFCB Fcb,
4183 IN BOOLEAN SynchronizeWithLazyWriter)
4184 {
4185 IO_STATUS_BLOCK IoStatus;
4186
4187 PAGED_CODE();
4188
4189 /* Deal with Cc */
4190 CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, &IoStatus);
4191 /* If we're asked to sync with LW, do it in case of success */
4192 if (SynchronizeWithLazyWriter && NT_SUCCESS(IoStatus.Status))
4193 {
4194 RxAcquirePagingIoResource((PRX_CONTEXT)NULL, Fcb);
4195 RxReleasePagingIoResource((PRX_CONTEXT)NULL, Fcb);
4196 }
4197
4198 DPRINT("Flushing for FCB %p returns %lx\n", Fcb, IoStatus.Status);
4199 return IoStatus.Status;
4200 }
4201
4202 /*
4203 * @implemented
4204 */
4205 VOID
4206 RxFreeFcbObject(
4207 PVOID Object)
4208 {
4209 PAGED_CODE();
4210
4211 DPRINT("Freeing %p\n", Object);
4212
4213 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4214 if (NodeType(Object) == RDBSS_NTC_FOBX || NodeType(Object) == RDBSS_NTC_SRVOPEN)
4215 {
4216 RxFreePoolWithTag(Object, RX_FCB_POOLTAG);
4217 }
4218 /* If that's a FCB... */
4219 else if (NodeTypeIsFcb(Object))
4220 {
4221 PFCB Fcb;
4222 PRDBSS_DEVICE_OBJECT DeviceObject;
4223
4224 Fcb = (PFCB)Object;
4225 DeviceObject = Fcb->RxDeviceObject;
4226
4227 /* Delete per stream contexts */
4228 FsRtlTeardownPerStreamContexts(&Fcb->Header);
4229
4230 SetFlag(Fcb->Header.Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH);
4231
4232 /* If there was a non-paged FCB allocated, free it */
4233 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
4234 {
4235 RxFreePoolWithTag(Fcb->NonPaged, RX_NONPAGEDFCB_POOLTAG);
4236 }
4237
4238 /* Free the FCB */
4239 RxFreePool(Fcb);
4240
4241 /* Update statistics */
4242 InterlockedDecrement(&RxNumberOfActiveFcbs);
4243 InterlockedDecrement((volatile long *)&DeviceObject->NumberOfActiveFcbs);
4244 }
4245 }
4246
4247 /*
4248 * @implemented
4249 */
4250 VOID
4251 RxFreeObject(
4252 PVOID pObject)
4253 {
4254 PAGED_CODE();
4255
4256 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4257 if (NodeType(pObject) == RDBSS_NTC_SRVCALL)
4258 {
4259 PSRV_CALL SrvCall;
4260 PRDBSS_DEVICE_OBJECT DeviceObject;
4261
4262 SrvCall = (PSRV_CALL)pObject;
4263 DeviceObject = SrvCall->RxDeviceObject;
4264 if (DeviceObject != NULL)
4265 {
4266 if (!BooleanFlagOn(DeviceObject->Dispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
4267 {
4268 ASSERT(SrvCall->Context == NULL);
4269 }
4270
4271 ASSERT(SrvCall->Context2 == NULL);
4272
4273 SrvCall->RxDeviceObject = NULL;
4274 }
4275 }
4276 else if (NodeType(pObject) == RDBSS_NTC_NETROOT)
4277 {
4278 PNET_ROOT NetRoot;
4279
4280 NetRoot = (PNET_ROOT)pObject;
4281 NetRoot->pSrvCall = NULL;
4282 NetRoot->NodeTypeCode = NodeType(pObject) | 0xF000;
4283 }
4284
4285 /* And just free the object */
4286 RxFreePool(pObject);
4287 }
4288
4289 /*
4290 * @implemented
4291 */
4292 VOID
4293 RxGatherRequestsForSrvOpen(
4294 IN OUT PSRV_CALL SrvCall,
4295 IN PSRV_OPEN SrvOpen,
4296 IN OUT PLIST_ENTRY RequestsListHead)
4297 {
4298 KIRQL OldIrql;
4299 LIST_ENTRY Discarded, *Entry;
4300 PCHANGE_BUFFERING_STATE_REQUEST Request;
4301
4302 /* Dispatch any pending operation first */
4303 RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &Discarded);
4304
4305 /* Then, get any entry related to our key and SRV_OPEN */
4306 KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
4307 Entry = SrvCall->BufferingManager.HandlerList.Flink;
4308 while (Entry != &SrvCall->BufferingManager.HandlerList)
4309 {
4310 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
4311 Entry = Entry->Flink;
4312 if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
4313 {
4314 RemoveEntryList(&Request->ListEntry);
4315 InsertTailList(RequestsListHead, &Request->ListEntry);
4316 }
4317 }
4318 KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
4319
4320 /* Perform the same search in the last change list */
4321 Entry = SrvCall->BufferingManager.LastChanceHandlerList.Flink;
4322 while (Entry != &SrvCall->BufferingManager.LastChanceHandlerList)
4323 {
4324 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
4325 Entry = Entry->Flink;
4326 if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
4327 {
4328 RemoveEntryList(&Request->ListEntry);
4329 InsertTailList(RequestsListHead, &Request->ListEntry);
4330 }
4331 }
4332
4333 /* Discard the discarded requests */
4334 RxpDiscardChangeBufferingStateRequests(&Discarded);
4335 }
4336
4337 /*
4338 * @implemented
4339 */
4340 PRDBSS_DEVICE_OBJECT
4341 RxGetDeviceObjectOfInstance(
4342 PVOID Instance)
4343 {
4344 NODE_TYPE_CODE NodeType;
4345 PRDBSS_DEVICE_OBJECT DeviceObject;
4346
4347 PAGED_CODE();
4348
4349 /* We only handle a few object types */
4350 NodeType = NodeType(Instance);
4351 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
4352 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) || (NodeType == RDBSS_NTC_FOBX));
4353
4354 /* Get the device object depending on the object */
4355 switch (NodeType)
4356 {
4357 case RDBSS_NTC_FOBX:
4358 {
4359 PFOBX Fobx;
4360
4361 Fobx = (PFOBX)Instance;
4362 DeviceObject = Fobx->RxDeviceObject;
4363 break;
4364 }
4365
4366 case RDBSS_NTC_SRVCALL:
4367 {
4368 PSRV_CALL SrvCall;
4369
4370 SrvCall = (PSRV_CALL)Instance;
4371 DeviceObject = SrvCall->RxDeviceObject;
4372 break;
4373 }
4374
4375 case RDBSS_NTC_NETROOT:
4376 {
4377 PNET_ROOT NetRoot;
4378
4379 NetRoot = (PNET_ROOT)Instance;
4380 DeviceObject = NetRoot->pSrvCall->RxDeviceObject;
4381 break;
4382 }
4383
4384 case RDBSS_NTC_V_NETROOT:
4385 {
4386 PV_NET_ROOT VNetRoot;
4387
4388 VNetRoot = (PV_NET_ROOT)Instance;
4389 DeviceObject = VNetRoot->pNetRoot->pSrvCall->RxDeviceObject;
4390 break;
4391 }
4392
4393 case RDBSS_NTC_SRVOPEN:
4394 {
4395 PSRV_OPEN SrvOpen;
4396
4397 SrvOpen = (PSRV_OPEN)Instance;
4398 DeviceObject = ((PFCB)SrvOpen->pFcb)->RxDeviceObject;
4399 break;
4400 }
4401
4402 default:
4403 DeviceObject = NULL;
4404 break;
4405 }
4406
4407 /* Job done */
4408 return DeviceObject;
4409 }
4410
4411 /*
4412 * @implemented
4413 */
4414 VOID
4415 RxGetFileSizeWithLock(
4416 IN PFCB Fcb,
4417 OUT PLONGLONG FileSize)
4418 {
4419 PAGED_CODE();
4420
4421 *FileSize = Fcb->Header.FileSize.QuadPart;
4422 }
4423
4424 /*
4425 * @implemented
4426 */
4427 PEPROCESS
4428 NTAPI
4429 RxGetRDBSSProcess(
4430 VOID)
4431 {
4432 return RxData.OurProcess;
4433 }
4434
4435 /*
4436 * @implemented
4437 */
4438 NTSTATUS
4439 RxInitializeBufferingManager(
4440 PSRV_CALL SrvCall)
4441 {
4442 KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
4443 InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
4444 InitializeListHead(&SrvCall->BufferingManager.HandlerList);
4445 InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
4446 SrvCall->BufferingManager.DispatcherActive = FALSE;
4447 SrvCall->BufferingManager.HandlerInactive = FALSE;
4448 SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
4449 SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
4450 InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
4451 ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
4452
4453 return STATUS_SUCCESS;
4454 }
4455
4456 /*
4457 * @implemented
4458 */
4459 VOID
4460 NTAPI
4461 RxInitializeContext(
4462 IN PIRP Irp,
4463 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
4464 IN ULONG InitialContextFlags,
4465 IN OUT PRX_CONTEXT RxContext)
4466 {
4467 PIO_STACK_LOCATION Stack;
4468
4469 /* Initialize our various fields */
4470 RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
4471 RxContext->NodeByteSize = sizeof(RX_CONTEXT);
4472 RxContext->ReferenceCount = 1;
4473 RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
4474 RxContext->RxDeviceObject = RxDeviceObject;
4475 KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
4476 RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
4477 InitializeListHead(&RxContext->BlockedOperations);
4478 RxContext->MRxCancelRoutine = NULL;
4479 RxContext->ResumeRoutine = NULL;
4480 RxContext->Flags |= InitialContextFlags;
4481 RxContext->CurrentIrp = Irp;
4482 RxContext->LastExecutionThread = PsGetCurrentThread();
4483 RxContext->OriginalThread = RxContext->LastExecutionThread;
4484
4485 /* If've got no IRP, mark RX_CONTEXT */
4486 if (Irp == NULL)
4487 {
4488 RxContext->CurrentIrpSp = NULL;
4489 RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
4490 RxContext->MinorFunction = 0;
4491 }
4492 else
4493 {
4494 /* Otherwise, first determine whether we are performing async operation */
4495 Stack = IoGetCurrentIrpStackLocation(Irp);
4496 if (Stack->FileObject != NULL)
4497 {
4498 PFCB Fcb;
4499
4500 Fcb = Stack->FileObject->FsContext;
4501 if (!IoIsOperationSynchronous(Irp) ||
4502 ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
4503 (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
4504 (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
4505 {
4506 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4507 }
4508 }
4509
4510 if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
4511 {
4512 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4513 }
4514 if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
4515 {
4516 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4517 }
4518
4519 /* Set proper flags if TopLevl IRP/Device */
4520 if (!RxIsThisTheTopLevelIrp(Irp))
4521 {
4522 RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
4523 }
4524 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
4525 {
4526 RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
4527 }
4528
4529 /* Copy stack information */
4530 RxContext->MajorFunction = Stack->MajorFunction;
4531 RxContext->MinorFunction = Stack->MinorFunction;
4532 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
4533 RxContext->CurrentIrpSp = Stack;
4534
4535 /* If we have a FO associated, learn for more */
4536 if (Stack->FileObject != NULL)
4537 {
4538 PFCB Fcb;
4539 PFOBX Fobx;
4540
4541 /* Get the FCB and CCB (FOBX) */
4542 Fcb = Stack->FileObject->FsContext;
4543 Fobx = Stack->FileObject->FsContext2;
4544 RxContext->pFcb = (PMRX_FCB)Fcb;
4545 if (Fcb != NULL && NodeTypeIsFcb(Fcb))
4546 {
4547 RxContext->NonPagedFcb = Fcb->NonPaged;
4548 }
4549
4550 /* We have a FOBX, this not a DFS opening, keep track of it */
4551 if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
4552 {
4553 RxContext->pFobx = (PMRX_FOBX)Fobx;
4554 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
4555 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
4556 {
4557 RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
4558 }
4559 }
4560 else
4561 {
4562 RxContext->pFobx = NULL;
4563 }
4564
4565 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4566 if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
4567 Fobx != NULL)
4568 {
4569 PV_NET_ROOT VNetRoot = NULL;
4570
4571 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
4572 {
4573 VNetRoot = Fcb->VNetRoot;
4574 }
4575 else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
4576 {
4577 VNetRoot = (PV_NET_ROOT)Fobx;
4578 }
4579
4580 if (VNetRoot != NULL)
4581 {
4582 RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
4583 }
4584 }
4585
4586 /* Remember if that's a write through file */
4587 RxContext->RealDevice = Stack->FileObject->DeviceObject;
4588 if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
4589 {
4590 RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
4591 }
4592 }
4593 }
4594
4595 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
4596 {
4597 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4598 RxContext, RxContext->MinorFunction, Irp,
4599 PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
4600 RxContext->SerialNumber);
4601 }
4602 }
4603
4604 /*
4605 * @implemented
4606 */
4607 NTSTATUS
4608 NTAPI
4609 RxInitializeDispatcher(
4610 VOID)
4611 {
4612 NTSTATUS Status;
4613 HANDLE ThreadHandle;
4614
4615 PAGED_CODE();
4616
4617 RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
4618 RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL;
4619
4620 /* Set appropriate timeouts: 10s & 60s */
4621 RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4622 RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4623 RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4624 RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
4625
4626 RxDispatcher.NumberOfProcessors = 1;
4627 RxDispatcher.OwnerProcess = IoGetCurrentProcess();
4628 RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues;
4629
4630 /* Initialize our dispatchers */
4631 Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher);
4632 if (!NT_SUCCESS(Status))
4633 {
4634 return Status;
4635 }
4636
4637 Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject);
4638 if (!NT_SUCCESS(Status))
4639 {
4640 return Status;
4641 }
4642
4643 /* And start them */
4644 RxDispatcher.State = RxDispatcherActive;
4645 InitializeListHead(&RxDispatcher.SpinUpRequests);
4646 KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock);
4647 KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0);
4648 KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0);
4649 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL,
4650 NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher);
4651 if (NT_SUCCESS(Status))
4652 {
4653 ZwClose(ThreadHandle);
4654 }
4655
4656 return Status;
4657 }
4658
4659 /*
4660 * @implemented
4661 */
4662 VOID
4663 RxInitializeFcbTable(
4664 IN OUT PRX_FCB_TABLE FcbTable,
4665 IN BOOLEAN CaseInsensitiveMatch)
4666 {
4667 USHORT i;
4668
4669 PAGED_CODE();
4670
4671 FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
4672 FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
4673
4674 ExInitializeResourceLite(&FcbTable->TableLock);
4675 FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
4676 FcbTable->Version = 0;
4677 FcbTable->TableEntryForNull = NULL;
4678
4679 FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
4680 for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
4681 {
4682 InitializeListHead(&FcbTable->HashBuckets[i]);
4683 }
4684
4685 FcbTable->Lookups = 0;
4686 FcbTable->FailedLookups = 0;
4687 FcbTable->Compares = 0;
4688 }
4689
4690 /*
4691 * @implemented
4692 */
4693 VOID
4694 NTAPI
4695 RxInitializeLowIoContext(
4696 OUT PLOWIO_CONTEXT LowIoContext,
4697 IN ULONG Operation)
4698 {
4699 PRX_CONTEXT RxContext;
4700 PIO_STACK_LOCATION Stack;
4701
4702 PAGED_CODE();
4703
4704 RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
4705 ASSERT(LowIoContext == &RxContext->LowIoContext);
4706
4707 Stack = RxContext->CurrentIrpSp;
4708
4709 KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
4710 RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread();
4711 RxContext->LowIoContext.Operation = Operation;
4712
4713 switch (Operation)
4714 {
4715 case LOWIO_OP_READ:
4716 case LOWIO_OP_WRITE:
4717 /* In case of RW, set a canary, to make sure these fields are properly set
4718 * they will be asserted when lowio request will be submit to mini-rdr
4719 * See LowIoSubmit()
4720 */
4721 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
4722 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
4723 RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
4724
4725 /* Keep track of paging IOs */
4726 if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
4727 {
4728 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO;
4729 }
4730 else
4731 {
4732 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
4733 }
4734
4735 break;
4736
4737 case LOWIO_OP_FSCTL:
4738 case LOWIO_OP_IOCTL:
4739 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4740 RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
4741 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0;
4742 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL;
4743 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0;
4744 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
4745 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
4746 break;
4747
4748 /* Nothing to do for these */
4749 case LOWIO_OP_SHAREDLOCK:
4750 case LOWIO_OP_EXCLUSIVELOCK:
4751 case LOWIO_OP_UNLOCK:
4752 case LOWIO_OP_UNLOCK_MULTIPLE:
4753 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
4754 case LOWIO_OP_CLEAROUT:
4755 break;
4756
4757 default:
4758 /* Should never happen */
4759 ASSERT(FALSE);
4760 break;
4761 }
4762 }
4763
4764 /*
4765 * @implemented
4766 */
4767 VOID
4768 RxInitializeLowIoPerFcbInfo(
4769 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
4770 {
4771 PAGED_CODE();
4772
4773 InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
4774 InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
4775 }
4776
4777 /*
4778 * @implemented
4779 */
4780 NTSTATUS
4781 RxInitializeMRxDispatcher(
4782 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
4783 {
4784 PAGED_CODE();
4785
4786 pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
4787 pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
4788
4789 return STATUS_SUCCESS;
4790 }
4791
4792 /*
4793 * @implemented
4794 */
4795 VOID
4796 RxInitializePrefixTable(
4797 IN OUT PRX_PREFIX_TABLE ThisTable,
4798 IN ULONG TableSize OPTIONAL,
4799 IN BOOLEAN CaseInsensitiveMatch)
4800 {
4801 PAGED_CODE();
4802
4803 if (TableSize == 0)
4804 {
4805 TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH;
4806 }
4807
4808 ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
4809 ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
4810 InitializeListHead(&ThisTable->MemberQueue);
4811 ThisTable->Version = 0;
4812 ThisTable->TableEntryForNull = NULL;
4813 ThisTable->IsNetNameTable = FALSE;
4814 ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
4815 ThisTable->TableSize = TableSize;
4816
4817 if (TableSize > 0)
4818 {
4819 USHORT i;
4820
4821 for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
4822 {
4823 InitializeListHead(&ThisTable->HashBuckets[i]);
4824 }
4825 }
4826 }
4827
4828 /*
4829 * @implemented
4830 */
4831 VOID
4832 RxInitializePurgeSyncronizationContext(
4833 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
4834 {
4835 PAGED_CODE();
4836
4837 InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
4838 PurgeSyncronizationContext->PurgeInProgress = FALSE;
4839 }
4840
4841 NTSTATUS
4842 RxInitializeSrvCallParameters(
4843 IN PRX_CONTEXT RxContext,
4844 IN OUT PSRV_CALL SrvCall)
4845 {
4846 PAGED_CODE();
4847
4848 SrvCall->pPrincipalName = NULL;
4849
4850 /* We only have stuff to initialize for file opening from DFS */
4851 if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
4852 {
4853 return STATUS_SUCCESS;
4854 }
4855
4856 ASSERT(RxContext->Create.EaBuffer != NULL);
4857
4858 UNIMPLEMENTED;
4859 return STATUS_NOT_IMPLEMENTED;
4860 }
4861
4862 /*
4863 * @implemented
4864 */
4865 NTSTATUS
4866 NTAPI
4867 RxInitializeRxTimer(
4868 VOID)
4869 {
4870 PAGED_CODE();
4871
4872 RxTimerInterval.QuadPart = -550000;
4873 KeInitializeSpinLock(&RxTimerLock);
4874 InitializeListHead(&RxTimerQueueHead);
4875 InitializeListHead(&RxRecurrentWorkItemsList);
4876 KeInitializeDpc(&RxTimerDpc, RxTimerDispatch, NULL);
4877 KeInitializeTimer(&RxTimer);
4878 RxTimerTickCount = 0;
4879
4880 return STATUS_SUCCESS;
4881 }
4882
4883 NTSTATUS
4884 RxInitializeVNetRootParameters(
4885 PRX_CONTEXT RxContext,
4886 OUT LUID *LogonId,
4887 OUT PULONG SessionId,
4888 OUT PUNICODE_STRING *UserNamePtr,
4889 OUT PUNICODE_STRING *UserDomainNamePtr,
4890 OUT PUNICODE_STRING *PasswordPtr,
4891 OUT PULONG Flags)
4892 {
4893 NTSTATUS Status;
4894 PACCESS_TOKEN Token;
4895
4896 PAGED_CODE();
4897
4898 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
4899 LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
4900
4901 *UserNamePtr = NULL;
4902 *UserDomainNamePtr = NULL;
4903 *PasswordPtr = NULL;
4904 /* By default, that's not CSC instance */
4905 *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
4906
4907 Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
4908 if (SeTokenIsRestricted(Token))
4909 {
4910 return STATUS_ACCESS_DENIED;
4911 }
4912
4913 /* Get LogonId */
4914 Status = SeQueryAuthenticationIdToken(Token, LogonId);
4915 if (!NT_SUCCESS(Status))
4916 {
4917 return Status;
4918 }
4919
4920 /* And SessionId */
4921 Status = SeQuerySessionIdToken(Token, SessionId);
4922 if (!NT_SUCCESS(Status))
4923 {
4924 return Status;
4925 }
4926
4927 if (RxContext->Create.UserName.Buffer != NULL)
4928 {
4929 UNIMPLEMENTED;
4930 Status = STATUS_NOT_IMPLEMENTED;
4931 goto Leave;
4932 }
4933
4934 /* Deal with connection credentials */
4935 if (RxContext->Create.UserDomainName.Buffer != NULL)
4936 {
4937 UNIMPLEMENTED;
4938 Status = STATUS_NOT_IMPLEMENTED;
4939 goto Leave;
4940 }
4941
4942 if (RxContext->Create.Password.Buffer != NULL)
4943 {
4944 UNIMPLEMENTED;
4945 Status = STATUS_NOT_IMPLEMENTED;
4946 goto Leave;
4947 }
4948
4949 Leave:
4950 if (NT_SUCCESS(Status))
4951 {
4952 /* If that's a CSC instance, mark it as such */
4953 if (RxIsThisACscAgentOpen(RxContext))
4954 {
4955 *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE;
4956 }
4957 return Status;
4958 }
4959
4960 return Status;
4961 }
4962
4963 /*
4964 * @implemented
4965 */
4966 VOID
4967 RxInitializeWorkQueue(
4968 PRX_WORK_QUEUE WorkQueue,
4969 WORK_QUEUE_TYPE WorkQueueType,
4970 ULONG MaximumNumberOfWorkerThreads,
4971 ULONG MinimumNumberOfWorkerThreads)
4972 {
4973 PAGED_CODE();
4974
4975 WorkQueue->Type = WorkQueueType;
4976 WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
4977 WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
4978
4979 WorkQueue->State = RxWorkQueueActive;
4980 WorkQueue->SpinUpRequestPending = FALSE;
4981 WorkQueue->pRundownContext = NULL;
4982 WorkQueue->NumberOfWorkItemsDispatched = 0;
4983 WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
4984 WorkQueue->CumulativeQueueLength = 0;
4985 WorkQueue->NumberOfSpinUpRequests = 0;
4986 WorkQueue->NumberOfActiveWorkerThreads = 0;
4987 WorkQueue->NumberOfIdleWorkerThreads = 0;
4988 WorkQueue->NumberOfFailedSpinUpRequests = 0;
4989 WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
4990 WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
4991 WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
4992 WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
4993 WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
4994 WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
4995 WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
4996 WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
4997 WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
4998 WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
4999 WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
5000 WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
5001 WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
5002
5003 KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
5004 KeInitializeSpinLock(&WorkQueue->SpinLock);
5005 }
5006
5007 /*
5008 * @implemented
5009 */
5010 NTSTATUS
5011 RxInitializeWorkQueueDispatcher(
5012 PRX_WORK_QUEUE_DISPATCHER Dispatcher)
5013 {
5014 NTSTATUS Status;
5015 ULONG MaximumNumberOfWorkerThreads;
5016
5017 PAGED_CODE();
5018
5019 /* Number of threads will depend on system capacity */
5020 if (MmQuerySystemSize() != MmLargeSystem)
5021 {
5022 MaximumNumberOfWorkerThreads = 5;
5023 }
5024 else
5025 {
5026 MaximumNumberOfWorkerThreads = 10;
5027 }
5028
5029 /* Initialize the work queues */
5030 RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue,
5031 MaximumNumberOfWorkerThreads, 1);
5032 RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1);
5033 RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1);
5034
5035 /* And start the worker threads */
5036 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue],
5037 RxBootstrapWorkerThreadDispatcher,
5038 &Dispatcher->WorkQueue[HyperCriticalWorkQueue]);
5039 if (!NT_SUCCESS(Status))
5040 {
5041 return Status;
5042 }
5043
5044 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue],
5045 RxBootstrapWorkerThreadDispatcher,
5046 &Dispatcher->WorkQueue[CriticalWorkQueue]);
5047 if (!NT_SUCCESS(Status))
5048 {
5049 return Status;
5050 }
5051
5052 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue],
5053 RxBootstrapWorkerThreadDispatcher,
5054 &Dispatcher->WorkQueue[DelayedWorkQueue]);
5055 return Status;
5056 }
5057
5058 /*
5059 * @implemented
5060 */
5061 VOID
5062 RxInitiateSrvOpenKeyAssociation(
5063 IN OUT PSRV_OPEN SrvOpen)
5064 {
5065 PRX_BUFFERING_MANAGER BufferingManager;
5066
5067 PAGED_CODE();
5068
5069 SrvOpen->Key = NULL;
5070
5071 /* Just keep track of the opening request */
5072 BufferingManager = &((PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall)->BufferingManager;
5073 InterlockedIncrement(&BufferingManager->NumberOfOutstandingOpens);
5074
5075 InitializeListHead(&SrvOpen->SrvOpenKeyList);
5076 }
5077
5078 /*
5079 * @implemented
5080 */
5081 NTSTATUS
5082 RxInsertWorkQueueItem(
5083 PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
5084 WORK_QUEUE_TYPE WorkQueueType,
5085 PRX_WORK_QUEUE_ITEM WorkQueueItem)
5086 {
5087 KIRQL OldIrql;
5088 NTSTATUS Status;
5089 BOOLEAN SpinUpThreads;
5090 PRX_WORK_QUEUE WorkQueue;
5091
5092 /* No dispatcher, nothing to insert */
5093 if (RxDispatcher.State != RxDispatcherActive)
5094 {
5095 return STATUS_UNSUCCESSFUL;
5096 }
5097
5098 /* Get the work queue */
5099 WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType];
5100
5101 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
5102 /* Only insert if the work queue is in decent state */
5103 if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL)
5104 {
5105 Status = STATUS_UNSUCCESSFUL;
5106 }
5107 else
5108 {
5109 SpinUpThreads = FALSE;
5110 WorkQueueItem->pDeviceObject = pMRxDeviceObject;
5111 InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
5112 WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
5113 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
5114
5115 /* If required (and possible!), spin up a new worker thread */
5116 if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched &&
5117 WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads &&
5118 !WorkQueue->SpinUpRequestPending)
5119 {
5120 WorkQueue->SpinUpRequestPending = TRUE;
5121 SpinUpThreads = TRUE;
5122 }
5123
5124 Status = STATUS_SUCCESS;
5125 }
5126 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
5127
5128 /* If we failed, return and still not insert item */
5129 if (!NT_SUCCESS(Status))
5130 {
5131 return Status;
5132 }
5133
5134 /* All fine, insert the item */
5135 KeInsertQueue(&WorkQueue->Queue, &WorkQueueItem->List);
5136
5137 /* And start a new worker thread if needed */
5138 if (SpinUpThreads)
5139 {
5140 RxSpinUpWorkerThreads(WorkQueue);
5141 }
5142
5143 return Status;
5144 }
5145
5146 BOOLEAN
5147 RxIsThisACscAgentOpen(
5148 IN PRX_CONTEXT RxContext)
5149 {
5150 BOOLEAN CscAgent;
5151
5152 CscAgent = FALSE;
5153
5154 /* Client Side Caching is DFS stuff - we don't support it */
5155 if (RxContext->Create.EaLength != 0)
5156 {
5157 UNIMPLEMENTED;
5158 }
5159
5160 if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL &&
5161 ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA)
5162 {
5163 CscAgent = TRUE;
5164 }
5165
5166 return CscAgent;
5167 }
5168
5169 VOID
5170 RxLockUserBuffer(
5171 IN PRX_CONTEXT RxContext,
5172 IN LOCK_OPERATION Operation,
5173 IN ULONG BufferLength)
5174 {
5175 PIRP Irp;
5176 PMDL Mdl = NULL;
5177
5178 PAGED_CODE();
5179
5180 _SEH2_TRY
5181 {
5182 Irp = RxContext->CurrentIrp;
5183 /* If we already have a MDL, make sure it's locked */
5184 if (Irp->MdlAddress != NULL)
5185 {
5186 ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress));
5187 }
5188 else
5189 {
5190 /* That likely means the driver asks for buffered IOs - we don't support it! */
5191 ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION));
5192
5193 /* If we have a real length */
5194 if (BufferLength > 0)
5195 {
5196 /* Allocate a MDL and lock it */
5197 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
5198 if (Mdl == NULL)
5199 {
5200 RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES;
5201 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
5202 }
5203
5204 MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
5205 }
5206 }
5207 }
5208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5209 {
5210 NTSTATUS Status;
5211
5212 Status = _SEH2_GetExceptionCode();
5213
5214 /* Free the possible MDL we have allocated */
5215 IoFreeMdl(Mdl);
5216 Irp->MdlAddress = NULL;
5217
5218 RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT;
5219
5220 /* Fix status */
5221 if (!FsRtlIsNtstatusExpected(Status))
5222 {
5223 Status = STATUS_INVALID_USER_BUFFER;
5224 }
5225
5226 RxContext->IoStatusBlock.Status = Status;
5227 ExRaiseStatus(Status);
5228 }
5229 _SEH2_END;
5230 }
5231
5232 /*
5233 * @implemented
5234 */
5235 NTSTATUS
5236 RxLowIoCompletionTail(
5237 IN PRX_CONTEXT RxContext)
5238 {
5239 NTSTATUS Status;
5240 USHORT Operation;
5241
5242 PAGED_CODE();
5243
5244 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
5245
5246 /* Only continue if we're at APC_LEVEL or lower */
5247 if (RxShouldPostCompletion() &&
5248 !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
5249 {
5250 return STATUS_MORE_PROCESSING_REQUIRED;
5251 }
5252
5253 /* Call the completion routine */
5254 DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine);
5255 Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
5256 if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY)
5257 {
5258 return Status;
5259 }
5260
5261 /* If it was a RW operation, for a paging file ... */
5262 Operation = RxContext->LowIoContext.Operation;
5263 if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
5264 {
5265 /* Remove ourselves from the list and resume operations */
5266 if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
5267 {
5268 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5269 RemoveEntryList(&RxContext->RxContextSerializationQLinks);
5270 RxContext->RxContextSerializationQLinks.Flink = NULL;
5271 RxContext->RxContextSerializationQLinks.Blink = NULL;
5272 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5273 RxResumeBlockedOperations_ALL(RxContext);
5274 }
5275 }
5276 else
5277 {
5278 /* Sanity check: we had known operation */
5279 ASSERT(Operation < LOWIO_OP_MAXIMUM);
5280 }
5281
5282 /* If not sync operation, complete now. Otherwise, caller has already completed */
5283 if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
5284 {
5285 RxCompleteRequest(RxContext, Status);
5286 }
5287
5288 DPRINT("Status: %x\n", Status);
5289 return Status;
5290 }
5291
5292 /*
5293 * @implemented
5294 */
5295 NTSTATUS
5296 NTAPI
5297 RxLowIoPopulateFsctlInfo(
5298 IN PRX_CONTEXT RxContext)
5299 {
5300 PMDL Mdl;
5301 PIRP Irp;
5302 UCHAR Method;
5303 PIO_STACK_LOCATION Stack;
5304
5305 PAGED_CODE();
5306
5307 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext);
5308
5309 Irp = RxContext->CurrentIrp;
5310 Stack = RxContext->CurrentIrpSp;
5311
5312 /* Copy stack parameters */
5313 RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
5314 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength;
5315 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength;
5316 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction;
5317 Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
5318
5319 /* Same buffer in case of buffered */
5320 if (Method == METHOD_BUFFERED)
5321 {
5322 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
5323 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
5324
5325 return STATUS_SUCCESS;
5326 }
5327
5328 /* Two buffers for neither */
5329 if (Method == METHOD_NEITHER)
5330 {
5331 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer;
5332 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
5333
5334 return STATUS_SUCCESS;
5335 }
5336
5337 /* Only IN/OUT remain */
5338 ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT);
5339
5340 /* Use system buffer for input */
5341 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
5342 /* And MDL for output */
5343 Mdl = Irp->MdlAddress;
5344 if (Mdl != NULL)
5345 {
5346 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
5347 if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)
5348 {
5349 return STATUS_INSUFFICIENT_RESOURCES;
5350 }
5351 }
5352 else
5353 {
5354 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
5355 }
5356
5357 return STATUS_SUCCESS;
5358 }
5359
5360 NTSTATUS
5361 NTAPI
5362 RxLowIoSubmit(
5363 IN PRX_CONTEXT RxContext,
5364 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine)
5365 {
5366 NTSTATUS Status;
5367 USHORT Operation;
5368 BOOLEAN Synchronous;
5369 PLOWIO_CONTEXT LowIoContext;
5370
5371 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine);
5372
5373 PAGED_CODE();
5374
5375 LowIoContext = &RxContext->LowIoContext;
5376 Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
5377
5378 LowIoContext->CompletionRoutine = CompletionRoutine;
5379
5380 Status = STATUS_SUCCESS;
5381 Operation = LowIoContext->Operation;
5382 switch (Operation)
5383 {
5384 case LOWIO_OP_READ:
5385 case LOWIO_OP_WRITE:
5386 /* Check that the parameters were properly set by caller
5387 * See comment in RxInitializeLowIoContext()
5388 */
5389 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE);
5390 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE);
5391
5392 /* Lock the buffer */
5393 RxLockUserBuffer(RxContext,
5394 (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess),
5395 LowIoContext->ParamsFor.ReadWrite.ByteCount);
5396 if (RxNewMapUserBuffer(RxContext) == NULL)
5397 {
5398 return STATUS_INSUFFICIENT_RESOURCES;
5399 }
5400 LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress;
5401
5402 /* If that's a paging IO, initialize serial operation */
5403 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
5404 {
5405 PFCB Fcb;
5406
5407 Fcb = (PFCB)RxContext->pFcb;
5408
5409 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5410 RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
5411 if (Operation == LOWIO_OP_READ)
5412 {
5413 InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks);
5414 }
5415 else
5416 {
5417 InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks);
5418 }
5419
5420 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5421 }
5422
5423 break;
5424
5425 case LOWIO_OP_FSCTL:
5426 case LOWIO_OP_IOCTL:
5427 /* Set FSCTL/IOCTL parameters */
5428 Status = RxLowIoPopulateFsctlInfo(RxContext);
5429 /* Check whether we're consistent: a length means a buffer */
5430 if (NT_SUCCESS(Status))
5431 {
5432 if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 &&
5433 LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
5434 (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 &&
5435 LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL))
5436 {
5437 Status = STATUS_INVALID_PARAMETER;
5438 }
5439 }
5440 break;
5441
5442 /* Nothing to do */
5443 case LOWIO_OP_SHAREDLOCK:
5444 case LOWIO_OP_EXCLUSIVELOCK:
5445 case LOWIO_OP_UNLOCK:
5446 case LOWIO_OP_UNLOCK_MULTIPLE:
5447 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
5448 case LOWIO_OP_CLEAROUT:
5449 break;
5450
5451 default:
5452 ASSERT(FALSE);
5453 Status = STATUS_INVALID_PARAMETER;
5454 break;
5455 }
5456
5457 /* No need to perform extra init in case of posting */
5458 RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED;
5459
5460 /* Preflight checks were OK, time to submit */
5461 if (NT_SUCCESS(Status))
5462 {
5463 PMINIRDR_DISPATCH Dispatch;
5464
5465 if (!Synchronous)
5466 {
5467 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
5468 /* If not synchronous, we're likely to return before the operation is finished */
5469 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
5470 {
5471 IoMarkIrpPending(RxContext->CurrentIrp);
5472 }
5473 }
5474
5475 Dispatch = RxContext->RxDeviceObject->Dispatch;
5476 if (Dispatch != NULL)
5477 {
5478 /* We'll try to execute until the mini-rdr doesn't return pending */
5479 do
5480 {
5481 RxContext->IoStatusBlock.Information = 0;
5482
5483 MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext));
5484 if (Status == STATUS_PENDING)
5485 {
5486 /* Unless it's not synchronous, caller will be happy with pending op */
5487 if (!Synchronous)
5488 {
5489 return Status;
5490 }
5491
5492 RxWaitSync(RxContext);
5493 Status = RxContext->IoStatusBlock.Status;
5494 }
5495 else
5496 {
5497 if (!Synchronous)
5498 {
5499 /* We had marked the IRP pending, whereas the operation finished, drop that */
5500 if (Status != STATUS_RETRY)
5501 {
5502 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
5503 {
5504 RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED;
5505 }
5506
5507 InterlockedDecrement((volatile long *)&RxContext->ReferenceCount);
5508 }
5509 }
5510 }
5511 } while (Status == STATUS_PENDING);
5512 }
5513 else
5514 {
5515 Status = STATUS_INVALID_PARAMETER;
5516 }
5517 }
5518
5519 /* Call completion and return */
5520 RxContext->IoStatusBlock.Status = Status;
5521 LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL;
5522 return RxLowIoCompletionTail(RxContext);
5523 }
5524
5525 /*
5526 * @implemented
5527 */
5528 PVOID
5529 RxMapSystemBuffer(
5530 IN PRX_CONTEXT RxContext)
5531 {
5532 PIRP Irp;
5533
5534 PAGED_CODE();
5535
5536 Irp = RxContext->CurrentIrp;
5537 /* We should have a MDL (buffered IOs are not supported!) */
5538 if (Irp->MdlAddress != NULL)
5539 {
5540 ASSERT(FALSE);
5541 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
5542 }
5543
5544 /* Just return system buffer */
5545 return Irp->AssociatedIrp.SystemBuffer;
5546 }
5547
5548 /*
5549 * @implemented
5550 */
5551 VOID
5552 RxMarkFobxOnCleanup(
5553 PFOBX pFobx,
5554 PBOOLEAN NeedPurge)
5555 {
5556 PFCB Fcb;
5557 PFOBX ScavengerFobx;
5558 LARGE_INTEGER TickCount;
5559 PRDBSS_SCAVENGER Scavenger;
5560
5561 PAGED_CODE();
5562
5563 /* No FOBX, nothing to mark */
5564 if (pFobx == NULL)
5565 {
5566 return;
5567 }
5568
5569 /* Query time for close */
5570 KeQueryTickCount(&TickCount);
5571
5572 Fcb = (PFCB)pFobx->pSrvOpen->pFcb;
5573 ASSERT(NodeTypeIsFcb(Fcb));
5574
5575 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
5576 RxAcquireScavengerMutex();
5577
5578 ScavengerFobx = NULL;
5579 /* If that's not a file, or even not a disk resource, just mark as dormant */
5580 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE || Fcb->VNetRoot->pNetRoot->DeviceType != FILE_DEVICE_DISK)
5581 {
5582 SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5583 InitializeListHead(&pFobx->ClosePendingList);
5584 ++Scavenger->NumberOfDormantFiles;
5585 }
5586 else
5587 {
5588 ASSERT(Scavenger->NumberOfDormantFiles >= 0);
5589 /* If we're about to reach the maximum dormant of FOBX */
5590 if (Scavenger->NumberOfDormantFiles >= Scavenger->MaximumNumberOfDormantFiles)
5591 {
5592 /* This should never be wrong... */
5593 if (!IsListEmpty(&Scavenger->ClosePendingFobxsList))
5594 {
5595 /* Then, take the first from the list (oldest) and save it for later purge */
5596 ScavengerFobx = CONTAINING_RECORD(Scavenger->ClosePendingFobxsList.Flink, FOBX, ClosePendingList);
5597 if (ScavengerFobx->pSrvOpen != NULL && ScavengerFobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
5598 {
5599 *NeedPurge = TRUE;
5600 ScavengerFobx = NULL;
5601 }
5602 else
5603 {
5604 RxReferenceNetFobx(ScavengerFobx);
5605 }
5606 }
5607 }
5608
5609 /* Mark ourselves as dormant */
5610 SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5611 pFobx->CloseTime.QuadPart = TickCount.QuadPart;
5612
5613 /* And insert us in the list of dormant files */
5614 InsertTailList(&Scavenger->ClosePendingFobxsList, &pFobx->ClosePendingList);
5615 /* If scavenger was inactive, start it */
5616 if (Scavenger->NumberOfDormantFiles++ == 0 && Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
5617 {
5618 Scavenger->State = RDBSS_SCAVENGER_DORMANT;
5619 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem, RxScavengerTimerRoutine,
5620 Fcb->RxDeviceObject, Scavenger->TimeLimit);
5621 }
5622 }
5623
5624 RxReleaseScavengerMutex();
5625
5626 /* If we had reached max */
5627 if (ScavengerFobx != NULL)
5628 {
5629 NTSTATUS Status;
5630
5631 /* Purge the oldest FOBX */
5632 Status = RxPurgeFobxFromCache(ScavengerFobx);
5633 if (Status != STATUS_SUCCESS)
5634 {
5635 *NeedPurge = TRUE;
5636 }
5637 }
5638 }
5639
5640 /*
5641 * @implemented
5642 */
5643 VOID
5644 RxMarkFobxOnClose(
5645 PFOBX Fobx)
5646 {
5647 PFCB Fcb;
5648 PRDBSS_SCAVENGER Scavenger;
5649
5650 PAGED_CODE();
5651
5652 /* No FOBX, nothing to mark */
5653 if (Fobx == NULL)
5654 {
5655 return;
5656 }
5657
5658 Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
5659 ASSERT(NodeTypeIsFcb(Fcb));
5660
5661 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
5662
5663 RxAcquireScavengerMutex();
5664 /* Only mark it if it was already marked as dormant */
5665 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT))
5666 {
5667 /* If FCB wasn't already decrement, do it now */
5668 if (!Fobx->fOpenCountDecremented)
5669 {
5670 Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
5671 ASSERT(NodeTypeIsFcb(Fcb));
5672 InterlockedDecrement((volatile long *)&Fcb->OpenCount);
5673
5674 Fobx->fOpenCountDecremented = TRUE;
5675 }
5676
5677 /* We're no longer dormant */
5678 InterlockedDecrement(&Scavenger->NumberOfDormantFiles);
5679 ClearFlag(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5680 }
5681
5682 /* If we were inserted in the scavenger, drop ourselves out */
5683 if (!IsListEmpty(&Fobx->ClosePendingList))
5684 {
5685 RemoveEntryList(&Fobx->ClosePendingList);
5686 InitializeListHead(&Fobx->ClosePendingList);
5687 }
5688
5689 RxReleaseScavengerMutex();
5690 }
5691
5692 /*
5693 * @implemented
5694 */
5695 PVOID
5696 RxNewMapUserBuffer(
5697 PRX_CONTEXT RxContext)
5698 {
5699 PIRP Irp;
5700
5701 PAGED_CODE();
5702
5703 Irp = RxContext->CurrentIrp;
5704 if (Irp->MdlAddress != NULL)
5705 {
5706 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
5707 }
5708
5709 return Irp->UserBuffer;
5710 }
5711
5712 BOOLEAN
5713 NTAPI
5714 RxNoOpAcquire(
5715 IN PVOID Fcb,
5716 IN BOOLEAN Wait)
5717 {
5718 UNIMPLEMENTED;
5719 return FALSE;
5720 }
5721
5722 VOID
5723 NTAPI
5724 RxNoOpRelease(
5725 IN PVOID Fcb)
5726 {
5727 UNIMPLEMENTED;
5728 }
5729
5730 VOID
5731 RxOrphanThisFcb(
5732 PFCB Fcb)
5733 {
5734 UNIMPLEMENTED;
5735 }
5736
5737 VOID
5738 RxOrphanSrvOpens(
5739 IN PV_NET_ROOT ThisVNetRoot)
5740 {
5741 PFCB Fcb;
5742 USHORT Bucket;
5743 PNET_ROOT NetRoot;
5744 PRX_FCB_TABLE FcbTable;
5745 PRX_PREFIX_TABLE PrefixTable;
5746
5747 PAGED_CODE();
5748
5749 /* Mailslot won't have any SRV_OPEN (to orphan) */
5750 NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
5751 if (NetRoot->Type == NET_ROOT_MAILSLOT)
5752 {
5753 return;
5754 }
5755
5756 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
5757 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
5758
5759 FcbTable = &NetRoot->FcbTable;
5760 RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
5761
5762 _SEH2_TRY
5763 {
5764 /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
5765 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
5766 {
5767 PLIST_ENTRY BucketList, Entry;
5768
5769 BucketList = &FcbTable->HashBuckets[Bucket];
5770 Entry = BucketList->Flink;
5771 while (Entry != BucketList)
5772 {
5773 Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
5774 Entry = Entry->Flink;
5775
5776 ASSERT(NodeTypeIsFcb(Fcb));
5777 RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
5778 }
5779 }
5780
5781 /* Of course, don't forget about NULL-entry */
5782 if (FcbTable->TableEntryForNull != NULL)
5783 {
5784 Fcb = CONTAINING_RECORD(FcbTable->TableEntryForNull, FCB, FcbTableEntry.HashLinks);
5785 ASSERT(NodeTypeIsFcb(Fcb));
5786 RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
5787 }
5788 }
5789 _SEH2_FINALLY
5790 {
5791 RxReleaseFcbTableLock(FcbTable);
5792 }
5793 _SEH2_END;
5794 }
5795
5796 VOID
5797 RxOrphanSrvOpensForThisFcb(
5798 IN PFCB Fcb,
5799 IN PV_NET_ROOT ThisVNetRoot,
5800 IN BOOLEAN OrphanAll)
5801 {
5802 UNIMPLEMENTED;
5803 }
5804
5805 /*
5806 * @implemented
5807 */
5808 BOOLEAN
5809 RxpAcquirePrefixTableLockShared(
5810 PRX_PREFIX_TABLE pTable,
5811 BOOLEAN Wait,
5812 BOOLEAN ProcessBufferingStateChangeRequests)
5813 {
5814 PAGED_CODE();
5815
5816 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
5817 pTable->TableLock.ActiveEntries);
5818
5819 return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
5820 }
5821
5822 /*
5823 * @implemented
5824 */
5825 BOOLEAN
5826 RxpAcquirePrefixTableLockExclusive(
5827 PRX_PREFIX_TABLE pTable,
5828 BOOLEAN Wait,
5829 BOOLEAN ProcessBufferingStateChangeRequests)
5830 {
5831 PAGED_CODE();
5832
5833 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
5834 pTable->TableLock.ActiveEntries);
5835
5836 return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait);
5837 }
5838
5839 /*
5840 * @implemented
5841 */
5842 BOOLEAN
5843 RxpDereferenceAndFinalizeNetFcb(
5844 OUT PFCB ThisFcb,
5845 IN PRX_CONTEXT RxContext,
5846 IN BOOLEAN RecursiveFinalize,
5847 IN BOOLEAN ForceFinalize)
5848 {
5849 NTSTATUS Status;
5850 ULONG References;
5851 PNET_ROOT NetRoot;
5852 BOOLEAN ResourceAcquired, NetRootReferenced, Freed;
5853
5854 PAGED_CODE();
5855
5856 ASSERT(!ForceFinalize);
5857 ASSERT(NodeTypeIsFcb(ThisFcb));
5858 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
5859
5860 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5861 References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount);
5862 if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1))
5863 {
5864 return FALSE;
5865 }
5866
5867 Freed = FALSE;
5868 Status = STATUS_SUCCESS;
5869 NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
5870 ResourceAcquired = FALSE;
5871 NetRootReferenced = FALSE;
5872 /* If FCB isn't orphaned, it still have context attached */
5873 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
5874 {
5875 /* Don't let NetRoot go away before we're done */
5876 RxReferenceNetRoot(NetRoot);
5877 NetRootReferenced = TRUE;
5878
5879 /* Try to acquire the table lock exclusively */
5880 if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable))
5881 {
5882 RxReferenceNetFcb(ThisFcb);
5883
5884 if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
5885 {
5886 if (RxContext != NULL && RxContext != CHANGE_BUFFERING_STATE_CONTEXT &&
5887 RxContext != CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
5888 {
5889 RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
5890 }
5891
5892 RxReleaseFcb(RxContext, ThisFcb);
5893
5894 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
5895
5896 Status = RxAcquireExclusiveFcb(RxContext, ThisFcb);
5897 }
5898
5899 References = RxDereferenceNetFcb(ThisFcb);
5900
5901 ResourceAcquired = TRUE;
5902 }
5903 }
5904
5905 /* If locking was OK (or not needed!), attempt finalization */
5906 if (Status == STATUS_SUCCESS)
5907 {
5908 Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
5909 }
5910
5911 /* Release table lock if acquired */
5912 if (ResourceAcquired)
5913 {
5914 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5915 }
5916
5917 /* We don't need the NetRoot anylonger */
5918 if (NetRootReferenced)
5919 {
5920 RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld);
5921 }
5922
5923 return Freed;
5924 }
5925
5926 /*
5927 * @implemented
5928 */
5929 LONG
5930 RxpDereferenceNetFcb(
5931 PFCB Fcb)
5932 {
5933 LONG NewCount;
5934
5935 PAGED_CODE();
5936
5937 ASSERT(NodeTypeIsFcb(Fcb));
5938
5939 NewCount = InterlockedDecrement((volatile long *)&Fcb->NodeReferenceCount);
5940 ASSERT(NewCount >= 0);
5941
5942 PRINT_REF_COUNT(NETFCB, NewCount);
5943
5944 return NewCount;
5945 }
5946
5947 /*
5948 * @implemented
5949 */
5950 VOID
5951 NTAPI
5952 RxpDestroySrvCall(
5953 IN PVOID Context)
5954 {
5955 NTSTATUS Status;
5956 PSRV_CALL SrvCall;
5957 BOOLEAN ForceFinalize;
5958 PRX_PREFIX_TABLE PrefixTable;
5959
5960 SrvCall = (PSRV_CALL)Context;
5961 /* At this step, RxFinalizeSrvCall already cleaned some fields */
5962 ASSERT(SrvCall->UpperFinalizationDone);
5963
5964 PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
5965 /* Were we called with ForceFinalize? */
5966 ForceFinalize = BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
5967
5968 /* Notify mini-rdr */
5969 MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch,
5970 MRxFinalizeSrvCall, ((PMRX_SRV_CALL)SrvCall,
5971 ForceFinalize));
5972 (void)Status;
5973
5974 /* Dereference our extra reference (set before queueing) */
5975 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
5976 InterlockedDecrement((volatile long *)&SrvCall->NodeReferenceCount);
5977 /* And finalize for real, with the right context */
5978 RxFinalizeSrvCall(SrvCall, FALSE, ForceFinalize);
5979 RxReleasePrefixTableLock(PrefixTable);
5980 }
5981
5982 /*
5983 * @implemented
5984 */
5985 VOID
5986 RxpDiscardChangeBufferingStateRequests(
5987 _Inout_ PLIST_ENTRY DiscardedRequests)
5988 {
5989 PLIST_ENTRY Entry;
5990
5991 PAGED_CODE();
5992
5993 /* No requests to discard */
5994 if (IsListEmpty(DiscardedRequests))
5995 {
5996 return;
5997 }
5998
5999 /* Free all the discarded requests */
6000 Entry = DiscardedRequests->Flink;
6001 while (Entry != DiscardedRequests)
6002 {
6003 PCHANGE_BUFFERING_STATE_REQUEST Request;
6004
6005 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
6006 Entry = Entry->Flink;
6007
6008 DPRINT("Req %p for %p (%p) discarded\n", Request, Request->SrvOpenKey, Request->SrvOpen);
6009
6010 RxPrepareRequestForReuse(Request);
6011 RxFreePool(Request);
6012 }
6013 }
6014
6015 /*
6016 * @implemented
6017 */
6018 VOID
6019 RxpDispatchChangeBufferingStateRequests(
6020 PSRV_CALL SrvCall,
6021 PSRV_OPEN SrvOpen,
6022 PLIST_ENTRY DiscardedRequests)
6023 {
6024 KIRQL OldIrql;
6025 NTSTATUS Status;
6026 BOOLEAN StartDispatcher;
6027 LIST_ENTRY AcceptedReqs;
6028 LIST_ENTRY DispatcherList;
6029 PRX_BUFFERING_MANAGER BufferingManager;
6030
6031 /* Initialize our lists */
6032 InitializeListHead(&AcceptedReqs);
6033 InitializeListHead(DiscardedRequests);
6034
6035 /* Transfer the requests to dispatch locally */
6036 BufferingManager = &SrvCall->BufferingManager;
6037 KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
6038 RxTransferList(&DispatcherList, &BufferingManager->DispatcherList);
6039 KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
6040
6041 /* If there were requests */
6042 if (!IsListEmpty(&DispatcherList))
6043 {
6044 PLIST_ENTRY Entry;
6045
6046 /* For each of the entries... */
6047 Entry = DispatcherList.Flink;
6048 while (Entry != &DispatcherList)
6049 {
6050 PCHANGE_BUFFERING_STATE_REQUEST Request;
6051
6052 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
6053 Entry = Entry->Flink;
6054
6055 /* If we have been provided a SRV_OPEN, see whether it matches */
6056 if (SrvOpen != NULL)
6057 {
6058 /* Match, the request is accepted */
6059 if (Request->SrvOpenKey == SrvOpen->Key)
6060 {
6061 Request->SrvOpen = SrvOpen;
6062 RxReferenceSrvOpen(SrvOpen);
6063
6064 RemoveEntryList(&Request->ListEntry);
6065 InsertTailList(&AcceptedReqs, &Request->ListEntry);
6066
6067 /* Move to the next entry */
6068 continue;
6069 }
6070 else
6071 {
6072 Status = STATUS_PENDING;
6073 }
6074 }
6075 else
6076 {
6077 /* No SRV_OPEN provided, try to find one */
6078 Status = RxpLookupSrvOpenForRequestLite(SrvCall, Request);
6079 }
6080
6081 /* We found a matching SRV_OPEN, accept the request */
6082 if (Status == STATUS_SUCCESS)
6083 {
6084 RemoveEntryList(&Request->ListEntry);
6085 InsertTailList(&AcceptedReqs, &Request->ListEntry);
6086 }
6087 /* Another run might help handling it, don't discard it */
6088 else if (Status == STATUS_PENDING)
6089 {
6090 continue;
6091 }
6092 /* Otherwise, discard the request */
6093 else
6094 {
6095 ASSERT(Status == STATUS_NOT_FOUND);
6096
6097 RemoveEntryList(&Request->ListEntry);
6098 InsertTailList(DiscardedRequests, &Request->ListEntry);
6099 }
6100 }
6101 }
6102
6103 KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
6104 /* Nothing to dispatch, no need to start dispatcher */
6105 if (IsListEmpty(&DispatcherList))
6106 {
6107 StartDispatcher = FALSE;
6108 }
6109 else
6110 {
6111 /* Transfer back the list of the not treated entries to the buffering manager */
6112 RxTransferList(&BufferingManager->DispatcherList, &DispatcherList);
6113 StartDispatcher = (BufferingManager->DispatcherActive == FALSE);
6114 /* If the dispatcher isn't active, start it */
6115 if (StartDispatcher)
6116 {
6117 BufferingManager->DispatcherActive = TRUE;
6118 }
6119 }
6120
6121 /* If there were accepted requests, move them to the buffering manager */
6122 if (!IsListEmpty(&AcceptedReqs))
6123 {
6124 RxTransferList(&BufferingManager->HandlerList, &AcceptedReqs);
6125 }
6126 KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
6127
6128 /* If we're to start the dispatcher, do it */
6129 if (StartDispatcher)
6130 {
6131 RxReferenceSrvCall(SrvCall);
6132 DPRINT("Starting dispatcher\n");
6133 RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
6134 &BufferingManager->DispatcherWorkItem,
6135 RxDispatchChangeBufferingStateRequests, SrvCall);
6136 }
6137 }
6138
6139 /*
6140 * @implemented
6141 */
6142 NTSTATUS
6143 RxpLookupSrvOpenForRequestLite(
6144 IN PSRV_CALL SrvCall,
6145 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request)
6146 {
6147 NTSTATUS Status;
6148 PLIST_ENTRY Entry;
6149 PSRV_OPEN SrvOpen;
6150
6151 PAGED_CODE();
6152
6153 Status = STATUS_SUCCESS;
6154 /* Browse all our associated SRV_OPENs to find the one! */
6155 for (Entry = SrvCall->BufferingManager.SrvOpenLists[0].Flink;
6156 Entry != &SrvCall->BufferingManager.SrvOpenLists[0];
6157 Entry = Entry->Flink)
6158 {
6159 /* Same key, not orphaned, this is ours */
6160 SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenKeyList);
6161 if (SrvOpen->Key == Request->SrvOpenKey)
6162 {
6163 if (!BooleanFlagOn(SrvOpen->pFcb->FcbState, FCB_STATE_ORPHANED))
6164 {
6165 RxReferenceSrvOpen(SrvOpen);
6166 break;
6167 }
6168 }
6169 }
6170
6171 /* We didn't manage to find a SRV_OPEN */
6172 if (Entry == &SrvCall->BufferingManager.SrvOpenLists[0])
6173 {
6174 SrvOpen = NULL;
6175
6176 /* The coming open might help, mark as pending for later retry */
6177 if (SrvCall->BufferingManager.NumberOfOutstandingOpens != 0)
6178 {
6179 Status = STATUS_PENDING;
6180 }
6181 /* Else, it's a complete failure */
6182 else
6183 {
6184 Status = STATUS_NOT_FOUND;
6185 }
6186 }
6187
6188 /* Return the (not) found SRV_OPEN */
6189 Request->SrvOpen = SrvOpen;
6190
6191 return Status;
6192 }
6193
6194 /*
6195 * @implemented
6196 */
6197 VOID
6198 RxpMarkInstanceForScavengedFinalization(
6199 PVOID Instance)
6200 {
6201 NODE_TYPE_CODE NodeType;
6202 PNODE_TYPE_AND_SIZE Node;
6203 PRDBSS_SCAVENGER Scavenger;
6204 PRDBSS_DEVICE_OBJECT DeviceObject;
6205 PLIST_ENTRY ScavengerHead, InstEntry;
6206
6207 PAGED_CODE();
6208
6209 /* If still referenced, don't mark it (broken caller) */
6210 Node = (PNODE_TYPE_AND_SIZE)Instance;
6211 if (Node->NodeReferenceCount > 1)
6212 {
6213 return;
6214 }
6215
6216 DeviceObject = RxGetDeviceObjectOfInstance(Instance);
6217 Scavenger = DeviceObject->pRdbssScavenger;
6218
6219 /* Mark the node */
6220 NodeType = NodeType(Instance);
6221 SetFlag(NodeType(Node), RX_SCAVENGER_MASK);
6222 DPRINT("Node %p has now the scavenger mark!\n", Instance);
6223
6224 /* Increase the count in the scavenger, and queue it */
6225 ScavengerHead = NULL;
6226 switch (NodeType)
6227 {
6228 case RDBSS_NTC_FOBX:
6229 ++Scavenger->FobxsToBeFinalized;
6230 ScavengerHead = &Scavenger->FobxFinalizationList;
6231 InstEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
6232 break;
6233
6234 case RDBSS_NTC_SRVCALL:
6235 ++Scavenger->SrvCallsToBeFinalized;
6236 ScavengerHead = &Scavenger->SrvCallFinalizationList;
6237 InstEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
6238 break;
6239
6240 case RDBSS_NTC_NETROOT:
6241 ++Scavenger->NetRootsToBeFinalized;
6242 ScavengerHead = &Scavenger->NetRootFinalizationList;
6243 InstEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
6244 break;
6245
6246 case RDBSS_NTC_V_NETROOT:
6247 ++Scavenger->VNetRootsToBeFinalized;
6248 ScavengerHead = &Scavenger->VNetRootFinalizationList;
6249 InstEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
6250 break;
6251
6252 case RDBSS_NTC_SRVOPEN:
6253 ++Scavenger->SrvOpensToBeFinalized;
6254 ScavengerHead = &Scavenger->SrvOpenFinalizationList;
6255 InstEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
6256 break;
6257 }
6258
6259 /* Extra ref for scavenger */
6260 InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
6261
6262 /* If matching type */
6263 if (ScavengerHead != NULL)
6264 {
6265 /* Insert in the scavenger list */
6266 InsertTailList(ScavengerHead, InstEntry);
6267
6268 /* And if it wasn't started, start it */
6269 if (Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
6270 {
6271 Scavenger->State = RDBSS_SCAVENGER_DORMANT;
6272 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
6273 RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
6274 }
6275 }
6276 }
6277
6278 /*
6279 * @implemented
6280 */
6281 NTSTATUS
6282 NTAPI
6283 RxPostOneShotTimerRequest(
6284 IN PRDBSS_DEVICE_OBJECT pDeviceObject,
6285 IN PRX_WORK_ITEM pWorkItem,
6286 IN PRX_WORKERTHREAD_ROUTINE Routine,
6287 IN PVOID pContext,
6288 IN LARGE_INTEGER TimeInterval)
6289 {
6290 KIRQL OldIrql;
6291
6292 ASSERT(pWorkItem != NULL);
6293
6294 /* Prepare the work item */
6295 ExInitializeWorkItem(&pWorkItem->WorkQueueItem, Routine, pContext);
6296 pWorkItem->WorkQueueItem.pDeviceObject = pDeviceObject;
6297
6298 /* Last tick can be computed with the number of times it was caller (timertickcount)
6299 * and the interval between calls
6300 */
6301 KeAcquireSpinLock(&RxTimerLock, &OldIrql);
6302 pWorkItem->LastTick = (TimeInterval.QuadPart / 550000) + RxTimerTickCount + 1;
6303 /* Insert in work queue */
6304 InsertTailList(&RxTimerQueueHead, &pWorkItem->WorkQueueItem.List);
6305 KeReleaseSpinLock(&RxTimerLock, OldIrql);
6306
6307 /* If there are queued events, queue an execution */
6308 if (IsListEmpty(&RxTimerQueueHead))
6309 {
6310 KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
6311 }
6312
6313 return STATUS_SUCCESS;
6314 }
6315
6316 /*
6317 * @implemented
6318 */
6319 NTSTATUS
6320 NTAPI
6321 RxPostToWorkerThread(
6322 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
6323 _In_ WORK_QUEUE_TYPE WorkQueueType,
6324 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem,
6325 _In_ PRX_WORKERTHREAD_ROUTINE Routine,
6326 _In_ PVOID pContext)
6327 {
6328 /* Initialize work queue item */
6329 pWorkQueueItem->List.Flink = NULL;
6330 pWorkQueueItem->WorkerRoutine = Routine;
6331 pWorkQueueItem->Parameter = pContext;
6332
6333 /* And insert it in the work queue */
6334 return RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, pWorkQueueItem);
6335 }
6336
6337 VOID
6338 RxpProcessChangeBufferingStateRequests(
6339 PSRV_CALL SrvCall,
6340 BOOLEAN UpdateHandlerState)
6341 {
6342 UNIMPLEMENTED;
6343 }
6344
6345 /*
6346 * @implemented
6347 */
6348 PRX_PREFIX_ENTRY
6349 RxPrefixTableInsertName(
6350 IN OUT PRX_PREFIX_TABLE ThisTable,
6351 IN OUT PRX_PREFIX_ENTRY ThisEntry,
6352 IN PVOID Container,
6353 IN PULONG ContainerRefCount,
6354 IN USHORT CaseInsensitiveLength,
6355 IN PRX_CONNECTION_ID ConnectionId
6356 )
6357 {
6358 PAGED_CODE();
6359
6360 DPRINT("Insert: %wZ\n", &ThisEntry->Prefix);
6361
6362 ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
6363 ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length);
6364
6365 /* Copy parameters and compute hash */
6366 ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength;
6367 ThisEntry->ContainingRecord = Container;
6368 ThisEntry->ContainerRefCount = ContainerRefCount;
6369 InterlockedIncrement((volatile long *)ContainerRefCount);
6370 ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix);
6371 DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue);
6372
6373 /* If no path length: this is entry for null path */
6374 if (ThisEntry->Prefix.Length == 0)
6375 {
6376 ThisTable->TableEntryForNull = ThisEntry;
6377 }
6378 /* Otherwise, insert in the appropriate bucket */
6379 else
6380 {
6381 InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks);
6382 }
6383
6384 /* If we had a connection ID, keep track of it */
6385 if (ConnectionId != NULL)
6386 {
6387 ThisEntry->ConnectionId.Luid = ConnectionId->Luid;
6388 }
6389 else
6390 {
6391 ThisEntry->ConnectionId.Luid.LowPart = 0;
6392 ThisEntry->ConnectionId.Luid.HighPart = 0;
6393 }
6394
6395 InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks);
6396 /* Reflect the changes */
6397 ++ThisTable->Version;
6398
6399 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue));
6400
6401 return ThisEntry;
6402 }
6403
6404 /*
6405 * @implemented
6406 */
6407 PVOID
6408 RxPrefixTableLookupName(
6409 IN PRX_PREFIX_TABLE ThisTable,
6410 IN PUNICODE_STRING CanonicalName,
6411 OUT PUNICODE_STRING RemainingName,
6412 IN PRX_CONNECTION_ID ConnectionId)
6413 {
6414 PVOID Container;
6415
6416 PAGED_CODE();
6417
6418 ASSERT(RxIsPrefixTableLockAcquired(ThisTable));
6419 ASSERT(CanonicalName->Length > 0);
6420
6421 /* Call the internal helper */
6422 Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId);
6423 if (Container == NULL)
6424 {
6425 return NULL;
6426 }
6427
6428 /* Reference our container before returning it */
6429 if (RdbssReferenceTracingValue != 0)
6430 {
6431 NODE_TYPE_CODE Type;
6432
6433 Type = (NodeType(Container) & ~RX_SCAVENGER_MASK);
6434 switch (Type)
6435 {
6436 case RDBSS_NTC_SRVCALL:
6437 RxReferenceSrvCall(Container);
6438 break;
6439
6440 case RDBSS_NTC_NETROOT:
6441 RxReferenceNetRoot(Container);
6442 break;
6443
6444 case RDBSS_NTC_V_NETROOT:
6445 RxReferenceVNetRoot(Container);
6446 break;
6447
6448 default:
6449 DPRINT1("Invalid node type: %x\n", Type);
6450 ASSERT(FALSE);
6451 RxReference(Container);
6452 break;
6453 }
6454 }
6455 else
6456 {
6457 RxReference(Container);
6458 }
6459
6460 return Container;
6461 }
6462
6463 /*
6464 * @implemented
6465 */
6466 LONG
6467 RxpReferenceNetFcb(
6468 PFCB Fcb)
6469 {
6470 LONG NewCount;
6471
6472 PAGED_CODE();
6473
6474 ASSERT(NodeTypeIsFcb(Fcb));
6475
6476 NewCount = InterlockedIncrement((volatile long *)&Fcb->NodeReferenceCount);
6477
6478 PRINT_REF_COUNT(NETFCB, Fcb->NodeReferenceCount);
6479
6480 return NewCount;
6481 }
6482
6483 /*
6484 * @implemented
6485 */
6486 VOID
6487 RxpReleasePrefixTableLock(
6488 PRX_PREFIX_TABLE pTable,
6489 BOOLEAN ProcessBufferingStateChangeRequests)
6490 {
6491 PAGED_CODE();
6492
6493 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
6494 pTable->TableLock.ActiveEntries);
6495
6496 ExReleaseResourceLite(&pTable->TableLock);
6497 }
6498
6499 /*
6500 * @implemented
6501 */
6502 VOID
6503 NTAPI
6504 RxPrepareContextForReuse(
6505 IN OUT PRX_CONTEXT RxContext)
6506 {
6507 PAGED_CODE();
6508
6509 /* When we reach that point, make sure mandatory parts are null-ed */
6510 if (RxContext->MajorFunction == IRP_MJ_CREATE)
6511 {
6512 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
6513 RxContext->Create.RdrFlags = 0;
6514 }
6515 else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
6516 {
6517 ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
6518 ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
6519 }
6520
6521 RxContext->ReferenceCount = 0;
6522 }
6523
6524 /*
6525 * @implemented
6526 */
6527 VOID
6528 RxPrepareRequestForReuse(
6529 PCHANGE_BUFFERING_STATE_REQUEST Request)
6530 {
6531 PSRV_OPEN SrvOpen;
6532
6533 PAGED_CODE();
6534
6535 SrvOpen = Request->SrvOpen;
6536
6537 /* If the request was already prepared for service */
6538 if (BooleanFlagOn(Request->Flags, RX_REQUEST_PREPARED_FOR_HANDLING))
6539 {
6540 /* We have to dereference the associated SRV_OPEN depending on the lock */
6541 if (RxIsFcbAcquiredExclusive(SrvOpen->pFcb))
6542 {
6543 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
6544 }
6545 else
6546 {
6547 RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
6548 }
6549 }
6550 /* Otherwise, just dereference */
6551 else if (SrvOpen != NULL)
6552 {
6553 RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
6554 }
6555
6556 Request->SrvOpen = NULL;
6557 }
6558
6559 /*
6560 * @implemented
6561 */
6562 VOID
6563 NTAPI
6564 RxProcessChangeBufferingStateRequests(
6565 _In_ PVOID SrvCall)
6566 {
6567 /* Call internal routine */
6568 RxUndoScavengerFinalizationMarking(SrvCall);
6569 RxpProcessChangeBufferingStateRequests(SrvCall, TRUE);
6570 }
6571
6572 /*
6573 * @implemented
6574 */
6575 VOID
6576 RxProcessChangeBufferingStateRequestsForSrvOpen(
6577 PSRV_OPEN SrvOpen)
6578 {
6579 LONG NumberOfBufferingChangeRequests, LockedOldBufferingToken, OldBufferingToken;
6580
6581 /* Get the current number of change requests */
6582 NumberOfBufferingChangeRequests = ((PSRV_CALL)SrvOpen->pVNetRoot->pNetRoot->pSrvCall)->BufferingManager.CumulativeNumberOfBufferingChangeRequests;
6583 /* Get our old token */
6584 OldBufferingToken = SrvOpen->BufferingToken;
6585 LockedOldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken,
6586 NumberOfBufferingChangeRequests,
6587 NumberOfBufferingChangeRequests);
6588 /* If buffering state changed in between, process changes */
6589 if (OldBufferingToken != LockedOldBufferingToken)
6590 {
6591 PFCB Fcb;
6592 NTSTATUS Status;
6593
6594 /* Acquire the FCB and start processing */
6595 Fcb = (PFCB)SrvOpen->pFcb;
6596 Status = RxAcquireExclusiveFcb(NULL, Fcb);
6597 if (Status == STATUS_SUCCESS)
6598 {
6599 RxProcessFcbChangeBufferingStateRequest(Fcb);
6600 RxReleaseFcb(NULL, Fcb);
6601 }
6602 }
6603 }
6604
6605 VOID
6606 RxProcessFcbChangeBufferingStateRequest(
6607 PFCB Fcb)
6608 {
6609 UNIMPLEMENTED;
6610 }
6611
6612 /*
6613 * @implemented
6614 */
6615 VOID
6616 RxpScavengeFobxs(
6617 PRDBSS_SCAVENGER Scavenger,
6618 PLIST_ENTRY FobxToScavenge)
6619 {
6620 /* Explore the whole list of FOBX to scavenge */
6621 while (!IsListEmpty(FobxToScavenge))
6622 {
6623 PFCB Fcb;
6624 PFOBX Fobx;
6625 PLIST_ENTRY Entry;
6626
6627 Entry = RemoveHeadList(FobxToScavenge);
6628 Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
6629 Fcb = (PFCB)Fobx->SrvOpen->pFcb;
6630
6631 /* Try to acquire the lock exclusively to perform finalization */
6632 if (RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS)
6633 {
6634 RxDereferenceNetRoot(Fobx, LHS_LockNotHeld);
6635 }
6636 else
6637 {
6638 RxReferenceNetFcb(Fcb);
6639 RxDereferenceNetRoot(Fobx, LHS_ExclusiveLockHeld);
6640
6641 if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
6642 {
6643 RxReleaseFcb(NULL, Fcb);
6644 }
6645 }
6646 }
6647 }
6648
6649 BOOLEAN
6650 RxpTrackDereference(
6651 _In_ ULONG TraceType,
6652 _In_ PCSTR FileName,
6653 _In_ ULONG Line,
6654 _In_ PVOID Instance)
6655 {
6656 PCSTR InstanceType;
6657 ULONG ReferenceCount;
6658
6659 PAGED_CODE();
6660
6661 if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
6662 {
6663 return TRUE;
6664 }
6665
6666 switch (TraceType)
6667 {
6668 case RDBSS_REF_TRACK_SRVCALL:
6669 InstanceType = "SrvCall";
6670 ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount;
6671 break;
6672
6673 case RDBSS_REF_TRACK_NETROOT:
6674 InstanceType = "NetRoot";
6675 ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount;
6676 break;
6677
6678 case RDBSS_REF_TRACK_VNETROOT:
6679 InstanceType = "VNetRoot";
6680 ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount;
6681 break;
6682
6683 case RDBSS_REF_TRACK_NETFOBX:
6684 InstanceType = "NetFobx";
6685 ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount;
6686 break;
6687
6688 case RDBSS_REF_TRACK_NETFCB:
6689 InstanceType = "NetFcb";
6690 ReferenceCount = ((PFCB)Instance)->NodeReferenceCount;
6691 break;
6692
6693 case RDBSS_REF_TRACK_SRVOPEN:
6694 InstanceType = "SrvOpen";
6695 ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount;
6696 break;
6697
6698 default:
6699 DPRINT1("Invalid node type!\n");
6700 return TRUE;
6701 }
6702
6703 if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING))
6704 {
6705 UNIMPLEMENTED;
6706 }
6707
6708 if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING))
6709 {
6710 DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount);
6711 }
6712
6713 return TRUE;
6714 }
6715
6716 VOID
6717 RxpTrackReference(
6718 _In_ ULONG TraceType,
6719 _In_ PCSTR FileName,
6720 _In_ ULONG Line,
6721 _In_ PVOID Instance)
6722 {
6723 PCSTR InstanceType;
6724 ULONG ReferenceCount;
6725
6726 if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
6727 {
6728 return;
6729 }
6730
6731 switch (TraceType)
6732 {
6733 case RDBSS_REF_TRACK_SRVCALL:
6734 InstanceType = "SrvCall";
6735 ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount;
6736 break;
6737
6738 case RDBSS_REF_TRACK_NETROOT:
6739 InstanceType = "NetRoot";
6740 ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount;
6741 break;
6742
6743 case RDBSS_REF_TRACK_VNETROOT:
6744 InstanceType = "VNetRoot";
6745 ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount;
6746 break;
6747
6748 case RDBSS_REF_TRACK_NETFOBX:
6749 InstanceType = "NetFobx";
6750 ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount;
6751 break;
6752
6753 case RDBSS_REF_TRACK_NETFCB:
6754 InstanceType = "NetFcb";
6755 ReferenceCount = ((PFCB)Instance)->NodeReferenceCount;
6756 break;
6757
6758 case RDBSS_REF_TRACK_SRVOPEN:
6759 InstanceType = "SrvOpen";
6760 ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount;
6761 break;
6762
6763 default:
6764 DPRINT1("Invalid node type!\n");
6765 return;
6766 }
6767
6768 if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING))
6769 {
6770 UNIMPLEMENTED;
6771 }
6772
6773 if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING))
6774 {
6775 DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount);
6776 }
6777 }
6778
6779 /*
6780 * @implemented
6781 */
6782 VOID
6783 RxpUndoScavengerFinalizationMarking(
6784 PVOID Instance)
6785 {
6786 PLIST_ENTRY ListEntry;
6787 PNODE_TYPE_AND_SIZE Node;
6788 PRDBSS_SCAVENGER Scavenger;
6789
6790 PAGED_CODE();
6791
6792 Node = (PNODE_TYPE_AND_SIZE)Instance;
6793 /* There's no marking - nothing to do */
6794 if (!BooleanFlagOn(NodeType(Node), RX_SCAVENGER_MASK))
6795 {
6796 return;
6797 }
6798
6799 /* First of all, remove the mark */
6800 ClearFlag(NodeType(Node), RX_SCAVENGER_MASK);
6801 DPRINT("Node %p no longer has the scavenger mark\n");
6802
6803 /* And now, remove from the scavenger */
6804 Scavenger = RxGetDeviceObjectOfInstance(Instance)->pRdbssScavenger;
6805 switch (NodeType(Node))
6806 {
6807 case RDBSS_NTC_FOBX:
6808 --Scavenger->FobxsToBeFinalized;
6809 ListEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
6810 break;
6811
6812 case RDBSS_NTC_SRVCALL:
6813 --Scavenger->SrvCallsToBeFinalized;
6814 ListEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
6815 break;
6816
6817 case RDBSS_NTC_NETROOT:
6818 --Scavenger->NetRootsToBeFinalized;
6819 ListEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
6820 break;
6821
6822 case RDBSS_NTC_V_NETROOT:
6823 --Scavenger->VNetRootsToBeFinalized;
6824 ListEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
6825 break;
6826
6827 case RDBSS_NTC_SRVOPEN:
6828 --Scavenger->SrvOpensToBeFinalized;
6829 ListEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
6830 break;
6831 }
6832
6833 /* Also, remove the extra ref from the scavenger */
6834 RemoveEntryList(ListEntry);
6835 InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
6836 }
6837
6838 /*
6839 * @implemented
6840 */
6841 VOID
6842 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6843 PSRV_OPEN SrvOpen)
6844 {
6845 PSRV_CALL SrvCall;
6846 LIST_ENTRY Discarded;
6847
6848 PAGED_CODE();
6849
6850 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
6851
6852 /* Initialize our discarded list */
6853 InitializeListHead(&Discarded);
6854
6855 SrvCall = (PSRV_CALL)SrvOpen->Fcb->VNetRoot->pNetRoot->pSrvCall;
6856 RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
6857
6858 /* Set the flag, and get the requests */
6859 InitializeListHead(&SrvOpen->SrvOpenKeyList);
6860 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED);
6861 RxGatherRequestsForSrvOpen(SrvCall, SrvOpen, &Discarded);
6862
6863 RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
6864
6865 /* If there were discarded requests */
6866 if (!IsListEmpty(&Discarded))
6867 {
6868 /* And a pending buffering state change */
6869 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
6870 {
6871 /* Clear the flag, and set the associated event - job done */
6872 RxAcquireSerializationMutex();
6873 ClearFlag(SrvOpen->Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
6874 if (SrvOpen->Fcb->pBufferingStateChangeCompletedEvent != NULL)
6875 {
6876 KeSetEvent(SrvOpen->Fcb->pBufferingStateChangeCompletedEvent, IO_NETWORK_INCREMENT, FALSE);
6877 }
6878 RxReleaseSerializationMutex();
6879 }
6880
6881 /* Drop the discarded requests */
6882 RxpDiscardChangeBufferingStateRequests(&Discarded);
6883 }
6884 }
6885
6886 /*
6887 * @implemented
6888 */
6889 VOID
6890 RxPurgeFcb(
6891 IN PFCB Fcb)
6892 {
6893 PAGED_CODE();
6894
6895 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
6896
6897 /* Reference our FCB so that it doesn't disappear */
6898 RxReferenceNetFcb(Fcb);
6899 /* Purge Cc if required */
6900 if (Fcb->OpenCount != 0)
6901 {
6902 RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE);
6903 }
6904
6905 /* If it wasn't freed, release the lock */
6906 if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
6907 {
6908 RxReleaseFcb(NULL, Fcb);
6909 }
6910 }
6911
6912 /*
6913 * @implemented
6914 */
6915 NTSTATUS
6916 RxPurgeFcbInSystemCache(
6917 IN PFCB Fcb,
6918 IN PLARGE_INTEGER FileOffset OPTIONAL,
6919 IN ULONG Length,
6920 IN BOOLEAN UninitializeCacheMaps,
6921 IN BOOLEAN FlushFile)
6922 {
6923 BOOLEAN Purged;
6924 NTSTATUS Status;
6925
6926 PAGED_CODE();
6927
6928 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
6929
6930 /* Try to flush first, if asked */
6931 if (FlushFile)
6932 {
6933 /* If flushing failed, just make some noise */
6934 Status = RxFlushFcbInSystemCache(Fcb, TRUE);
6935 if (!NT_SUCCESS(Status))
6936 {
6937 PVOID CallersAddress, CallersCaller;
6938
6939 RtlGetCallersAddress(&CallersAddress, &CallersCaller);
6940 DPRINT1("Flush failed with status %lx for FCB %p\n", Status, Fcb);
6941 DPRINT1("Caller was %p %p\n", CallersAddress, CallersCaller);
6942 }
6943 }
6944
6945 /* Deal with Cc for purge */
6946 Purged = CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, FileOffset,
6947 Length, UninitializeCacheMaps);
6948 /* If purge failed, force section closing */
6949 if (!Purged)
6950 {
6951 MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
6952
6953 RxReleaseFcb(NULL, Fcb);
6954 Purged = MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
6955 RxAcquireExclusiveFcb(NULL, Fcb);
6956 }
6957
6958 /* Return appropriate status */
6959 Status = (Purged ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
6960 DPRINT("Purge for FCB %p returns %lx\n", Fcb, Status);
6961
6962 return Status;
6963 }
6964
6965 /*
6966 * @implemented
6967 */
6968 BOOLEAN
6969 RxPurgeFobx(
6970 PFOBX pFobx)
6971 {
6972 NTSTATUS Status;
6973 PFCB FcbToBePurged;
6974
6975 PAGED_CODE();
6976
6977 /* Get the associated FCB */
6978 FcbToBePurged = (PFCB)pFobx->pSrvOpen->pFcb;
6979 Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
6980 ASSERT(Status == STATUS_SUCCESS);
6981
6982 /* Purge it */
6983 Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
6984 if (Status != STATUS_SUCCESS)
6985 {
6986 DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged, pFobx);
6987 return FALSE;
6988 }
6989
6990 /* And flush */
6991 if (!MmFlushImageSection(&FcbToBePurged->NonPaged->SectionObjectPointers, MmFlushForWrite))
6992 {
6993 DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged, pFobx);
6994 return FALSE;
6995 }
6996
6997 DPRINT("Purge OK for %p (%p)\n", FcbToBePurged, pFobx);
6998 return TRUE;
6999 }
7000
7001 /*
7002 * @implemented
7003 */
7004 NTSTATUS
7005 RxPurgeFobxFromCache(
7006 PFOBX FobxToBePurged)
7007 {
7008 NTSTATUS Status;
7009 PFCB FcbToBePurged;
7010
7011 PAGED_CODE();
7012
7013 FcbToBePurged = (PFCB)FobxToBePurged->pSrvOpen->pFcb;
7014 ASSERT(FcbToBePurged != NULL);
7015
7016 /* If we cannot have our FCB exclusively, give up */
7017 Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
7018 if (Status != STATUS_SUCCESS)
7019 {
7020 RxDereferenceNetFobx(FobxToBePurged, LHS_LockNotHeld);
7021 return Status;
7022 }
7023
7024 /* Don't let the FCB disappear */
7025 RxReferenceNetFcb(FcbToBePurged);
7026
7027 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
7028 if (BooleanFlagOn(FobxToBePurged->Flags, FOBX_FLAG_SRVOPEN_CLOSED) || FobxToBePurged->pSrvOpen->UncleanFobxCount != 0)
7029 {
7030 DPRINT("FCB purge skipped\n");
7031 }
7032 else
7033 {
7034 Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
7035 }
7036
7037 RxDereferenceNetFobx(FobxToBePurged, LHS_ExclusiveLockHeld);
7038 /* Drop our extra reference */
7039 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged, NULL, FALSE, FALSE))
7040 {
7041 RxReleaseFcb(NULL, FcbToBePurged);
7042 }
7043
7044 return Status;
7045 }
7046
7047 /*
7048 * @implemented
7049 */
7050 NTSTATUS
7051 RxPurgeRelatedFobxs(
7052 PNET_ROOT NetRoot,
7053 PRX_CONTEXT RxContext,
7054 BOOLEAN AttemptFinalization,
7055 PFCB PurgingFcb)
7056 {
7057 PLIST_ENTRY Entry;
7058 ULONG SuccessfullPurge;
7059 PRDBSS_SCAVENGER Scavenger;
7060 PRDBSS_DEVICE_OBJECT RxDeviceObject;
7061 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx;
7062
7063 PAGED_CODE();
7064
7065 RxDeviceObject = RxContext->RxDeviceObject;
7066 Scavenger = RxDeviceObject->pRdbssScavenger;
7067 PurgeSyncCtx = &NetRoot->PurgeSyncronizationContext;
7068
7069 RxAcquireScavengerMutex();
7070
7071 /* If there's already a purge in progress */
7072 if (PurgeSyncCtx->PurgeInProgress)
7073 {
7074 /* Add our RX_CONTEXT to the current run */
7075 InsertTailList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion,
7076 &RxContext->RxContextSerializationQLinks);
7077
7078 /* And wait until it's done */
7079 RxReleaseScavengerMutex();
7080 RxWaitSync(RxContext);
7081 RxAcquireScavengerMutex();
7082 }
7083
7084 /* Start the purge */
7085 PurgeSyncCtx->PurgeInProgress = TRUE;
7086
7087 /* While the purge is still handling our NET_ROOT, do nothing but wait */
7088 while (Scavenger->CurrentNetRootForClosePendingProcessing == NetRoot)
7089 {
7090 RxReleaseScavengerMutex();
7091 KeWaitForSingleObject(&Scavenger->ClosePendingProcessingSyncEvent, Executive,
7092 KernelMode, TRUE, NULL);
7093 RxAcquireScavengerMutex();
7094 }
7095
7096 /* Now, for all the entries */
7097 SuccessfullPurge = 0;
7098 Entry = Scavenger->ClosePendingFobxsList.Flink;
7099 while (Entry != &Scavenger->ClosePendingFobxsList)
7100 {
7101 PFCB Fcb;
7102 PFOBX Fobx;
7103 BOOLEAN Success;
7104
7105 Fobx = CONTAINING_RECORD(Entry, FOBX, ClosePendingList);
7106 DPRINT("Dealing with FOBX: %p\n", Fobx);
7107
7108 Entry = Entry->Flink;
7109
7110 /* If it's not matching our NET_ROOT, ignore */
7111 if (Fobx->pSrvOpen == NULL ||
7112 Fobx->pSrvOpen->pFcb == NULL ||
7113 ((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot == NULL ||
7114 (PNET_ROOT)((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot->pNetRoot != NetRoot)
7115 {
7116 continue;
7117 }
7118
7119 /* Determine if it matches our FCB */
7120 Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
7121 if (PurgingFcb != NULL && NodeType(PurgingFcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY &&
7122 PurgingFcb != Fcb)
7123 {
7124 NTSTATUS Status;
7125
7126 MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
7127 if (Status == STATUS_SUCCESS)
7128 {
7129 continue;
7130 }
7131 }
7132
7133 /* Matching, we'll purge it */
7134 RemoveEntryList(&Fobx->ClosePendingList);
7135
7136 /* Reference it so that it doesn't disappear */
7137 RxReferenceNetFobx(Fobx);
7138
7139 RxReleaseScavengerMutex();
7140
7141 /* And purge */
7142 Success = RxPurgeFobx(Fobx);
7143 if (Success)
7144 {
7145 ++SuccessfullPurge;
7146 }
7147
7148 /* If we don't have to finalize it (or if we cannot acquire lock exclusively
7149 * Just normally dereference
7150 */
7151 if ((AttemptFinalization == DONT_ATTEMPT_FINALIZE_ON_PURGE) ||
7152 RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS)
7153 {
7154 RxDereferenceNetFobx(Fobx, LHS_LockNotHeld);
7155 }
7156 /* Otherwise, finalize */
7157 else
7158 {
7159 RxReferenceNetFcb(Fcb);
7160 RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
7161 if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
7162 {
7163 RxReleaseFcb(NULL, Fcb);
7164 }
7165 }
7166
7167 if (!Success)
7168 {
7169 DPRINT1("Failed purging %p (%p)\n", Fcb, Fobx);
7170 }
7171
7172 RxAcquireScavengerMutex();
7173 }
7174
7175 /* If no contexts left, purge is not running */
7176 if (IsListEmpty(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion))
7177 {
7178 PurgeSyncCtx->PurgeInProgress = FALSE;
7179 }
7180 /* Otherwise, notify a waiter it can start */
7181 else
7182 {
7183 PRX_CONTEXT Context;
7184
7185 Entry = RemoveHeadList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion);
7186 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, RxContextSerializationQLinks);
7187
7188 RxSignalSynchronousWaiter(Context);
7189 }
7190
7191 RxReleaseScavengerMutex();
7192
7193 return (SuccessfullPurge > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
7194 }
7195
7196 /*
7197 * @implemented
7198 */
7199 VOID
7200 RxpWorkerThreadDispatcher(
7201 IN PRX_WORK_QUEUE WorkQueue,
7202 IN PLARGE_INTEGER WaitInterval)
7203 {
7204 NTSTATUS Status;
7205 PVOID Parameter;
7206 PETHREAD CurrentThread;
7207 BOOLEAN KillThread, Dereference;
7208 PRX_WORK_QUEUE_ITEM WorkQueueItem;
7209 PWORKER_THREAD_ROUTINE WorkerRoutine;
7210
7211 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
7212
7213 /* Reference ourselves */
7214 CurrentThread = PsGetCurrentThread();
7215 Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
7216 ASSERT(NT_SUCCESS(Status));
7217
7218 /* Infinite loop for worker */
7219 KillThread = FALSE;
7220 Dereference = FALSE;
7221 do
7222 {
7223 KIRQL OldIrql;
7224 PLIST_ENTRY ListEntry;
7225
7226 /* Remove an entry from the work queue */
7227 ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval);
7228 if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT)
7229 {
7230 PRDBSS_DEVICE_OBJECT DeviceObject;
7231
7232 WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List);
7233
7234 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched);
7235 InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
7236 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
7237
7238 /* Get the parameters, and null-them in the struct */
7239 WorkerRoutine = WorkQueueItem->WorkerRoutine;
7240 Parameter = WorkQueueItem->Parameter;
7241 DeviceObject = WorkQueueItem->pDeviceObject;
7242
7243 WorkQueueItem->List.Flink = NULL;
7244 WorkQueueItem->WorkerRoutine = NULL;
7245 WorkQueueItem->Parameter = NULL;
7246 WorkQueueItem->pDeviceObject = NULL;
7247
7248 /* Call the routine */
7249 DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter);
7250 WorkerRoutine(Parameter);
7251
7252 /* Are we going down now? */
7253 if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0)
7254 {
7255 PKEVENT TearDownEvent;
7256
7257 TearDownEvent = InterlockedExchangePointer((void * volatile*)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
7258 if (TearDownEvent != NULL)
7259 {
7260 KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
7261 }
7262 }
7263
7264 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
7265 }
7266
7267 /* Shall we shutdown... */
7268 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
7269 switch (WorkQueue->State)
7270 {
7271 /* Our queue is active, kill it if we have no more items to dispatch
7272 * and more threads than the required minimum
7273 */
7274 case RxWorkQueueActive:
7275 if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0)
7276 {
7277 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
7278 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
7279 {
7280 KillThread = TRUE;
7281 Dereference = TRUE;
7282 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
7283 }
7284
7285 if (KillThread)
7286 {
7287 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
7288 }
7289 }
7290 break;
7291
7292 /* The queue is inactive: kill it we have more threads than the required minimum */
7293 case RxWorkQueueInactive:
7294 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
7295 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
7296 {
7297 KillThread = TRUE;
7298 Dereference = TRUE;
7299 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
7300 }
7301
7302 if (KillThread)
7303 {
7304 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
7305 }
7306 break;
7307
7308 /* Rundown in progress..., kill it for sure! */
7309 case RxWorkQueueRundownInProgress:
7310 {
7311 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext;
7312
7313 ASSERT(WorkQueue->pRundownContext != NULL);
7314
7315 RundownContext = WorkQueue->pRundownContext;
7316 RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread;
7317
7318 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
7319 KillThread = TRUE;
7320 Dereference = FALSE;
7321
7322 if (WorkQueue->NumberOfActiveWorkerThreads == 0)
7323 {
7324 KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
7325 }
7326
7327 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
7328 }
7329 break;
7330
7331 default:
7332 break;
7333 }
7334 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
7335 } while (!KillThread);
7336
7337 DPRINT("Killed worker thread\n");
7338
7339 /* Do we have to dereference ourselves? */
7340 if (Dereference)
7341 {
7342 ObDereferenceObject(CurrentThread);
7343 }
7344
7345 /* Dump last executed routine */
7346 if (DumpDispatchRoutine)
7347 {
7348 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
7349 }
7350
7351 PsTerminateSystemThread(STATUS_SUCCESS);
7352 }
7353
7354 VOID
7355 RxReference(
7356 IN OUT PVOID Instance)
7357 {
7358 NODE_TYPE_CODE NodeType;
7359 PNODE_TYPE_AND_SIZE Node;
7360
7361 PAGED_CODE();
7362
7363 RxAcquireScavengerMutex();
7364
7365 /* We can only reference a few structs */
7366 NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK;
7367 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
7368 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
7369 (NodeType == RDBSS_NTC_FOBX));
7370
7371 Node = (PNODE_TYPE_AND_SIZE)Instance;
7372 InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
7373
7374 /* Trace refcount if asked */
7375 switch (NodeType)
7376 {
7377 case RDBSS_NTC_SRVCALL:
7378 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
7379 break;
7380
7381 case RDBSS_NTC_NETROOT:
7382 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
7383 break;
7384
7385 case RDBSS_NTC_V_NETROOT:
7386 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
7387 break;
7388
7389 case RDBSS_NTC_SRVOPEN:
7390 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
7391 break;
7392
7393 case RDBSS_NTC_FOBX:
7394 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
7395 break;
7396
7397 default:
7398 ASSERT(FALSE);
7399 break;
7400 }
7401
7402 RxpUndoScavengerFinalizationMarking(Instance);
7403 RxReleaseScavengerMutex();
7404 }
7405
7406 /*
7407 * @implemented
7408 */
7409 VOID
7410 NTAPI
7411 RxReinitializeContext(
7412 IN OUT PRX_CONTEXT RxContext)
7413 {
7414 PIRP Irp;
7415 PRDBSS_DEVICE_OBJECT RxDeviceObject;
7416 ULONG InitialContextFlags, SavedFlags;
7417
7418 PAGED_CODE();
7419
7420 /* Backup a few flags */
7421 Irp = RxContext->CurrentIrp;
7422 RxDeviceObject = RxContext->RxDeviceObject;
7423 SavedFlags = RxContext->Flags & RX_CONTEXT_PRESERVED_FLAGS;
7424 InitialContextFlags = RxContext->Flags & RX_CONTEXT_INITIALIZATION_FLAGS;
7425
7426 /* Reset our context */
7427 RxPrepareContextForReuse(RxContext);
7428
7429 /* Zero everything */
7430 RtlZeroMemory(&RxContext->MajorFunction, sizeof(RX_CONTEXT) - FIELD_OFFSET(RX_CONTEXT, MajorFunction));
7431
7432 /* Restore saved flags */
7433 RxContext->Flags = SavedFlags;
7434 /* And reinit the context */
7435 RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, RxContext);
7436 }
7437
7438 /*
7439 * @implemented
7440 */
7441 VOID
7442 NTAPI
7443 RxReleaseFcbFromLazyWrite(
7444 PVOID Context)
7445 {
7446 PFCB Fcb;
7447
7448 PAGED_CODE();
7449
7450 Fcb = Context;
7451 /* The received context is a FCB */
7452 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
7453 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
7454
7455 /* Lazy writer is releasing lock, so forget about it */
7456 Fcb->Specific.Fcb.LazyWriteThread = NULL;
7457
7458 /* If we were top level IRP, unwind */
7459 if (RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP)
7460 {
7461 RxUnwindTopLevelIrp(NULL);
7462 }
7463
7464 /* And finally, release the lock */
7465 Fcb->PagingIoResourceFile = NULL;
7466 Fcb->PagingIoResourceLine = 0;
7467 ExReleaseResourceLite(Fcb->Header.PagingIoResource);
7468 }
7469
7470 /*
7471 * @implemented
7472 */
7473 VOID
7474 NTAPI
7475 RxReleaseFcbFromReadAhead(
7476 PVOID Context)
7477 {
7478 PFCB Fcb;
7479
7480 PAGED_CODE();
7481
7482 Fcb = Context;
7483 /* The received context is a FCB */
7484 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB);
7485 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
7486
7487 /* Top Level IRP is CC */
7488 ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
7489 RxUnwindTopLevelIrp(NULL);
7490
7491 ExReleaseResourceLite(Fcb->Header.Resource);
7492 }
7493
7494 VOID
7495 NTAPI
7496 RxReleaseFileForNtCreateSection(
7497 PFILE_OBJECT FileObject)
7498 {
7499 UNIMPLEMENTED;
7500 }
7501
7502 NTSTATUS
7503 NTAPI
7504 RxReleaseForCcFlush(
7505 PFILE_OBJECT FileObject,
7506 PDEVICE_OBJECT DeviceObject)
7507 {
7508 UNIMPLEMENTED;
7509 return STATUS_NOT_IMPLEMENTED;
7510 }
7511
7512 /*
7513 * @implemented
7514 */
7515 VOID
7516 RxRemoveNameNetFcb(
7517 OUT PFCB ThisFcb)
7518 {
7519 PNET_ROOT NetRoot;
7520
7521 PAGED_CODE();
7522
7523 ASSERT(NodeTypeIsFcb(ThisFcb));
7524
7525 /* Just remove the entry from the FCB_TABLE */
7526 NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
7527 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
7528 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
7529
7530 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
7531 DPRINT("FCB (%p) %wZ removed\n", ThisFcb, &ThisFcb->FcbTableEntry.Path);
7532 /* Mark, so that we don't try to do it twice */
7533 SetFlag(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED);
7534 }
7535
7536 /*
7537 * @implemented
7538 */
7539 VOID
7540 RxRemovePrefixTableEntry(
7541 IN OUT PRX_PREFIX_TABLE ThisTable,
7542 IN OUT PRX_PREFIX_ENTRY Entry)
7543 {
7544 PAGED_CODE();
7545
7546 ASSERT(NodeType(Entry) == RDBSS_NTC_PREFIX_ENTRY);
7547 ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
7548
7549 /* Check whether we're asked to remove null entry */
7550 if (Entry->Prefix.Length == 0)
7551 {
7552 ThisTable->TableEntryForNull = NULL;
7553 }
7554 else
7555 {
7556 RemoveEntryList(&Entry->HashLinks);
7557 }
7558
7559 Entry->ContainingRecord = NULL;
7560
7561 /* Also remove it from global list */
7562 RemoveEntryList(&Entry->MemberQLinks);
7563
7564 ++ThisTable->Version;
7565 }
7566
7567 /*
7568 * @implemented
7569 */
7570 VOID
7571 RxRemoveVirtualNetRootFromNetRoot(
7572 PNET_ROOT NetRoot,
7573 PV_NET_ROOT VNetRoot)
7574 {
7575 PRX_PREFIX_TABLE PrefixTable;
7576
7577 PAGED_CODE();
7578
7579 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
7580 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
7581
7582 /* Remove the VNetRoot from the list in the NetRoot */
7583 --NetRoot->NumberOfVirtualNetRoots;
7584 RemoveEntryList(&VNetRoot->NetRootListEntry);
7585
7586 /* Fix the NetRoot if we were the default VNetRoot */
7587 if (NetRoot->DefaultVNetRoot == VNetRoot)
7588 {
7589 /* Put the first one available */
7590 if (!IsListEmpty(&NetRoot->VirtualNetRoots))
7591 {
7592 NetRoot->DefaultVNetRoot = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry);
7593 }
7594 /* Otherwise, none */
7595 else
7596 {
7597 NetRoot->DefaultVNetRoot = NULL;
7598 }
7599 }
7600
7601 /* If there are still other VNetRoot available, we're done */
7602 if (!IsListEmpty(&NetRoot->VirtualNetRoots))
7603 {
7604 return;
7605 }
7606
7607 /* Otherwise, initiate NetRoot finalization */
7608 if (!BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
7609 {
7610 RxRemovePrefixTableEntry(PrefixTable, &NetRoot->PrefixEntry);
7611 SetFlag(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED);
7612 }
7613
7614 /* Notify mini-rdr */
7615 if (NetRoot->pSrvCall != NULL && NetRoot->pSrvCall->RxDeviceObject != NULL)
7616 {
7617 NTSTATUS Status;
7618
7619 MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
7620 MRxFinalizeNetRoot, ((PMRX_NET_ROOT)NetRoot, FALSE));
7621 (void)Status;
7622 }
7623 }
7624
7625 VOID
7626 RxResumeBlockedOperations_ALL(
7627 IN OUT PRX_CONTEXT RxContext)
7628 {
7629 LIST_ENTRY BlockedOps;
7630
7631 PAGED_CODE();
7632
7633 /* Get the blocked operations */
7634 RxTransferListWithMutex(&BlockedOps, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex);
7635
7636 if (!IsListEmpty(&BlockedOps))
7637 {
7638 UNIMPLEMENTED;
7639 }
7640 }
7641
7642 VOID
7643 NTAPI
7644 RxResumeBlockedOperations_Serially(
7645 IN OUT PRX_CONTEXT RxContext,
7646 IN OUT PLIST_ENTRY BlockingIoQ)
7647 {
7648 PAGED_CODE();
7649
7650 RxAcquireSerializationMutex();
7651
7652 /* This can only happen on pipes */
7653 if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7654 {
7655 RxReleaseSerializationMutex();
7656 return;
7657 }
7658
7659 UNIMPLEMENTED;
7660
7661 RxReleaseSerializationMutex();
7662 }
7663
7664 /*
7665 * @implemented
7666 */
7667 VOID
7668 RxSetFileSizeWithLock(
7669 IN OUT PFCB Fcb,
7670 IN PLONGLONG FileSize)
7671 {
7672 PAGED_CODE();
7673
7674 /* Set attribute and increase version */
7675 Fcb->Header.FileSize.QuadPart = *FileSize;
7676 ++Fcb->ulFileSizeVersion;
7677 }
7678
7679 /*
7680 * @implemented
7681 */
7682 VOID
7683 RxScavengeFobxsForNetRoot(
7684 PNET_ROOT NetRoot,
7685 PFCB PurgingFcb,
7686 BOOLEAN SynchronizeWithScavenger)
7687 {
7688 PRDBSS_SCAVENGER Scavenger;
7689 PRDBSS_DEVICE_OBJECT RxDeviceObject;
7690
7691 PAGED_CODE();
7692
7693 RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject;
7694 Scavenger = RxDeviceObject->pRdbssScavenger;
7695
7696 /* Wait for the scavenger, if asked to */
7697 if (SynchronizeWithScavenger)
7698 {
7699 KeWaitForSingleObject(&Scavenger->SyncEvent, Executive, KernelMode, FALSE, NULL);
7700 }
7701
7702 RxAcquireScavengerMutex();
7703
7704 /* If there's nothing left to do... */
7705 if (Scavenger->FobxsToBeFinalized <= 0)
7706 {
7707 RxReleaseScavengerMutex();
7708 }
7709 else
7710 {
7711 PLIST_ENTRY Entry;
7712 LIST_ENTRY FobxToScavenge;
7713
7714 InitializeListHead(&FobxToScavenge);
7715
7716 /* Browse all the FOBXs to finalize */
7717 Entry = Scavenger->FobxFinalizationList.Flink;
7718 while (Entry != &Scavenger->FobxFinalizationList)
7719 {
7720 PFOBX Fobx;
7721
7722 Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList);
7723 Entry = Entry->Flink;
7724
7725 if (Fobx->SrvOpen != NULL)
7726 {
7727 PFCB Fcb;
7728
7729 Fcb = (PFCB)Fobx->SrvOpen->pFcb;
7730
7731 /* If it matches our NET_ROOT */
7732 if ((PNET_ROOT)Fcb->pNetRoot == NetRoot)
7733 {
7734 NTSTATUS Status;
7735
7736 /* Check whether it matches our FCB */
7737 Status = STATUS_MORE_PROCESSING_REQUIRED;
7738 if (PurgingFcb != NULL && PurgingFcb != Fcb)
7739 {
7740 MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb));
7741 }
7742
7743 /* If so, add it to the list of the FOBXs to scavenge */
7744 if (Status != STATUS_SUCCESS)
7745 {
7746 RxReferenceNetFobx(Fobx);
7747 ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
7748
7749 RemoveEntryList(&Fobx->ScavengerFinalizationList);
7750 InsertTailList(&FobxToScavenge, &Fobx->ScavengerFinalizationList);
7751 }
7752 }
7753 }
7754 }
7755
7756 RxReleaseScavengerMutex();
7757
7758 /* Now, scavenge all the extracted FOBX */
7759 RxpScavengeFobxs(Scavenger, &FobxToScavenge);
7760 }
7761
7762 if (SynchronizeWithScavenger)
7763 {
7764 KeSetEvent(&Scavenger->SyncEvent, IO_NO_INCREMENT, FALSE);
7765 }
7766 }
7767
7768 /*
7769 * @implemented
7770 */
7771 BOOLEAN
7772 RxScavengeRelatedFobxs(
7773 PFCB Fcb)
7774 {
7775 PFOBX Fobx;
7776 LIST_ENTRY LocalList;
7777 PLIST_ENTRY NextEntry;
7778 PRDBSS_SCAVENGER Scavenger;
7779
7780 PAGED_CODE();
7781
7782 /* First of all, check whether there are FOBX to scavenge */
7783 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
7784 RxAcquireScavengerMutex();
7785 if (Scavenger->FobxsToBeFinalized <= 0)
7786 {
7787 RxReleaseScavengerMutex();
7788 return FALSE;
7789 }
7790
7791 /* Initialize our local list which will hold all the FOBX to scavenge so
7792 * that we don't acquire the scavenger mutex too long
7793 */
7794 InitializeListHead(&LocalList);
7795
7796 /* Technically, that condition should all be true... */
7797 if (!IsListEmpty(&Scavenger->FobxFinalizationList))
7798 {
7799 PLIST_ENTRY NextEntry, LastEntry;
7800
7801 /* Browse all the FCBs to find the matching ones */
7802 NextEntry = Scavenger->FobxFinalizationList.Flink;
7803 LastEntry = &Scavenger->FobxFinalizationList;
7804 while (NextEntry != LastEntry)
7805 {
7806 Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList);
7807 NextEntry = NextEntry->Flink;
7808 /* Matching our FCB? Let's finalize it */
7809 if (Fobx->pSrvOpen != NULL && Fobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
7810 {
7811 RxpUndoScavengerFinalizationMarking(Fobx);
7812 ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
7813 InsertTailList(&LocalList, &Fobx->ScavengerFinalizationList);
7814 }
7815 }
7816 }
7817
7818 RxReleaseScavengerMutex();
7819
7820 /* Nothing to scavenge? Quit */
7821 if (IsListEmpty(&LocalList))
7822 {
7823 return FALSE;
7824 }
7825
7826 /* Now, finalize all the extracted FOBX */
7827 while (!IsListEmpty(&LocalList))
7828 {
7829 NextEntry = RemoveHeadList(&LocalList);
7830 Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList);
7831 RxFinalizeNetFobx(Fobx, TRUE, TRUE);
7832 }
7833
7834 return TRUE;
7835 }
7836
7837 VOID
7838 RxScavengerFinalizeEntries(
7839 PRDBSS_DEVICE_OBJECT DeviceObject)
7840 {
7841 UNIMPLEMENTED;
7842 }
7843
7844 /*
7845 * @implemented
7846 */
7847 VOID
7848 NTAPI
7849 RxScavengerTimerRoutine(
7850 PVOID Context)
7851 {
7852 BOOLEAN Requeue;
7853 PRDBSS_DEVICE_OBJECT DeviceObject;
7854 PRDBSS_SCAVENGER Scavenger;
7855
7856 PAGED_CODE();
7857
7858 DeviceObject = Context;
7859 Scavenger = DeviceObject->pRdbssScavenger;
7860
7861 Requeue = FALSE;
7862 RxAcquireScavengerMutex();
7863 /* If the scavenger was dormant, wake it up! */
7864 if (Scavenger->State == RDBSS_SCAVENGER_DORMANT)
7865 {
7866 /* Done */
7867 Scavenger->State = RDBSS_SCAVENGER_ACTIVE;
7868 KeResetEvent(&Scavenger->ScavengeEvent);
7869
7870 /* Scavenger the entries */
7871 RxReleaseScavengerMutex();
7872 RxScavengerFinalizeEntries(DeviceObject);
7873 RxAcquireScavengerMutex();
7874
7875 /* If we're still active (race) */
7876 if (Scavenger->State == RDBSS_SCAVENGER_ACTIVE)
7877 {
7878 /* If there are new entries to scavenge, stay dormant and requeue a run */
7879 if (Scavenger->NumberOfDormantFiles + Scavenger->SrvCallsToBeFinalized +
7880 Scavenger->NetRootsToBeFinalized + Scavenger->VNetRootsToBeFinalized +
7881 Scavenger->FcbsToBeFinalized + Scavenger->SrvOpensToBeFinalized +
7882 Scavenger->FobxsToBeFinalized != 0)
7883 {
7884 Requeue = TRUE;
7885 Scavenger->State = RDBSS_SCAVENGER_DORMANT;
7886 }
7887 /* Otherwise, we're inactive again */
7888 else
7889 {
7890 Scavenger->State = RDBSS_SCAVENGER_INACTIVE;
7891 }
7892 }
7893
7894 RxReleaseScavengerMutex();
7895
7896 /* Requeue an execution */
7897 if (Requeue)
7898 {
7899 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
7900 RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
7901 }
7902 }
7903 else
7904 {
7905 RxReleaseScavengerMutex();
7906 }
7907
7908 KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE);
7909 }
7910
7911 BOOLEAN
7912 RxScavengeVNetRoots(
7913 PRDBSS_DEVICE_OBJECT RxDeviceObject)
7914 {
7915 UNIMPLEMENTED;
7916 return FALSE;
7917 }
7918
7919 /*
7920 * @implemented
7921 */
7922 VOID
7923 NTAPI
7924 RxSpinUpRequestsDispatcher(
7925 PVOID Dispatcher)
7926 {
7927 NTSTATUS Status;
7928 PRX_DISPATCHER RxDispatcher;
7929
7930 Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
7931 if (!NT_SUCCESS(Status))
7932 {
7933 PsTerminateSystemThread(STATUS_SUCCESS);
7934 }
7935
7936 RxDispatcher = Dispatcher;
7937
7938 do
7939 {
7940 KIRQL OldIrql;
7941 PLIST_ENTRY ListEntry;
7942
7943 Status = KeWaitForSingleObject(&RxDispatcher->SpinUpRequestsEvent, Executive,
7944 KernelMode, FALSE, &RxSpinUpDispatcherWaitInterval);
7945 ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_TIMEOUT));
7946
7947 KeAcquireSpinLock(&RxDispatcher->SpinUpRequestsLock, &OldIrql);
7948 if (!IsListEmpty(&RxDispatcher->SpinUpRequests))
7949 {
7950 ListEntry = RemoveHeadList(&RxDispatcher->SpinUpRequests);
7951 }
7952 else
7953 {
7954 ListEntry = &RxDispatcher->SpinUpRequests;
7955 }
7956 KeResetEvent(&RxDispatcher->SpinUpRequestsEvent);
7957 KeReleaseSpinLock(&RxDispatcher->SpinUpRequestsLock, OldIrql);
7958
7959 while (ListEntry != &RxDispatcher->SpinUpRequests)
7960 {
7961 PWORK_QUEUE_ITEM WorkItem;
7962 PRX_WORK_QUEUE WorkQueue;
7963
7964 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List);
7965 WorkQueue = WorkItem->Parameter;
7966
7967 InterlockedDecrement(&WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse);
7968
7969 DPRINT("Workqueue: calling %p(%p)\n", WorkItem->WorkerRoutine, WorkItem->Parameter);
7970 WorkItem->WorkerRoutine(WorkItem->Parameter);
7971 }
7972 } while (RxDispatcher->State == RxDispatcherActive);
7973
7974 KeSetEvent(&RxDispatcher->SpinUpRequestsTearDownEvent, IO_NO_INCREMENT, FALSE);
7975 PsTerminateSystemThread(STATUS_SUCCESS);
7976 }
7977
7978 /*
7979 * @implemented
7980 */
7981 NTSTATUS
7982 RxSpinUpWorkerThread(
7983 PRX_WORK_QUEUE WorkQueue,
7984 PRX_WORKERTHREAD_ROUTINE Routine,
7985 PVOID Parameter)
7986 {
7987 KIRQL OldIrql;
7988 NTSTATUS Status;
7989 HANDLE ThreadHandle;
7990
7991 PAGED_CODE();
7992
7993 /* If work queue is inactive, that cannot work */
7994 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
7995 if (WorkQueue->State != RxWorkQueueActive)
7996 {
7997 Status = STATUS_UNSUCCESSFUL;
7998 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
7999 }
8000 else
8001 {
8002 ++WorkQueue->NumberOfActiveWorkerThreads;
8003 Status = STATUS_SUCCESS;
8004 }
8005 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
8006
8007 /* Quit on failure */
8008 if (!NT_SUCCESS(Status))
8009 {
8010 return Status;
8011 }
8012
8013 /* Spin up the worker thread */
8014 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, Routine, Parameter);
8015 if (NT_SUCCESS(Status))
8016 {
8017 ZwClose(ThreadHandle);
8018 return Status;
8019 }
8020 /* Read well: we reached that point because it failed! */
8021 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue, Status);
8022
8023 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
8024 --WorkQueue->NumberOfActiveWorkerThreads;
8025 ++WorkQueue->NumberOfFailedSpinUpRequests;
8026
8027 /* Rundown, no more active threads, set the event! */
8028 if (WorkQueue->NumberOfActiveWorkerThreads == 0 &&
8029 WorkQueue->State == RxWorkQueueRundownInProgress)
8030 {
8031 KeSetEvent(&WorkQueue->pRundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
8032 }
8033
8034 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
8035
8036 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
8037
8038 return Status;
8039 }
8040
8041 VOID
8042 RxSpinUpWorkerThreads(
8043 PRX_WORK_QUEUE WorkQueue)
8044 {
8045 UNIMPLEMENTED;
8046 }
8047
8048 VOID
8049 RxSynchronizeWithScavenger(
8050 IN PRX_CONTEXT RxContext)
8051 {
8052 UNIMPLEMENTED;
8053 }
8054
8055 /*
8056 * @implemented
8057 */
8058 ULONG
8059 RxTableComputeHashValue(
8060 IN PUNICODE_STRING Name)
8061 {
8062 ULONG Hash;
8063 SHORT Loops[8];
8064 USHORT MaxChar, i;
8065
8066 PAGED_CODE();
8067
8068 MaxChar = Name->Length / sizeof(WCHAR);
8069
8070 Loops[0] = 1;
8071 Loops[1] = MaxChar - 1;
8072 Loops[2] = MaxChar - 2;
8073 Loops[3] = MaxChar - 3;
8074 Loops[4] = MaxChar - 4;
8075 Loops[5] = MaxChar / 4;
8076 Loops[6] = 2 * MaxChar / 4;
8077 Loops[7] = 3 * MaxChar / 4;
8078
8079 Hash = 0;
8080 for (i = 0; i < 8; ++i)
8081 {
8082 SHORT Idx;
8083
8084 Idx = Loops[i];
8085 if (Idx >= 0 && Idx < MaxChar)
8086 {
8087 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
8088 }
8089 }
8090
8091 return Hash;
8092 }
8093
8094 /*
8095 * @implemented
8096 */
8097 ULONG
8098 RxTableComputePathHashValue(
8099 IN PUNICODE_STRING Name)
8100 {
8101 ULONG Hash;
8102 SHORT Loops[8];
8103 USHORT MaxChar, i;
8104
8105 PAGED_CODE();
8106
8107 MaxChar = Name->Length / sizeof(WCHAR);
8108
8109 Loops[0] = 1;
8110 Loops[1] = MaxChar - 1;
8111 Loops[2] = MaxChar - 2;
8112 Loops[3] = MaxChar - 3;
8113 Loops[4] = MaxChar - 4;
8114 Loops[5] = MaxChar / 4;
8115 Loops[6] = 2 * MaxChar / 4;
8116 Loops[7] = 3 * MaxChar / 4;
8117
8118 Hash = 0;
8119 for (i = 0; i < 8; ++i)
8120 {
8121 SHORT Idx;
8122
8123 Idx = Loops[i];
8124 if (Idx >= 0 && Idx < MaxChar)
8125 {
8126 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
8127 }
8128 }
8129
8130 return Hash;
8131 }
8132
8133 /*
8134 * @implemented
8135 */
8136 PVOID
8137 RxTableLookupName(
8138 IN PRX_PREFIX_TABLE ThisTable,
8139 IN PUNICODE_STRING Name,
8140 OUT PUNICODE_STRING RemainingName,
8141 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
8142 {
8143 PVOID Container;
8144 USHORT i, MaxChar;
8145 PRX_PREFIX_ENTRY Entry;
8146 RX_CONNECTION_ID NullId;
8147 UNICODE_STRING LookupString;
8148
8149 PAGED_CODE();
8150
8151 /* If caller didn't provide a connection ID, setup one */
8152 if (ThisTable->IsNetNameTable && RxConnectionId == NULL)
8153 {
8154 NullId.Luid.LowPart = 0;
8155 NullId.Luid.HighPart = 0;
8156 RxConnectionId = &NullId;
8157 }
8158
8159 /* Validate name */
8160 ASSERT(Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR);
8161
8162 Entry = NULL;
8163 Container = NULL;
8164 LookupString.Buffer = Name->Buffer;
8165 MaxChar = Name->Length / sizeof(WCHAR);
8166 /* We'll perform the lookup, path component after another */
8167 for (i = 1; i < MaxChar; ++i)
8168 {
8169 ULONG Hash;
8170 PRX_PREFIX_ENTRY CurEntry;
8171
8172 /* Don't cut in the middle of a path element */
8173 if (Name->Buffer[i] != OBJ_NAME_PATH_SEPARATOR && Name->Buffer[i] != ':')
8174 {
8175 continue;
8176 }
8177
8178 /* Perform lookup in the table */
8179 LookupString.Length = i * sizeof(WCHAR);
8180 Hash = RxTableComputeHashValue(&LookupString);
8181 CurEntry = RxTableLookupName_ExactLengthMatch(ThisTable, &LookupString, Hash, RxConnectionId);
8182 #if DBG
8183 ++ThisTable->Lookups;
8184 #endif
8185 /* Entry not found, move to the next component */
8186 if (CurEntry == NULL)
8187 {
8188 #if DBG
8189 ++ThisTable->FailedLookups;
8190 #endif
8191 continue;
8192 }
8193
8194 Entry = CurEntry;
8195 ASSERT(Entry->ContainingRecord != NULL);
8196 Container = Entry->ContainingRecord;
8197
8198 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
8199 if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_NETROOT)
8200 {
8201 PNET_ROOT NetRoot;
8202
8203 NetRoot = (PNET_ROOT)Entry->ContainingRecord;
8204 /* If there's a default one, perfect, that's a match */
8205 if (NetRoot->DefaultVNetRoot != NULL)
8206 {
8207 Container = NetRoot->DefaultVNetRoot;
8208 }
8209 /* If none (that shouldn't happen!), try to find one */
8210 else
8211 {
8212 /* Use the first one in the list */
8213 if (!IsListEmpty(&NetRoot->VirtualNetRoots))
8214 {
8215 Container = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry);
8216 }
8217 /* Really, really, shouldn't happen */
8218 else
8219 {
8220 ASSERT(FALSE);
8221 Entry = NULL;
8222 Container = NULL;
8223 }
8224 }
8225
8226 break;
8227 }
8228 else if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_V_NETROOT)
8229 {
8230 break;
8231 }
8232 else
8233 {
8234 ASSERT((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_SRVCALL);
8235 }
8236 }
8237
8238 /* Entry was found */
8239 if (Entry != NULL)
8240 {
8241 DPRINT("Found\n");
8242
8243 ASSERT(Name->Length >= Entry->Prefix.Length);
8244
8245 /* Setup remaining name */
8246 RemainingName->Buffer = Add2Ptr(Name->Buffer, Entry->Prefix.Length);
8247 RemainingName->Length = Name->Length - Entry->Prefix.Length;
8248 RemainingName->MaximumLength = Name->Length - Entry->Prefix.Length;
8249 }
8250 else
8251 {
8252 /* Otherwise, that's the whole name */
8253 RemainingName = Name;
8254 }
8255
8256 return Container;
8257 }
8258
8259 /*
8260 * @implemented
8261 */
8262 PRX_PREFIX_ENTRY
8263 RxTableLookupName_ExactLengthMatch(
8264 IN PRX_PREFIX_TABLE ThisTable,
8265 IN PUNICODE_STRING Name,
8266 IN ULONG HashValue,
8267 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
8268 {
8269 PLIST_ENTRY ListEntry, HashBucket;
8270
8271 PAGED_CODE();
8272
8273 ASSERT(RxConnectionId != NULL);
8274
8275 /* Select the right bucket */
8276 HashBucket = HASH_BUCKET(ThisTable, HashValue);
8277 DPRINT("Looking in bucket: %p for %x\n", HashBucket, HashValue);
8278 /* If bucket is empty, no match */
8279 if (IsListEmpty(HashBucket))
8280 {
8281 return NULL;
8282 }
8283
8284 /* Browse all the entries in the bucket */
8285 for (ListEntry = HashBucket->Flink;
8286 ListEntry != HashBucket;
8287 ListEntry = ListEntry->Flink)
8288 {
8289 PVOID Container;
8290 PRX_PREFIX_ENTRY Entry;
8291 BOOLEAN CaseInsensitive;
8292 PUNICODE_STRING CmpName, CmpPrefix;
8293 UNICODE_STRING InsensitiveName, InsensitivePrefix;
8294
8295 Entry = CONTAINING_RECORD(ListEntry, RX_PREFIX_ENTRY, HashLinks);
8296 ++ThisTable->Considers;
8297 ASSERT(HashBucket == HASH_BUCKET(ThisTable, Entry->SavedHashValue));
8298
8299 Container = Entry->ContainingRecord;
8300 ASSERT(Container != NULL);
8301
8302 /* Not the same hash, not the same length, move on */
8303 if (Entry->SavedHashValue != HashValue || Entry->Prefix.Length != Name->Length)
8304 {
8305 continue;
8306 }
8307
8308 ++ThisTable->Compares;
8309 /* If we have to perform a case insensitive compare on a portion... */
8310 if (Entry->CaseInsensitiveLength != 0)
8311 {
8312 ASSERT(Entry->CaseInsensitiveLength <= Name->Length);
8313
8314 /* Perform the case insensitive check on the asked length */
8315 InsensitiveName.Buffer = Name->Buffer;
8316 InsensitivePrefix.Buffer = Entry->Prefix.Buffer;
8317 InsensitiveName.Length = Entry->CaseInsensitiveLength;
8318 InsensitivePrefix.Length = Entry->CaseInsensitiveLength;
8319 /* No match, move to the next entry */
8320 if (!RtlEqualUnicodeString(&InsensitiveName, &InsensitivePrefix, TRUE))
8321 {
8322 continue;
8323 }
8324
8325 /* Was the case insensitive covering the whole name? */
8326 if (Name->Length == Entry->CaseInsensitiveLength)
8327 {
8328 /* If connection ID also matches, that a complete match! */
8329 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
8330 {
8331 return Entry;
8332 }
8333 }
8334
8335 /* Otherwise, we have to continue with the sensitive match.... */
8336 InsensitiveName.Buffer = Add2Ptr(InsensitiveName.Buffer, Entry->CaseInsensitiveLength);
8337 InsensitivePrefix.Buffer = Add2Ptr(InsensitivePrefix.Buffer, Entry->CaseInsensitiveLength);
8338 InsensitiveName.Length = Name->Length - Entry->CaseInsensitiveLength;
8339 InsensitivePrefix.Length = Entry->Prefix.Length - Entry->CaseInsensitiveLength;
8340
8341 CmpName = &InsensitiveName;
8342 CmpPrefix = &InsensitivePrefix;
8343 CaseInsensitive = FALSE;
8344 }
8345 else
8346 {
8347 CmpName = Name;
8348 CmpPrefix = &Entry->Prefix;
8349 CaseInsensitive = ThisTable->CaseInsensitiveMatch;
8350 }
8351
8352 /* Perform the compare, if there's a match, also check for connection ID */
8353 if (RtlEqualUnicodeString(CmpName, CmpPrefix, CaseInsensitive))
8354 {
8355 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
8356 {
8357 return Entry;
8358 }
8359 }
8360 }
8361
8362 return NULL;
8363 }
8364
8365 /*
8366 * @implemented
8367 */
8368 NTSTATUS
8369 RxTearDownBufferingManager(
8370 PSRV_CALL SrvCall)
8371 {
8372 PAGED_CODE();
8373
8374 /* Nothing to do */
8375 return STATUS_SUCCESS;
8376 }
8377
8378 /*
8379 * @implemented
8380 */
8381 VOID
8382 NTAPI
8383 RxTimerDispatch(
8384 _In_ struct _KDPC *Dpc,
8385 _In_opt_ PVOID DeferredContext,
8386 _In_opt_ PVOID SystemArgument1,
8387 _In_opt_ PVOID SystemArgument2)
8388 {
8389 BOOLEAN Set;
8390 LIST_ENTRY LocalList;
8391 PLIST_ENTRY ListEntry;
8392 PRX_WORK_ITEM WorkItem;
8393
8394 InitializeListHead(&LocalList);
8395
8396 KeAcquireSpinLockAtDpcLevel(&RxTimerLock);
8397 ++RxTimerTickCount;
8398
8399 /* Find any entry matching */
8400 if (!IsListEmpty(&RxTimerQueueHead))
8401 {
8402 ListEntry = RxTimerQueueHead.Flink;
8403 do
8404 {
8405 WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
8406 if (WorkItem->LastTick == RxTimerTickCount)
8407 {
8408 ListEntry = ListEntry->Flink;
8409
8410 RemoveEntryList(&WorkItem->WorkQueueItem.List);
8411 InsertTailList(&LocalList, &WorkItem->WorkQueueItem.List);
8412 }
8413 else
8414 {
8415 ListEntry = ListEntry->Flink;
8416 }
8417 } while (ListEntry != &RxTimerQueueHead);
8418 }
8419 /* Do we have to requeue a later execution? */
8420 Set = !IsListEmpty(&RxTimerQueueHead);
8421
8422 KeReleaseSpinLockFromDpcLevel(&RxTimerLock);
8423
8424 /* Requeue if list wasn't empty */
8425 if (Set)
8426 {
8427 KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
8428 }
8429
8430 /* If we had matching entries */
8431 if (!IsListEmpty(&LocalList))
8432 {
8433 /* Post them, one after another */
8434 ListEntry = LocalList.Flink;
8435 do
8436 {
8437 WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
8438 ListEntry = ListEntry->Flink;
8439
8440 WorkItem->WorkQueueItem.List.Flink = NULL;
8441 WorkItem->WorkQueueItem.List.Blink = NULL;
8442 RxPostToWorkerThread(WorkItem->WorkQueueItem.pDeviceObject, CriticalWorkQueue,
8443 &WorkItem->WorkQueueItem, WorkItem->WorkQueueItem.WorkerRoutine,
8444 WorkItem->WorkQueueItem.Parameter);
8445 }
8446 while (ListEntry != &LocalList);
8447 }
8448 }
8449
8450 #ifdef RDBSS_TRACKER
8451 /*
8452 * @implemented
8453 */
8454 VOID
8455 RxTrackerUpdateHistory(
8456 _Inout_opt_ PRX_CONTEXT RxContext,
8457 _Inout_ PMRX_FCB MrxFcb,
8458 _In_ ULONG Operation,
8459 _In_ ULONG LineNumber,
8460 _In_ PCSTR FileName,
8461 _In_ ULONG SerialNumber)
8462 {
8463 PFCB Fcb;
8464 RX_FCBTRACKER_CASES Case;
8465
8466 /* Check for null or special context */
8467 if (RxContext == NULL)
8468 {
8469 Case = RX_FCBTRACKER_CASE_NULLCONTEXT;
8470 }
8471 else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT)
8472 {
8473 Case = RX_FCBTRACKER_CASE_CBS_CONTEXT;
8474 }
8475 else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
8476 {
8477 Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT;
8478 }
8479 else
8480 {
8481 ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT);
8482 Case = RX_FCBTRACKER_CASE_NORMAL;
8483 }
8484
8485 /* If caller provided a FCB, update its history */
8486 if (MrxFcb != NULL)
8487 {
8488 Fcb = (PFCB)MrxFcb;
8489 ASSERT(NodeTypeIsFcb(Fcb));
8490
8491 /* Only one acquire operation, so many release operations... */
8492 if (Operation == TRACKER_ACQUIRE_FCB)
8493 {
8494 ++Fcb->FcbAcquires[Case];
8495 }
8496 else
8497 {
8498 ++Fcb->FcbReleases[Case];
8499 }
8500 }
8501
8502 /* If we have a normal context, update its history about this function calls */
8503 if (Case == RX_FCBTRACKER_CASE_NORMAL)
8504 {
8505 ULONG TrackerHistoryPointer;
8506
8507 /* Only one acquire operation, so many release operations... */
8508 if (Operation == TRACKER_ACQUIRE_FCB)
8509 {
8510 InterlockedIncrement(&RxContext->AcquireReleaseFcbTrackerX);
8511 }
8512 else
8513 {
8514 InterlockedDecrement(&RxContext->AcquireReleaseFcbTrackerX);
8515 }
8516
8517 /* We only keep track of the 32 first calls */
8518 TrackerHistoryPointer = InterlockedExchangeAdd((volatile long *)&RxContext->TrackerHistoryPointer, 1);
8519 if (TrackerHistoryPointer < RDBSS_TRACKER_HISTORY_SIZE)
8520 {
8521 RxContext->TrackerHistory[TrackerHistoryPointer].AcquireRelease = Operation;
8522 RxContext->TrackerHistory[TrackerHistoryPointer].LineNumber = LineNumber;
8523 RxContext->TrackerHistory[TrackerHistoryPointer].FileName = (PSZ)FileName;
8524 RxContext->TrackerHistory[TrackerHistoryPointer].SavedTrackerValue = RxContext->AcquireReleaseFcbTrackerX;
8525 RxContext->TrackerHistory[TrackerHistoryPointer].Flags = RxContext->Flags;
8526 }
8527
8528 /* If it's negative, then we released once more than we acquired it?! */
8529 ASSERT(RxContext->AcquireReleaseFcbTrackerX >= 0);
8530 }
8531 }
8532 #endif
8533
8534 VOID
8535 RxTrackPagingIoResource(
8536 _Inout_ PVOID Instance,
8537 _In_ ULONG Type,
8538 _In_ ULONG Line,
8539 _In_ PCSTR File)
8540 {
8541 UNIMPLEMENTED;
8542 }
8543
8544 /*
8545 * @implemented
8546 */
8547 VOID
8548 RxUndoScavengerFinalizationMarking(
8549 PVOID Instance)
8550 {
8551 /* Just call internal routine with mutex held */
8552 RxAcquireScavengerMutex();
8553 RxpUndoScavengerFinalizationMarking(Instance);
8554 RxReleaseScavengerMutex();
8555 }
8556
8557 /*
8558 * @implemented
8559 */
8560 VOID
8561 RxUninitializeVNetRootParameters(
8562 IN PUNICODE_STRING UserName,
8563 IN PUNICODE_STRING UserDomainName,
8564 IN PUNICODE_STRING Password,
8565 OUT PULONG Flags)
8566 {
8567 PAGED_CODE();
8568
8569 /* Only free what could have been allocated */
8570 if (UserName != NULL)
8571 {
8572 RxFreePool(UserName);
8573 }
8574
8575 if (UserDomainName != NULL)
8576 {
8577 RxFreePool(UserDomainName);
8578 }
8579
8580 if (Password != NULL)
8581 {
8582 RxFreePool(Password);
8583 }
8584
8585 /* And remove the possibly set CSC agent flag */
8586 if (Flags != NULL)
8587 {
8588 (*Flags) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
8589 }
8590 }
8591
8592 /*
8593 * @implemented
8594 */
8595 VOID
8596 RxUpdateCondition(
8597 IN RX_BLOCK_CONDITION NewConditionValue,
8598 OUT PRX_BLOCK_CONDITION Condition,
8599 IN OUT PLIST_ENTRY TransitionWaitList)
8600 {
8601 PRX_CONTEXT Context;
8602 LIST_ENTRY SerializationQueue;
8603
8604 PAGED_CODE();
8605
8606 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue, Condition, TransitionWaitList);
8607
8608 /* Set the new condition */
8609 RxAcquireSerializationMutex();
8610 ASSERT(NewConditionValue != Condition_InTransition);
8611 *Condition = NewConditionValue;
8612 /* And get the serialization queue for treatment */
8613 RxTransferList(&SerializationQueue, TransitionWaitList);
8614 RxReleaseSerializationMutex();
8615
8616 /* Handle the serialization queue */
8617 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
8618 while (Context != NULL)
8619 {
8620 /* If the caller asked for post, post the request */
8621 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
8622 {
8623 Context->Flags &= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION;
8624 RxFsdPostRequest(Context);
8625 }
8626 /* Otherwise, wake up sleeping waiters */
8627 else
8628 {
8629 RxSignalSynchronousWaiter(Context);
8630 }
8631
8632 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
8633 }
8634 }
8635
8636 /*
8637 * @implemented
8638 */
8639 VOID
8640 RxVerifyOperationIsLegal(
8641 IN PRX_CONTEXT RxContext)
8642 {
8643 PIRP Irp;
8644 PMRX_FOBX Fobx;
8645 BOOLEAN FlagSet;
8646 PFILE_OBJECT FileObject;
8647 PIO_STACK_LOCATION Stack;
8648
8649 PAGED_CODE();
8650
8651 Irp = RxContext->CurrentIrp;
8652 Stack = RxContext->CurrentIrpSp;
8653 FileObject = Stack->FileObject;
8654
8655 /* We'll only check stuff on opened files, this requires an IRP and a FO */
8656 if (Irp == NULL || FileObject == NULL)
8657 {
8658 return;
8659 }
8660
8661 /* Set no exception for breakpoint - remember whether is was already set */
8662 FlagSet = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8663 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8664
8665 /* If we have a CCB, perform a few checks on opened file */
8666 Fobx = RxContext->pFobx;
8667 if (Fobx != NULL)
8668 {
8669 PMRX_SRV_OPEN SrvOpen;
8670
8671 SrvOpen = Fobx->pSrvOpen;
8672 if (SrvOpen != NULL)
8673 {
8674 UCHAR MajorFunction;
8675
8676 MajorFunction = RxContext->MajorFunction;
8677 /* Only allow closing/cleanup operations on renamed files */
8678 if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE &&
8679 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
8680 {
8681 RxContext->IoStatusBlock.Status = STATUS_FILE_RENAMED;
8682 ExRaiseStatus(STATUS_FILE_RENAMED);
8683 }
8684
8685 /* Only allow closing/cleanup operations on deleted files */
8686 if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE &&
8687 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED))
8688 {
8689 RxContext->IoStatusBlock.Status = STATUS_FILE_DELETED;
8690 ExRaiseStatus(STATUS_FILE_DELETED);
8691 }
8692 }
8693 }
8694
8695 /* If that's an open operation */
8696 if (RxContext->MajorFunction == IRP_MJ_CREATE)
8697 {
8698 PFILE_OBJECT RelatedFileObject;
8699
8700 /* We won't allow an open operation relative to a file to be deleted */
8701 RelatedFileObject = FileObject->RelatedFileObject;
8702 if (RelatedFileObject != NULL)
8703 {
8704 PMRX_FCB Fcb;
8705
8706 Fcb = RelatedFileObject->FsContext;
8707 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
8708 {
8709 RxContext->IoStatusBlock.Status = STATUS_DELETE_PENDING;
8710 ExRaiseStatus(STATUS_DELETE_PENDING);
8711 }
8712 }
8713 }
8714
8715 /* If cleanup was completed */
8716 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
8717 {
8718 if (!BooleanFlagOn(Irp->Flags, IRP_PAGING_IO))
8719 {
8720 UCHAR MajorFunction;
8721
8722 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
8723 MajorFunction = Stack->MajorFunction;
8724 if (MajorFunction != IRP_MJ_CLOSE && MajorFunction != IRP_MJ_QUERY_INFORMATION &&
8725 MajorFunction != IRP_MJ_SET_INFORMATION)
8726 {
8727 if ((MajorFunction != IRP_MJ_READ && MajorFunction != IRP_MJ_WRITE) ||
8728 !BooleanFlagOn(Stack->MinorFunction, IRP_MN_COMPLETE))
8729 {
8730 RxContext->IoStatusBlock.Status = STATUS_FILE_CLOSED;
8731 ExRaiseStatus(STATUS_FILE_CLOSED);
8732 }
8733 }
8734 }
8735 }
8736
8737 /* If flag was already set, don't clear it */
8738 if (!FlagSet)
8739 {
8740 ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8741 }
8742 }
8743
8744 /*
8745 * @implemented
8746 */
8747 VOID
8748 RxWaitForStableCondition(
8749 IN PRX_BLOCK_CONDITION Condition,
8750 IN OUT PLIST_ENTRY TransitionWaitList,
8751 IN OUT PRX_CONTEXT RxContext,
8752 OUT NTSTATUS *AsyncStatus OPTIONAL)
8753 {
8754 BOOLEAN Wait;
8755 NTSTATUS LocalStatus;
8756
8757 PAGED_CODE();
8758
8759 /* Make sure to always get status */
8760 if (AsyncStatus == NULL)
8761 {
8762 AsyncStatus = &LocalStatus;
8763 }
8764
8765 /* By default, it's a success */
8766 *AsyncStatus = STATUS_SUCCESS;
8767
8768 Wait = FALSE;
8769 /* If it's not stable, we've to wait */
8770 if (!StableCondition(*Condition))
8771 {
8772 /* Lock the mutex */
8773 RxAcquireSerializationMutex();
8774 /* Still not stable? */
8775 if (!StableCondition(*Condition))
8776 {
8777 /* Insert us in the wait list for processing on stable condition */
8778 RxInsertContextInSerializationQueue(TransitionWaitList, RxContext);
8779
8780 /* If we're asked to post on stable, don't wait, and just return pending */
8781 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
8782 {
8783 *AsyncStatus = STATUS_PENDING;
8784 }
8785 else
8786 {
8787 Wait = TRUE;
8788 }
8789 }
8790 RxReleaseSerializationMutex();
8791
8792 /* We don't post on stable, so, just wait... */
8793 if (Wait)
8794 {
8795 RxWaitSync(RxContext);
8796 }
8797 }
8798 }
8799
8800 /*
8801 * @implemented
8802 */
8803 VOID
8804 NTAPI
8805 RxWorkItemDispatcher(
8806 PVOID Context)
8807 {
8808 PRX_WORK_DISPATCH_ITEM DispatchItem = Context;
8809
8810 DPRINT("Calling: %p, %p\n", DispatchItem->DispatchRoutine, DispatchItem->DispatchRoutineParameter);
8811
8812 DispatchItem->DispatchRoutine(DispatchItem->DispatchRoutineParameter);
8813
8814 RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
8815 }
8816
8817 /*
8818 * @implemented
8819 */
8820 PVOID
8821 NTAPI
8822 _RxAllocatePoolWithTag(
8823 _In_ POOL_TYPE PoolType,
8824 _In_ SIZE_T NumberOfBytes,
8825 _In_ ULONG Tag)
8826 {
8827 return ExAllocatePoolWithTagPriority(PoolType, NumberOfBytes, Tag, LowPoolPriority);
8828 }
8829
8830 /*
8831 * @implemented
8832 */
8833 VOID
8834 NTAPI
8835 _RxFreePool(
8836 _In_ PVOID Buffer)
8837 {
8838 ExFreePoolWithTag(Buffer, 0);
8839 }
8840
8841 /*
8842 * @implemented
8843 */
8844 VOID
8845 NTAPI
8846 _RxFreePoolWithTag(
8847 _In_ PVOID Buffer,
8848 _In_ ULONG Tag)
8849 {
8850 ExFreePoolWithTag(Buffer, Tag);
8851 }
8852
8853 NTSTATUS
8854 __RxAcquireFcb(
8855 _Inout_ PFCB Fcb,
8856 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL,
8857 _In_ ULONG Mode
8858 #ifdef RDBSS_TRACKER
8859 ,
8860 _In_ ULONG LineNumber,
8861 _In_ PCSTR FileName,
8862 _In_ ULONG SerialNumber
8863 #endif
8864 )
8865 {
8866 NTSTATUS Status;
8867 BOOLEAN SpecialContext, CanWait, Acquired, ContextIsPresent;
8868
8869 PAGED_CODE();
8870
8871 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb, RxContext, Mode, LineNumber, FileName, SerialNumber);
8872
8873 SpecialContext = FALSE;
8874 ContextIsPresent = FALSE;
8875 /* Check for special context */
8876 if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT || RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
8877 {
8878 SpecialContext = TRUE;
8879 }
8880
8881 /* We don't handle buffering state change yet... */
8882 if (!RxIsFcbAcquired(Fcb) && !SpecialContext &&
8883 BooleanFlagOn(Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING))
8884 {
8885 UNIMPLEMENTED;
8886 }
8887
8888 /* Nor special contexts */
8889 if (SpecialContext)
8890 {
8891 UNIMPLEMENTED;
8892 }
8893
8894 /* If we don't have a context, assume we can wait! */
8895 if (RxContext == NULL)
8896 {
8897 CanWait = TRUE;
8898 }
8899 else
8900 {
8901 /* That said: we have a real context! */
8902 ContextIsPresent = TRUE;
8903
8904 /* If we've been cancelled in between, give up */
8905 Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
8906 if (!NT_SUCCESS(Status))
8907 {
8908 return Status;
8909 }
8910
8911 /* Can we wait? */
8912 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
8913 }
8914
8915 while (TRUE)
8916 {
8917 /* Assume we cannot lock */
8918 Status = STATUS_LOCK_NOT_GRANTED;
8919
8920 /* Lock according to what the caller asked */
8921 switch (Mode)
8922 {
8923 case FCB_MODE_EXCLUSIVE:
8924 Acquired = ExAcquireResourceExclusiveLite(Fcb->Header.Resource, CanWait);
8925 break;
8926
8927 case FCB_MODE_SHARED:
8928 Acquired = ExAcquireResourceSharedLite(Fcb->Header.Resource, CanWait);
8929 break;
8930
8931 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE:
8932 Acquired = ExAcquireSharedWaitForExclusive(Fcb->Header.Resource, CanWait);
8933 break;
8934
8935 default:
8936 ASSERT(Mode == FCB_MODE_SHARED_STARVE_EXCLUSIVE);
8937 Acquired = ExAcquireSharedStarveExclusive(Fcb->Header.Resource, CanWait);
8938 break;
8939 }
8940
8941 /* Lock granted! */
8942 if (Acquired)
8943 {
8944 Status = STATUS_SUCCESS;
8945 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
8946
8947 /* Handle paging write - not implemented */
8948 if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
8949 {
8950 UNIMPLEMENTED;
8951 }
8952 }
8953
8954 /* And break, that cool! */
8955 if (Acquired)
8956 {
8957 break;
8958 }
8959
8960 /* If it failed, return immediately */
8961 if (!NT_SUCCESS(Status))
8962 {
8963 return Status;
8964 }
8965 }
8966
8967 /* If we don't have to check for valid operation, job done, nothing more to do */
8968 if (!ContextIsPresent || BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK))
8969 {
8970 if (NT_SUCCESS(Status))
8971 {
8972 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
8973 }
8974
8975 return Status;
8976 }
8977
8978 /* Verify operation */
8979 _SEH2_TRY
8980 {
8981 RxVerifyOperationIsLegal(RxContext);
8982 }
8983 _SEH2_FINALLY
8984 {
8985 /* If it failed, release lock and fail */
8986 if (_SEH2_AbnormalTermination())
8987 {
8988 ExReleaseResourceLite(Fcb->Header.Resource);
8989 Status = STATUS_LOCK_NOT_GRANTED;
8990 }
8991 }
8992 _SEH2_END;
8993
8994 if (NT_SUCCESS(Status))
8995 {
8996 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
8997 }
8998
8999 DPRINT("Status: %x\n", Status);
9000 return Status;
9001 }
9002
9003 /*
9004 * @implemented
9005 */
9006 VOID
9007 __RxItsTheSameContext(
9008 _In_ PRX_CONTEXT RxContext,
9009 _In_ ULONG CapturedRxContextSerialNumber,
9010 _In_ ULONG Line,
9011 _In_ PCSTR File)
9012 {
9013 /* Check we have a context with the same serial number */
9014 if (NodeType(RxContext) != RDBSS_NTC_RX_CONTEXT ||
9015 RxContext->SerialNumber != CapturedRxContextSerialNumber)
9016 {
9017 /* Just be noisy */
9018 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext, Line, File);
9019 }
9020 }
9021
9022 VOID
9023 __RxReleaseFcb(
9024 _Inout_opt_ PRX_CONTEXT RxContext,
9025 _Inout_ PMRX_FCB MrxFcb
9026 #ifdef RDBSS_TRACKER
9027 ,
9028 _In_ ULONG LineNumber,
9029 _In_ PCSTR FileName,
9030 _In_ ULONG SerialNumber
9031 #endif
9032 )
9033 {
9034 BOOLEAN IsExclusive, BufferingPending;
9035
9036 RxAcquireSerializationMutex();
9037
9038 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
9039 IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
9040
9041 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9042 * then just release the FCB
9043 */
9044 if (!BufferingPending || !IsExclusive)
9045 {
9046 RxTrackerUpdateHistory(RxContext, MrxFcb, (!BufferingPending ? TRACKER_RELEASE_FCB_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING),
9047 LineNumber, FileName, SerialNumber);
9048 ExReleaseResourceLite(MrxFcb->Header.Resource);
9049 }
9050
9051 RxReleaseSerializationMutex();
9052
9053 /* And finally leave */
9054 if (!BufferingPending || !IsExclusive)
9055 {
9056 return;
9057 }
9058
9059 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb));
9060
9061 /* Otherwise, handle buffering state and release */
9062 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
9063
9064 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING, LineNumber, FileName, SerialNumber);
9065 ExReleaseResourceLite(MrxFcb->Header.Resource);
9066 }
9067
9068 VOID
9069 __RxReleaseFcbForThread(
9070 _Inout_opt_ PRX_CONTEXT RxContext,
9071 _Inout_ PMRX_FCB MrxFcb,
9072 _In_ ERESOURCE_THREAD ResourceThreadId
9073 #ifdef RDBSS_TRACKER
9074 ,
9075 _In_ ULONG LineNumber,
9076 _In_ PCSTR FileName,
9077 _In_ ULONG SerialNumber
9078 #endif
9079 )
9080 {
9081 BOOLEAN IsExclusive, BufferingPending;
9082
9083 RxAcquireSerializationMutex();
9084
9085 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
9086 IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
9087
9088 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9089 * then just release the FCB
9090 */
9091 if (!BufferingPending || !IsExclusive)
9092 {
9093 RxTrackerUpdateHistory(RxContext, MrxFcb,
9094 (!BufferingPending ? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING),
9095 LineNumber, FileName, SerialNumber);
9096 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
9097 }
9098
9099 RxReleaseSerializationMutex();
9100
9101 /* And finally leave */
9102 if (!BufferingPending || !IsExclusive)
9103 {
9104 return;
9105 }
9106
9107 /* Otherwise, handle buffering state and release */
9108 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING, LineNumber, FileName, SerialNumber);
9109 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
9110 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
9111 }