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