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