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