d3bd22a98eb0e70a0306c4857cb14efe4b46126a
[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 NTSTATUS
2442 NTAPI
2443 RxFinalizeConnection(
2444 IN OUT PNET_ROOT NetRoot,
2445 IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
2446 IN LOGICAL ForceFilesClosed)
2447 {
2448 NTSTATUS Status;
2449 PRX_PREFIX_TABLE PrefixTable;
2450 ULONG UncleanAny, UncleanDir;
2451 LONG FilesOpen, AdditionalRef;
2452 BOOLEAN PrefixLocked, FcbTableLocked, ForceClose;
2453
2454 PAGED_CODE();
2455
2456 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
2457
2458 /* Get a BOOLEAN out of LOGICAL
2459 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2460 */
2461 ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE);
2462
2463 /* First, delete any notification change */
2464 Status = RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot, ForceClose);
2465 /* If it failed, continue if forced */
2466 if (Status != STATUS_SUCCESS && !ForceFilesClosed)
2467 {
2468 return Status;
2469 }
2470 /* Reset status, in case notification deletion failed */
2471 Status = STATUS_SUCCESS;
2472
2473 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
2474
2475 PrefixLocked = FALSE;
2476 FcbTableLocked = FALSE;
2477 FilesOpen = 0;
2478 AdditionalRef = 0;
2479 UncleanAny = 0;
2480 UncleanDir = 0;
2481 _SEH2_TRY
2482 {
2483 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
2484 PrefixLocked = TRUE;
2485
2486 RxReferenceNetRoot(NetRoot);
2487
2488 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
2489 FcbTableLocked = TRUE;
2490
2491 /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2492 if (!VNetRoot->ConnectionFinalizationDone)
2493 {
2494 USHORT Bucket;
2495 PRX_FCB_TABLE FcbTable;
2496
2497 DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix);
2498
2499 /* We'll browse all its associated FCB to check whether they're open/orphaned */
2500 FcbTable = &NetRoot->FcbTable;
2501 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2502 {
2503 PLIST_ENTRY BucketList, Entry;
2504
2505 BucketList = &FcbTable->HashBuckets[Bucket];
2506 Entry = BucketList->Flink;
2507 while (Entry != BucketList)
2508 {
2509 PFCB Fcb;
2510
2511 Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
2512 Entry = Entry->Flink;
2513
2514 /* FCB for this connection, go ahead */
2515 if (Fcb->VNetRoot == VNetRoot)
2516 {
2517 /* It's still open, and no force? Fail and keep track */
2518 if (Fcb->UncleanCount > 0 && !ForceClose)
2519 {
2520 Status = STATUS_CONNECTION_IN_USE;
2521 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
2522 {
2523 ++UncleanDir;
2524 }
2525 else
2526 {
2527 ++UncleanAny;
2528 }
2529 }
2530 else
2531 {
2532 /* Else, force purge */
2533 ASSERT(NodeTypeIsFcb(Fcb));
2534
2535 Status = RxAcquireExclusiveFcb(NULL, Fcb);
2536 ASSERT(Status == STATUS_SUCCESS);
2537
2538 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
2539
2540 RxScavengeRelatedFobxs(Fcb);
2541 RxPurgeFcb(Fcb);
2542
2543 /* We don't need to release FCB lock, FCB finalize will take care of it */
2544 }
2545 }
2546 }
2547 }
2548
2549 /* No files left, our V_NET_ROOT is finalized */
2550 if (VNetRoot->NumberOfFobxs == 0)
2551 {
2552 VNetRoot->ConnectionFinalizationDone = TRUE;
2553 }
2554 }
2555
2556 /* Keep Number of open files and track of the extra reference */
2557 FilesOpen = VNetRoot->NumberOfFobxs;
2558 AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken;
2559 /* If force close, caller doesn't want to keep connection alive
2560 * and wants it totally close, so drop the V_NET_ROOT too
2561 */
2562 if (ForceClose)
2563 {
2564 RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE);
2565 }
2566 }
2567 _SEH2_FINALLY
2568 {
2569 /* Release what was acquired */
2570 if (FcbTableLocked)
2571 {
2572 RxReleaseFcbTableLock(&NetRoot->FcbTable);
2573 }
2574
2575 /* If close is forced, only fix status if there are open files */
2576 if (ForceClose)
2577 {
2578 if (Status != STATUS_SUCCESS && UncleanAny != 0)
2579 {
2580 Status = STATUS_FILES_OPEN;
2581 }
2582 }
2583 /* Else, fix status and fail closing if there are open files */
2584 else
2585 {
2586 if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0)
2587 {
2588 Status = STATUS_FILES_OPEN;
2589 }
2590 }
2591
2592 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen);
2593
2594 /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2595 * only if it was still referenced!
2596 */
2597 if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0)
2598 {
2599 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0;
2600 RxDereferenceVNetRoot(VNetRoot, LHS_ExclusiveLockHeld);
2601 }
2602
2603 if (PrefixLocked)
2604 {
2605 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
2606 RxReleasePrefixTableLock(PrefixTable);
2607 }
2608 }
2609 _SEH2_END;
2610
2611 return Status;
2612 }
2613
2614 /*
2615 * @implemented
2616 */
2617 VOID
2618 RxFinalizeFcbTable(
2619 IN OUT PRX_FCB_TABLE FcbTable)
2620 {
2621 USHORT Bucket;
2622
2623 PAGED_CODE();
2624
2625 /* Just delete the lock */
2626 ExDeleteResourceLite(&FcbTable->TableLock);
2627
2628 /* And make sure (checked) that the table is really empty... */
2629 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2630 {
2631 ASSERT(IsListEmpty(&FcbTable->HashBuckets[Bucket]));
2632 }
2633 }
2634
2635 /*
2636 * @implemented
2637 */
2638 BOOLEAN
2639 RxFinalizeNetFcb(
2640 OUT PFCB ThisFcb,
2641 IN BOOLEAN RecursiveFinalize,
2642 IN BOOLEAN ForceFinalize,
2643 IN LONG ReferenceCount)
2644 {
2645 PAGED_CODE();
2646
2647 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount);
2648 DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path);
2649
2650 /* Make sure we have an exclusively acquired FCB */
2651 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb);
2652 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
2653
2654 /* We shouldn't force finalization... */
2655 ASSERT(!ForceFinalize);
2656
2657 /* If recurisve, finalize all the associated SRV_OPEN */
2658 if (RecursiveFinalize)
2659 {
2660 PLIST_ENTRY ListEntry;
2661
2662 for (ListEntry = ThisFcb->SrvOpenList.Flink;
2663 ListEntry != &ThisFcb->SrvOpenList;
2664 ListEntry = ListEntry->Flink)
2665 {
2666 PSRV_OPEN SrvOpen;
2667
2668 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks);
2669 RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize);
2670 }
2671 }
2672 /* If FCB is still in use, that's over */
2673 else
2674 {
2675 if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0)
2676 {
2677 ASSERT(ReferenceCount > 0);
2678
2679 return FALSE;
2680 }
2681 }
2682
2683 ASSERT(ReferenceCount >= 1);
2684
2685 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2686 if (ReferenceCount != 1 && !ForceFinalize)
2687 {
2688 return FALSE;
2689 }
2690
2691 ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0)));
2692
2693 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb->OpenCount, ForceFinalize);
2694
2695 /* If finalization was not already initiated, go ahead */
2696 if (!ThisFcb->UpperFinalizationDone)
2697 {
2698 /* Free any FCB_LOCK */
2699 if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
2700 {
2701 FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock);
2702
2703 while (ThisFcb->BufferedLocks.List != NULL)
2704 {
2705 PFCB_LOCK Entry;
2706
2707 Entry = ThisFcb->BufferedLocks.List;
2708 ThisFcb->BufferedLocks.List = Entry->Next;
2709
2710 RxFreePool(Entry);
2711 }
2712 }
2713
2714 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2715 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
2716 {
2717 PNET_ROOT NetRoot;
2718
2719 NetRoot = (PNET_ROOT)ThisFcb->pNetRoot;
2720
2721 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
2722 /* So, remove it */
2723 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED))
2724 {
2725 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
2726 }
2727 }
2728
2729 ThisFcb->UpperFinalizationDone = TRUE;
2730 }
2731
2732 ASSERT(ReferenceCount >= 1);
2733
2734 /* Even if forced, don't allow broken free */
2735 if (ReferenceCount != 1)
2736 {
2737 return FALSE;
2738 }
2739
2740 /* Now, release everything */
2741 if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL)
2742 {
2743 RxFreePool(ThisFcb->pBufferingStateChangeCompletedEvent);
2744 }
2745
2746 if (ThisFcb->MRxDispatch != NULL)
2747 {
2748 ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb));
2749 }
2750
2751 ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource);
2752 ExDeleteResourceLite(ThisFcb->Header.Resource);
2753 ExDeleteResourceLite(ThisFcb->Header.PagingIoResource);
2754
2755 InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs);
2756 RxDereferenceVNetRoot(ThisFcb->VNetRoot, LHS_LockNotHeld);
2757
2758 ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks));
2759 ASSERT(!ThisFcb->fMiniInited);
2760
2761 /* And free the object */
2762 RxFreeFcbObject(ThisFcb);
2763
2764 return TRUE;
2765 }
2766
2767 /*
2768 * @implemented
2769 */
2770 BOOLEAN
2771 RxFinalizeNetFobx(
2772 _Out_ PFOBX ThisFobx,
2773 _In_ BOOLEAN RecursiveFinalize,
2774 _In_ BOOLEAN ForceFinalize)
2775 {
2776 PFCB Fcb;
2777 PSRV_OPEN SrvOpen;
2778
2779 PAGED_CODE();
2780
2781 ASSERT(NodeType(ThisFobx) == RDBSS_NTC_FOBX);
2782
2783 /* Only finalize if forced or if there's no ref left */
2784 if (ThisFobx->NodeReferenceCount != 0 &&
2785 !ForceFinalize)
2786 {
2787 return FALSE;
2788 }
2789
2790 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx, ThisFobx->NodeReferenceCount, ForceFinalize);
2791
2792 SrvOpen = ThisFobx->SrvOpen;
2793 Fcb = SrvOpen->Fcb;
2794 /* If it wasn't finalized yet, do it */
2795 if (!ThisFobx->UpperFinalizationDone)
2796 {
2797 ASSERT(NodeType(SrvOpen->Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
2798 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
2799
2800 /* Remove it from the SRV_OPEN */
2801 RemoveEntryList(&ThisFobx->FobxQLinks);
2802
2803 /* If we were used to browse a directory, free the query buffer */
2804 if (BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_FREE_UNICODE))
2805 {
2806 RxFreePoolWithTag(ThisFobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
2807 }
2808
2809 /* Notify the mini-rdr */
2810 if (Fcb->MRxDispatch != NULL && Fcb->MRxDispatch->MRxDeallocateForFobx != NULL)
2811 {
2812 Fcb->MRxDispatch->MRxDeallocateForFobx((PMRX_FOBX)ThisFobx);
2813 }
2814
2815 /* If the SRV_OPEN wasn't closed yet, do it */
2816 if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
2817 {
2818 NTSTATUS Status;
2819
2820 Status = RxCloseAssociatedSrvOpen(ThisFobx, FALSE);
2821 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen, ThisFobx, Status);
2822 }
2823
2824 /* Finalization done */
2825 ThisFobx->UpperFinalizationDone = TRUE;
2826 }
2827
2828 /* If we're still referenced, don't go any further! */
2829 if (ThisFobx->NodeReferenceCount != 0)
2830 {
2831 return FALSE;
2832 }
2833
2834 /* At that point, everything should be closed */
2835 ASSERT(IsListEmpty(&ThisFobx->ClosePendingList));
2836
2837 /* Was the FOBX allocated with another object?
2838 * If so, mark the buffer free in said object
2839 */
2840 if (ThisFobx == Fcb->InternalFobx)
2841 {
2842 ClearFlag(Fcb->FcbState, FCB_STATE_FOBX_USED);
2843 }
2844 else if (ThisFobx == SrvOpen->InternalFobx)
2845 {
2846 ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED);
2847 }
2848
2849 ThisFobx->pSrvOpen = NULL;
2850
2851 /* A FOBX less */
2852 InterlockedDecrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs);
2853
2854 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
2855
2856 /* If it wasn't allocated with another object, free the FOBX */
2857 if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_ENCLOSED_ALLOCATED))
2858 {
2859 RxFreeFcbObject(ThisFobx);
2860 }
2861
2862 return TRUE;
2863 }
2864
2865 /*
2866 * @implemented
2867 */
2868 BOOLEAN
2869 RxFinalizeNetRoot(
2870 OUT PNET_ROOT ThisNetRoot,
2871 IN BOOLEAN RecursiveFinalize,
2872 IN BOOLEAN ForceFinalize)
2873 {
2874 PSRV_CALL SrvCall;
2875 PRX_FCB_TABLE FcbTable;
2876 PRX_PREFIX_TABLE PrefixTable;
2877
2878 PAGED_CODE();
2879
2880 ASSERT(NodeType(ThisNetRoot) == RDBSS_NTC_NETROOT);
2881
2882 PrefixTable = ThisNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
2883 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
2884
2885 /* If sme finalization is already ongoing, leave */
2886 if (BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS))
2887 {
2888 return FALSE;
2889 }
2890
2891 /* Mark we're finalizing */
2892 SetFlag(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS);
2893
2894 FcbTable = &ThisNetRoot->FcbTable;
2895 /* Did caller asked us to finalize any associated FCB? */
2896 if (RecursiveFinalize)
2897 {
2898 USHORT Bucket;
2899
2900 /* Browse all the FCBs in our FCB table */
2901 RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
2902 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
2903 {
2904 PLIST_ENTRY HashBucket, ListEntry;
2905
2906 HashBucket = &FcbTable->HashBuckets[Bucket];
2907 ListEntry = HashBucket->Flink;
2908 while (ListEntry != HashBucket)
2909 {
2910 PFCB Fcb;
2911
2912 Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks);
2913 ASSERT(NodeTypeIsFcb(Fcb));
2914
2915 ListEntry = ListEntry->Flink;
2916
2917 /* If the FCB isn't orphaned, then, it's time to purge it */
2918 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
2919 {
2920 NTSTATUS Status;
2921
2922 Status = RxAcquireExclusiveFcb(NULL, Fcb);
2923 ASSERT(Status == STATUS_SUCCESS);
2924 RxPurgeFcb(Fcb);
2925 }
2926 }
2927 }
2928 RxReleaseFcbTableLock(FcbTable);
2929 }
2930
2931 /* Only finalize if forced or if there's a single ref left */
2932 if (ThisNetRoot->NodeReferenceCount != 1 && !ForceFinalize)
2933 {
2934 return FALSE;
2935 }
2936
2937 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot, &ThisNetRoot->PrefixEntry.Prefix);
2938
2939 /* If we're still referenced, don't go any further! */
2940 if (ThisNetRoot->NodeReferenceCount != 1)
2941 {
2942 return FALSE;
2943 }
2944
2945 /* Finalize the FCB table (and make sure it's empty!) */
2946 RxFinalizeFcbTable(FcbTable);
2947
2948 /* If name wasn't remove already, do it now */
2949 if (!BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
2950 {
2951 RxRemovePrefixTableEntry(PrefixTable, &ThisNetRoot->PrefixEntry);
2952 }
2953
2954 /* Delete the object */
2955 SrvCall = (PSRV_CALL)ThisNetRoot->pSrvCall;
2956 RxFreeObject(ThisNetRoot);
2957
2958 /* And dereference the associated SRV_CALL */
2959 if (SrvCall != NULL)
2960 {
2961 RxDereferenceSrvCall(SrvCall, LHS_ExclusiveLockHeld);
2962 }
2963
2964 return TRUE;
2965 }
2966
2967 /*
2968 * @implemented
2969 */
2970 BOOLEAN
2971 RxFinalizeSrvCall(
2972 OUT PSRV_CALL ThisSrvCall,
2973 IN BOOLEAN RecursiveFinalize,
2974 IN BOOLEAN ForceFinalize)
2975 {
2976 PRX_PREFIX_TABLE PrefixTable;
2977
2978 PAGED_CODE();
2979
2980 ASSERT(NodeType(ThisSrvCall) == RDBSS_NTC_SRVCALL);
2981
2982 PrefixTable = ThisSrvCall->RxDeviceObject->pRxNetNameTable;
2983 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
2984
2985 /* Only finalize if forced or if there's a single ref left */
2986 if (ThisSrvCall->NodeReferenceCount != 1 &&
2987 !ForceFinalize)
2988 {
2989 return FALSE;
2990 }
2991
2992 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall, &ThisSrvCall->PrefixEntry.Prefix);
2993
2994 /* If it wasn't finalized yet, do it */
2995 if (!ThisSrvCall->UpperFinalizationDone)
2996 {
2997 BOOLEAN WillFree;
2998
2999 /* Remove ourselves from prefix table */
3000 RxRemovePrefixTableEntry(PrefixTable, &ThisSrvCall->PrefixEntry);
3001
3002 /* Remember our third arg, in case we get queued for later execution */
3003 if (ForceFinalize)
3004 {
3005 SetFlag(ThisSrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
3006 }
3007
3008 /* And done */
3009 ThisSrvCall->UpperFinalizationDone = TRUE;
3010
3011 /* Would defered execution free the object? */
3012 WillFree = (ThisSrvCall->NodeReferenceCount == 1);
3013
3014 /* If we have a device object */
3015 if (ThisSrvCall->RxDeviceObject != NULL)
3016 {
3017 NTSTATUS Status;
3018
3019 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3020 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3021 {
3022 /* Extra ref, as usual */
3023 InterlockedIncrement((volatile long *)&ThisSrvCall->NodeReferenceCount);
3024 /* And dispatch */
3025 RxDispatchToWorkerThread(ThisSrvCall->RxDeviceObject, DelayedWorkQueue, RxpDestroySrvCall, ThisSrvCall);
3026
3027 /* Return to the caller, in advance, whether we're freeing the object or not */
3028 return WillFree;
3029 }
3030
3031 /* If in the right thread already, call the mini-rdr */
3032 MINIRDR_CALL_THROUGH(Status, ThisSrvCall->RxDeviceObject->Dispatch,
3033 MRxFinalizeSrvCall, ((PMRX_SRV_CALL)ThisSrvCall, ForceFinalize));
3034 (void)Status;
3035 }
3036 }
3037
3038 /* If we're still referenced, don't go any further! */
3039 if (ThisSrvCall->NodeReferenceCount != 1)
3040 {
3041 return FALSE;
3042 }
3043
3044 /* Don't leak */
3045 if (ThisSrvCall->pDomainName != NULL)
3046 {
3047 RxFreePool(ThisSrvCall->pDomainName);
3048 }
3049
3050 /* And free! */
3051 RxTearDownBufferingManager(ThisSrvCall);
3052 RxFreeObject(ThisSrvCall);
3053
3054 return TRUE;
3055 }
3056
3057 /*
3058 * @implemented
3059 */
3060 BOOLEAN
3061 RxFinalizeSrvOpen(
3062 OUT PSRV_OPEN ThisSrvOpen,
3063 IN BOOLEAN RecursiveFinalize,
3064 IN BOOLEAN ForceFinalize)
3065 {
3066 PFCB Fcb;
3067
3068 PAGED_CODE();
3069
3070 /* We have to have a SRV_OPEN */
3071 ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN);
3072
3073 /* If that's a recursive finalization, finalize any related FOBX */
3074 if (RecursiveFinalize)
3075 {
3076 PLIST_ENTRY ListEntry;
3077
3078 ListEntry = ThisSrvOpen->FobxList.Flink;
3079 while (ListEntry != &ThisSrvOpen->FobxList)
3080 {
3081 PFOBX Fobx;
3082
3083 Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks);
3084 ListEntry = ListEntry->Flink;
3085 RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize);
3086 }
3087 }
3088
3089 /* If we have still references, don't finalize unless forced */
3090 if (ThisSrvOpen->NodeReferenceCount != 0 &&
3091 !ForceFinalize)
3092 {
3093 return FALSE;
3094 }
3095
3096 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize);
3097
3098 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3099 Fcb = (PFCB)ThisSrvOpen->pFcb;
3100 if ((!ThisSrvOpen->UpperFinalizationDone && ThisSrvOpen->Condition != Condition_Good) ||
3101 BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
3102 {
3103 PV_NET_ROOT VNetRoot;
3104
3105 /* Associated FCB can't be fake one */
3106 ASSERT(NodeType(Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB);
3107 ASSERT(RxIsFcbAcquiredExclusive (Fcb));
3108
3109 /* Purge any pending operation */
3110 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen);
3111
3112 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3113 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
3114 {
3115 NTSTATUS Status;
3116
3117 MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen));
3118 (void)Status;
3119 }
3120
3121 /* Remove ourselves from the FCB */
3122 RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3123 InitializeListHead(&ThisSrvOpen->SrvOpenQLinks);
3124 ++Fcb->SrvOpenListVersion;
3125
3126 /* If we have a V_NET_ROOT, dereference it */
3127 VNetRoot = (PV_NET_ROOT)ThisSrvOpen->pVNetRoot;
3128 if (VNetRoot != NULL)
3129 {
3130 InterlockedDecrement((volatile long *)&VNetRoot->pNetRoot->NumberOfSrvOpens);
3131 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3132 ThisSrvOpen->pVNetRoot = NULL;
3133 }
3134
3135 /* Finalization done */
3136 ThisSrvOpen->UpperFinalizationDone = TRUE;
3137 }
3138
3139 /* Don't free memory if still referenced */
3140 if (ThisSrvOpen->NodeReferenceCount != 0)
3141 {
3142 return FALSE;
3143 }
3144
3145 /* No key association left */
3146 ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList));
3147
3148 /* If we're still in some FCB, remove us */
3149 if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks))
3150 {
3151 RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks);
3152 }
3153
3154 /* If enclosed allocation, mark the memory zone free and dereference FCB */
3155 if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED))
3156 {
3157 ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED);
3158 RxDereferenceNetFcb(Fcb);
3159 }
3160 /* Otherwise, free the memory */
3161 else
3162 {
3163 RxFreeFcbObject(ThisSrvOpen);
3164 }
3165
3166 return TRUE;
3167 }
3168
3169 /*
3170 * @implemented
3171 */
3172 BOOLEAN
3173 RxFinalizeVNetRoot(
3174 OUT PV_NET_ROOT ThisVNetRoot,
3175 IN BOOLEAN RecursiveFinalize,
3176 IN BOOLEAN ForceFinalize)
3177 {
3178 PNET_ROOT NetRoot;
3179 PRX_PREFIX_TABLE PrefixTable;
3180
3181 PAGED_CODE();
3182
3183 ASSERT(NodeType(ThisVNetRoot) == RDBSS_NTC_V_NETROOT);
3184
3185 PrefixTable = ThisVNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
3186 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
3187
3188 /* Only finalize if forced or if there's a single ref left */
3189 if (ThisVNetRoot->NodeReferenceCount != 1 &&
3190 !ForceFinalize)
3191 {
3192 return FALSE;
3193 }
3194
3195 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot, &ThisVNetRoot->PrefixEntry.Prefix);
3196
3197 NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
3198 /* If it wasn't finalized yet, do it */
3199 if (!ThisVNetRoot->UpperFinalizationDone)
3200 {
3201 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT);
3202
3203 /* Reference the NetRoot so that it doesn't disappear */
3204 RxReferenceNetRoot(NetRoot);
3205 RxOrphanSrvOpens(ThisVNetRoot);
3206 /* Remove us from the available VNetRoot for NetRoot */
3207 RxRemoveVirtualNetRootFromNetRoot(NetRoot, ThisVNetRoot);
3208 /* Remove extra ref */
3209 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
3210
3211 /* Remove ourselves from prefix table */
3212 RxRemovePrefixTableEntry(PrefixTable, &ThisVNetRoot->PrefixEntry);
3213
3214 /* Finalization done */
3215 ThisVNetRoot->UpperFinalizationDone = TRUE;
3216 }
3217
3218 /* If we're still referenced, don't go any further! */
3219 if (ThisVNetRoot->NodeReferenceCount != 1)
3220 {
3221 return FALSE;
3222 }
3223
3224 /* If there's an associated device, notify mini-rdr */
3225 if (NetRoot->pSrvCall->RxDeviceObject != NULL)
3226 {
3227 NTSTATUS Status;
3228
3229 MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
3230 MRxFinalizeVNetRoot, ((PMRX_V_NET_ROOT)ThisVNetRoot, FALSE));
3231 (void)Status;
3232 }
3233
3234 /* Free parameters */
3235 RxUninitializeVNetRootParameters(ThisVNetRoot->pUserName, ThisVNetRoot->pUserDomainName,
3236 ThisVNetRoot->pPassword, &ThisVNetRoot->Flags);
3237 /* Dereference our NetRoot, we won't reference it anymore */
3238 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld);
3239
3240 /* And free the object! */
3241 RxFreePoolWithTag(ThisVNetRoot, RX_V_NETROOT_POOLTAG);
3242
3243 return TRUE;
3244 }
3245
3246 NTSTATUS
3247 RxFindOrConstructVirtualNetRoot(
3248 IN PRX_CONTEXT RxContext,
3249 IN PUNICODE_STRING CanonicalName,
3250 IN NET_ROOT_TYPE NetRootType,
3251 IN PUNICODE_STRING RemainingName)
3252 {
3253 ULONG Flags;
3254 NTSTATUS Status;
3255 PVOID Container;
3256 BOOLEAN Construct;
3257 PV_NET_ROOT VNetRoot;
3258 RX_CONNECTION_ID ConnectionID;
3259 PRDBSS_DEVICE_OBJECT RxDeviceObject;
3260 LOCK_HOLDING_STATE LockHoldingState;
3261
3262 PAGED_CODE();
3263
3264 RxDeviceObject = RxContext->RxDeviceObject;
3265 ASSERT(RxDeviceObject->Dispatch != NULL);
3266 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH);
3267
3268 /* Ask the mini-rdr for connection ID */
3269 ConnectionID.SessionID = 0;
3270 if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL)
3271 {
3272 Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID);
3273 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED)
3274 {
3275 /* mini-rdr is expected not to fail - unless it's not implemented */
3276 DPRINT1("Failed to initialize connection ID\n");
3277 ASSERT(FALSE);
3278 }
3279 }
3280
3281 RxContext->Create.NetNamePrefixEntry = NULL;
3282
3283 Status = STATUS_MORE_PROCESSING_REQUIRED;
3284 RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE);
3285 LockHoldingState = LHS_SharedLockHeld;
3286 Construct = TRUE;
3287 Flags = 0;
3288
3289 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3290 while (TRUE)
3291 {
3292 PNET_ROOT NetRoot;
3293 PV_NET_ROOT SavedVNetRoot;
3294
3295 /* Look in prefix table */
3296 Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID);
3297 if (Container != NULL)
3298 {
3299 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3300 if (NodeType(Container) != RDBSS_NTC_V_NETROOT)
3301 {
3302 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3303 RxDereferenceSrvCall(Container, LockHoldingState);
3304 }
3305 else
3306 {
3307 VNetRoot = Container;
3308 NetRoot = VNetRoot->NetRoot;
3309
3310 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3311 if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) ||
3312 NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3313 {
3314 Status = STATUS_BAD_NETWORK_PATH;
3315 SavedVNetRoot = NULL;
3316 }
3317 else
3318 {
3319 LUID LogonId;
3320 ULONG SessionId;
3321 PUNICODE_STRING UserName, UserDomain, Password;
3322
3323 /* We can reuse if we use same credentials */
3324 Status = RxInitializeVNetRootParameters(RxContext, &LogonId,
3325 &SessionId, &UserName,
3326 &UserDomain, &Password,
3327 &Flags);
3328 if (NT_SUCCESS(Status))
3329 {
3330 SavedVNetRoot = VNetRoot;
3331 Status = RxCheckVNetRootCredentials(RxContext, VNetRoot,
3332 &LogonId, UserName,
3333 UserDomain, Password,
3334 Flags);
3335 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
3336 {
3337 PLIST_ENTRY ListEntry;
3338
3339 for (ListEntry = NetRoot->VirtualNetRoots.Flink;
3340 ListEntry != &NetRoot->VirtualNetRoots;
3341 ListEntry = ListEntry->Flink)
3342 {
3343 SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry);
3344 Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot,
3345 &LogonId, UserName,
3346 UserDomain, Password,
3347 Flags);
3348 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
3349 {
3350 break;
3351 }
3352 }
3353
3354 if (ListEntry == &NetRoot->VirtualNetRoots)
3355 {
3356 SavedVNetRoot = NULL;
3357 }
3358 }
3359
3360 if (!NT_SUCCESS(Status))
3361 {
3362 SavedVNetRoot = NULL;
3363 }
3364
3365 RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags);
3366 }
3367 }
3368
3369 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3370 if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status))
3371 {
3372 if (SavedVNetRoot == NULL)
3373 {
3374 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3375 }
3376 }
3377 /* Reference VNetRoot we'll keep, and dereference current */
3378 else if (SavedVNetRoot != VNetRoot)
3379 {
3380 RxDereferenceVNetRoot(VNetRoot, LockHoldingState);
3381 if (SavedVNetRoot != NULL)
3382 {
3383 RxReferenceVNetRoot(SavedVNetRoot);
3384 }
3385 }
3386 }
3387
3388 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3389 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
3390 {
3391 Construct = FALSE;
3392 break;
3393 }
3394 }
3395
3396 /* If we're locked exclusive, we won't loop again, it was the second pass */
3397 if (LockHoldingState != LHS_SharedLockHeld)
3398 {
3399 break;
3400 }
3401
3402 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3403 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE))
3404 {
3405 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3406 LockHoldingState = LHS_ExclusiveLockHeld;
3407 break;
3408 }
3409
3410 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3411 RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE);
3412 LockHoldingState = LHS_ExclusiveLockHeld;
3413 }
3414
3415 /* We didn't fail, and didn't find any VNetRoot, construct one */
3416 if (Construct)
3417 {
3418 ASSERT(LockHoldingState == LHS_ExclusiveLockHeld);
3419
3420 Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID);
3421 ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld);
3422
3423 if (Status == STATUS_SUCCESS)
3424 {
3425 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length);
3426 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length);
3427 ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length);
3428
3429 RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length);
3430 RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length;
3431 RemainingName->MaximumLength = RemainingName->Length;
3432
3433 if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE))
3434 {
3435 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot);
3436 }
3437 VNetRoot->Flags |= Flags;
3438 }
3439 }
3440
3441 /* Release the prefix table - caller expects it to be released */
3442 if (LockHoldingState != LHS_LockNotHeld)
3443 {
3444 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable);
3445 }
3446
3447 /* If we failed creating, quit */
3448 if (Status != STATUS_SUCCESS)
3449 {
3450 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status);
3451 return Status;
3452 }
3453
3454 /* Otherwise, wait until the VNetRoot is stable */
3455 DPRINT("Waiting for stable condition for: %p\n", VNetRoot);
3456 RxWaitForStableVNetRoot(VNetRoot, RxContext);
3457 /* It's all good, update the RX_CONTEXT with all our structs */
3458 if (VNetRoot->Condition == Condition_Good)
3459 {
3460 PNET_ROOT NetRoot;
3461
3462 NetRoot = VNetRoot->NetRoot;
3463 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3464 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3465 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall;
3466 }
3467 else
3468 {
3469 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
3470 RxContext->Create.pVNetRoot = NULL;
3471 Status = STATUS_BAD_NETWORK_PATH;
3472 }
3473
3474 return Status;
3475 }
3476
3477 /*
3478 * @implemented
3479 */
3480 NTSTATUS
3481 RxFindOrCreateConnections(
3482 _In_ PRX_CONTEXT RxContext,
3483 _In_ PUNICODE_STRING CanonicalName,
3484 _In_ NET_ROOT_TYPE NetRootType,
3485 _Out_ PUNICODE_STRING LocalNetRootName,
3486 _Out_ PUNICODE_STRING FilePathName,
3487 _Inout_ PLOCK_HOLDING_STATE LockState,
3488 _In_ PRX_CONNECTION_ID RxConnectionId)
3489 {
3490 PVOID Container;
3491 PSRV_CALL SrvCall;
3492 PNET_ROOT NetRoot;
3493 PV_NET_ROOT VNetRoot;
3494 NTSTATUS Status = STATUS_UNSUCCESSFUL;
3495 PRX_PREFIX_TABLE PrefixTable;
3496 UNICODE_STRING RemainingName, NetRootName;
3497
3498 PAGED_CODE();
3499
3500 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3501 RxContext, CanonicalName, NetRootType, LocalNetRootName,
3502 FilePathName, LockState, RxConnectionId);
3503
3504 *FilePathName = *CanonicalName;
3505 LocalNetRootName->Length = 0;
3506 LocalNetRootName->MaximumLength = 0;
3507 LocalNetRootName->Buffer = CanonicalName->Buffer;
3508
3509 /* UNC path, split it */
3510 if (FilePathName->Buffer[1] == ';')
3511 {
3512 BOOLEAN Slash;
3513 USHORT i, Length;
3514
3515 Slash = FALSE;
3516 for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i)
3517 {
3518 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR)
3519 {
3520 Slash = TRUE;
3521 break;
3522 }
3523 }
3524
3525 if (!Slash)
3526 {
3527 return STATUS_OBJECT_NAME_INVALID;
3528 }
3529
3530 FilePathName->Buffer = &FilePathName->Buffer[i];
3531 Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer);
3532 LocalNetRootName->Length = Length;
3533 LocalNetRootName->MaximumLength = Length;
3534 FilePathName->Length -= Length;
3535
3536 DPRINT("CanonicalName: %wZ\n", CanonicalName);
3537 DPRINT(" -> FilePathName: %wZ\n", FilePathName);
3538 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName);
3539 }
3540
3541 Container = NULL;
3542 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable;
3543
3544 _SEH2_TRY
3545 {
3546 RetryLookup:
3547 ASSERT(*LockState != LHS_LockNotHeld);
3548
3549 /* If previous lookup left something, dereference it */
3550 if (Container != NULL)
3551 {
3552 switch (NodeType(Container))
3553 {
3554 case RDBSS_NTC_SRVCALL:
3555 RxDereferenceSrvCall(Container, *LockState);
3556 break;
3557
3558 case RDBSS_NTC_NETROOT:
3559 RxDereferenceNetRoot(Container, *LockState);
3560 break;
3561
3562 case RDBSS_NTC_V_NETROOT:
3563 RxDereferenceVNetRoot(Container, *LockState);
3564 break;
3565
3566 default:
3567 /* Should never happen */
3568 ASSERT(FALSE);
3569 break;
3570 }
3571 }
3572
3573 /* Look for our NetRoot in prefix table */
3574 Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId);
3575 DPRINT("Container %p for path %wZ\n", Container, FilePathName);
3576
3577 while (TRUE)
3578 {
3579 UNICODE_STRING SrvCallName;
3580
3581 SrvCall = NULL;
3582 NetRoot = NULL;
3583 VNetRoot = NULL;
3584
3585 /* Assume we didn't succeed */
3586 RxContext->Create.pVNetRoot = NULL;
3587 RxContext->Create.pNetRoot = NULL;
3588 RxContext->Create.pSrvCall = NULL;
3589 RxContext->Create.Type = NetRootType;
3590
3591 /* If we found something */
3592 if (Container != NULL)
3593 {
3594 /* A VNetRoot */
3595 if (NodeType(Container) == RDBSS_NTC_V_NETROOT)
3596 {
3597 VNetRoot = Container;
3598 /* Use its NetRoot */
3599 NetRoot = VNetRoot->NetRoot;
3600
3601 /* If it's not stable, wait for it to be stable */
3602 if (NetRoot->Condition == Condition_InTransition)
3603 {
3604 RxReleasePrefixTableLock(PrefixTable);
3605 DPRINT("Waiting for stable condition for: %p\n", NetRoot);
3606 RxWaitForStableNetRoot(NetRoot, RxContext);
3607 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3608 *LockState = LHS_ExclusiveLockHeld;
3609
3610 /* Now that's it's ok, retry lookup to find what we want */
3611 if (NetRoot->Condition == Condition_Good)
3612 {
3613 goto RetryLookup;
3614 }
3615 }
3616
3617 /* Is the associated netroot good? */
3618 if (NetRoot->Condition == Condition_Good)
3619 {
3620 SrvCall = (PSRV_CALL)NetRoot->pSrvCall;
3621
3622 /* If it is, and SrvCall as well, then, we have our active connection */
3623 if (SrvCall->Condition == Condition_Good &&
3624 SrvCall->RxDeviceObject == RxContext->RxDeviceObject)
3625 {
3626 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3627 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3628 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3629
3630 Status = STATUS_CONNECTION_ACTIVE;
3631 _SEH2_LEAVE;
3632 }
3633 }
3634
3635 /* If VNetRoot was well constructed, it means the connection is active */
3636 if (VNetRoot->ConstructionStatus == STATUS_SUCCESS)
3637 {
3638 Status = STATUS_CONNECTION_ACTIVE;
3639 }
3640 else
3641 {
3642 Status = VNetRoot->ConstructionStatus;
3643 }
3644
3645 RxDereferenceVNetRoot(VNetRoot, *LockState);
3646 _SEH2_LEAVE;
3647 }
3648 /* Can only be a SrvCall */
3649 else
3650 {
3651 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL);
3652 SrvCall = Container;
3653
3654 /* Wait for the SRV_CALL to be stable */
3655 if (SrvCall->Condition == Condition_InTransition)
3656 {
3657 RxReleasePrefixTableLock(PrefixTable);
3658 DPRINT("Waiting for stable condition for: %p\n", SrvCall);
3659 RxWaitForStableSrvCall(SrvCall, RxContext);
3660 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3661 *LockState = LHS_ExclusiveLockHeld;
3662
3663 /* It went good, loop again to find what we look for */
3664 if (SrvCall->Condition == Condition_Good)
3665 {
3666 goto RetryLookup;
3667 }
3668 }
3669
3670 /* If it's not good... */
3671 if (SrvCall->Condition != Condition_Good)
3672 {
3673 /* But SRV_CALL was well constructed, assume a connection was active */
3674 if (SrvCall->Status == STATUS_SUCCESS)
3675 {
3676 Status = STATUS_CONNECTION_ACTIVE;
3677 }
3678 else
3679 {
3680 Status = SrvCall->Status;
3681 }
3682
3683 RxDereferenceSrvCall(SrvCall, *LockState);
3684 _SEH2_LEAVE;
3685 }
3686 }
3687 }
3688
3689 /* If we found a SRV_CALL not matching our DO, quit */
3690 if (SrvCall != NULL && SrvCall->Condition == Condition_Good &&
3691 SrvCall->RxDeviceObject != RxContext->RxDeviceObject)
3692 {
3693 RxDereferenceSrvCall(SrvCall, *LockState);
3694 Status = STATUS_BAD_NETWORK_NAME;
3695 _SEH2_LEAVE;
3696 }
3697
3698 /* Now, we want exclusive lock */
3699 if (*LockState == LHS_SharedLockHeld)
3700 {
3701 if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE))
3702 {
3703 RxReleasePrefixTableLock(PrefixTable);
3704 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3705 *LockState = LHS_ExclusiveLockHeld;
3706 goto RetryLookup;
3707 }
3708
3709 RxReleasePrefixTableLock(PrefixTable);
3710 *LockState = LHS_ExclusiveLockHeld;
3711 }
3712
3713 ASSERT(*LockState == LHS_ExclusiveLockHeld);
3714
3715 /* If we reach that point, we found something, no need to create something */
3716 if (Container != NULL)
3717 {
3718 break;
3719 }
3720
3721 /* Get the name for the SRV_CALL */
3722 RxExtractServerName(FilePathName, &SrvCallName, NULL);
3723 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName);
3724 /* And create the SRV_CALL */
3725 SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId);
3726 if (SrvCall == NULL)
3727 {
3728 Status = STATUS_INSUFFICIENT_RESOURCES;
3729 _SEH2_LEAVE;
3730 }
3731
3732 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3733 RxReferenceSrvCall(SrvCall);
3734 RxContext->Create.pVNetRoot = NULL;
3735 RxContext->Create.pNetRoot = NULL;
3736 RxContext->Create.pSrvCall = NULL;
3737 RxContext->Create.Type = NetRootType;
3738 Container = SrvCall;
3739
3740 /* Construct SRV_CALL, ie, use mini-rdr */
3741 Status = RxConstructSrvCall(RxContext, SrvCall, LockState);
3742 ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable));
3743 if (Status != STATUS_SUCCESS)
3744 {
3745 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status);
3746 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3747 RxDereferenceSrvCall(SrvCall, *LockState);
3748 RxReleasePrefixTableLock(PrefixTable);
3749 _SEH2_LEAVE;
3750 }
3751
3752 /* Loop again to make use of SRV_CALL stable condition wait */
3753 }
3754
3755 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3756 ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good));
3757 ASSERT(NetRoot == NULL && VNetRoot == NULL);
3758 ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject);
3759
3760 /* Call mini-rdr to get NetRoot name */
3761 SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL);
3762 /* And create the NetRoot with that name */
3763 NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId);
3764 if (NetRoot == NULL)
3765 {
3766 Status = STATUS_INSUFFICIENT_RESOURCES;
3767 _SEH2_LEAVE;
3768 }
3769 NetRoot->Type = NetRootType;
3770
3771 RxDereferenceSrvCall(SrvCall, *LockState);
3772
3773 /* Finally, create the associated VNetRoot */
3774 VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId);
3775 if (VNetRoot == NULL)
3776 {
3777 RxFinalizeNetRoot(NetRoot, TRUE, TRUE);
3778 Status = STATUS_INSUFFICIENT_RESOURCES;
3779 _SEH2_LEAVE;
3780 }
3781 RxReferenceVNetRoot(VNetRoot);
3782
3783 /* We're get closer! */
3784 NetRoot->Condition = Condition_InTransition;
3785 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall;
3786 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot;
3787 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
3788
3789 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3790 Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState);
3791 if (!NT_SUCCESS(Status))
3792 {
3793 RxTransitionVNetRoot(VNetRoot, Condition_Bad);
3794 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition);
3795 RxDereferenceVNetRoot(VNetRoot, *LockState);
3796
3797 RxContext->Create.pNetRoot = NULL;
3798 RxContext->Create.pVNetRoot = NULL;
3799 }
3800 else
3801 {
3802 PIO_STACK_LOCATION Stack;
3803
3804 ASSERT(*LockState == LHS_ExclusiveLockHeld);
3805
3806 Stack = RxContext->CurrentIrpSp;
3807 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION))
3808 {
3809 RxExclusivePrefixTableLockToShared(PrefixTable);
3810 *LockState = LHS_SharedLockHeld;
3811 }
3812 }
3813 }
3814 _SEH2_FINALLY
3815 {
3816 if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE)
3817 {
3818 if (*LockState != LHS_LockNotHeld)
3819 {
3820 RxReleasePrefixTableLock(PrefixTable);
3821 *LockState = LHS_LockNotHeld;
3822 }
3823 }
3824 }
3825 _SEH2_END;
3826
3827 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status);
3828 return Status;
3829 }
3830
3831 /*
3832 * @implemented
3833 */
3834 VOID
3835 NTAPI
3836 RxFinishFcbInitialization(
3837 IN OUT PMRX_FCB Fcb,
3838 IN RX_FILE_TYPE FileType,
3839 IN PFCB_INIT_PACKET InitPacket OPTIONAL)
3840 {
3841 RX_FILE_TYPE OldType;
3842
3843 PAGED_CODE();
3844
3845 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket);
3846
3847 OldType = NodeType(Fcb);
3848 NodeType(Fcb) = FileType;
3849 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
3850 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT)
3851 {
3852 FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3853 }
3854 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
3855 else if (InitPacket != NULL)
3856 {
3857 FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks,
3858 InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart,
3859 InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart,
3860 InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart,
3861 InitPacket->pValidDataLength->QuadPart);
3862 }
3863
3864 if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
3865 FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
3866 {
3867 /* If our FCB newly points to a file, initiliaze everything related */
3868 if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE)
3869
3870 {
3871 if (OldType != RDBSS_NTC_STORAGE_TYPE_FILE)
3872 {
3873 RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo);
3874 FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, RxLockOperationCompletion,
3875 RxUnlockOperation);
3876
3877 ((PFCB)Fcb)->BufferedLocks.List = NULL;
3878 ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0;
3879
3880 Fcb->Header.IsFastIoPossible = FastIoIsQuestionable;
3881 }
3882 }
3883 /* If not a file, validate type */
3884 else
3885 {
3886 ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT);
3887 }
3888 }
3889 }
3890
3891 /*
3892 * @implemented
3893 */
3894 NTSTATUS
3895 RxFinishSrvCallConstruction(
3896 PMRX_SRVCALLDOWN_STRUCTURE Calldown)
3897 {
3898 NTSTATUS Status;
3899 PSRV_CALL SrvCall;
3900 PRX_CONTEXT Context;
3901 RX_BLOCK_CONDITION Condition;
3902 PRX_PREFIX_TABLE PrefixTable;
3903
3904 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown);
3905
3906 SrvCall = (PSRV_CALL)Calldown->SrvCall;
3907 Context = Calldown->RxContext;
3908 PrefixTable = Context->RxDeviceObject->pRxNetNameTable;
3909
3910 /* We have a winner, notify him */
3911 if (Calldown->BestFinisher != NULL)
3912 {
3913 DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName);
3914
3915 ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher);
3916
3917 MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch,
3918 MRxSrvCallWinnerNotify,
3919 ((PMRX_SRV_CALL)SrvCall, TRUE,
3920 Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext));
3921 if (Status != STATUS_SUCCESS)
3922 {
3923 Condition = Condition_Bad;
3924 }
3925 else
3926 {
3927 Condition = Condition_Good;
3928 }
3929 }
3930 /* Otherwise, just fail our SRV_CALL */
3931 else
3932 {
3933 Status = Calldown->CallbackContexts[0].Status;
3934 Condition = Condition_Bad;
3935 }
3936
3937 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
3938 RxTransitionSrvCall(SrvCall, Condition);
3939 RxFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG);
3940
3941 /* If async, finish it here, otherwise, caller has already finished the stuff */
3942 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION))
3943 {
3944 DPRINT("Finishing async call\n");
3945
3946 RxReleasePrefixTableLock(PrefixTable);
3947
3948 /* Make sure we weren't cancelled in-between */
3949 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED))
3950 {
3951 Status = STATUS_CANCELLED;
3952 }
3953
3954 /* In case that was a create, context can be reused */
3955 if (Context->MajorFunction == IRP_MJ_CREATE)
3956 {
3957 RxpPrepareCreateContextForReuse(Context);
3958 }
3959
3960 /* If that's a failure, reset everything and return failure */
3961 if (Status != STATUS_SUCCESS)
3962 {
3963 Context->MajorFunction = Context->CurrentIrpSp->MajorFunction;
3964 if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL)
3965 {
3966 if (Context->Info.Buffer != NULL)
3967 {
3968 RxFreePool(Context->Info.Buffer);
3969 Context->Info.Buffer = NULL;
3970 }
3971 }
3972 Context->CurrentIrp->IoStatus.Information = 0;
3973 Context->CurrentIrp->IoStatus.Status = Status;
3974 RxCompleteRequest(Context, Status);
3975 }
3976 /* Otherwise, call resume routine and done! */
3977 else
3978 {
3979 Status = Context->ResumeRoutine(Context);
3980 if (Status != STATUS_PENDING)
3981 {
3982 RxCompleteRequest(Context, Status);
3983 }
3984
3985 DPRINT("Not completing, pending\n");
3986 }
3987 }
3988
3989 RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld);
3990 return Status;
3991 }
3992
3993 /*
3994 * @implemented
3995 */
3996 VOID
3997 NTAPI
3998 RxFinishSrvCallConstructionDispatcher(
3999 IN PVOID Context)
4000 {
4001 KIRQL OldIrql;
4002 BOOLEAN Direct, KeepLoop;
4003
4004 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context);
4005
4006 /* In case of failure of starting dispatcher, context is not set
4007 * We keep track of it to fail associated SRV_CALL
4008 */
4009 Direct = (Context == NULL);
4010
4011 /* Separated thread, loop forever */
4012 while (TRUE)
4013 {
4014 PLIST_ENTRY ListEntry;
4015 PMRX_SRVCALLDOWN_STRUCTURE Calldown;
4016
4017 /* If there are no SRV_CALL to finalize left, just finish thread */
4018 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
4019 if (IsListEmpty(&RxSrvCalldownList))
4020 {
4021 KeepLoop = FALSE;
4022 RxSrvCallConstructionDispatcherActive = FALSE;
4023 }
4024 /* Otherwise, get the SRV_CALL to finish construction */
4025 else
4026 {
4027 ListEntry = RemoveHeadList(&RxSrvCalldownList);
4028 KeepLoop = TRUE;
4029 }
4030 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
4031
4032 /* Nothing to do */
4033 if (!KeepLoop)
4034 {
4035 break;
4036 }
4037
4038 /* If direct is set, reset the finisher to avoid electing a winner
4039 * and fail SRV_CALL (see upper comment)
4040 */
4041 Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList);
4042 if (Direct)
4043 {
4044 Calldown->BestFinisher = NULL;
4045 }
4046 /* Finish SRV_CALL construction */
4047 RxFinishSrvCallConstruction(Calldown);
4048 }
4049 }
4050
4051 /*
4052 * @implemented
4053 */
4054 NTSTATUS
4055 RxFlushFcbInSystemCache(
4056 IN PFCB Fcb,
4057 IN BOOLEAN SynchronizeWithLazyWriter)
4058 {
4059 IO_STATUS_BLOCK IoStatus;
4060
4061 PAGED_CODE();
4062
4063 /* Deal with Cc */
4064 CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, &IoStatus);
4065 /* If we're asked to sync with LW, do it in case of success */
4066 if (SynchronizeWithLazyWriter && NT_SUCCESS(IoStatus.Status))
4067 {
4068 RxAcquirePagingIoResource((PRX_CONTEXT)NULL, Fcb);
4069 RxReleasePagingIoResource((PRX_CONTEXT)NULL, Fcb);
4070 }
4071
4072 DPRINT("Flushing for FCB %p returns %lx\n", Fcb, IoStatus.Status);
4073 return IoStatus.Status;
4074 }
4075
4076 /*
4077 * @implemented
4078 */
4079 VOID
4080 RxFreeFcbObject(
4081 PVOID Object)
4082 {
4083 PAGED_CODE();
4084
4085 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4086 if (NodeType(Object) == RDBSS_NTC_FOBX || NodeType(Object) == RDBSS_NTC_SRVOPEN)
4087 {
4088 RxFreePoolWithTag(Object, RX_FCB_POOLTAG);
4089 }
4090 /* If that's a FCB... */
4091 else if (NodeTypeIsFcb(Object))
4092 {
4093 PFCB Fcb;
4094 PRDBSS_DEVICE_OBJECT DeviceObject;
4095
4096 Fcb = (PFCB)Object;
4097 DeviceObject = Fcb->RxDeviceObject;
4098
4099 /* Delete per stream contexts */
4100 FsRtlTeardownPerStreamContexts(&Fcb->Header);
4101
4102 SetFlag(Fcb->Header.Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH);
4103
4104 /* If there was a non-paged FCB allocated, free it */
4105 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
4106 {
4107 RxFreePoolWithTag(Fcb->NonPaged, RX_NONPAGEDFCB_POOLTAG);
4108 }
4109
4110 /* Free the FCB */
4111 RxFreePool(Fcb);
4112
4113 /* Update statistics */
4114 InterlockedDecrement(&RxNumberOfActiveFcbs);
4115 InterlockedDecrement((volatile long *)&DeviceObject->NumberOfActiveFcbs);
4116 }
4117 }
4118
4119 /*
4120 * @implemented
4121 */
4122 VOID
4123 RxFreeObject(
4124 PVOID pObject)
4125 {
4126 PAGED_CODE();
4127
4128 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4129 if (NodeType(pObject) == RDBSS_NTC_SRVCALL)
4130 {
4131 PSRV_CALL SrvCall;
4132 PRDBSS_DEVICE_OBJECT DeviceObject;
4133
4134 SrvCall = (PSRV_CALL)pObject;
4135 DeviceObject = SrvCall->RxDeviceObject;
4136 if (DeviceObject != NULL)
4137 {
4138 if (!BooleanFlagOn(DeviceObject->Dispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION))
4139 {
4140 ASSERT(SrvCall->Context == NULL);
4141 }
4142
4143 ASSERT(SrvCall->Context2 == NULL);
4144
4145 SrvCall->RxDeviceObject = NULL;
4146 }
4147 }
4148 else if (NodeType(pObject) == RDBSS_NTC_NETROOT)
4149 {
4150 PNET_ROOT NetRoot;
4151
4152 NetRoot = (PNET_ROOT)pObject;
4153 NetRoot->pSrvCall = NULL;
4154 NetRoot->NodeTypeCode = NodeType(pObject) | 0xF000;
4155 }
4156
4157 /* And just free the object */
4158 RxFreePool(pObject);
4159 }
4160
4161 /*
4162 * @implemented
4163 */
4164 VOID
4165 RxGatherRequestsForSrvOpen(
4166 IN OUT PSRV_CALL SrvCall,
4167 IN PSRV_OPEN SrvOpen,
4168 IN OUT PLIST_ENTRY RequestsListHead)
4169 {
4170 KIRQL OldIrql;
4171 LIST_ENTRY Discarded, *Entry;
4172 PCHANGE_BUFFERING_STATE_REQUEST Request;
4173
4174 /* Dispatch any pending operation first */
4175 RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &Discarded);
4176
4177 /* Then, get any entry related to our key and SRV_OPEN */
4178 KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql);
4179 Entry = SrvCall->BufferingManager.HandlerList.Flink;
4180 while (Entry != &SrvCall->BufferingManager.HandlerList)
4181 {
4182 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
4183 Entry = Entry->Flink;
4184 if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
4185 {
4186 RemoveEntryList(&Request->ListEntry);
4187 InsertTailList(RequestsListHead, &Request->ListEntry);
4188 }
4189 }
4190 KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql);
4191
4192 /* Perform the same search in the last change list */
4193 Entry = SrvCall->BufferingManager.LastChanceHandlerList.Flink;
4194 while (Entry != &SrvCall->BufferingManager.LastChanceHandlerList)
4195 {
4196 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
4197 Entry = Entry->Flink;
4198 if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen)
4199 {
4200 RemoveEntryList(&Request->ListEntry);
4201 InsertTailList(RequestsListHead, &Request->ListEntry);
4202 }
4203 }
4204
4205 /* Discard the discarded requests */
4206 RxpDiscardChangeBufferingStateRequests(&Discarded);
4207 }
4208
4209 /*
4210 * @implemented
4211 */
4212 PRDBSS_DEVICE_OBJECT
4213 RxGetDeviceObjectOfInstance(
4214 PVOID Instance)
4215 {
4216 NODE_TYPE_CODE NodeType;
4217 PRDBSS_DEVICE_OBJECT DeviceObject;
4218
4219 PAGED_CODE();
4220
4221 /* We only handle a few object types */
4222 NodeType = NodeType(Instance);
4223 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
4224 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) || (NodeType == RDBSS_NTC_FOBX));
4225
4226 /* Get the device object depending on the object */
4227 switch (NodeType)
4228 {
4229 case RDBSS_NTC_FOBX:
4230 {
4231 PFOBX Fobx;
4232
4233 Fobx = (PFOBX)Instance;
4234 DeviceObject = Fobx->RxDeviceObject;
4235 break;
4236 }
4237
4238 case RDBSS_NTC_SRVCALL:
4239 {
4240 PSRV_CALL SrvCall;
4241
4242 SrvCall = (PSRV_CALL)Instance;
4243 DeviceObject = SrvCall->RxDeviceObject;
4244 break;
4245 }
4246
4247 case RDBSS_NTC_NETROOT:
4248 {
4249 PNET_ROOT NetRoot;
4250
4251 NetRoot = (PNET_ROOT)Instance;
4252 DeviceObject = NetRoot->pSrvCall->RxDeviceObject;
4253 break;
4254 }
4255
4256 case RDBSS_NTC_V_NETROOT:
4257 {
4258 PV_NET_ROOT VNetRoot;
4259
4260 VNetRoot = (PV_NET_ROOT)Instance;
4261 DeviceObject = VNetRoot->pNetRoot->pSrvCall->RxDeviceObject;
4262 break;
4263 }
4264
4265 case RDBSS_NTC_SRVOPEN:
4266 {
4267 PSRV_OPEN SrvOpen;
4268
4269 SrvOpen = (PSRV_OPEN)Instance;
4270 DeviceObject = ((PFCB)SrvOpen->pFcb)->RxDeviceObject;
4271 break;
4272 }
4273
4274 default:
4275 DeviceObject = NULL;
4276 break;
4277 }
4278
4279 /* Job done */
4280 return DeviceObject;
4281 }
4282
4283 /*
4284 * @implemented
4285 */
4286 VOID
4287 RxGetFileSizeWithLock(
4288 IN PFCB Fcb,
4289 OUT PLONGLONG FileSize)
4290 {
4291 PAGED_CODE();
4292
4293 *FileSize = Fcb->Header.FileSize.QuadPart;
4294 }
4295
4296 /*
4297 * @implemented
4298 */
4299 PEPROCESS
4300 NTAPI
4301 RxGetRDBSSProcess(
4302 VOID)
4303 {
4304 return RxData.OurProcess;
4305 }
4306
4307 /*
4308 * @implemented
4309 */
4310 NTSTATUS
4311 RxInitializeBufferingManager(
4312 PSRV_CALL SrvCall)
4313 {
4314 KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock);
4315 InitializeListHead(&SrvCall->BufferingManager.DispatcherList);
4316 InitializeListHead(&SrvCall->BufferingManager.HandlerList);
4317 InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList);
4318 SrvCall->BufferingManager.DispatcherActive = FALSE;
4319 SrvCall->BufferingManager.HandlerInactive = FALSE;
4320 SrvCall->BufferingManager.LastChanceHandlerActive = FALSE;
4321 SrvCall->BufferingManager.NumberOfOutstandingOpens = 0;
4322 InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]);
4323 ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex);
4324
4325 return STATUS_SUCCESS;
4326 }
4327
4328 /*
4329 * @implemented
4330 */
4331 VOID
4332 NTAPI
4333 RxInitializeContext(
4334 IN PIRP Irp,
4335 IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
4336 IN ULONG InitialContextFlags,
4337 IN OUT PRX_CONTEXT RxContext)
4338 {
4339 PIO_STACK_LOCATION Stack;
4340
4341 /* Initialize our various fields */
4342 RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
4343 RxContext->NodeByteSize = sizeof(RX_CONTEXT);
4344 RxContext->ReferenceCount = 1;
4345 RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1);
4346 RxContext->RxDeviceObject = RxDeviceObject;
4347 KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE);
4348 RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
4349 InitializeListHead(&RxContext->BlockedOperations);
4350 RxContext->MRxCancelRoutine = NULL;
4351 RxContext->ResumeRoutine = NULL;
4352 RxContext->Flags |= InitialContextFlags;
4353 RxContext->CurrentIrp = Irp;
4354 RxContext->LastExecutionThread = PsGetCurrentThread();
4355 RxContext->OriginalThread = RxContext->LastExecutionThread;
4356
4357 /* If've got no IRP, mark RX_CONTEXT */
4358 if (Irp == NULL)
4359 {
4360 RxContext->CurrentIrpSp = NULL;
4361 RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
4362 RxContext->MinorFunction = 0;
4363 }
4364 else
4365 {
4366 /* Otherwise, first determine whether we are performing async operation */
4367 Stack = IoGetCurrentIrpStackLocation(Irp);
4368 if (Stack->FileObject != NULL)
4369 {
4370 PFCB Fcb;
4371
4372 Fcb = Stack->FileObject->FsContext;
4373 if (!IoIsOperationSynchronous(Irp) ||
4374 ((Fcb != NULL && NodeTypeIsFcb(Fcb)) &&
4375 (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
4376 (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE))))
4377 {
4378 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4379 }
4380 }
4381
4382 if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)
4383 {
4384 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4385 }
4386 if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
4387 {
4388 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION;
4389 }
4390
4391 /* Set proper flags if TopLevl IRP/Device */
4392 if (!RxIsThisTheTopLevelIrp(Irp))
4393 {
4394 RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL;
4395 }
4396 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject)
4397 {
4398 RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL;
4399 }
4400
4401 /* Copy stack information */
4402 RxContext->MajorFunction = Stack->MajorFunction;
4403 RxContext->MinorFunction = Stack->MinorFunction;
4404 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
4405 RxContext->CurrentIrpSp = Stack;
4406
4407 /* If we have a FO associated, learn for more */
4408 if (Stack->FileObject != NULL)
4409 {
4410 PFCB Fcb;
4411 PFOBX Fobx;
4412
4413 /* Get the FCB and CCB (FOBX) */
4414 Fcb = Stack->FileObject->FsContext;
4415 Fobx = Stack->FileObject->FsContext2;
4416 RxContext->pFcb = (PMRX_FCB)Fcb;
4417 if (Fcb != NULL && NodeTypeIsFcb(Fcb))
4418 {
4419 RxContext->NonPagedFcb = Fcb->NonPaged;
4420 }
4421
4422 /* We have a FOBX, this not a DFS opening, keep track of it */
4423 if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))
4424 {
4425 RxContext->pFobx = (PMRX_FOBX)Fobx;
4426 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
4427 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
4428 {
4429 RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber);
4430 }
4431 }
4432 else
4433 {
4434 RxContext->pFobx = NULL;
4435 }
4436
4437 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4438 if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY &&
4439 Fobx != NULL)
4440 {
4441 PV_NET_ROOT VNetRoot = NULL;
4442
4443 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX)
4444 {
4445 VNetRoot = Fcb->VNetRoot;
4446 }
4447 else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT)
4448 {
4449 VNetRoot = (PV_NET_ROOT)Fobx;
4450 }
4451
4452 if (VNetRoot != NULL)
4453 {
4454 RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot;
4455 }
4456 }
4457
4458 /* Remember if that's a write through file */
4459 RxContext->RealDevice = Stack->FileObject->DeviceObject;
4460 if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH))
4461 {
4462 RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH;
4463 }
4464 }
4465 }
4466
4467 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL)
4468 {
4469 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4470 RxContext, RxContext->MinorFunction, Irp,
4471 PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx,
4472 RxContext->SerialNumber);
4473 }
4474 }
4475
4476 /*
4477 * @implemented
4478 */
4479 NTSTATUS
4480 NTAPI
4481 RxInitializeDispatcher(
4482 VOID)
4483 {
4484 NTSTATUS Status;
4485 HANDLE ThreadHandle;
4486
4487 PAGED_CODE();
4488
4489 RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
4490 RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL;
4491
4492 /* Set appropriate timeouts: 10s & 60s */
4493 RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4494 RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4495 RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10;
4496 RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10;
4497
4498 RxDispatcher.NumberOfProcessors = 1;
4499 RxDispatcher.OwnerProcess = IoGetCurrentProcess();
4500 RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues;
4501
4502 /* Initialize our dispatchers */
4503 Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher);
4504 if (!NT_SUCCESS(Status))
4505 {
4506 return Status;
4507 }
4508
4509 Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject);
4510 if (!NT_SUCCESS(Status))
4511 {
4512 return Status;
4513 }
4514
4515 /* And start them */
4516 RxDispatcher.State = RxDispatcherActive;
4517 InitializeListHead(&RxDispatcher.SpinUpRequests);
4518 KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock);
4519 KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0);
4520 KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0);
4521 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL,
4522 NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher);
4523 if (NT_SUCCESS(Status))
4524 {
4525 ZwClose(ThreadHandle);
4526 }
4527
4528 return Status;
4529 }
4530
4531 /*
4532 * @implemented
4533 */
4534 VOID
4535 RxInitializeFcbTable(
4536 IN OUT PRX_FCB_TABLE FcbTable,
4537 IN BOOLEAN CaseInsensitiveMatch)
4538 {
4539 USHORT i;
4540
4541 PAGED_CODE();
4542
4543 FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE;
4544 FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE);
4545
4546 ExInitializeResourceLite(&FcbTable->TableLock);
4547 FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
4548 FcbTable->Version = 0;
4549 FcbTable->TableEntryForNull = NULL;
4550
4551 FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS;
4552 for (i = 0; i < FcbTable->NumberOfBuckets; ++i)
4553 {
4554 InitializeListHead(&FcbTable->HashBuckets[i]);
4555 }
4556
4557 FcbTable->Lookups = 0;
4558 FcbTable->FailedLookups = 0;
4559 FcbTable->Compares = 0;
4560 }
4561
4562 /*
4563 * @implemented
4564 */
4565 VOID
4566 NTAPI
4567 RxInitializeLowIoContext(
4568 OUT PLOWIO_CONTEXT LowIoContext,
4569 IN ULONG Operation)
4570 {
4571 PRX_CONTEXT RxContext;
4572 PIO_STACK_LOCATION Stack;
4573
4574 PAGED_CODE();
4575
4576 RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext);
4577 ASSERT(LowIoContext == &RxContext->LowIoContext);
4578
4579 Stack = RxContext->CurrentIrpSp;
4580
4581 KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
4582 RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread();
4583 RxContext->LowIoContext.Operation = Operation;
4584
4585 switch (Operation)
4586 {
4587 case LOWIO_OP_READ:
4588 case LOWIO_OP_WRITE:
4589 /* In case of RW, set a canary, to make sure these fields are properly set
4590 * they will be asserted when lowio request will be submit to mini-rdr
4591 * See LowIoSubmit()
4592 */
4593 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE;
4594 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE;
4595 RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key;
4596
4597 /* Keep track of paging IOs */
4598 if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO))
4599 {
4600 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO;
4601 }
4602 else
4603 {
4604 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0;
4605 }
4606
4607 break;
4608
4609 case LOWIO_OP_FSCTL:
4610 case LOWIO_OP_IOCTL:
4611 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4612 RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0;
4613 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0;
4614 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL;
4615 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0;
4616 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
4617 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0;
4618 break;
4619
4620 /* Nothing to do for these */
4621 case LOWIO_OP_SHAREDLOCK:
4622 case LOWIO_OP_EXCLUSIVELOCK:
4623 case LOWIO_OP_UNLOCK:
4624 case LOWIO_OP_UNLOCK_MULTIPLE:
4625 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
4626 case LOWIO_OP_CLEAROUT:
4627 break;
4628
4629 default:
4630 /* Should never happen */
4631 ASSERT(FALSE);
4632 break;
4633 }
4634 }
4635
4636 /*
4637 * @implemented
4638 */
4639 VOID
4640 RxInitializeLowIoPerFcbInfo(
4641 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo)
4642 {
4643 PAGED_CODE();
4644
4645 InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding);
4646 InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding);
4647 }
4648
4649 /*
4650 * @implemented
4651 */
4652 NTSTATUS
4653 RxInitializeMRxDispatcher(
4654 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject)
4655 {
4656 PAGED_CODE();
4657
4658 pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0;
4659 pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL;
4660
4661 return STATUS_SUCCESS;
4662 }
4663
4664 /*
4665 * @implemented
4666 */
4667 VOID
4668 RxInitializePrefixTable(
4669 IN OUT PRX_PREFIX_TABLE ThisTable,
4670 IN ULONG TableSize OPTIONAL,
4671 IN BOOLEAN CaseInsensitiveMatch)
4672 {
4673 PAGED_CODE();
4674
4675 if (TableSize == 0)
4676 {
4677 TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH;
4678 }
4679
4680 ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE;
4681 ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE);
4682 InitializeListHead(&ThisTable->MemberQueue);
4683 ThisTable->Version = 0;
4684 ThisTable->TableEntryForNull = NULL;
4685 ThisTable->IsNetNameTable = FALSE;
4686 ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch;
4687 ThisTable->TableSize = TableSize;
4688
4689 if (TableSize > 0)
4690 {
4691 USHORT i;
4692
4693 for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i)
4694 {
4695 InitializeListHead(&ThisTable->HashBuckets[i]);
4696 }
4697 }
4698 }
4699
4700 /*
4701 * @implemented
4702 */
4703 VOID
4704 RxInitializePurgeSyncronizationContext(
4705 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext)
4706 {
4707 PAGED_CODE();
4708
4709 InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion);
4710 PurgeSyncronizationContext->PurgeInProgress = FALSE;
4711 }
4712
4713 NTSTATUS
4714 RxInitializeSrvCallParameters(
4715 IN PRX_CONTEXT RxContext,
4716 IN OUT PSRV_CALL SrvCall)
4717 {
4718 PAGED_CODE();
4719
4720 SrvCall->pPrincipalName = NULL;
4721
4722 /* We only have stuff to initialize for file opening from DFS */
4723 if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0)
4724 {
4725 return STATUS_SUCCESS;
4726 }
4727
4728 ASSERT(RxContext->Create.EaBuffer != NULL);
4729
4730 UNIMPLEMENTED;
4731 return STATUS_NOT_IMPLEMENTED;
4732 }
4733
4734 /*
4735 * @implemented
4736 */
4737 NTSTATUS
4738 NTAPI
4739 RxInitializeRxTimer(
4740 VOID)
4741 {
4742 PAGED_CODE();
4743
4744 RxTimerInterval.QuadPart = -550000;
4745 KeInitializeSpinLock(&RxTimerLock);
4746 InitializeListHead(&RxTimerQueueHead);
4747 InitializeListHead(&RxRecurrentWorkItemsList);
4748 KeInitializeDpc(&RxTimerDpc, RxTimerDispatch, NULL);
4749 KeInitializeTimer(&RxTimer);
4750 RxTimerTickCount = 0;
4751
4752 return STATUS_SUCCESS;
4753 }
4754
4755 NTSTATUS
4756 RxInitializeVNetRootParameters(
4757 PRX_CONTEXT RxContext,
4758 OUT LUID *LogonId,
4759 OUT PULONG SessionId,
4760 OUT PUNICODE_STRING *UserNamePtr,
4761 OUT PUNICODE_STRING *UserDomainNamePtr,
4762 OUT PUNICODE_STRING *PasswordPtr,
4763 OUT PULONG Flags)
4764 {
4765 NTSTATUS Status;
4766 PACCESS_TOKEN Token;
4767
4768 PAGED_CODE();
4769
4770 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext,
4771 LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags);
4772
4773 *UserNamePtr = NULL;
4774 *UserDomainNamePtr = NULL;
4775 *PasswordPtr = NULL;
4776 /* By default, that's not CSC instance */
4777 *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
4778
4779 Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext);
4780 if (SeTokenIsRestricted(Token))
4781 {
4782 return STATUS_ACCESS_DENIED;
4783 }
4784
4785 /* Get LogonId */
4786 Status = SeQueryAuthenticationIdToken(Token, LogonId);
4787 if (!NT_SUCCESS(Status))
4788 {
4789 return Status;
4790 }
4791
4792 /* And SessionId */
4793 Status = SeQuerySessionIdToken(Token, SessionId);
4794 if (!NT_SUCCESS(Status))
4795 {
4796 return Status;
4797 }
4798
4799 if (RxContext->Create.UserName.Buffer != NULL)
4800 {
4801 UNIMPLEMENTED;
4802 Status = STATUS_NOT_IMPLEMENTED;
4803 goto Leave;
4804 }
4805
4806 /* Deal with connection credentials */
4807 if (RxContext->Create.UserDomainName.Buffer != NULL)
4808 {
4809 UNIMPLEMENTED;
4810 Status = STATUS_NOT_IMPLEMENTED;
4811 goto Leave;
4812 }
4813
4814 if (RxContext->Create.Password.Buffer != NULL)
4815 {
4816 UNIMPLEMENTED;
4817 Status = STATUS_NOT_IMPLEMENTED;
4818 goto Leave;
4819 }
4820
4821 Leave:
4822 if (NT_SUCCESS(Status))
4823 {
4824 /* If that's a CSC instance, mark it as such */
4825 if (RxIsThisACscAgentOpen(RxContext))
4826 {
4827 *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE;
4828 }
4829 return Status;
4830 }
4831
4832 return Status;
4833 }
4834
4835 /*
4836 * @implemented
4837 */
4838 VOID
4839 RxInitializeWorkQueue(
4840 PRX_WORK_QUEUE WorkQueue,
4841 WORK_QUEUE_TYPE WorkQueueType,
4842 ULONG MaximumNumberOfWorkerThreads,
4843 ULONG MinimumNumberOfWorkerThreads)
4844 {
4845 PAGED_CODE();
4846
4847 WorkQueue->Type = WorkQueueType;
4848 WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads;
4849 WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads;
4850
4851 WorkQueue->State = RxWorkQueueActive;
4852 WorkQueue->SpinUpRequestPending = FALSE;
4853 WorkQueue->pRundownContext = NULL;
4854 WorkQueue->NumberOfWorkItemsDispatched = 0;
4855 WorkQueue->NumberOfWorkItemsToBeDispatched = 0;
4856 WorkQueue->CumulativeQueueLength = 0;
4857 WorkQueue->NumberOfSpinUpRequests = 0;
4858 WorkQueue->NumberOfActiveWorkerThreads = 0;
4859 WorkQueue->NumberOfIdleWorkerThreads = 0;
4860 WorkQueue->NumberOfFailedSpinUpRequests = 0;
4861 WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0;
4862 WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL;
4863 WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL;
4864 WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL;
4865 WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL;
4866 WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL;
4867 WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL;
4868 WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL;
4869 WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL;
4870 WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL;
4871 WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL;
4872 WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL;
4873 WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL;
4874
4875 KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads);
4876 KeInitializeSpinLock(&WorkQueue->SpinLock);
4877 }
4878
4879 /*
4880 * @implemented
4881 */
4882 NTSTATUS
4883 RxInitializeWorkQueueDispatcher(
4884 PRX_WORK_QUEUE_DISPATCHER Dispatcher)
4885 {
4886 NTSTATUS Status;
4887 ULONG MaximumNumberOfWorkerThreads;
4888
4889 PAGED_CODE();
4890
4891 /* Number of threads will depend on system capacity */
4892 if (MmQuerySystemSize() != MmLargeSystem)
4893 {
4894 MaximumNumberOfWorkerThreads = 5;
4895 }
4896 else
4897 {
4898 MaximumNumberOfWorkerThreads = 10;
4899 }
4900
4901 /* Initialize the work queues */
4902 RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue,
4903 MaximumNumberOfWorkerThreads, 1);
4904 RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1);
4905 RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1);
4906
4907 /* And start the worker threads */
4908 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue],
4909 RxBootstrapWorkerThreadDispatcher,
4910 &Dispatcher->WorkQueue[HyperCriticalWorkQueue]);
4911 if (!NT_SUCCESS(Status))
4912 {
4913 return Status;
4914 }
4915
4916 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue],
4917 RxBootstrapWorkerThreadDispatcher,
4918 &Dispatcher->WorkQueue[CriticalWorkQueue]);
4919 if (!NT_SUCCESS(Status))
4920 {
4921 return Status;
4922 }
4923
4924 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue],
4925 RxBootstrapWorkerThreadDispatcher,
4926 &Dispatcher->WorkQueue[DelayedWorkQueue]);
4927 return Status;
4928 }
4929
4930 /*
4931 * @implemented
4932 */
4933 VOID
4934 RxInitiateSrvOpenKeyAssociation(
4935 IN OUT PSRV_OPEN SrvOpen)
4936 {
4937 PRX_BUFFERING_MANAGER BufferingManager;
4938
4939 PAGED_CODE();
4940
4941 SrvOpen->Key = NULL;
4942
4943 /* Just keep track of the opening request */
4944 BufferingManager = &((PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall)->BufferingManager;
4945 InterlockedIncrement(&BufferingManager->NumberOfOutstandingOpens);
4946
4947 InitializeListHead(&SrvOpen->SrvOpenKeyList);
4948 }
4949
4950 /*
4951 * @implemented
4952 */
4953 NTSTATUS
4954 RxInsertWorkQueueItem(
4955 PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
4956 WORK_QUEUE_TYPE WorkQueueType,
4957 PRX_WORK_QUEUE_ITEM WorkQueueItem)
4958 {
4959 KIRQL OldIrql;
4960 NTSTATUS Status;
4961 BOOLEAN SpinUpThreads;
4962 PRX_WORK_QUEUE WorkQueue;
4963
4964 /* No dispatcher, nothing to insert */
4965 if (RxDispatcher.State != RxDispatcherActive)
4966 {
4967 return STATUS_UNSUCCESSFUL;
4968 }
4969
4970 /* Get the work queue */
4971 WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType];
4972
4973 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
4974 /* Only insert if the work queue is in decent state */
4975 if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL)
4976 {
4977 Status = STATUS_UNSUCCESSFUL;
4978 }
4979 else
4980 {
4981 SpinUpThreads = FALSE;
4982 WorkQueueItem->pDeviceObject = pMRxDeviceObject;
4983 InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads);
4984 WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched;
4985 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
4986
4987 /* If required (and possible!), spin up a new worker thread */
4988 if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched &&
4989 WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads &&
4990 !WorkQueue->SpinUpRequestPending)
4991 {
4992 WorkQueue->SpinUpRequestPending = TRUE;
4993 SpinUpThreads = TRUE;
4994 }
4995
4996 Status = STATUS_SUCCESS;
4997 }
4998 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
4999
5000 /* If we failed, return and still not insert item */
5001 if (!NT_SUCCESS(Status))
5002 {
5003 return Status;
5004 }
5005
5006 /* All fine, insert the item */
5007 KeInsertQueue(&WorkQueue->Queue, &WorkQueueItem->List);
5008
5009 /* And start a new worker thread if needed */
5010 if (SpinUpThreads)
5011 {
5012 RxSpinUpWorkerThreads(WorkQueue);
5013 }
5014
5015 return Status;
5016 }
5017
5018 BOOLEAN
5019 RxIsThisACscAgentOpen(
5020 IN PRX_CONTEXT RxContext)
5021 {
5022 BOOLEAN CscAgent;
5023
5024 CscAgent = FALSE;
5025
5026 /* Client Side Caching is DFS stuff - we don't support it */
5027 if (RxContext->Create.EaLength != 0)
5028 {
5029 UNIMPLEMENTED;
5030 }
5031
5032 if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL &&
5033 ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA)
5034 {
5035 CscAgent = TRUE;
5036 }
5037
5038 return CscAgent;
5039 }
5040
5041 VOID
5042 RxLockUserBuffer(
5043 IN PRX_CONTEXT RxContext,
5044 IN LOCK_OPERATION Operation,
5045 IN ULONG BufferLength)
5046 {
5047 PIRP Irp;
5048 PMDL Mdl = NULL;
5049
5050 PAGED_CODE();
5051
5052 _SEH2_TRY
5053 {
5054 Irp = RxContext->CurrentIrp;
5055 /* If we already have a MDL, make sure it's locked */
5056 if (Irp->MdlAddress != NULL)
5057 {
5058 ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress));
5059 }
5060 else
5061 {
5062 /* That likely means the driver asks for buffered IOs - we don't support it! */
5063 ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION));
5064
5065 /* If we have a real length */
5066 if (BufferLength > 0)
5067 {
5068 /* Allocate a MDL and lock it */
5069 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp);
5070 if (Mdl == NULL)
5071 {
5072 RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES;
5073 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
5074 }
5075
5076 MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation);
5077 }
5078 }
5079 }
5080 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5081 {
5082 NTSTATUS Status;
5083
5084 Status = _SEH2_GetExceptionCode();
5085
5086 /* Free the possible MDL we have allocated */
5087 IoFreeMdl(Mdl);
5088 Irp->MdlAddress = NULL;
5089
5090 RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT;
5091
5092 /* Fix status */
5093 if (!FsRtlIsNtstatusExpected(Status))
5094 {
5095 Status = STATUS_INVALID_USER_BUFFER;
5096 }
5097
5098 RxContext->IoStatusBlock.Status = Status;
5099 ExRaiseStatus(Status);
5100 }
5101 _SEH2_END;
5102 }
5103
5104 /*
5105 * @implemented
5106 */
5107 NTSTATUS
5108 RxLowIoCompletionTail(
5109 IN PRX_CONTEXT RxContext)
5110 {
5111 NTSTATUS Status;
5112 USHORT Operation;
5113
5114 PAGED_CODE();
5115
5116 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext);
5117
5118 /* Only continue if we're at APC_LEVEL or lower */
5119 if (RxShouldPostCompletion() &&
5120 !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL))
5121 {
5122 return STATUS_MORE_PROCESSING_REQUIRED;
5123 }
5124
5125 /* Call the completion routine */
5126 DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine);
5127 Status = RxContext->LowIoContext.CompletionRoutine(RxContext);
5128 if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY)
5129 {
5130 return Status;
5131 }
5132
5133 /* If it was a RW operation, for a paging file ... */
5134 Operation = RxContext->LowIoContext.Operation;
5135 if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE)
5136 {
5137 /* Remove ourselves from the list and resume operations */
5138 if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
5139 {
5140 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5141 RemoveEntryList(&RxContext->RxContextSerializationQLinks);
5142 RxContext->RxContextSerializationQLinks.Flink = NULL;
5143 RxContext->RxContextSerializationQLinks.Blink = NULL;
5144 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5145 RxResumeBlockedOperations_ALL(RxContext);
5146 }
5147 }
5148 else
5149 {
5150 /* Sanity check: we had known operation */
5151 ASSERT(Operation < LOWIO_OP_MAXIMUM);
5152 }
5153
5154 /* If not sync operation, complete now. Otherwise, caller has already completed */
5155 if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
5156 {
5157 RxCompleteRequest(RxContext, Status);
5158 }
5159
5160 DPRINT("Status: %x\n", Status);
5161 return Status;
5162 }
5163
5164 /*
5165 * @implemented
5166 */
5167 NTSTATUS
5168 NTAPI
5169 RxLowIoPopulateFsctlInfo(
5170 IN PRX_CONTEXT RxContext)
5171 {
5172 PMDL Mdl;
5173 PIRP Irp;
5174 UCHAR Method;
5175 PIO_STACK_LOCATION Stack;
5176
5177 PAGED_CODE();
5178
5179 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext);
5180
5181 Irp = RxContext->CurrentIrp;
5182 Stack = RxContext->CurrentIrpSp;
5183
5184 /* Copy stack parameters */
5185 RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
5186 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength;
5187 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength;
5188 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction;
5189 Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode);
5190
5191 /* Same buffer in case of buffered */
5192 if (Method == METHOD_BUFFERED)
5193 {
5194 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
5195 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer;
5196
5197 return STATUS_SUCCESS;
5198 }
5199
5200 /* Two buffers for neither */
5201 if (Method == METHOD_NEITHER)
5202 {
5203 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer;
5204 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer;
5205
5206 return STATUS_SUCCESS;
5207 }
5208
5209 /* Only IN/OUT remain */
5210 ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT);
5211
5212 /* Use system buffer for input */
5213 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer;
5214 /* And MDL for output */
5215 Mdl = Irp->MdlAddress;
5216 if (Mdl != NULL)
5217 {
5218 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
5219 if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL)
5220 {
5221 return STATUS_INSUFFICIENT_RESOURCES;
5222 }
5223 }
5224 else
5225 {
5226 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL;
5227 }
5228
5229 return STATUS_SUCCESS;
5230 }
5231
5232 NTSTATUS
5233 NTAPI
5234 RxLowIoSubmit(
5235 IN PRX_CONTEXT RxContext,
5236 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine)
5237 {
5238 NTSTATUS Status;
5239 USHORT Operation;
5240 BOOLEAN Synchronous;
5241 PLOWIO_CONTEXT LowIoContext;
5242
5243 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine);
5244
5245 PAGED_CODE();
5246
5247 LowIoContext = &RxContext->LowIoContext;
5248 Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
5249
5250 LowIoContext->CompletionRoutine = CompletionRoutine;
5251
5252 Status = STATUS_SUCCESS;
5253 Operation = LowIoContext->Operation;
5254 switch (Operation)
5255 {
5256 case LOWIO_OP_READ:
5257 case LOWIO_OP_WRITE:
5258 /* Check that the parameters were properly set by caller
5259 * See comment in RxInitializeLowIoContext()
5260 */
5261 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE);
5262 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE);
5263
5264 /* Lock the buffer */
5265 RxLockUserBuffer(RxContext,
5266 (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess),
5267 LowIoContext->ParamsFor.ReadWrite.ByteCount);
5268 if (RxNewMapUserBuffer(RxContext) == NULL)
5269 {
5270 return STATUS_INSUFFICIENT_RESOURCES;
5271 }
5272 LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress;
5273
5274 /* If that's a paging IO, initialize serial operation */
5275 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO))
5276 {
5277 PFCB Fcb;
5278
5279 Fcb = (PFCB)RxContext->pFcb;
5280
5281 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5282 RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex;
5283 if (Operation == LOWIO_OP_READ)
5284 {
5285 InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks);
5286 }
5287 else
5288 {
5289 InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks);
5290 }
5291
5292 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex);
5293 }
5294
5295 break;
5296
5297 case LOWIO_OP_FSCTL:
5298 case LOWIO_OP_IOCTL:
5299 /* Set FSCTL/IOCTL parameters */
5300 Status = RxLowIoPopulateFsctlInfo(RxContext);
5301 /* Check whether we're consistent: a length means a buffer */
5302 if (NT_SUCCESS(Status))
5303 {
5304 if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 &&
5305 LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
5306 (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 &&
5307 LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL))
5308 {
5309 Status = STATUS_INVALID_PARAMETER;
5310 }
5311 }
5312 break;
5313
5314 /* Nothing to do */
5315 case LOWIO_OP_SHAREDLOCK:
5316 case LOWIO_OP_EXCLUSIVELOCK:
5317 case LOWIO_OP_UNLOCK:
5318 case LOWIO_OP_UNLOCK_MULTIPLE:
5319 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY:
5320 case LOWIO_OP_CLEAROUT:
5321 break;
5322
5323 default:
5324 ASSERT(FALSE);
5325 Status = STATUS_INVALID_PARAMETER;
5326 break;
5327 }
5328
5329 /* No need to perform extra init in case of posting */
5330 RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED;
5331
5332 /* Preflight checks were OK, time to submit */
5333 if (NT_SUCCESS(Status))
5334 {
5335 PMINIRDR_DISPATCH Dispatch;
5336
5337 if (!Synchronous)
5338 {
5339 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
5340 /* If not synchronous, we're likely to return before the operation is finished */
5341 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
5342 {
5343 IoMarkIrpPending(RxContext->CurrentIrp);
5344 }
5345 }
5346
5347 Dispatch = RxContext->RxDeviceObject->Dispatch;
5348 if (Dispatch != NULL)
5349 {
5350 /* We'll try to execute until the mini-rdr doesn't return pending */
5351 do
5352 {
5353 RxContext->IoStatusBlock.Information = 0;
5354
5355 MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext));
5356 if (Status == STATUS_PENDING)
5357 {
5358 /* Unless it's not synchronous, caller will be happy with pending op */
5359 if (!Synchronous)
5360 {
5361 return Status;
5362 }
5363
5364 RxWaitSync(RxContext);
5365 Status = RxContext->IoStatusBlock.Status;
5366 }
5367 else
5368 {
5369 if (!Synchronous)
5370 {
5371 /* We had marked the IRP pending, whereas the operation finished, drop that */
5372 if (Status != STATUS_RETRY)
5373 {
5374 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP))
5375 {
5376 RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED;
5377 }
5378
5379 InterlockedDecrement((volatile long *)&RxContext->ReferenceCount);
5380 }
5381 }
5382 }
5383 } while (Status == STATUS_PENDING);
5384 }
5385 else
5386 {
5387 Status = STATUS_INVALID_PARAMETER;
5388 }
5389 }
5390
5391 /* Call completion and return */
5392 RxContext->IoStatusBlock.Status = Status;
5393 LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL;
5394 return RxLowIoCompletionTail(RxContext);
5395 }
5396
5397 /*
5398 * @implemented
5399 */
5400 PVOID
5401 RxMapSystemBuffer(
5402 IN PRX_CONTEXT RxContext)
5403 {
5404 PIRP Irp;
5405
5406 PAGED_CODE();
5407
5408 Irp = RxContext->CurrentIrp;
5409 /* We should have a MDL (buffered IOs are not supported!) */
5410 if (Irp->MdlAddress != NULL)
5411 {
5412 ASSERT(FALSE);
5413 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
5414 }
5415
5416 /* Just return system buffer */
5417 return Irp->AssociatedIrp.SystemBuffer;
5418 }
5419
5420 /*
5421 * @implemented
5422 */
5423 VOID
5424 RxMarkFobxOnCleanup(
5425 PFOBX pFobx,
5426 PBOOLEAN NeedPurge)
5427 {
5428 PFCB Fcb;
5429 PFOBX ScavengerFobx;
5430 LARGE_INTEGER TickCount;
5431 PRDBSS_SCAVENGER Scavenger;
5432
5433 PAGED_CODE();
5434
5435 /* No FOBX, nothing to mark */
5436 if (pFobx == NULL)
5437 {
5438 return;
5439 }
5440
5441 /* Query time for close */
5442 KeQueryTickCount(&TickCount);
5443
5444 Fcb = (PFCB)pFobx->pSrvOpen->pFcb;
5445 ASSERT(NodeTypeIsFcb(Fcb));
5446
5447 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
5448 RxAcquireScavengerMutex();
5449
5450 ScavengerFobx = NULL;
5451 /* If that's not a file, or even not a disk resource, just mark as dormant */
5452 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE || Fcb->VNetRoot->pNetRoot->DeviceType != FILE_DEVICE_DISK)
5453 {
5454 SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5455 InitializeListHead(&pFobx->ClosePendingList);
5456 ++Scavenger->NumberOfDormantFiles;
5457 }
5458 else
5459 {
5460 ASSERT(Scavenger->NumberOfDormantFiles >= 0);
5461 /* If we're about to reach the maximum dormant of FOBX */
5462 if (Scavenger->NumberOfDormantFiles >= Scavenger->MaximumNumberOfDormantFiles)
5463 {
5464 /* This should never be wrong... */
5465 if (!IsListEmpty(&Scavenger->ClosePendingFobxsList))
5466 {
5467 /* Then, take the first from the list (oldest) and save it for later purge */
5468 ScavengerFobx = CONTAINING_RECORD(Scavenger->ClosePendingFobxsList.Flink, FOBX, ClosePendingList);
5469 if (ScavengerFobx->pSrvOpen != NULL && ScavengerFobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
5470 {
5471 *NeedPurge = TRUE;
5472 ScavengerFobx = NULL;
5473 }
5474 else
5475 {
5476 RxReferenceNetFobx(ScavengerFobx);
5477 }
5478 }
5479 }
5480
5481 /* Mark ourselves as dormant */
5482 SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5483 pFobx->CloseTime.QuadPart = TickCount.QuadPart;
5484
5485 /* And insert us in the list of dormant files */
5486 InsertTailList(&Scavenger->ClosePendingFobxsList, &pFobx->ClosePendingList);
5487 /* If scavenger was inactive, start it */
5488 if (Scavenger->NumberOfDormantFiles++ == 0 && Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
5489 {
5490 Scavenger->State = RDBSS_SCAVENGER_DORMANT;
5491 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem, RxScavengerTimerRoutine,
5492 Fcb->RxDeviceObject, Scavenger->TimeLimit);
5493 }
5494 }
5495
5496 RxReleaseScavengerMutex();
5497
5498 /* If we had reached max */
5499 if (ScavengerFobx != NULL)
5500 {
5501 NTSTATUS Status;
5502
5503 /* Purge the oldest FOBX */
5504 Status = RxPurgeFobxFromCache(ScavengerFobx);
5505 if (Status != STATUS_SUCCESS)
5506 {
5507 *NeedPurge = TRUE;
5508 }
5509 }
5510 }
5511
5512 /*
5513 * @implemented
5514 */
5515 VOID
5516 RxMarkFobxOnClose(
5517 PFOBX Fobx)
5518 {
5519 PFCB Fcb;
5520 PRDBSS_SCAVENGER Scavenger;
5521
5522 PAGED_CODE();
5523
5524 /* No FOBX, nothing to mark */
5525 if (Fobx == NULL)
5526 {
5527 return;
5528 }
5529
5530 Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
5531 ASSERT(NodeTypeIsFcb(Fcb));
5532
5533 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
5534
5535 RxAcquireScavengerMutex();
5536 /* Only mark it if it was already marked as dormant */
5537 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT))
5538 {
5539 /* If FCB wasn't already decrement, do it now */
5540 if (!Fobx->fOpenCountDecremented)
5541 {
5542 Fcb = (PFCB)Fobx->pSrvOpen->pFcb;
5543 ASSERT(NodeTypeIsFcb(Fcb));
5544 InterlockedDecrement((volatile long *)&Fcb->OpenCount);
5545
5546 Fobx->fOpenCountDecremented = TRUE;
5547 }
5548
5549 /* We're no longer dormant */
5550 InterlockedDecrement(&Scavenger->NumberOfDormantFiles);
5551 ClearFlag(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
5552 }
5553
5554 /* If we were inserted in the scavenger, drop ourselves out */
5555 if (!IsListEmpty(&Fobx->ClosePendingList))
5556 {
5557 RemoveEntryList(&Fobx->ClosePendingList);
5558 InitializeListHead(&Fobx->ClosePendingList);
5559 }
5560
5561 RxReleaseScavengerMutex();
5562 }
5563
5564 /*
5565 * @implemented
5566 */
5567 PVOID
5568 RxNewMapUserBuffer(
5569 PRX_CONTEXT RxContext)
5570 {
5571 PIRP Irp;
5572
5573 PAGED_CODE();
5574
5575 Irp = RxContext->CurrentIrp;
5576 if (Irp->MdlAddress != NULL)
5577 {
5578 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
5579 }
5580
5581 return Irp->UserBuffer;
5582 }
5583
5584 BOOLEAN
5585 NTAPI
5586 RxNoOpAcquire(
5587 IN PVOID Fcb,
5588 IN BOOLEAN Wait)
5589 {
5590 UNIMPLEMENTED;
5591 return FALSE;
5592 }
5593
5594 VOID
5595 NTAPI
5596 RxNoOpRelease(
5597 IN PVOID Fcb)
5598 {
5599 UNIMPLEMENTED;
5600 }
5601
5602 VOID
5603 RxOrphanThisFcb(
5604 PFCB Fcb)
5605 {
5606 UNIMPLEMENTED;
5607 }
5608
5609 VOID
5610 RxOrphanSrvOpens(
5611 IN PV_NET_ROOT ThisVNetRoot)
5612 {
5613 PFCB Fcb;
5614 USHORT Bucket;
5615 PNET_ROOT NetRoot;
5616 PRX_FCB_TABLE FcbTable;
5617 PRX_PREFIX_TABLE PrefixTable;
5618
5619 PAGED_CODE();
5620
5621 /* Mailslot won't have any SRV_OPEN (to orphan) */
5622 NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot;
5623 if (NetRoot->Type == NET_ROOT_MAILSLOT)
5624 {
5625 return;
5626 }
5627
5628 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
5629 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable));
5630
5631 FcbTable = &NetRoot->FcbTable;
5632 RxAcquireFcbTableLockExclusive(FcbTable, TRUE);
5633
5634 _SEH2_TRY
5635 {
5636 /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
5637 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket)
5638 {
5639 PLIST_ENTRY BucketList, Entry;
5640
5641 BucketList = &FcbTable->HashBuckets[Bucket];
5642 Entry = BucketList->Flink;
5643 while (Entry != BucketList)
5644 {
5645 Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks);
5646 Entry = Entry->Flink;
5647
5648 ASSERT(NodeTypeIsFcb(Fcb));
5649 RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
5650 }
5651 }
5652
5653 /* Of course, don't forget about NULL-entry */
5654 if (FcbTable->TableEntryForNull != NULL)
5655 {
5656 Fcb = CONTAINING_RECORD(FcbTable->TableEntryForNull, FCB, FcbTableEntry.HashLinks);
5657 ASSERT(NodeTypeIsFcb(Fcb));
5658 RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE);
5659 }
5660 }
5661 _SEH2_FINALLY
5662 {
5663 RxReleaseFcbTableLock(FcbTable);
5664 }
5665 _SEH2_END;
5666 }
5667
5668 VOID
5669 RxOrphanSrvOpensForThisFcb(
5670 IN PFCB Fcb,
5671 IN PV_NET_ROOT ThisVNetRoot,
5672 IN BOOLEAN OrphanAll)
5673 {
5674 UNIMPLEMENTED;
5675 }
5676
5677 /*
5678 * @implemented
5679 */
5680 BOOLEAN
5681 RxpAcquirePrefixTableLockShared(
5682 PRX_PREFIX_TABLE pTable,
5683 BOOLEAN Wait,
5684 BOOLEAN ProcessBufferingStateChangeRequests)
5685 {
5686 PAGED_CODE();
5687
5688 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
5689 pTable->TableLock.ActiveEntries);
5690
5691 return ExAcquireResourceSharedLite(&pTable->TableLock, Wait);
5692 }
5693
5694 /*
5695 * @implemented
5696 */
5697 BOOLEAN
5698 RxpAcquirePrefixTableLockExclusive(
5699 PRX_PREFIX_TABLE pTable,
5700 BOOLEAN Wait,
5701 BOOLEAN ProcessBufferingStateChangeRequests)
5702 {
5703 PAGED_CODE();
5704
5705 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests,
5706 pTable->TableLock.ActiveEntries);
5707
5708 return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait);
5709 }
5710
5711 /*
5712 * @implemented
5713 */
5714 BOOLEAN
5715 RxpDereferenceAndFinalizeNetFcb(
5716 OUT PFCB ThisFcb,
5717 IN PRX_CONTEXT RxContext,
5718 IN BOOLEAN RecursiveFinalize,
5719 IN BOOLEAN ForceFinalize)
5720 {
5721 NTSTATUS Status;
5722 ULONG References;
5723 PNET_ROOT NetRoot;
5724 BOOLEAN ResourceAcquired, NetRootReferenced, Freed;
5725
5726 PAGED_CODE();
5727
5728 ASSERT(!ForceFinalize);
5729 ASSERT(NodeTypeIsFcb(ThisFcb));
5730 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
5731
5732 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5733 References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount);
5734 if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1))
5735 {
5736 return FALSE;
5737 }
5738
5739 Freed = FALSE;
5740 Status = STATUS_SUCCESS;
5741 NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
5742 ResourceAcquired = FALSE;
5743 NetRootReferenced = FALSE;
5744 /* If FCB isn't orphaned, it still have context attached */
5745 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED))
5746 {
5747 /* Don't let NetRoot go away before we're done */
5748 RxReferenceNetRoot(NetRoot);
5749 NetRootReferenced = TRUE;
5750
5751 /* Try to acquire the table lock exclusively */
5752 if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable))
5753 {
5754 RxReferenceNetFcb(ThisFcb);
5755
5756 if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
5757 {
5758 if (RxContext != NULL && RxContext != CHANGE_BUFFERING_STATE_CONTEXT &&
5759 RxContext != CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
5760 {
5761 RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK;
5762 }
5763
5764 RxReleaseFcb(RxContext, ThisFcb);
5765
5766 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
5767
5768 Status = RxAcquireExclusiveFcb(RxContext, ThisFcb);
5769 }
5770
5771 References = RxDereferenceNetFcb(ThisFcb);
5772
5773 ResourceAcquired = TRUE;
5774 }
5775 }
5776
5777 /* If locking was OK (or not needed!), attempt finalization */
5778 if (Status == STATUS_SUCCESS)
5779 {
5780 Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References);
5781 }
5782
5783 /* Release table lock if acquired */
5784 if (ResourceAcquired)
5785 {
5786 RxReleaseFcbTableLock(&NetRoot->FcbTable);
5787 }
5788
5789 /* We don't need the NetRoot anylonger */
5790 if (NetRootReferenced)
5791 {
5792 RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld);
5793 }
5794
5795 return Freed;
5796 }
5797
5798 /*
5799 * @implemented
5800 */
5801 LONG
5802 RxpDereferenceNetFcb(
5803 PFCB Fcb)
5804 {
5805 LONG NewCount;
5806
5807 PAGED_CODE();
5808
5809 ASSERT(NodeTypeIsFcb(Fcb));
5810
5811 NewCount = InterlockedDecrement((volatile long *)&Fcb->NodeReferenceCount);
5812 ASSERT(NewCount >= 0);
5813
5814 PRINT_REF_COUNT(NETFCB, NewCount);
5815
5816 return NewCount;
5817 }
5818
5819 /*
5820 * @implemented
5821 */
5822 VOID
5823 NTAPI
5824 RxpDestroySrvCall(
5825 IN PVOID Context)
5826 {
5827 NTSTATUS Status;
5828 PSRV_CALL SrvCall;
5829 BOOLEAN ForceFinalize;
5830 PRX_PREFIX_TABLE PrefixTable;
5831
5832 SrvCall = (PSRV_CALL)Context;
5833 /* At this step, RxFinalizeSrvCall already cleaned some fields */
5834 ASSERT(SrvCall->UpperFinalizationDone);
5835
5836 PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable;
5837 /* Were we called with ForceFinalize? */
5838 ForceFinalize = BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED);
5839
5840 /* Notify mini-rdr */
5841 MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch,
5842 MRxFinalizeSrvCall, ((PMRX_SRV_CALL)SrvCall,
5843 ForceFinalize));
5844 (void)Status;
5845
5846 /* Dereference our extra reference (set before queueing) */
5847 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE);
5848 InterlockedDecrement((volatile long *)&SrvCall->NodeReferenceCount);
5849 /* And finalize for real, with the right context */
5850 RxFinalizeSrvCall(SrvCall, FALSE, ForceFinalize);
5851 RxReleasePrefixTableLock(PrefixTable);
5852 }
5853
5854 /*
5855 * @implemented
5856 */
5857 VOID
5858 RxpDiscardChangeBufferingStateRequests(
5859 _Inout_ PLIST_ENTRY DiscardedRequests)
5860 {
5861 PLIST_ENTRY Entry;
5862
5863 PAGED_CODE();
5864
5865 /* No requests to discard */
5866 if (IsListEmpty(DiscardedRequests))
5867 {
5868 return;
5869 }
5870
5871 /* Free all the discarded requests */
5872 Entry = DiscardedRequests->Flink;
5873 while (Entry != DiscardedRequests)
5874 {
5875 PCHANGE_BUFFERING_STATE_REQUEST Request;
5876
5877 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
5878 Entry = Entry->Flink;
5879
5880 DPRINT("Req %p for %p (%p) discarded\n", Request, Request->SrvOpenKey, Request->SrvOpen);
5881
5882 RxPrepareRequestForReuse(Request);
5883 RxFreePool(Request);
5884 }
5885 }
5886
5887 /*
5888 * @implemented
5889 */
5890 VOID
5891 RxpDispatchChangeBufferingStateRequests(
5892 PSRV_CALL SrvCall,
5893 PSRV_OPEN SrvOpen,
5894 PLIST_ENTRY DiscardedRequests)
5895 {
5896 KIRQL OldIrql;
5897 NTSTATUS Status;
5898 BOOLEAN StartDispatcher;
5899 LIST_ENTRY AcceptedReqs;
5900 LIST_ENTRY DispatcherList;
5901 PRX_BUFFERING_MANAGER BufferingManager;
5902
5903 /* Initialize our lists */
5904 InitializeListHead(&AcceptedReqs);
5905 InitializeListHead(DiscardedRequests);
5906
5907 /* Transfer the requests to dispatch locally */
5908 BufferingManager = &SrvCall->BufferingManager;
5909 KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
5910 RxTransferList(&DispatcherList, &BufferingManager->DispatcherList);
5911 KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
5912
5913 /* If there were requests */
5914 if (!IsListEmpty(&DispatcherList))
5915 {
5916 PLIST_ENTRY Entry;
5917
5918 /* For each of the entries... */
5919 Entry = DispatcherList.Flink;
5920 while (Entry != &DispatcherList)
5921 {
5922 PCHANGE_BUFFERING_STATE_REQUEST Request;
5923
5924 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry);
5925 Entry = Entry->Flink;
5926
5927 /* If we have been provided a SRV_OPEN, see whether it matches */
5928 if (SrvOpen != NULL)
5929 {
5930 /* Match, the request is accepted */
5931 if (Request->SrvOpenKey == SrvOpen->Key)
5932 {
5933 Request->SrvOpen = SrvOpen;
5934 RxReferenceSrvOpen(SrvOpen);
5935
5936 RemoveEntryList(&Request->ListEntry);
5937 InsertTailList(&AcceptedReqs, &Request->ListEntry);
5938
5939 /* Move to the next entry */
5940 continue;
5941 }
5942 else
5943 {
5944 Status = STATUS_PENDING;
5945 }
5946 }
5947 else
5948 {
5949 /* No SRV_OPEN provided, try to find one */
5950 Status = RxpLookupSrvOpenForRequestLite(SrvCall, Request);
5951 }
5952
5953 /* We found a matching SRV_OPEN, accept the request */
5954 if (Status == STATUS_SUCCESS)
5955 {
5956 RemoveEntryList(&Request->ListEntry);
5957 InsertTailList(&AcceptedReqs, &Request->ListEntry);
5958 }
5959 /* Another run might help handling it, don't discard it */
5960 else if (Status == STATUS_PENDING)
5961 {
5962 continue;
5963 }
5964 /* Otherwise, discard the request */
5965 else
5966 {
5967 ASSERT(Status == STATUS_NOT_FOUND);
5968
5969 RemoveEntryList(&Request->ListEntry);
5970 InsertTailList(DiscardedRequests, &Request->ListEntry);
5971 }
5972 }
5973 }
5974
5975 KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql);
5976 /* Nothing to dispatch, no need to start dispatcher */
5977 if (IsListEmpty(&DispatcherList))
5978 {
5979 StartDispatcher = FALSE;
5980 }
5981 else
5982 {
5983 /* Transfer back the list of the not treated entries to the buffering manager */
5984 RxTransferList(&BufferingManager->DispatcherList, &DispatcherList);
5985 StartDispatcher = (BufferingManager->DispatcherActive == FALSE);
5986 /* If the dispatcher isn't active, start it */
5987 if (StartDispatcher)
5988 {
5989 BufferingManager->DispatcherActive = TRUE;
5990 }
5991 }
5992
5993 /* If there were accepted requests, move them to the buffering manager */
5994 if (!IsListEmpty(&AcceptedReqs))
5995 {
5996 RxTransferList(&BufferingManager->HandlerList, &AcceptedReqs);
5997 }
5998 KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql);
5999
6000 /* If we're to start the dispatcher, do it */
6001 if (StartDispatcher)
6002 {
6003 RxReferenceSrvCall(SrvCall);
6004 DPRINT("Starting dispatcher\n");
6005 RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue,
6006 &BufferingManager->DispatcherWorkItem,
6007 RxDispatchChangeBufferingStateRequests, SrvCall);
6008 }
6009 }
6010
6011 /*
6012 * @implemented
6013 */
6014 NTSTATUS
6015 RxpLookupSrvOpenForRequestLite(
6016 IN PSRV_CALL SrvCall,
6017 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request)
6018 {
6019 NTSTATUS Status;
6020 PLIST_ENTRY Entry;
6021 PSRV_OPEN SrvOpen;
6022
6023 PAGED_CODE();
6024
6025 Status = STATUS_SUCCESS;
6026 /* Browse all our associated SRV_OPENs to find the one! */
6027 for (Entry = SrvCall->BufferingManager.SrvOpenLists[0].Flink;
6028 Entry != &SrvCall->BufferingManager.SrvOpenLists[0];
6029 Entry = Entry->Flink)
6030 {
6031 /* Same key, not orphaned, this is ours */
6032 SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenKeyList);
6033 if (SrvOpen->Key == Request->SrvOpenKey)
6034 {
6035 if (!BooleanFlagOn(SrvOpen->pFcb->FcbState, FCB_STATE_ORPHANED))
6036 {
6037 RxReferenceSrvOpen(SrvOpen);
6038 break;
6039 }
6040 }
6041 }
6042
6043 /* We didn't manage to find a SRV_OPEN */
6044 if (Entry == &SrvCall->BufferingManager.SrvOpenLists[0])
6045 {
6046 SrvOpen = NULL;
6047
6048 /* The coming open might help, mark as pending for later retry */
6049 if (SrvCall->BufferingManager.NumberOfOutstandingOpens != 0)
6050 {
6051 Status = STATUS_PENDING;
6052 }
6053 /* Else, it's a complete failure */
6054 else
6055 {
6056 Status = STATUS_NOT_FOUND;
6057 }
6058 }
6059
6060 /* Return the (not) found SRV_OPEN */
6061 Request->SrvOpen = SrvOpen;
6062
6063 return Status;
6064 }
6065
6066 /*
6067 * @implemented
6068 */
6069 VOID
6070 RxpMarkInstanceForScavengedFinalization(
6071 PVOID Instance)
6072 {
6073 NODE_TYPE_CODE NodeType;
6074 PNODE_TYPE_AND_SIZE Node;
6075 PRDBSS_SCAVENGER Scavenger;
6076 PRDBSS_DEVICE_OBJECT DeviceObject;
6077 PLIST_ENTRY ScavengerHead, InstEntry;
6078
6079 PAGED_CODE();
6080
6081 /* If still referenced, don't mark it (broken caller) */
6082 Node = (PNODE_TYPE_AND_SIZE)Instance;
6083 if (Node->NodeReferenceCount > 1)
6084 {
6085 return;
6086 }
6087
6088 DeviceObject = RxGetDeviceObjectOfInstance(Instance);
6089 Scavenger = DeviceObject->pRdbssScavenger;
6090
6091 /* Mark the node */
6092 NodeType = NodeType(Instance);
6093 SetFlag(NodeType(Node), RX_SCAVENGER_MASK);
6094 DPRINT("Node %p has now the scavenger mark!\n", Instance);
6095
6096 /* Increase the count in the scavenger, and queue it */
6097 ScavengerHead = NULL;
6098 switch (NodeType)
6099 {
6100 case RDBSS_NTC_FOBX:
6101 ++Scavenger->FobxsToBeFinalized;
6102 ScavengerHead = &Scavenger->FobxFinalizationList;
6103 InstEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
6104 break;
6105
6106 case RDBSS_NTC_SRVCALL:
6107 ++Scavenger->SrvCallsToBeFinalized;
6108 ScavengerHead = &Scavenger->SrvCallFinalizationList;
6109 InstEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
6110 break;
6111
6112 case RDBSS_NTC_NETROOT:
6113 ++Scavenger->NetRootsToBeFinalized;
6114 ScavengerHead = &Scavenger->NetRootFinalizationList;
6115 InstEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
6116 break;
6117
6118 case RDBSS_NTC_V_NETROOT:
6119 ++Scavenger->VNetRootsToBeFinalized;
6120 ScavengerHead = &Scavenger->VNetRootFinalizationList;
6121 InstEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
6122 break;
6123
6124 case RDBSS_NTC_SRVOPEN:
6125 ++Scavenger->SrvOpensToBeFinalized;
6126 ScavengerHead = &Scavenger->SrvOpenFinalizationList;
6127 InstEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
6128 break;
6129 }
6130
6131 /* Extra ref for scavenger */
6132 InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
6133
6134 /* If matching type */
6135 if (ScavengerHead != NULL)
6136 {
6137 /* Insert in the scavenger list */
6138 InsertTailList(ScavengerHead, InstEntry);
6139
6140 /* And if it wasn't started, start it */
6141 if (Scavenger->State == RDBSS_SCAVENGER_INACTIVE)
6142 {
6143 Scavenger->State = RDBSS_SCAVENGER_DORMANT;
6144 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
6145 RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
6146 }
6147 }
6148 }
6149
6150 /*
6151 * @implemented
6152 */
6153 NTSTATUS
6154 NTAPI
6155 RxPostOneShotTimerRequest(
6156 IN PRDBSS_DEVICE_OBJECT pDeviceObject,
6157 IN PRX_WORK_ITEM pWorkItem,
6158 IN PRX_WORKERTHREAD_ROUTINE Routine,
6159 IN PVOID pContext,
6160 IN LARGE_INTEGER TimeInterval)
6161 {
6162 KIRQL OldIrql;
6163
6164 ASSERT(pWorkItem != NULL);
6165
6166 /* Prepare the work item */
6167 ExInitializeWorkItem(&pWorkItem->WorkQueueItem, Routine, pContext);
6168 pWorkItem->WorkQueueItem.pDeviceObject = pDeviceObject;
6169
6170 /* Last tick can be computed with the number of times it was caller (timertickcount)
6171 * and the interval between calls
6172 */
6173 KeAcquireSpinLock(&RxTimerLock, &OldIrql);
6174 pWorkItem->LastTick = (TimeInterval.QuadPart / 550000) + RxTimerTickCount + 1;
6175 /* Insert in work queue */
6176 InsertTailList(&RxTimerQueueHead, &pWorkItem->WorkQueueItem.List);
6177 KeReleaseSpinLock(&RxTimerLock, OldIrql);
6178
6179 /* If there are queued events, queue an execution */
6180 if (IsListEmpty(&RxTimerQueueHead))
6181 {
6182 KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
6183 }
6184
6185 return STATUS_SUCCESS;
6186 }
6187
6188 /*
6189 * @implemented
6190 */
6191 NTSTATUS
6192 NTAPI
6193 RxPostToWorkerThread(
6194 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject,
6195 _In_ WORK_QUEUE_TYPE WorkQueueType,
6196 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem,
6197 _In_ PRX_WORKERTHREAD_ROUTINE Routine,
6198 _In_ PVOID pContext)
6199 {
6200 /* Initialize work queue item */
6201 pWorkQueueItem->List.Flink = NULL;
6202 pWorkQueueItem->WorkerRoutine = Routine;
6203 pWorkQueueItem->Parameter = pContext;
6204
6205 /* And insert it in the work queue */
6206 return RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, pWorkQueueItem);
6207 }
6208
6209 VOID
6210 RxpProcessChangeBufferingStateRequests(
6211 PSRV_CALL SrvCall,
6212 BOOLEAN UpdateHandlerState)
6213 {
6214 UNIMPLEMENTED;
6215 }
6216
6217 /*
6218 * @implemented
6219 */
6220 PRX_PREFIX_ENTRY
6221 RxPrefixTableInsertName(
6222 IN OUT PRX_PREFIX_TABLE ThisTable,
6223 IN OUT PRX_PREFIX_ENTRY ThisEntry,
6224 IN PVOID Container,
6225 IN PULONG ContainerRefCount,
6226 IN USHORT CaseInsensitiveLength,
6227 IN PRX_CONNECTION_ID ConnectionId
6228 )
6229 {
6230 PAGED_CODE();
6231
6232 DPRINT("Insert: %wZ\n", &ThisEntry->Prefix);
6233
6234 ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
6235 ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length);
6236
6237 /* Copy parameters and compute hash */
6238 ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength;
6239 ThisEntry->ContainingRecord = Container;
6240 ThisEntry->ContainerRefCount = ContainerRefCount;
6241 InterlockedIncrement((volatile long *)ContainerRefCount);
6242 ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix);
6243 DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue);
6244
6245 /* If no path length: this is entry for null path */
6246 if (ThisEntry->Prefix.Length == 0)
6247 {
6248 ThisTable->TableEntryForNull = ThisEntry;
6249 }
6250 /* Otherwise, insert in the appropriate bucket */
6251 else
6252 {
6253 InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks);
6254 }
6255
6256 /* If we had a connection ID, keep track of it */
6257 if (ConnectionId != NULL)
6258 {
6259 ThisEntry->ConnectionId.Luid = ConnectionId->Luid;
6260 }
6261 else
6262 {
6263 ThisEntry->ConnectionId.Luid.LowPart = 0;
6264 ThisEntry->ConnectionId.Luid.HighPart = 0;
6265 }
6266
6267 InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks);
6268 /* Reflect the changes */
6269 ++ThisTable->Version;
6270
6271 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue));
6272
6273 return ThisEntry;
6274 }
6275
6276 /*
6277 * @implemented
6278 */
6279 PVOID
6280 RxPrefixTableLookupName(
6281 IN PRX_PREFIX_TABLE ThisTable,
6282 IN PUNICODE_STRING CanonicalName,
6283 OUT PUNICODE_STRING RemainingName,
6284 IN PRX_CONNECTION_ID ConnectionId)
6285 {
6286 PVOID Container;
6287
6288 PAGED_CODE();
6289
6290 ASSERT(RxIsPrefixTableLockAcquired(ThisTable));
6291 ASSERT(CanonicalName->Length > 0);
6292
6293 /* Call the internal helper */
6294 Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId);
6295 if (Container == NULL)
6296 {
6297 return NULL;
6298 }
6299
6300 /* Reference our container before returning it */
6301 if (RdbssReferenceTracingValue != 0)
6302 {
6303 NODE_TYPE_CODE Type;
6304
6305 Type = NodeType(Container);
6306 switch (Type)
6307 {
6308 case RDBSS_NTC_SRVCALL:
6309 RxReferenceSrvCall(Container);
6310 break;
6311
6312 case RDBSS_NTC_NETROOT:
6313 RxReferenceNetRoot(Container);
6314 break;
6315
6316 case RDBSS_NTC_V_NETROOT:
6317 RxReferenceVNetRoot(Container);
6318 break;
6319
6320 default:
6321 ASSERT(FALSE);
6322 break;
6323 }
6324 }
6325 else
6326 {
6327 RxReference(Container);
6328 }
6329
6330 return Container;
6331 }
6332
6333 /*
6334 * @implemented
6335 */
6336 LONG
6337 RxpReferenceNetFcb(
6338 PFCB Fcb)
6339 {
6340 LONG NewCount;
6341
6342 PAGED_CODE();
6343
6344 ASSERT(NodeTypeIsFcb(Fcb));
6345
6346 NewCount = InterlockedIncrement((volatile long *)&Fcb->NodeReferenceCount);
6347
6348 PRINT_REF_COUNT(NETFCB, Fcb->NodeReferenceCount);
6349
6350 return NewCount;
6351 }
6352
6353 /*
6354 * @implemented
6355 */
6356 VOID
6357 RxpReleasePrefixTableLock(
6358 PRX_PREFIX_TABLE pTable,
6359 BOOLEAN ProcessBufferingStateChangeRequests)
6360 {
6361 PAGED_CODE();
6362
6363 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests,
6364 pTable->TableLock.ActiveEntries);
6365
6366 ExReleaseResourceLite(&pTable->TableLock);
6367 }
6368
6369 /*
6370 * @implemented
6371 */
6372 VOID
6373 NTAPI
6374 RxPrepareContextForReuse(
6375 IN OUT PRX_CONTEXT RxContext)
6376 {
6377 PAGED_CODE();
6378
6379 /* When we reach that point, make sure mandatory parts are null-ed */
6380 if (RxContext->MajorFunction == IRP_MJ_CREATE)
6381 {
6382 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL);
6383 RxContext->Create.RdrFlags = 0;
6384 }
6385 else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE)
6386 {
6387 ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
6388 ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
6389 }
6390
6391 RxContext->ReferenceCount = 0;
6392 }
6393
6394 /*
6395 * @implemented
6396 */
6397 VOID
6398 RxPrepareRequestForReuse(
6399 PCHANGE_BUFFERING_STATE_REQUEST Request)
6400 {
6401 PSRV_OPEN SrvOpen;
6402
6403 PAGED_CODE();
6404
6405 SrvOpen = Request->SrvOpen;
6406
6407 /* If the request was already prepared for service */
6408 if (BooleanFlagOn(Request->Flags, RX_REQUEST_PREPARED_FOR_HANDLING))
6409 {
6410 /* We have to dereference the associated SRV_OPEN depending on the lock */
6411 if (RxIsFcbAcquiredExclusive(SrvOpen->pFcb))
6412 {
6413 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
6414 }
6415 else
6416 {
6417 RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
6418 }
6419 }
6420 /* Otherwise, just dereference */
6421 else if (SrvOpen != NULL)
6422 {
6423 RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld);
6424 }
6425
6426 Request->SrvOpen = NULL;
6427 }
6428
6429 /*
6430 * @implemented
6431 */
6432 VOID
6433 NTAPI
6434 RxProcessChangeBufferingStateRequests(
6435 _In_ PVOID SrvCall)
6436 {
6437 /* Call internal routine */
6438 RxUndoScavengerFinalizationMarking(SrvCall);
6439 RxpProcessChangeBufferingStateRequests(SrvCall, TRUE);
6440 }
6441
6442 /*
6443 * @implemented
6444 */
6445 VOID
6446 RxProcessChangeBufferingStateRequestsForSrvOpen(
6447 PSRV_OPEN SrvOpen)
6448 {
6449 LONG NumberOfBufferingChangeRequests, LockedOldBufferingToken, OldBufferingToken;
6450
6451 /* Get the current number of change requests */
6452 NumberOfBufferingChangeRequests = ((PSRV_CALL)SrvOpen->pVNetRoot->pNetRoot->pSrvCall)->BufferingManager.CumulativeNumberOfBufferingChangeRequests;
6453 /* Get our old token */
6454 OldBufferingToken = SrvOpen->BufferingToken;
6455 LockedOldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken,
6456 NumberOfBufferingChangeRequests,
6457 NumberOfBufferingChangeRequests);
6458 /* If buffering state changed in between, process changes */
6459 if (OldBufferingToken != LockedOldBufferingToken)
6460 {
6461 PFCB Fcb;
6462 NTSTATUS Status;
6463
6464 /* Acquire the FCB and start processing */
6465 Fcb = (PFCB)SrvOpen->pFcb;
6466 Status = RxAcquireExclusiveFcb(NULL, Fcb);
6467 if (Status == STATUS_SUCCESS)
6468 {
6469 RxProcessFcbChangeBufferingStateRequest(Fcb);
6470 RxReleaseFcb(NULL, Fcb);
6471 }
6472 }
6473 }
6474
6475 VOID
6476 RxProcessFcbChangeBufferingStateRequest(
6477 PFCB Fcb)
6478 {
6479 UNIMPLEMENTED;
6480 }
6481
6482 BOOLEAN
6483 RxpTrackDereference(
6484 _In_ ULONG TraceType,
6485 _In_ PCSTR FileName,
6486 _In_ ULONG Line,
6487 _In_ PVOID Instance)
6488 {
6489 PAGED_CODE();
6490
6491 if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
6492 {
6493 return TRUE;
6494 }
6495
6496 UNIMPLEMENTED;
6497 return TRUE;
6498 }
6499
6500 VOID
6501 RxpTrackReference(
6502 _In_ ULONG TraceType,
6503 _In_ PCSTR FileName,
6504 _In_ ULONG Line,
6505 _In_ PVOID Instance)
6506 {
6507 if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType))
6508 {
6509 return;
6510 }
6511
6512 UNIMPLEMENTED;
6513 }
6514
6515 /*
6516 * @implemented
6517 */
6518 VOID
6519 RxpUndoScavengerFinalizationMarking(
6520 PVOID Instance)
6521 {
6522 PLIST_ENTRY ListEntry;
6523 PNODE_TYPE_AND_SIZE Node;
6524 PRDBSS_SCAVENGER Scavenger;
6525
6526 PAGED_CODE();
6527
6528 Node = (PNODE_TYPE_AND_SIZE)Instance;
6529 /* There's no marking - nothing to do */
6530 if (!BooleanFlagOn(NodeType(Node), RX_SCAVENGER_MASK))
6531 {
6532 return;
6533 }
6534
6535 /* First of all, remove the mark */
6536 ClearFlag(NodeType(Node), RX_SCAVENGER_MASK);
6537 DPRINT("Node %p no longer has the scavenger mark\n");
6538
6539 /* And now, remove from the scavenger */
6540 Scavenger = RxGetDeviceObjectOfInstance(Instance)->pRdbssScavenger;
6541 switch (NodeType(Node))
6542 {
6543 case RDBSS_NTC_FOBX:
6544 --Scavenger->FobxsToBeFinalized;
6545 ListEntry = &((PFOBX)Instance)->ScavengerFinalizationList;
6546 break;
6547
6548 case RDBSS_NTC_SRVCALL:
6549 --Scavenger->SrvCallsToBeFinalized;
6550 ListEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList;
6551 break;
6552
6553 case RDBSS_NTC_NETROOT:
6554 --Scavenger->NetRootsToBeFinalized;
6555 ListEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList;
6556 break;
6557
6558 case RDBSS_NTC_V_NETROOT:
6559 --Scavenger->VNetRootsToBeFinalized;
6560 ListEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList;
6561 break;
6562
6563 case RDBSS_NTC_SRVOPEN:
6564 --Scavenger->SrvOpensToBeFinalized;
6565 ListEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList;
6566 break;
6567 }
6568
6569 /* Also, remove the extra ref from the scavenger */
6570 RemoveEntryList(ListEntry);
6571 InterlockedDecrement((volatile long *)&Node->NodeReferenceCount);
6572 }
6573
6574 /*
6575 * @implemented
6576 */
6577 VOID
6578 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6579 PSRV_OPEN SrvOpen)
6580 {
6581 PSRV_CALL SrvCall;
6582 LIST_ENTRY Discarded;
6583
6584 PAGED_CODE();
6585
6586 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb));
6587
6588 /* Initialize our discarded list */
6589 InitializeListHead(&Discarded);
6590
6591 SrvCall = (PSRV_CALL)SrvOpen->Fcb->VNetRoot->pNetRoot->pSrvCall;
6592 RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager);
6593
6594 /* Set the flag, and get the requests */
6595 InitializeListHead(&SrvOpen->SrvOpenKeyList);
6596 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED);
6597 RxGatherRequestsForSrvOpen(SrvCall, SrvOpen, &Discarded);
6598
6599 RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager);
6600
6601 /* If there were discarded requests */
6602 if (!IsListEmpty(&Discarded))
6603 {
6604 /* And a pending buffering state change */
6605 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
6606 {
6607 /* Clear the flag, and set the associated event - job done */
6608 RxAcquireSerializationMutex();
6609 ClearFlag(SrvOpen->Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
6610 if (SrvOpen->Fcb->pBufferingStateChangeCompletedEvent != NULL)
6611 {
6612 KeSetEvent(SrvOpen->Fcb->pBufferingStateChangeCompletedEvent, IO_NETWORK_INCREMENT, FALSE);
6613 }
6614 RxReleaseSerializationMutex();
6615 }
6616
6617 /* Drop the discarded requests */
6618 RxpDiscardChangeBufferingStateRequests(&Discarded);
6619 }
6620 }
6621
6622 /*
6623 * @implemented
6624 */
6625 VOID
6626 RxPurgeFcb(
6627 IN PFCB Fcb)
6628 {
6629 PAGED_CODE();
6630
6631 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
6632
6633 /* Reference our FCB so that it doesn't disappear */
6634 RxReferenceNetFcb(Fcb);
6635 /* Purge Cc if required */
6636 if (Fcb->OpenCount != 0)
6637 {
6638 RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE);
6639 }
6640
6641 /* If it wasn't freed, release the lock */
6642 if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE))
6643 {
6644 RxReleaseFcb(NULL, Fcb);
6645 }
6646 }
6647
6648 /*
6649 * @implemented
6650 */
6651 NTSTATUS
6652 RxPurgeFcbInSystemCache(
6653 IN PFCB Fcb,
6654 IN PLARGE_INTEGER FileOffset OPTIONAL,
6655 IN ULONG Length,
6656 IN BOOLEAN UninitializeCacheMaps,
6657 IN BOOLEAN FlushFile)
6658 {
6659 BOOLEAN Purged;
6660 NTSTATUS Status;
6661
6662 PAGED_CODE();
6663
6664 ASSERT(RxIsFcbAcquiredExclusive(Fcb));
6665
6666 /* Try to flush first, if asked */
6667 if (FlushFile)
6668 {
6669 /* If flushing failed, just make some noise */
6670 Status = RxFlushFcbInSystemCache(Fcb, TRUE);
6671 if (!NT_SUCCESS(Status))
6672 {
6673 PVOID CallersAddress, CallersCaller;
6674
6675 RtlGetCallersAddress(&CallersAddress, &CallersCaller);
6676 DPRINT1("Flush failed with status %lx for FCB %p\n", Status, Fcb);
6677 DPRINT1("Caller was %p %p\n", CallersAddress, CallersCaller);
6678 }
6679 }
6680
6681 /* Deal with Cc for purge */
6682 Purged = CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, FileOffset,
6683 Length, UninitializeCacheMaps);
6684 /* If purge failed, force section closing */
6685 if (!Purged)
6686 {
6687 MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
6688
6689 RxReleaseFcb(NULL, Fcb);
6690 Purged = MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
6691 RxAcquireExclusiveFcb(NULL, Fcb);
6692 }
6693
6694 /* Return appropriate status */
6695 Status = (Purged ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
6696 DPRINT("Purge for FCB %p returns %lx\n", Fcb, Status);
6697
6698 return Status;
6699 }
6700
6701 /*
6702 * @implemented
6703 */
6704 NTSTATUS
6705 RxPurgeFobxFromCache(
6706 PFOBX FobxToBePurged)
6707 {
6708 NTSTATUS Status;
6709 PFCB FcbToBePurged;
6710
6711 PAGED_CODE();
6712
6713 FcbToBePurged = (PFCB)FobxToBePurged->pSrvOpen->pFcb;
6714 ASSERT(FcbToBePurged != NULL);
6715
6716 /* If we cannot have our FCB exclusively, give up */
6717 Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged);
6718 if (Status != STATUS_SUCCESS)
6719 {
6720 RxDereferenceNetFobx(FobxToBePurged, LHS_LockNotHeld);
6721 return Status;
6722 }
6723
6724 /* Don't let the FCB disappear */
6725 RxReferenceNetFcb(FcbToBePurged);
6726
6727 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
6728 if (BooleanFlagOn(FobxToBePurged->Flags, FOBX_FLAG_SRVOPEN_CLOSED) || FobxToBePurged->pSrvOpen->UncleanFobxCount != 0)
6729 {
6730 DPRINT("FCB purge skipped\n");
6731 }
6732 else
6733 {
6734 Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE);
6735 }
6736
6737 RxDereferenceNetFobx(FobxToBePurged, LHS_ExclusiveLockHeld);
6738 /* Drop our extra reference */
6739 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged, NULL, FALSE, FALSE))
6740 {
6741 RxReleaseFcb(NULL, FcbToBePurged);
6742 }
6743
6744 return Status;
6745 }
6746
6747 /*
6748 * @implemented
6749 */
6750 VOID
6751 RxpWorkerThreadDispatcher(
6752 IN PRX_WORK_QUEUE WorkQueue,
6753 IN PLARGE_INTEGER WaitInterval)
6754 {
6755 NTSTATUS Status;
6756 PVOID Parameter;
6757 PETHREAD CurrentThread;
6758 BOOLEAN KillThread, Dereference;
6759 PRX_WORK_QUEUE_ITEM WorkQueueItem;
6760 PWORKER_THREAD_ROUTINE WorkerRoutine;
6761
6762 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
6763
6764 /* Reference ourselves */
6765 CurrentThread = PsGetCurrentThread();
6766 Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
6767 ASSERT(NT_SUCCESS(Status));
6768
6769 /* Infinite loop for worker */
6770 KillThread = FALSE;
6771 Dereference = FALSE;
6772 do
6773 {
6774 KIRQL OldIrql;
6775 PLIST_ENTRY ListEntry;
6776
6777 /* Remove an entry from the work queue */
6778 ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval);
6779 if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT)
6780 {
6781 PRDBSS_DEVICE_OBJECT DeviceObject;
6782
6783 WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List);
6784
6785 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched);
6786 InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched);
6787 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
6788
6789 /* Get the parameters, and null-them in the struct */
6790 WorkerRoutine = WorkQueueItem->WorkerRoutine;
6791 Parameter = WorkQueueItem->Parameter;
6792 DeviceObject = WorkQueueItem->pDeviceObject;
6793
6794 WorkQueueItem->List.Flink = NULL;
6795 WorkQueueItem->WorkerRoutine = NULL;
6796 WorkQueueItem->Parameter = NULL;
6797 WorkQueueItem->pDeviceObject = NULL;
6798
6799 /* Call the routine */
6800 DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter);
6801 WorkerRoutine(Parameter);
6802
6803 /* Are we going down now? */
6804 if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0)
6805 {
6806 PKEVENT TearDownEvent;
6807
6808 TearDownEvent = InterlockedExchangePointer((void * volatile*)&DeviceObject->DispatcherContext.pTearDownEvent, NULL);
6809 if (TearDownEvent != NULL)
6810 {
6811 KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE);
6812 }
6813 }
6814
6815 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads);
6816 }
6817
6818 /* Shall we shutdown... */
6819 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
6820 switch (WorkQueue->State)
6821 {
6822 /* Our queue is active, kill it if we have no more items to dispatch
6823 * and more threads than the required minimum
6824 */
6825 case RxWorkQueueActive:
6826 if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0)
6827 {
6828 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
6829 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
6830 {
6831 KillThread = TRUE;
6832 Dereference = TRUE;
6833 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
6834 }
6835
6836 if (KillThread)
6837 {
6838 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
6839 }
6840 }
6841 break;
6842
6843 /* The queue is inactive: kill it we have more threads than the required minimum */
6844 case RxWorkQueueInactive:
6845 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0);
6846 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads)
6847 {
6848 KillThread = TRUE;
6849 Dereference = TRUE;
6850 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
6851 }
6852
6853 if (KillThread)
6854 {
6855 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
6856 }
6857 break;
6858
6859 /* Rundown in progress..., kill it for sure! */
6860 case RxWorkQueueRundownInProgress:
6861 {
6862 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext;
6863
6864 ASSERT(WorkQueue->pRundownContext != NULL);
6865
6866 RundownContext = WorkQueue->pRundownContext;
6867 RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread;
6868
6869 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads);
6870 KillThread = TRUE;
6871 Dereference = FALSE;
6872
6873 if (WorkQueue->NumberOfActiveWorkerThreads == 0)
6874 {
6875 KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
6876 }
6877
6878 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads);
6879 }
6880 break;
6881
6882 default:
6883 break;
6884 }
6885 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
6886 } while (!KillThread);
6887
6888 DPRINT("Killed worker thread\n");
6889
6890 /* Do we have to dereference ourselves? */
6891 if (Dereference)
6892 {
6893 ObDereferenceObject(CurrentThread);
6894 }
6895
6896 /* Dump last executed routine */
6897 if (DumpDispatchRoutine)
6898 {
6899 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem);
6900 }
6901
6902 PsTerminateSystemThread(STATUS_SUCCESS);
6903 }
6904
6905 VOID
6906 RxReference(
6907 IN OUT PVOID Instance)
6908 {
6909 NODE_TYPE_CODE NodeType;
6910 PNODE_TYPE_AND_SIZE Node;
6911
6912 PAGED_CODE();
6913
6914 RxAcquireScavengerMutex();
6915
6916 /* We can only reference a few structs */
6917 NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK;
6918 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) ||
6919 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) ||
6920 (NodeType == RDBSS_NTC_FOBX));
6921
6922 Node = (PNODE_TYPE_AND_SIZE)Instance;
6923 InterlockedIncrement((volatile long *)&Node->NodeReferenceCount);
6924
6925 /* Trace refcount if asked */
6926 switch (NodeType)
6927 {
6928 case RDBSS_NTC_SRVCALL:
6929 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount);
6930 break;
6931
6932 case RDBSS_NTC_NETROOT:
6933 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount);
6934 break;
6935
6936 case RDBSS_NTC_V_NETROOT:
6937 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount);
6938 break;
6939
6940 case RDBSS_NTC_SRVOPEN:
6941 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount);
6942 break;
6943
6944 case RDBSS_NTC_FOBX:
6945 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount);
6946 break;
6947
6948 default:
6949 ASSERT(FALSE);
6950 break;
6951 }
6952
6953 RxpUndoScavengerFinalizationMarking(Instance);
6954 RxReleaseScavengerMutex();
6955 }
6956
6957 /*
6958 * @implemented
6959 */
6960 VOID
6961 RxRemoveNameNetFcb(
6962 OUT PFCB ThisFcb)
6963 {
6964 PNET_ROOT NetRoot;
6965
6966 PAGED_CODE();
6967
6968 ASSERT(NodeTypeIsFcb(ThisFcb));
6969
6970 /* Just remove the entry from the FCB_TABLE */
6971 NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot;
6972 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable));
6973 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb));
6974
6975 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb);
6976 DPRINT("FCB (%p) %wZ removed\n", ThisFcb, &ThisFcb->FcbTableEntry.Path);
6977 /* Mark, so that we don't try to do it twice */
6978 SetFlag(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED);
6979 }
6980
6981 /*
6982 * @implemented
6983 */
6984 VOID
6985 RxRemovePrefixTableEntry(
6986 IN OUT PRX_PREFIX_TABLE ThisTable,
6987 IN OUT PRX_PREFIX_ENTRY Entry)
6988 {
6989 PAGED_CODE();
6990
6991 ASSERT(NodeType(Entry) == RDBSS_NTC_PREFIX_ENTRY);
6992 ASSERT(RxIsPrefixTableLockExclusive(ThisTable));
6993
6994 /* Check whether we're asked to remove null entry */
6995 if (Entry->Prefix.Length == 0)
6996 {
6997 ThisTable->TableEntryForNull = NULL;
6998 }
6999 else
7000 {
7001 RemoveEntryList(&Entry->HashLinks);
7002 }
7003
7004 Entry->ContainingRecord = NULL;
7005
7006 /* Also remove it from global list */
7007 RemoveEntryList(&Entry->MemberQLinks);
7008
7009 ++ThisTable->Version;
7010 }
7011
7012 /*
7013 * @implemented
7014 */
7015 VOID
7016 RxRemoveVirtualNetRootFromNetRoot(
7017 PNET_ROOT NetRoot,
7018 PV_NET_ROOT VNetRoot)
7019 {
7020 PRX_PREFIX_TABLE PrefixTable;
7021
7022 PAGED_CODE();
7023
7024 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable;
7025 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable));
7026
7027 /* Remove the VNetRoot from the list in the NetRoot */
7028 --NetRoot->NumberOfVirtualNetRoots;
7029 RemoveEntryList(&VNetRoot->NetRootListEntry);
7030
7031 /* Fix the NetRoot if we were the default VNetRoot */
7032 if (NetRoot->DefaultVNetRoot == VNetRoot)
7033 {
7034 /* Put the first one available */
7035 if (!IsListEmpty(&NetRoot->VirtualNetRoots))
7036 {
7037 NetRoot->DefaultVNetRoot = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry);
7038 }
7039 /* Otherwise, none */
7040 else
7041 {
7042 NetRoot->DefaultVNetRoot = NULL;
7043 }
7044 }
7045
7046 /* If there are still other VNetRoot available, we're done */
7047 if (!IsListEmpty(&NetRoot->VirtualNetRoots))
7048 {
7049 return;
7050 }
7051
7052 /* Otherwise, initiate NetRoot finalization */
7053 if (!BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED))
7054 {
7055 RxRemovePrefixTableEntry(PrefixTable, &NetRoot->PrefixEntry);
7056 SetFlag(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED);
7057 }
7058
7059 /* Notify mini-rdr */
7060 if (NetRoot->pSrvCall != NULL && NetRoot->pSrvCall->RxDeviceObject != NULL)
7061 {
7062 NTSTATUS Status;
7063
7064 MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch,
7065 MRxFinalizeNetRoot, ((PMRX_NET_ROOT)NetRoot, FALSE));
7066 (void)Status;
7067 }
7068 }
7069
7070 VOID
7071 RxResumeBlockedOperations_ALL(
7072 IN OUT PRX_CONTEXT RxContext)
7073 {
7074 LIST_ENTRY BlockedOps;
7075
7076 PAGED_CODE();
7077
7078 /* Get the blocked operations */
7079 RxTransferListWithMutex(&BlockedOps, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex);
7080
7081 if (!IsListEmpty(&BlockedOps))
7082 {
7083 UNIMPLEMENTED;
7084 }
7085 }
7086
7087 VOID
7088 NTAPI
7089 RxResumeBlockedOperations_Serially(
7090 IN OUT PRX_CONTEXT RxContext,
7091 IN OUT PLIST_ENTRY BlockingIoQ)
7092 {
7093 PAGED_CODE();
7094
7095 RxAcquireSerializationMutex();
7096
7097 /* This can only happen on pipes */
7098 if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
7099 {
7100 RxReleaseSerializationMutex();
7101 return;
7102 }
7103
7104 UNIMPLEMENTED;
7105
7106 RxReleaseSerializationMutex();
7107 }
7108
7109 /*
7110 * @implemented
7111 */
7112 BOOLEAN
7113 RxScavengeRelatedFobxs(
7114 PFCB Fcb)
7115 {
7116 PFOBX Fobx;
7117 LIST_ENTRY LocalList;
7118 PLIST_ENTRY NextEntry;
7119 PRDBSS_SCAVENGER Scavenger;
7120
7121 PAGED_CODE();
7122
7123 /* First of all, check whether there are FOBX to scavenge */
7124 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger;
7125 RxAcquireScavengerMutex();
7126 if (Scavenger->FobxsToBeFinalized <= 0)
7127 {
7128 RxReleaseScavengerMutex();
7129 return FALSE;
7130 }
7131
7132 /* Initialize our local list which will hold all the FOBX to scavenge so
7133 * that we don't acquire the scavenger mutex too long
7134 */
7135 InitializeListHead(&LocalList);
7136
7137 /* Technically, that condition should all be true... */
7138 if (!IsListEmpty(&Scavenger->FobxFinalizationList))
7139 {
7140 PLIST_ENTRY NextEntry, LastEntry;
7141
7142 /* Browse all the FCBs to find the matching ones */
7143 NextEntry = Scavenger->FobxFinalizationList.Flink;
7144 LastEntry = &Scavenger->FobxFinalizationList;
7145 while (NextEntry != LastEntry)
7146 {
7147 Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList);
7148 NextEntry = NextEntry->Flink;
7149 /* Matching our FCB? Let's finalize it */
7150 if (Fobx->pSrvOpen != NULL && Fobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb))
7151 {
7152 RxpUndoScavengerFinalizationMarking(Fobx);
7153 ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX);
7154 InsertTailList(&LocalList, &Fobx->ScavengerFinalizationList);
7155 }
7156 }
7157 }
7158
7159 RxReleaseScavengerMutex();
7160
7161 /* Nothing to scavenge? Quit */
7162 if (IsListEmpty(&LocalList))
7163 {
7164 return FALSE;
7165 }
7166
7167 /* Now, finalize all the extracted FOBX */
7168 while (!IsListEmpty(&LocalList))
7169 {
7170 NextEntry = RemoveHeadList(&LocalList);
7171 Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList);
7172 RxFinalizeNetFobx(Fobx, TRUE, TRUE);
7173 }
7174
7175 return TRUE;
7176 }
7177
7178 VOID
7179 RxScavengerFinalizeEntries(
7180 PRDBSS_DEVICE_OBJECT DeviceObject)
7181 {
7182 UNIMPLEMENTED;
7183 }
7184
7185 /*
7186 * @implemented
7187 */
7188 VOID
7189 NTAPI
7190 RxScavengerTimerRoutine(
7191 PVOID Context)
7192 {
7193 BOOLEAN Requeue;
7194 PRDBSS_DEVICE_OBJECT DeviceObject;
7195 PRDBSS_SCAVENGER Scavenger;
7196
7197 PAGED_CODE();
7198
7199 DeviceObject = Context;
7200 Scavenger = DeviceObject->pRdbssScavenger;
7201
7202 Requeue = FALSE;
7203 RxAcquireScavengerMutex();
7204 /* If the scavenger was dormant, wake it up! */
7205 if (Scavenger->State == RDBSS_SCAVENGER_DORMANT)
7206 {
7207 /* Done */
7208 Scavenger->State = RDBSS_SCAVENGER_ACTIVE;
7209 KeResetEvent(&Scavenger->ScavengeEvent);
7210
7211 /* Scavenger the entries */
7212 RxReleaseScavengerMutex();
7213 RxScavengerFinalizeEntries(DeviceObject);
7214 RxAcquireScavengerMutex();
7215
7216 /* If we're still active (race) */
7217 if (Scavenger->State == RDBSS_SCAVENGER_ACTIVE)
7218 {
7219 /* If there are new entries to scavenge, stay dormant and requeue a run */
7220 if (Scavenger->NumberOfDormantFiles + Scavenger->SrvCallsToBeFinalized +
7221 Scavenger->NetRootsToBeFinalized + Scavenger->VNetRootsToBeFinalized +
7222 Scavenger->FcbsToBeFinalized + Scavenger->SrvOpensToBeFinalized +
7223 Scavenger->FobxsToBeFinalized != 0)
7224 {
7225 Requeue = TRUE;
7226 Scavenger->State = RDBSS_SCAVENGER_DORMANT;
7227 }
7228 /* Otherwise, we're inactive again */
7229 else
7230 {
7231 Scavenger->State = RDBSS_SCAVENGER_INACTIVE;
7232 }
7233 }
7234
7235 RxReleaseScavengerMutex();
7236
7237 /* Requeue an execution */
7238 if (Requeue)
7239 {
7240 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem,
7241 RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit);
7242 }
7243 }
7244 else
7245 {
7246 RxReleaseScavengerMutex();
7247 }
7248
7249 KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE);
7250 }
7251
7252 BOOLEAN
7253 RxScavengeVNetRoots(
7254 PRDBSS_DEVICE_OBJECT RxDeviceObject)
7255 {
7256 UNIMPLEMENTED;
7257 return FALSE;
7258 }
7259
7260 /*
7261 * @implemented
7262 */
7263 VOID
7264 NTAPI
7265 RxSpinUpRequestsDispatcher(
7266 PVOID Dispatcher)
7267 {
7268 NTSTATUS Status;
7269 PRX_DISPATCHER RxDispatcher;
7270
7271 Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, *PsThreadType, KernelMode);
7272 if (!NT_SUCCESS(Status))
7273 {
7274 PsTerminateSystemThread(STATUS_SUCCESS);
7275 }
7276
7277 RxDispatcher = Dispatcher;
7278
7279 do
7280 {
7281 KIRQL OldIrql;
7282 PLIST_ENTRY ListEntry;
7283
7284 Status = KeWaitForSingleObject(&RxDispatcher->SpinUpRequestsEvent, Executive,
7285 KernelMode, FALSE, &RxSpinUpDispatcherWaitInterval);
7286 ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_TIMEOUT));
7287
7288 KeAcquireSpinLock(&RxDispatcher->SpinUpRequestsLock, &OldIrql);
7289 if (!IsListEmpty(&RxDispatcher->SpinUpRequests))
7290 {
7291 ListEntry = RemoveHeadList(&RxDispatcher->SpinUpRequests);
7292 }
7293 else
7294 {
7295 ListEntry = &RxDispatcher->SpinUpRequests;
7296 }
7297 KeResetEvent(&RxDispatcher->SpinUpRequestsEvent);
7298 KeReleaseSpinLock(&RxDispatcher->SpinUpRequestsLock, OldIrql);
7299
7300 while (ListEntry != &RxDispatcher->SpinUpRequests)
7301 {
7302 PWORK_QUEUE_ITEM WorkItem;
7303 PRX_WORK_QUEUE WorkQueue;
7304
7305 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List);
7306 WorkQueue = WorkItem->Parameter;
7307
7308 InterlockedDecrement(&WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse);
7309
7310 DPRINT("Workqueue: calling %p(%p)\n", WorkItem->WorkerRoutine, WorkItem->Parameter);
7311 WorkItem->WorkerRoutine(WorkItem->Parameter);
7312 }
7313 } while (RxDispatcher->State == RxDispatcherActive);
7314
7315 KeSetEvent(&RxDispatcher->SpinUpRequestsTearDownEvent, IO_NO_INCREMENT, FALSE);
7316 PsTerminateSystemThread(STATUS_SUCCESS);
7317 }
7318
7319 /*
7320 * @implemented
7321 */
7322 NTSTATUS
7323 RxSpinUpWorkerThread(
7324 PRX_WORK_QUEUE WorkQueue,
7325 PRX_WORKERTHREAD_ROUTINE Routine,
7326 PVOID Parameter)
7327 {
7328 KIRQL OldIrql;
7329 NTSTATUS Status;
7330 HANDLE ThreadHandle;
7331
7332 PAGED_CODE();
7333
7334 /* If work queue is inactive, that cannot work */
7335 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
7336 if (WorkQueue->State != RxWorkQueueActive)
7337 {
7338 Status = STATUS_UNSUCCESSFUL;
7339 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
7340 }
7341 else
7342 {
7343 ++WorkQueue->NumberOfActiveWorkerThreads;
7344 Status = STATUS_SUCCESS;
7345 }
7346 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
7347
7348 /* Quit on failure */
7349 if (!NT_SUCCESS(Status))
7350 {
7351 return Status;
7352 }
7353
7354 /* Spin up the worker thread */
7355 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, Routine, Parameter);
7356 if (NT_SUCCESS(Status))
7357 {
7358 ZwClose(ThreadHandle);
7359 return Status;
7360 }
7361 /* Read well: we reached that point because it failed! */
7362 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue, Status);
7363
7364 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql);
7365 --WorkQueue->NumberOfActiveWorkerThreads;
7366 ++WorkQueue->NumberOfFailedSpinUpRequests;
7367
7368 /* Rundown, no more active threads, set the event! */
7369 if (WorkQueue->NumberOfActiveWorkerThreads == 0 &&
7370 WorkQueue->State == RxWorkQueueRundownInProgress)
7371 {
7372 KeSetEvent(&WorkQueue->pRundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE);
7373 }
7374
7375 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads);
7376
7377 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql);
7378
7379 return Status;
7380 }
7381
7382 VOID
7383 RxSpinUpWorkerThreads(
7384 PRX_WORK_QUEUE WorkQueue)
7385 {
7386 UNIMPLEMENTED;
7387 }
7388
7389 VOID
7390 RxSynchronizeWithScavenger(
7391 IN PRX_CONTEXT RxContext)
7392 {
7393 UNIMPLEMENTED;
7394 }
7395
7396 /*
7397 * @implemented
7398 */
7399 ULONG
7400 RxTableComputeHashValue(
7401 IN PUNICODE_STRING Name)
7402 {
7403 ULONG Hash;
7404 SHORT Loops[8];
7405 USHORT MaxChar, i;
7406
7407 PAGED_CODE();
7408
7409 MaxChar = Name->Length / sizeof(WCHAR);
7410
7411 Loops[0] = 1;
7412 Loops[1] = MaxChar - 1;
7413 Loops[2] = MaxChar - 2;
7414 Loops[3] = MaxChar - 3;
7415 Loops[4] = MaxChar - 4;
7416 Loops[5] = MaxChar / 4;
7417 Loops[6] = 2 * MaxChar / 4;
7418 Loops[7] = 3 * MaxChar / 4;
7419
7420 Hash = 0;
7421 for (i = 0; i < 8; ++i)
7422 {
7423 SHORT Idx;
7424
7425 Idx = Loops[i];
7426 if (Idx >= 0 && Idx < MaxChar)
7427 {
7428 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
7429 }
7430 }
7431
7432 return Hash;
7433 }
7434
7435 /*
7436 * @implemented
7437 */
7438 ULONG
7439 RxTableComputePathHashValue(
7440 IN PUNICODE_STRING Name)
7441 {
7442 ULONG Hash;
7443 SHORT Loops[8];
7444 USHORT MaxChar, i;
7445
7446 PAGED_CODE();
7447
7448 MaxChar = Name->Length / sizeof(WCHAR);
7449
7450 Loops[0] = 1;
7451 Loops[1] = MaxChar - 1;
7452 Loops[2] = MaxChar - 2;
7453 Loops[3] = MaxChar - 3;
7454 Loops[4] = MaxChar - 4;
7455 Loops[5] = MaxChar / 4;
7456 Loops[6] = 2 * MaxChar / 4;
7457 Loops[7] = 3 * MaxChar / 4;
7458
7459 Hash = 0;
7460 for (i = 0; i < 8; ++i)
7461 {
7462 SHORT Idx;
7463
7464 Idx = Loops[i];
7465 if (Idx >= 0 && Idx < MaxChar)
7466 {
7467 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash;
7468 }
7469 }
7470
7471 return Hash;
7472 }
7473
7474 /*
7475 * @implemented
7476 */
7477 PVOID
7478 RxTableLookupName(
7479 IN PRX_PREFIX_TABLE ThisTable,
7480 IN PUNICODE_STRING Name,
7481 OUT PUNICODE_STRING RemainingName,
7482 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
7483 {
7484 PVOID Container;
7485 USHORT i, MaxChar;
7486 PRX_PREFIX_ENTRY Entry;
7487 RX_CONNECTION_ID NullId;
7488 UNICODE_STRING LookupString;
7489
7490 PAGED_CODE();
7491
7492 /* If caller didn't provide a connection ID, setup one */
7493 if (ThisTable->IsNetNameTable && RxConnectionId == NULL)
7494 {
7495 NullId.Luid.LowPart = 0;
7496 NullId.Luid.HighPart = 0;
7497 RxConnectionId = &NullId;
7498 }
7499
7500 /* Validate name */
7501 ASSERT(Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR);
7502
7503 Entry = NULL;
7504 Container = NULL;
7505 LookupString.Buffer = Name->Buffer;
7506 MaxChar = Name->Length / sizeof(WCHAR);
7507 /* We'll perform the lookup, path component after another */
7508 for (i = 1; i < MaxChar; ++i)
7509 {
7510 ULONG Hash;
7511 PRX_PREFIX_ENTRY CurEntry;
7512
7513 /* Don't cut in the middle of a path element */
7514 if (Name->Buffer[i] != OBJ_NAME_PATH_SEPARATOR && Name->Buffer[i] != ':')
7515 {
7516 continue;
7517 }
7518
7519 /* Perform lookup in the table */
7520 LookupString.Length = i * sizeof(WCHAR);
7521 Hash = RxTableComputeHashValue(&LookupString);
7522 CurEntry = RxTableLookupName_ExactLengthMatch(ThisTable, &LookupString, Hash, RxConnectionId);
7523 #if DBG
7524 ++ThisTable->Lookups;
7525 #endif
7526 /* Entry not found, move to the next component */
7527 if (CurEntry == NULL)
7528 {
7529 #if DBG
7530 ++ThisTable->FailedLookups;
7531 #endif
7532 continue;
7533 }
7534
7535 Entry = CurEntry;
7536 ASSERT(Entry->ContainingRecord != NULL);
7537 Container = Entry->ContainingRecord;
7538
7539 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
7540 if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_NETROOT)
7541 {
7542 PNET_ROOT NetRoot;
7543
7544 NetRoot = (PNET_ROOT)Entry->ContainingRecord;
7545 /* If there's a default one, perfect, that's a match */
7546 if (NetRoot->DefaultVNetRoot != NULL)
7547 {
7548 Container = NetRoot->DefaultVNetRoot;
7549 }
7550 /* If none (that shouldn't happen!), try to find one */
7551 else
7552 {
7553 /* Use the first one in the list */
7554 if (!IsListEmpty(&NetRoot->VirtualNetRoots))
7555 {
7556 Container = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry);
7557 }
7558 /* Really, really, shouldn't happen */
7559 else
7560 {
7561 ASSERT(FALSE);
7562 Entry = NULL;
7563 Container = NULL;
7564 }
7565 }
7566
7567 break;
7568 }
7569 else if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_V_NETROOT)
7570 {
7571 break;
7572 }
7573 else
7574 {
7575 ASSERT((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_SRVCALL);
7576 }
7577 }
7578
7579 /* Entry was found */
7580 if (Entry != NULL)
7581 {
7582 DPRINT("Found\n");
7583
7584 ASSERT(Name->Length >= Entry->Prefix.Length);
7585
7586 /* Setup remaining name */
7587 RemainingName->Buffer = Add2Ptr(Name->Buffer, Entry->Prefix.Length);
7588 RemainingName->Length = Name->Length - Entry->Prefix.Length;
7589 RemainingName->MaximumLength = Name->Length - Entry->Prefix.Length;
7590 }
7591 else
7592 {
7593 /* Otherwise, that's the whole name */
7594 RemainingName = Name;
7595 }
7596
7597 return Container;
7598 }
7599
7600 /*
7601 * @implemented
7602 */
7603 PRX_PREFIX_ENTRY
7604 RxTableLookupName_ExactLengthMatch(
7605 IN PRX_PREFIX_TABLE ThisTable,
7606 IN PUNICODE_STRING Name,
7607 IN ULONG HashValue,
7608 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId)
7609 {
7610 PLIST_ENTRY ListEntry, HashBucket;
7611
7612 PAGED_CODE();
7613
7614 ASSERT(RxConnectionId != NULL);
7615
7616 /* Select the right bucket */
7617 HashBucket = HASH_BUCKET(ThisTable, HashValue);
7618 DPRINT("Looking in bucket: %p for %x\n", HashBucket, HashValue);
7619 /* If bucket is empty, no match */
7620 if (IsListEmpty(HashBucket))
7621 {
7622 return NULL;
7623 }
7624
7625 /* Browse all the entries in the bucket */
7626 for (ListEntry = HashBucket->Flink;
7627 ListEntry != HashBucket;
7628 ListEntry = ListEntry->Flink)
7629 {
7630 PVOID Container;
7631 PRX_PREFIX_ENTRY Entry;
7632 BOOLEAN CaseInsensitive;
7633 PUNICODE_STRING CmpName, CmpPrefix;
7634 UNICODE_STRING InsensitiveName, InsensitivePrefix;
7635
7636 Entry = CONTAINING_RECORD(ListEntry, RX_PREFIX_ENTRY, HashLinks);
7637 ++ThisTable->Considers;
7638 ASSERT(HashBucket == HASH_BUCKET(ThisTable, Entry->SavedHashValue));
7639
7640 Container = Entry->ContainingRecord;
7641 ASSERT(Container != NULL);
7642
7643 /* Not the same hash, not the same length, move on */
7644 if (Entry->SavedHashValue != HashValue || Entry->Prefix.Length != Name->Length)
7645 {
7646 continue;
7647 }
7648
7649 ++ThisTable->Compares;
7650 /* If we have to perform a case insensitive compare on a portion... */
7651 if (Entry->CaseInsensitiveLength != 0)
7652 {
7653 ASSERT(Entry->CaseInsensitiveLength <= Name->Length);
7654
7655 /* Perform the case insensitive check on the asked length */
7656 InsensitiveName.Buffer = Name->Buffer;
7657 InsensitivePrefix.Buffer = Entry->Prefix.Buffer;
7658 InsensitiveName.Length = Entry->CaseInsensitiveLength;
7659 InsensitivePrefix.Length = Entry->CaseInsensitiveLength;
7660 /* No match, move to the next entry */
7661 if (!RtlEqualUnicodeString(&InsensitiveName, &InsensitivePrefix, TRUE))
7662 {
7663 continue;
7664 }
7665
7666 /* Was the case insensitive covering the whole name? */
7667 if (Name->Length == Entry->CaseInsensitiveLength)
7668 {
7669 /* If connection ID also matches, that a complete match! */
7670 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
7671 {
7672 return Entry;
7673 }
7674 }
7675
7676 /* Otherwise, we have to continue with the sensitive match.... */
7677 InsensitiveName.Buffer = Add2Ptr(InsensitiveName.Buffer, Entry->CaseInsensitiveLength);
7678 InsensitivePrefix.Buffer = Add2Ptr(InsensitivePrefix.Buffer, Entry->CaseInsensitiveLength);
7679 InsensitiveName.Length = Name->Length - Entry->CaseInsensitiveLength;
7680 InsensitivePrefix.Length = Entry->Prefix.Length - Entry->CaseInsensitiveLength;
7681
7682 CmpName = &InsensitiveName;
7683 CmpPrefix = &InsensitivePrefix;
7684 CaseInsensitive = FALSE;
7685 }
7686 else
7687 {
7688 CmpName = Name;
7689 CmpPrefix = &Entry->Prefix;
7690 CaseInsensitive = ThisTable->CaseInsensitiveMatch;
7691 }
7692
7693 /* Perform the compare, if there's a match, also check for connection ID */
7694 if (RtlEqualUnicodeString(CmpName, CmpPrefix, CaseInsensitive))
7695 {
7696 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId))
7697 {
7698 return Entry;
7699 }
7700 }
7701 }
7702
7703 return NULL;
7704 }
7705
7706 /*
7707 * @implemented
7708 */
7709 NTSTATUS
7710 RxTearDownBufferingManager(
7711 PSRV_CALL SrvCall)
7712 {
7713 PAGED_CODE();
7714
7715 /* Nothing to do */
7716 return STATUS_SUCCESS;
7717 }
7718
7719 /*
7720 * @implemented
7721 */
7722 VOID
7723 NTAPI
7724 RxTimerDispatch(
7725 _In_ struct _KDPC *Dpc,
7726 _In_opt_ PVOID DeferredContext,
7727 _In_opt_ PVOID SystemArgument1,
7728 _In_opt_ PVOID SystemArgument2)
7729 {
7730 BOOLEAN Set;
7731 LIST_ENTRY LocalList;
7732 PLIST_ENTRY ListEntry;
7733 PRX_WORK_ITEM WorkItem;
7734
7735 InitializeListHead(&LocalList);
7736
7737 KeAcquireSpinLockAtDpcLevel(&RxTimerLock);
7738 ++RxTimerTickCount;
7739
7740 /* Find any entry matching */
7741 if (!IsListEmpty(&RxTimerQueueHead))
7742 {
7743 ListEntry = RxTimerQueueHead.Flink;
7744 do
7745 {
7746 WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
7747 if (WorkItem->LastTick == RxTimerTickCount)
7748 {
7749 ListEntry = ListEntry->Flink;
7750
7751 RemoveEntryList(&WorkItem->WorkQueueItem.List);
7752 InsertTailList(&LocalList, &WorkItem->WorkQueueItem.List);
7753 }
7754 else
7755 {
7756 ListEntry = ListEntry->Flink;
7757 }
7758 } while (ListEntry != &RxTimerQueueHead);
7759 }
7760 /* Do we have to requeue a later execution? */
7761 Set = !IsListEmpty(&RxTimerQueueHead);
7762
7763 KeReleaseSpinLockFromDpcLevel(&RxTimerLock);
7764
7765 /* Requeue if list wasn't empty */
7766 if (Set)
7767 {
7768 KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc);
7769 }
7770
7771 /* If we had matching entries */
7772 if (!IsListEmpty(&LocalList))
7773 {
7774 /* Post them, one after another */
7775 ListEntry = LocalList.Flink;
7776 do
7777 {
7778 WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List);
7779 ListEntry = ListEntry->Flink;
7780
7781 WorkItem->WorkQueueItem.List.Flink = NULL;
7782 WorkItem->WorkQueueItem.List.Blink = NULL;
7783 RxPostToWorkerThread(WorkItem->WorkQueueItem.pDeviceObject, CriticalWorkQueue,
7784 &WorkItem->WorkQueueItem, WorkItem->WorkQueueItem.WorkerRoutine,
7785 WorkItem->WorkQueueItem.Parameter);
7786 }
7787 while (ListEntry != &LocalList);
7788 }
7789 }
7790
7791 /*
7792 * @implemented
7793 */
7794 VOID
7795 RxTrackerUpdateHistory(
7796 _Inout_opt_ PRX_CONTEXT RxContext,
7797 _Inout_ PMRX_FCB MrxFcb,
7798 _In_ ULONG Operation,
7799 _In_ ULONG LineNumber,
7800 _In_ PCSTR FileName,
7801 _In_ ULONG SerialNumber)
7802 {
7803 PFCB Fcb;
7804 RX_FCBTRACKER_CASES Case;
7805
7806 /* Check for null or special context */
7807 if (RxContext == NULL)
7808 {
7809 Case = RX_FCBTRACKER_CASE_NULLCONTEXT;
7810 }
7811 else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT)
7812 {
7813 Case = RX_FCBTRACKER_CASE_CBS_CONTEXT;
7814 }
7815 else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
7816 {
7817 Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT;
7818 }
7819 else
7820 {
7821 ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT);
7822 Case = RX_FCBTRACKER_CASE_NORMAL;
7823 }
7824
7825 /* If caller provided a FCB, update its history */
7826 if (MrxFcb != NULL)
7827 {
7828 Fcb = (PFCB)MrxFcb;
7829 ASSERT(NodeTypeIsFcb(Fcb));
7830
7831 /* Only one acquire operation, so many release operations... */
7832 if (Operation == TRACKER_ACQUIRE_FCB)
7833 {
7834 ++Fcb->FcbAcquires[Case];
7835 }
7836 else
7837 {
7838 ++Fcb->FcbReleases[Case];
7839 }
7840 }
7841
7842 /* If we have a normal context, update its history about this function calls */
7843 if (Case == RX_FCBTRACKER_CASE_NORMAL)
7844 {
7845 ULONG TrackerHistoryPointer;
7846
7847 /* Only one acquire operation, so many release operations... */
7848 if (Operation == TRACKER_ACQUIRE_FCB)
7849 {
7850 InterlockedIncrement(&RxContext->AcquireReleaseFcbTrackerX);
7851 }
7852 else
7853 {
7854 InterlockedDecrement(&RxContext->AcquireReleaseFcbTrackerX);
7855 }
7856
7857 /* We only keep track of the 32 first calls */
7858 TrackerHistoryPointer = InterlockedExchangeAdd((volatile long *)&RxContext->TrackerHistoryPointer, 1);
7859 if (TrackerHistoryPointer < RDBSS_TRACKER_HISTORY_SIZE)
7860 {
7861 RxContext->TrackerHistory[TrackerHistoryPointer].AcquireRelease = Operation;
7862 RxContext->TrackerHistory[TrackerHistoryPointer].LineNumber = LineNumber;
7863 RxContext->TrackerHistory[TrackerHistoryPointer].FileName = (PSZ)FileName;
7864 RxContext->TrackerHistory[TrackerHistoryPointer].SavedTrackerValue = RxContext->AcquireReleaseFcbTrackerX;
7865 RxContext->TrackerHistory[TrackerHistoryPointer].Flags = RxContext->Flags;
7866 }
7867
7868 /* If it's negative, then we released once more than we acquired it?! */
7869 ASSERT(RxContext->AcquireReleaseFcbTrackerX >= 0);
7870 }
7871 }
7872
7873 VOID
7874 RxTrackPagingIoResource(
7875 _Inout_ PVOID Instance,
7876 _In_ ULONG Type,
7877 _In_ ULONG Line,
7878 _In_ PCSTR File)
7879 {
7880 UNIMPLEMENTED;
7881 }
7882
7883 /*
7884 * @implemented
7885 */
7886 VOID
7887 RxUndoScavengerFinalizationMarking(
7888 PVOID Instance)
7889 {
7890 /* Just call internal routine with mutex held */
7891 RxAcquireScavengerMutex();
7892 RxpUndoScavengerFinalizationMarking(Instance);
7893 RxReleaseScavengerMutex();
7894 }
7895
7896 /*
7897 * @implemented
7898 */
7899 VOID
7900 RxUninitializeVNetRootParameters(
7901 IN PUNICODE_STRING UserName,
7902 IN PUNICODE_STRING UserDomainName,
7903 IN PUNICODE_STRING Password,
7904 OUT PULONG Flags)
7905 {
7906 PAGED_CODE();
7907
7908 /* Only free what could have been allocated */
7909 if (UserName != NULL)
7910 {
7911 RxFreePool(UserName);
7912 }
7913
7914 if (UserDomainName != NULL)
7915 {
7916 RxFreePool(UserDomainName);
7917 }
7918
7919 if (Password != NULL)
7920 {
7921 RxFreePool(Password);
7922 }
7923
7924 /* And remove the possibly set CSC agent flag */
7925 if (Flags != NULL)
7926 {
7927 (*Flags) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE;
7928 }
7929 }
7930
7931 /*
7932 * @implemented
7933 */
7934 VOID
7935 RxUpdateCondition(
7936 IN RX_BLOCK_CONDITION NewConditionValue,
7937 OUT PRX_BLOCK_CONDITION Condition,
7938 IN OUT PLIST_ENTRY TransitionWaitList)
7939 {
7940 PRX_CONTEXT Context;
7941 LIST_ENTRY SerializationQueue;
7942
7943 PAGED_CODE();
7944
7945 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue, Condition, TransitionWaitList);
7946
7947 /* Set the new condition */
7948 RxAcquireSerializationMutex();
7949 ASSERT(NewConditionValue != Condition_InTransition);
7950 *Condition = NewConditionValue;
7951 /* And get the serialization queue for treatment */
7952 RxTransferList(&SerializationQueue, TransitionWaitList);
7953 RxReleaseSerializationMutex();
7954
7955 /* Handle the serialization queue */
7956 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
7957 while (Context != NULL)
7958 {
7959 /* If the caller asked for post, post the request */
7960 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
7961 {
7962 Context->Flags &= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION;
7963 RxFsdPostRequest(Context);
7964 }
7965 /* Otherwise, wake up sleeping waiters */
7966 else
7967 {
7968 RxSignalSynchronousWaiter(Context);
7969 }
7970
7971 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue);
7972 }
7973 }
7974
7975 /*
7976 * @implemented
7977 */
7978 VOID
7979 RxVerifyOperationIsLegal(
7980 IN PRX_CONTEXT RxContext)
7981 {
7982 PIRP Irp;
7983 PMRX_FOBX Fobx;
7984 BOOLEAN FlagSet;
7985 PFILE_OBJECT FileObject;
7986 PIO_STACK_LOCATION Stack;
7987
7988 PAGED_CODE();
7989
7990 Irp = RxContext->CurrentIrp;
7991 Stack = RxContext->CurrentIrpSp;
7992 FileObject = Stack->FileObject;
7993
7994 /* We'll only check stuff on opened files, this requires an IRP and a FO */
7995 if (Irp == NULL || FileObject == NULL)
7996 {
7997 return;
7998 }
7999
8000 /* Set no exception for breakpoint - remember whether is was already set */
8001 FlagSet = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8002 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8003
8004 /* If we have a CCB, perform a few checks on opened file */
8005 Fobx = RxContext->pFobx;
8006 if (Fobx != NULL)
8007 {
8008 PMRX_SRV_OPEN SrvOpen;
8009
8010 SrvOpen = Fobx->pSrvOpen;
8011 if (SrvOpen != NULL)
8012 {
8013 UCHAR MajorFunction;
8014
8015 MajorFunction = RxContext->MajorFunction;
8016 /* Only allow closing/cleanup operations on renamed files */
8017 if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE &&
8018 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
8019 {
8020 RxContext->IoStatusBlock.Status = STATUS_FILE_RENAMED;
8021 ExRaiseStatus(STATUS_FILE_RENAMED);
8022 }
8023
8024 /* Only allow closing/cleanup operations on deleted files */
8025 if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE &&
8026 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED))
8027 {
8028 RxContext->IoStatusBlock.Status = STATUS_FILE_DELETED;
8029 ExRaiseStatus(STATUS_FILE_DELETED);
8030 }
8031 }
8032 }
8033
8034 /* If that's an open operation */
8035 if (RxContext->MajorFunction == IRP_MJ_CREATE)
8036 {
8037 PFILE_OBJECT RelatedFileObject;
8038
8039 /* We won't allow an open operation relative to a file to be deleted */
8040 RelatedFileObject = FileObject->RelatedFileObject;
8041 if (RelatedFileObject != NULL)
8042 {
8043 PMRX_FCB Fcb;
8044
8045 Fcb = RelatedFileObject->FsContext;
8046 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
8047 {
8048 RxContext->IoStatusBlock.Status = STATUS_DELETE_PENDING;
8049 ExRaiseStatus(STATUS_DELETE_PENDING);
8050 }
8051 }
8052 }
8053
8054 /* If cleanup was completed */
8055 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
8056 {
8057 if (!BooleanFlagOn(Irp->Flags, IRP_PAGING_IO))
8058 {
8059 UCHAR MajorFunction;
8060
8061 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
8062 MajorFunction = Stack->MajorFunction;
8063 if (MajorFunction != IRP_MJ_CLOSE && MajorFunction != IRP_MJ_QUERY_INFORMATION &&
8064 MajorFunction != IRP_MJ_SET_INFORMATION)
8065 {
8066 if ((MajorFunction != IRP_MJ_READ && MajorFunction != IRP_MJ_WRITE) ||
8067 !BooleanFlagOn(Stack->MinorFunction, IRP_MN_COMPLETE))
8068 {
8069 RxContext->IoStatusBlock.Status = STATUS_FILE_CLOSED;
8070 ExRaiseStatus(STATUS_FILE_CLOSED);
8071 }
8072 }
8073 }
8074 }
8075
8076 /* If flag was already set, don't clear it */
8077 if (!FlagSet)
8078 {
8079 ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT);
8080 }
8081 }
8082
8083 /*
8084 * @implemented
8085 */
8086 VOID
8087 RxWaitForStableCondition(
8088 IN PRX_BLOCK_CONDITION Condition,
8089 IN OUT PLIST_ENTRY TransitionWaitList,
8090 IN OUT PRX_CONTEXT RxContext,
8091 OUT NTSTATUS *AsyncStatus OPTIONAL)
8092 {
8093 BOOLEAN Wait;
8094 NTSTATUS LocalStatus;
8095
8096 PAGED_CODE();
8097
8098 /* Make sure to always get status */
8099 if (AsyncStatus == NULL)
8100 {
8101 AsyncStatus = &LocalStatus;
8102 }
8103
8104 /* By default, it's a success */
8105 *AsyncStatus = STATUS_SUCCESS;
8106
8107 Wait = FALSE;
8108 /* If it's not stable, we've to wait */
8109 if (!StableCondition(*Condition))
8110 {
8111 /* Lock the mutex */
8112 RxAcquireSerializationMutex();
8113 /* Still not stable? */
8114 if (!StableCondition(*Condition))
8115 {
8116 /* Insert us in the wait list for processing on stable condition */
8117 RxInsertContextInSerializationQueue(TransitionWaitList, RxContext);
8118
8119 /* If we're asked to post on stable, don't wait, and just return pending */
8120 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION))
8121 {
8122 *AsyncStatus = STATUS_PENDING;
8123 }
8124 else
8125 {
8126 Wait = TRUE;
8127 }
8128 }
8129 RxReleaseSerializationMutex();
8130
8131 /* We don't post on stable, so, just wait... */
8132 if (Wait)
8133 {
8134 RxWaitSync(RxContext);
8135 }
8136 }
8137 }
8138
8139 /*
8140 * @implemented
8141 */
8142 VOID
8143 NTAPI
8144 RxWorkItemDispatcher(
8145 PVOID Context)
8146 {
8147 PRX_WORK_DISPATCH_ITEM DispatchItem = Context;
8148
8149 DPRINT("Calling: %p, %p\n", DispatchItem->DispatchRoutine, DispatchItem->DispatchRoutineParameter);
8150
8151 DispatchItem->DispatchRoutine(DispatchItem->DispatchRoutineParameter);
8152
8153 RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG);
8154 }
8155
8156 /*
8157 * @implemented
8158 */
8159 PVOID
8160 NTAPI
8161 _RxAllocatePoolWithTag(
8162 _In_ POOL_TYPE PoolType,
8163 _In_ SIZE_T NumberOfBytes,
8164 _In_ ULONG Tag)
8165 {
8166 return ExAllocatePoolWithTagPriority(PoolType, NumberOfBytes, Tag, LowPoolPriority);
8167 }
8168
8169 /*
8170 * @implemented
8171 */
8172 VOID
8173 NTAPI
8174 _RxFreePool(
8175 _In_ PVOID Buffer)
8176 {
8177 ExFreePoolWithTag(Buffer, 0);
8178 }
8179
8180 /*
8181 * @implemented
8182 */
8183 VOID
8184 NTAPI
8185 _RxFreePoolWithTag(
8186 _In_ PVOID Buffer,
8187 _In_ ULONG Tag)
8188 {
8189 ExFreePoolWithTag(Buffer, Tag);
8190 }
8191
8192 NTSTATUS
8193 __RxAcquireFcb(
8194 _Inout_ PFCB Fcb,
8195 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL,
8196 _In_ ULONG Mode
8197 #ifdef RDBSS_TRACKER
8198 ,
8199 _In_ ULONG LineNumber,
8200 _In_ PCSTR FileName,
8201 _In_ ULONG SerialNumber
8202 #endif
8203 )
8204 {
8205 NTSTATUS Status;
8206 BOOLEAN SpecialContext, CanWait, Acquired, ContextIsPresent;
8207
8208 PAGED_CODE();
8209
8210 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb, RxContext, Mode, LineNumber, FileName, SerialNumber);
8211
8212 SpecialContext = FALSE;
8213 ContextIsPresent = FALSE;
8214 /* Check for special context */
8215 if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT || RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT)
8216 {
8217 SpecialContext = TRUE;
8218 }
8219
8220 /* We don't handle buffering state change yet... */
8221 if (!RxIsFcbAcquired(Fcb) && !SpecialContext &&
8222 BooleanFlagOn(Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING))
8223 {
8224 UNIMPLEMENTED;
8225 }
8226
8227 /* Nor special contexts */
8228 if (SpecialContext)
8229 {
8230 UNIMPLEMENTED;
8231 }
8232
8233 /* If we don't have a context, assume we can wait! */
8234 if (RxContext == NULL)
8235 {
8236 CanWait = TRUE;
8237 }
8238 else
8239 {
8240 /* That said: we have a real context! */
8241 ContextIsPresent = TRUE;
8242
8243 /* If we've been cancelled in between, give up */
8244 Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS;
8245 if (!NT_SUCCESS(Status))
8246 {
8247 return Status;
8248 }
8249
8250 /* Can we wait? */
8251 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
8252 }
8253
8254 while (TRUE)
8255 {
8256 /* Assume we cannot lock */
8257 Status = STATUS_LOCK_NOT_GRANTED;
8258
8259 /* Lock according to what the caller asked */
8260 switch (Mode)
8261 {
8262 case FCB_MODE_EXCLUSIVE:
8263 Acquired = ExAcquireResourceExclusiveLite(Fcb->Header.Resource, CanWait);
8264 break;
8265
8266 case FCB_MODE_SHARED:
8267 Acquired = ExAcquireResourceSharedLite(Fcb->Header.Resource, CanWait);
8268 break;
8269
8270 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE:
8271 Acquired = ExAcquireSharedWaitForExclusive(Fcb->Header.Resource, CanWait);
8272 break;
8273
8274 default:
8275 ASSERT(Mode == FCB_MODE_SHARED_STARVE_EXCLUSIVE);
8276 Acquired = ExAcquireSharedStarveExclusive(Fcb->Header.Resource, CanWait);
8277 break;
8278 }
8279
8280 /* Lock granted! */
8281 if (Acquired)
8282 {
8283 Status = STATUS_SUCCESS;
8284 ASSERT_CORRECT_FCB_STRUCTURE(Fcb);
8285
8286 /* Handle paging write - not implemented */
8287 if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
8288 {
8289 UNIMPLEMENTED;
8290 }
8291 }
8292
8293 /* And break, that cool! */
8294 if (Acquired)
8295 {
8296 break;
8297 }
8298
8299 /* If it failed, return immediately */
8300 if (!NT_SUCCESS(Status))
8301 {
8302 return Status;
8303 }
8304 }
8305
8306 /* If we don't have to check for valid operation, job done, nothing more to do */
8307 if (!ContextIsPresent || BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK))
8308 {
8309 if (NT_SUCCESS(Status))
8310 {
8311 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
8312 }
8313
8314 return Status;
8315 }
8316
8317 /* Verify operation */
8318 _SEH2_TRY
8319 {
8320 RxVerifyOperationIsLegal(RxContext);
8321 }
8322 _SEH2_FINALLY
8323 {
8324 /* If it failed, release lock and fail */
8325 if (_SEH2_AbnormalTermination())
8326 {
8327 ExReleaseResourceLite(Fcb->Header.Resource);
8328 Status = STATUS_LOCK_NOT_GRANTED;
8329 }
8330 }
8331 _SEH2_END;
8332
8333 if (NT_SUCCESS(Status))
8334 {
8335 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber);
8336 }
8337
8338 DPRINT("Status: %x\n", Status);
8339 return Status;
8340 }
8341
8342 /*
8343 * @implemented
8344 */
8345 VOID
8346 __RxItsTheSameContext(
8347 _In_ PRX_CONTEXT RxContext,
8348 _In_ ULONG CapturedRxContextSerialNumber,
8349 _In_ ULONG Line,
8350 _In_ PCSTR File)
8351 {
8352 /* Check we have a context with the same serial number */
8353 if (NodeType(RxContext) != RDBSS_NTC_RX_CONTEXT ||
8354 RxContext->SerialNumber != CapturedRxContextSerialNumber)
8355 {
8356 /* Just be noisy */
8357 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext, Line, File);
8358 }
8359 }
8360
8361 VOID
8362 __RxReleaseFcb(
8363 _Inout_opt_ PRX_CONTEXT RxContext,
8364 _Inout_ PMRX_FCB MrxFcb
8365 #ifdef RDBSS_TRACKER
8366 ,
8367 _In_ ULONG LineNumber,
8368 _In_ PCSTR FileName,
8369 _In_ ULONG SerialNumber
8370 #endif
8371 )
8372 {
8373 BOOLEAN IsExclusive, BufferingPending;
8374
8375 RxAcquireSerializationMutex();
8376
8377 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
8378 IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
8379
8380 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
8381 * then just release the FCB
8382 */
8383 if (!BufferingPending || !IsExclusive)
8384 {
8385 RxTrackerUpdateHistory(RxContext, MrxFcb, (!BufferingPending ? TRACKER_RELEASE_FCB_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING),
8386 LineNumber, FileName, SerialNumber);
8387 ExReleaseResourceLite(MrxFcb->Header.Resource);
8388 }
8389
8390 RxReleaseSerializationMutex();
8391
8392 /* And finally leave */
8393 if (!BufferingPending || !IsExclusive)
8394 {
8395 return;
8396 }
8397
8398 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb));
8399
8400 /* Otherwise, handle buffering state and release */
8401 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
8402
8403 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING, LineNumber, FileName, SerialNumber);
8404 ExReleaseResourceLite(MrxFcb->Header.Resource);
8405 }
8406
8407 VOID
8408 __RxReleaseFcbForThread(
8409 _Inout_opt_ PRX_CONTEXT RxContext,
8410 _Inout_ PMRX_FCB MrxFcb,
8411 _In_ ERESOURCE_THREAD ResourceThreadId
8412 #ifdef RDBSS_TRACKER
8413 ,
8414 _In_ ULONG LineNumber,
8415 _In_ PCSTR FileName,
8416 _In_ ULONG SerialNumber
8417 #endif
8418 )
8419 {
8420 BOOLEAN IsExclusive, BufferingPending;
8421
8422 RxAcquireSerializationMutex();
8423
8424 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING);
8425 IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource);
8426
8427 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
8428 * then just release the FCB
8429 */
8430 if (!BufferingPending || !IsExclusive)
8431 {
8432 RxTrackerUpdateHistory(RxContext, MrxFcb,
8433 (!BufferingPending ? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING),
8434 LineNumber, FileName, SerialNumber);
8435 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
8436 }
8437
8438 RxReleaseSerializationMutex();
8439
8440 /* And finally leave */
8441 if (!BufferingPending || !IsExclusive)
8442 {
8443 return;
8444 }
8445
8446 /* Otherwise, handle buffering state and release */
8447 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING, LineNumber, FileName, SerialNumber);
8448 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb);
8449 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId);
8450 }