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