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