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