3 * Copyright (C) 2017 ReactOS Team
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.
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.
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.
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)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
);
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown
);
54 RxFinishSrvCallConstructionDispatcher(
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
60 WORK_QUEUE_TYPE WorkQueueType
,
61 PRX_WORK_DISPATCH_ITEM DispatchItem
);
65 PRX_CONTEXT RxContext
);
72 extern ULONG ReadAheadGranularity
;
74 volatile LONG RxNumberOfActiveFcbs
= 0;
75 ULONG SerialNumber
= 1;
77 volatile ULONG RxContextSerialNumberCounter
;
78 BOOLEAN RxStopOnLoudCompletion
= TRUE
;
79 BOOLEAN RxSrvCallConstructionDispatcherActive
= FALSE
;
80 LIST_ENTRY RxSrvCalldownList
;
81 RX_SPIN_LOCK RxStrucSupSpinLock
;
82 ULONG RdbssReferenceTracingValue
;
83 LARGE_INTEGER RxWorkQueueWaitInterval
[RxMaximumWorkQueue
];
84 LARGE_INTEGER RxSpinUpDispatcherWaitInterval
;
85 RX_DISPATCHER RxDispatcher
;
86 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues
;
87 FAST_MUTEX RxLowIoPagingIoSyncMutex
;
88 BOOLEAN RxContinueFromAssert
= TRUE
;
90 BOOLEAN DumpDispatchRoutine
= TRUE
;
92 BOOLEAN DumpDispatchRoutine
= FALSE
;
102 RxAssert(#exp, __FILE__, __LINE__, NULL); \
105 /* FUNCTIONS ****************************************************************/
111 RxAddVirtualNetRootToNetRoot(
113 PV_NET_ROOT VNetRoot
)
117 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
119 /* Insert in the VNetRoot list - make sure lock is held */
120 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
122 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
123 ++NetRoot
->NumberOfVirtualNetRoots
;
124 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
132 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
133 NODE_TYPE_CODE NodeType
,
136 PVOID AlreadyAllocatedObject
)
141 PVOID Buffer
, PAPNBuffer
;
142 PNON_PAGED_FCB NonPagedFcb
;
143 PMINIRDR_DISPATCH Dispatch
;
144 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
148 Dispatch
= RxDeviceObject
->Dispatch
;
161 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
162 if (NodeType
== RDBSS_NTC_FOBX
)
164 FobxSize
= sizeof(FOBX
);
165 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
167 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
170 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
171 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
173 SrvOpenSize
= sizeof(SRV_OPEN
);
174 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
176 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
179 FobxSize
= sizeof(FOBX
);
180 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
182 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
185 /* Otherwise, we're asked to allocate a FCB */
188 /* So, allocate the FCB and its extension if asked */
189 FcbSize
= sizeof(FCB
);
190 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
192 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
195 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
196 * Otherwise, it will be allocated later on, specifically
198 if (PoolType
== NonPagedPool
)
200 NonPagedSize
= sizeof(NON_PAGED_FCB
);
203 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
204 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
206 SrvOpenSize
= sizeof(SRV_OPEN
);
207 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
209 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
212 FobxSize
= sizeof(FOBX
);
213 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
215 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
220 /* If we already have a buffer, go ahead */
221 if (AlreadyAllocatedObject
!= NULL
)
223 Buffer
= AlreadyAllocatedObject
;
225 /* Otherwise, allocate it */
228 Buffer
= ExAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
235 /* Now, get the pointers - FOBX is easy */
236 if (NodeType
== RDBSS_NTC_FOBX
)
240 /* SRV_OPEN first, FOBX next */
241 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
244 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
246 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
252 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
254 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
256 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
257 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
260 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
261 if (PoolType
!= NonPagedPool
)
263 NonPagedFcb
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
264 if (NonPagedFcb
== NULL
)
266 ExFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
270 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
272 /* Otherwise, just point at the right place in what has been allocated previously */
275 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
276 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
280 /* If we have allocated a SRV_OPEN, initialize it */
283 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
285 if (NodeType
== RDBSS_NTC_SRVOPEN
)
287 SrvOpen
->InternalFobx
= Fobx
;
291 SrvOpen
->InternalFobx
= NULL
;
292 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
295 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
297 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
300 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
303 /* If we have allocated a FOBX, initialize it */
306 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
308 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
310 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
314 /* If we have allocated a FCB, initialize it */
317 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
319 Fcb
->NonPaged
= NonPagedFcb
;
320 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
321 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
322 NonPagedFcb
->FcbBackPointer
= Fcb
;
324 Fcb
->InternalSrvOpen
= SrvOpen
;
325 Fcb
->InternalFobx
= Fobx
;
327 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
328 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
329 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
331 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
333 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
336 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
338 InterlockedIncrement(&RxNumberOfActiveFcbs
);
339 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
341 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
342 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
353 NODE_TYPE_CODE NodeType
,
354 PMINIRDR_DISPATCH MRxDispatch
,
357 ULONG Tag
, ObjectSize
;
358 PVOID Object
, *Extension
;
359 PRX_PREFIX_ENTRY PrefixEntry
;
360 USHORT StructSize
, ExtensionSize
;
364 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
368 case RDBSS_NTC_SRVCALL
:
369 Tag
= RX_SRVCALL_POOLTAG
;
370 StructSize
= sizeof(SRV_CALL
);
371 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
373 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
377 case RDBSS_NTC_NETROOT
:
378 Tag
= RX_NETROOT_POOLTAG
;
379 StructSize
= sizeof(NET_ROOT
);
380 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
382 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
386 case RDBSS_NTC_V_NETROOT
:
387 Tag
= RX_V_NETROOT_POOLTAG
;
388 StructSize
= sizeof(V_NET_ROOT
);
389 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
391 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
400 /* Now, allocate the object */
401 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
402 Object
= ExAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
408 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
410 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
413 case RDBSS_NTC_SRVCALL
:
414 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
415 Extension
= &((PSRV_CALL
)Object
)->Context
;
416 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
419 case RDBSS_NTC_NETROOT
:
420 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
421 Extension
= &((PNET_ROOT
)Object
)->Context
;
422 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
425 case RDBSS_NTC_V_NETROOT
:
426 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
427 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
435 /* Set the prefix table unicode string */
436 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
437 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
438 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
439 PrefixEntry
->Prefix
.Length
= NameLength
;
440 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
441 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
443 /* Return the extension if we are asked to manage it */
444 if (ExtensionSize
!= 0)
446 *Extension
= Add2Ptr(Object
, StructSize
);
465 /* If we're not asked to continue, just stop the system */
466 if (!RxContinueFromAssert
)
468 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
471 /* Otherwise, capture context to offer the user to dump it */
472 RtlCaptureContext(&Context
);
474 /* Loop until the user hits 'i' */
477 /* If no file provided, use empty name */
483 /* If no message provided, use empty one */
489 /* Display the message */
490 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
491 /* And ask the user */
492 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
493 /* If he asks for ignore, quit
494 * In case of invalid input, ask again
496 if (Response
[0] != 'B' && Response
[0] != 'b')
498 if (Response
[0] == 'I' || Response
[0] == 'i')
506 /* Break: offer the user to dump the context and break */
507 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
510 /* Continue looping, so that after dump, execution can continue (with ignore) */
519 RxBootstrapWorkerThreadDispatcher(
522 PRX_WORK_QUEUE RxWorkQueue
;
526 RxWorkQueue
= WorkQueue
;
527 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
531 RxCheckVNetRootCredentials(
532 PRX_CONTEXT RxContext
,
533 PV_NET_ROOT VNetRoot
,
535 PUNICODE_STRING UserName
,
536 PUNICODE_STRING UserDomain
,
537 PUNICODE_STRING Password
,
542 /* If that's a UNC name, there's nothing to process */
543 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
544 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
547 return STATUS_MORE_PROCESSING_REQUIRED
;
550 /* Compare the logon ID in the VNetRoot with the one provided */
551 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
553 return STATUS_MORE_PROCESSING_REQUIRED
;
556 /* No credential provided? That's OK */
557 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
559 return STATUS_SUCCESS
;
564 return STATUS_NOT_IMPLEMENTED
;
576 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
578 ASSERT(Context
!= NULL
);
579 ASSERT(Context
->CurrentIrp
!= NULL
);
580 Irp
= Context
->CurrentIrp
;
582 /* Debug what the caller asks for */
583 if (Context
->LoudCompletionString
!= NULL
)
585 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
586 /* Does the user asks to stop on failed completion */
587 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
589 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
593 /* Complete for real */
594 Context
->CurrentIrp
= NULL
;
595 RxCompleteRequest_Real(Context
, Irp
, Status
);
597 DPRINT("Status: %lx\n", Status
);
605 RxCompleteRequest_Real(
606 IN PRX_CONTEXT RxContext
,
612 PIO_STACK_LOCATION Stack
;
614 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
616 /* Nothing to complete, just free context */
619 DPRINT("NULL IRP for %p\n", RxContext
);
620 if (RxContext
!= NULL
)
622 RxDereferenceAndDeleteRxContext_Real(RxContext
);
628 /* Remove cancel routine */
629 IoAcquireCancelSpinLock(&OldIrql
);
630 IoSetCancelRoutine(Irp
, NULL
);
631 IoReleaseCancelSpinLock(OldIrql
);
633 /* Select the boost, given the success/paging operation */
634 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
636 Boost
= IO_DISK_INCREMENT
;
640 Irp
->IoStatus
.Information
= 0;
641 Boost
= IO_NO_INCREMENT
;
643 Irp
->IoStatus
.Status
= Status
;
645 if (RxContext
!= NULL
)
647 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
648 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
650 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
651 RxContext
->MinorFunction
, RxContext
, Irp
,
652 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
656 /* If that's an opening, there might be a canonical name allocated,
657 * if completion isn't pending, release it
659 Stack
= IoGetCurrentIrpStackLocation(Irp
);
660 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
663 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
665 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
668 RxpPrepareCreateContextForReuse(RxContext
);
669 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
672 /* If it's a write, validate the correct behavior of the operation */
673 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
675 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
677 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
681 /* If it's pending, make sure IRP is marked as such */
682 if (RxContext
!= NULL
)
684 if (RxContext
->PendingReturned
)
686 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
691 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
692 IoCompleteRequest(Irp
, Boost
);
694 /* If there's a context, dereference it */
695 if (RxContext
!= NULL
)
697 RxDereferenceAndDeleteRxContext_Real(RxContext
);
702 RxCompleteSrvOpenKeyAssociation(
703 IN OUT PSRV_OPEN SrvOpen
)
713 IN PRX_CONTEXT RxContext
,
714 IN PSRV_CALL SrvCall
,
715 IN PNET_ROOT NetRoot
,
716 IN PV_NET_ROOT VirtualNetRoot
,
717 OUT PLOCK_HOLDING_STATE LockHoldingState
)
720 PRX_PREFIX_TABLE PrefixTable
;
721 PMRX_CREATENETROOT_CONTEXT Context
;
722 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
726 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
727 VirtualNetRoot
, LockHoldingState
);
729 /* Validate the lock is exclusively held */
730 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
731 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
733 /* Allocate the context */
734 Context
= ExAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
737 return STATUS_INSUFFICIENT_RESOURCES
;
740 /* We can release lock now */
741 RxReleasePrefixTableLock(PrefixTable
);
742 *LockHoldingState
= LHS_LockNotHeld
;
744 RootCondition
= Condition_Bad
;
745 VRootCondition
= Condition_Bad
;
747 /* Initialize the context */
748 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
749 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
750 Context
->RxContext
= RxContext
;
751 Context
->pVNetRoot
= VirtualNetRoot
;
752 Context
->Callback
= RxCreateNetRootCallBack
;
754 /* And call the mini-rdr */
755 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
756 if (Status
== STATUS_PENDING
)
758 /* Wait for the mini-rdr to be done */
759 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
760 /* Update the structures condition according to mini-rdr return */
761 if (NT_SUCCESS(Context
->NetRootStatus
))
763 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
765 RootCondition
= Condition_Good
;
766 VRootCondition
= Condition_Good
;
767 Status
= STATUS_SUCCESS
;
771 RootCondition
= Condition_Good
;
772 Status
= Context
->VirtualNetRootStatus
;
777 Status
= Context
->VirtualNetRootStatus
;
778 if (NT_SUCCESS(Status
))
780 Status
= Context
->NetRootStatus
;
786 /* It has to return STATUS_PENDING! */
790 /* Acquire lock again - for caller lock status will remain unchanged */
791 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
792 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
793 *LockHoldingState
= LHS_ExclusiveLockHeld
;
795 /* Do the transition to the condition got from mini-rdr */
796 RxTransitionNetRoot(NetRoot
, RootCondition
);
797 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
799 /* Context is not longer needed */
800 ExFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
802 DPRINT("Status: %x\n", Status
);
812 IN PRX_CONTEXT RxContext
,
813 IN PSRV_CALL SrvCall
,
814 OUT PLOCK_HOLDING_STATE LockHoldingState
)
817 PRX_PREFIX_TABLE PrefixTable
;
818 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
819 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
820 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
824 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
826 /* Validate the lock is exclusively held */
827 RxDeviceObject
= RxContext
->RxDeviceObject
;
828 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
829 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
831 /* Allocate the context for mini-rdr */
832 Calldown
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
833 if (Calldown
== NULL
)
835 SrvCall
->Context
= NULL
;
836 SrvCall
->Condition
= Condition_Bad
;
837 RxReleasePrefixTableLock(PrefixTable
);
838 *LockHoldingState
= LHS_LockNotHeld
;
839 return STATUS_INSUFFICIENT_RESOURCES
;
843 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
845 SrvCall
->Context
= NULL
;
846 SrvCall
->Condition
= Condition_InTransition
;
848 RxReleasePrefixTableLock(PrefixTable
);
849 *LockHoldingState
= LHS_LockNotHeld
;
851 CallbackContext
= &Calldown
->CallbackContexts
[0];
852 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
853 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
854 CallbackContext
->SrvCalldownStructure
= Calldown
;
855 CallbackContext
->CallbackContextOrdinal
= 0;
856 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
858 RxReferenceSrvCall(SrvCall
);
860 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
861 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
863 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
867 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
870 Calldown
->NumberToWait
= 1;
871 Calldown
->NumberRemaining
= 1;
872 Calldown
->RxContext
= RxContext
;
873 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
874 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
875 Calldown
->BestFinisher
= NULL
;
876 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
877 InitializeListHead(&Calldown
->SrvCalldownList
);
879 /* Call the mini-rdr */
880 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
881 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
882 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
883 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
884 /* It has to return STATUS_PENDING! */
885 ASSERT(Status
== STATUS_PENDING
);
887 /* No async, start completion */
888 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
890 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
892 /* Finish construction - we'll notify mini-rdr it's the winner */
893 Status
= RxFinishSrvCallConstruction(Calldown
);
894 if (!NT_SUCCESS(Status
))
896 RxReleasePrefixTableLock(PrefixTable
);
897 *LockHoldingState
= LHS_LockNotHeld
;
901 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
902 *LockHoldingState
= LHS_ExclusiveLockHeld
;
906 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
914 RxConstructVirtualNetRoot(
915 IN PRX_CONTEXT RxContext
,
916 IN PUNICODE_STRING CanonicalName
,
917 IN NET_ROOT_TYPE NetRootType
,
918 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
919 OUT PLOCK_HOLDING_STATE LockHoldingState
,
920 OUT PRX_CONNECTION_ID RxConnectionId
)
923 PV_NET_ROOT VNetRoot
;
924 RX_BLOCK_CONDITION Condition
;
925 UNICODE_STRING LocalNetRootName
, FilePathName
;
929 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
932 Condition
= Condition_Bad
;
933 /* Before creating the VNetRoot, try to find the appropriate connection */
934 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
935 &LocalNetRootName
, &FilePathName
,
936 LockHoldingState
, RxConnectionId
);
937 /* Found and active */
938 if (Status
== STATUS_CONNECTION_ACTIVE
)
940 /* We need a new VNetRoot */
941 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
942 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
943 if (VNetRoot
!= NULL
)
945 RxReferenceVNetRoot(VNetRoot
);
948 /* Dereference previous VNetRoot */
949 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
950 /* Reset and start construct (new structures will replace old ones) */
951 RxContext
->Create
.pSrvCall
= NULL
;
952 RxContext
->Create
.pNetRoot
= NULL
;
953 RxContext
->Create
.pVNetRoot
= NULL
;
955 /* Construct new NetRoot */
956 if (VNetRoot
!= NULL
)
958 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
959 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
960 if (NT_SUCCESS(Status
))
962 Condition
= Condition_Good
;
967 Status
= STATUS_INSUFFICIENT_RESOURCES
;
972 /* If it failed creating the connection, leave */
973 if (Status
!= STATUS_SUCCESS
)
975 if (*LockHoldingState
!= LHS_LockNotHeld
)
977 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
978 *LockHoldingState
= LHS_LockNotHeld
;
981 *VirtualNetRootPointer
= VNetRoot
;
982 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
986 *LockHoldingState
= LHS_ExclusiveLockHeld
;
988 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
989 Condition
= Condition_Good
;
992 /* We have a non stable VNetRoot - transition it */
993 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
995 RxTransitionVNetRoot(VNetRoot
, Condition
);
998 /* If recreation failed */
999 if (Status
!= STATUS_SUCCESS
)
1001 /* Dereference potential VNetRoot */
1002 if (VNetRoot
!= NULL
)
1004 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1005 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1010 if (*LockHoldingState
!= LHS_LockNotHeld
)
1012 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1013 *LockHoldingState
= LHS_LockNotHeld
;
1017 *VirtualNetRootPointer
= VNetRoot
;
1021 /* Return the allocated VNetRoot */
1022 *VirtualNetRootPointer
= VNetRoot
;
1031 IN PRX_CONTEXT RxContext
,
1032 IN PV_NET_ROOT VNetRoot
,
1033 IN PUNICODE_STRING Name
)
1039 NODE_TYPE_CODE NodeType
;
1040 PIO_STACK_LOCATION Stack
;
1041 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1045 /* We need a decent VNetRoot */
1046 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1048 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1049 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1050 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1052 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1053 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1055 Stack
= RxContext
->CurrentIrpSp
;
1057 /* Do we need to create a fake FCB? Like for renaming */
1058 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1059 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1060 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1062 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1063 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1065 /* Allocate the FCB */
1066 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1067 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1073 /* Initialize the FCB */
1074 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1075 Fcb
->RxDeviceObject
= RxDeviceObject
;
1076 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1077 Fcb
->VNetRoot
= VNetRoot
;
1078 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1080 InitializeListHead(&Fcb
->SrvOpenList
);
1081 Fcb
->SrvOpenListVersion
= 0;
1083 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1084 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1085 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1086 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1087 NetRoot
->InnerNamePrefix
.Length
);
1088 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1090 /* Copy back parameters from RxContext */
1091 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1093 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1096 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1098 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1100 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1103 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1105 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1108 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1109 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1111 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1112 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1114 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1115 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1117 /* Fake FCB doesn't go in prefix table */
1120 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1121 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1122 DPRINT("Fake FCB: %p\n", Fcb
);
1126 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1129 RxReferenceVNetRoot(VNetRoot
);
1130 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1132 Fcb
->ulFileSizeVersion
= 0;
1134 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1135 RxReferenceNetFcb(Fcb
);
1146 OUT PRX_CONTEXT RxContext
,
1147 IN PMRX_SRV_OPEN MrxSrvOpen
)
1158 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1159 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1160 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1161 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1164 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1165 /* Can we use pre-allocated FOBX? */
1166 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1168 Fobx
= Fcb
->InternalFobx
;
1169 /* Call allocate to initialize the FOBX */
1170 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1171 /* Mark it used now */
1172 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1173 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1175 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1177 Fobx
= SrvOpen
->InternalFobx
;
1178 /* Call allocate to initialize the FOBX */
1179 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1180 /* Mark it used now */
1181 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1182 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1186 /* Last case, we cannot, allocate a FOBX */
1187 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1191 /* Allocation failed! */
1198 Fobx
->Flags
= Flags
;
1200 /* Initialize throttling */
1201 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1202 if (NetRoot
!= NULL
)
1204 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1206 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1207 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1208 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1210 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1212 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1213 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1214 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1218 /* Propagate flags fron RxContext */
1219 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1221 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1224 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1226 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1230 Fobx
->FobxSerialNumber
= 0;
1231 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1232 Fobx
->NodeReferenceCount
= 1;
1233 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1235 RxReferenceSrvOpen(SrvOpen
);
1236 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1238 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1239 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1240 InitializeListHead(&Fobx
->ClosePendingList
);
1242 Fobx
->CloseTime
.QuadPart
= 0;
1243 Fobx
->fOpenCountDecremented
= FALSE
;
1245 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1247 return (PMRX_FOBX
)Fobx
;
1255 IN PSRV_CALL SrvCall
,
1256 IN PUNICODE_STRING Name
,
1257 IN ULONG NetRootFlags
,
1258 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1261 USHORT CaseInsensitiveLength
;
1262 PRX_PREFIX_TABLE PrefixTable
;
1264 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1268 /* We need a SRV_CALL */
1269 ASSERT(SrvCall
!= NULL
);
1271 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1272 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1274 /* Get name length */
1275 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1276 if (CaseInsensitiveLength
> MAXUSHORT
)
1281 /* Allocate the NetRoot */
1282 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1283 CaseInsensitiveLength
);
1284 if (NetRoot
== NULL
)
1289 /* Construct name */
1290 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1291 Name
->Buffer
, Name
->Length
);
1292 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1294 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1295 SrvCall
->PrefixEntry
.Prefix
.Length
);
1298 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1300 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1302 /* Inisert in prefix table */
1303 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1304 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1307 /* Prepare the FCB table */
1308 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1310 InitializeListHead(&NetRoot
->TransitionWaitList
);
1311 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1312 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1314 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1316 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1317 NetRoot
->Flags
|= NetRootFlags
;
1318 NetRoot
->DiskParameters
.ClusterSize
= 1;
1319 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1320 NetRoot
->SrvCall
= SrvCall
;
1322 RxReferenceSrvCall(SrvCall
);
1324 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1333 RxCreateNetRootCallBack(
1334 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1338 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1348 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1349 IN ULONG InitialContextFlags
)
1352 PRX_CONTEXT Context
;
1354 ASSERT(RxDeviceObject
!= NULL
);
1356 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1358 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1359 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1361 /* Allocate the context from our lookaside list */
1362 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1363 if (Context
== NULL
)
1368 /* And initialize it */
1369 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1370 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1371 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1373 /* Add it to our global list */
1374 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1375 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1376 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1378 DPRINT("Context: %p\n", Context
);
1387 IN PRX_CONTEXT RxContext
,
1388 IN PUNICODE_STRING Name
,
1389 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1390 IN PRX_CONNECTION_ID RxConnectionId
)
1397 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1399 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1401 /* Get the name length */
1402 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1403 if (InnerNamePrefix
!= NULL
)
1405 NameLength
+= InnerNamePrefix
->Length
;
1408 /* Allocate the object */
1409 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1410 if (SrvCall
== NULL
)
1416 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1417 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1418 RxInitializeBufferingManager(SrvCall
);
1419 InitializeListHead(&SrvCall
->TransitionWaitList
);
1420 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1421 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1422 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1423 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1424 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1425 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1426 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1427 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1429 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1438 RxCreateSrvCallCallBack(
1439 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1443 PRX_CONTEXT RxContext
;
1444 ULONG NumberRemaining
;
1445 BOOLEAN StartDispatcher
;
1446 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1448 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1450 /* Get our context structures */
1451 Calldown
= Context
->SrvCalldownStructure
;
1452 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1454 /* If it is a success, that's the winner */
1455 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1456 if (Context
->Status
== STATUS_SUCCESS
)
1458 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1459 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1461 NumberRemaining
= --Calldown
->NumberRemaining
;
1462 SrvCall
->Status
= Context
->Status
;
1463 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1465 /* Still some to ask, keep going */
1466 if (NumberRemaining
!= 0)
1471 /* If that's not async, signal we're done */
1472 RxContext
= Calldown
->RxContext
;
1473 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1475 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1478 /* If that's a mailslot, finish construction, no more to do */
1479 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1481 RxFinishSrvCallConstruction(Calldown
);
1485 /* Queue our finish call for delayed completion */
1486 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1487 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1488 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1489 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1490 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1492 /* If we have to start dispatcher, go ahead */
1493 if (StartDispatcher
)
1497 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1498 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1499 if (!NT_SUCCESS(Status
))
1501 /* It failed - run it manually.... */
1502 RxFinishSrvCallConstructionDispatcher(NULL
);
1512 IN PV_NET_ROOT VNetRoot
,
1521 ASSERT(NodeTypeIsFcb(Fcb
));
1522 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1524 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1528 SrvOpen
= Fcb
->InternalSrvOpen
;
1529 /* Check whethet we have to allocate a new SRV_OPEN */
1530 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1531 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1532 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1535 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1536 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1541 /* Otherwise, just use internal one and initialize it */
1542 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1543 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1544 Fcb
->InternalSrvOpen
);
1545 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1546 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1549 /* If SrvOpen was properly allocated, initialize it */
1550 if (SrvOpen
!= NULL
)
1552 SrvOpen
->Flags
= Flags
;
1553 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1554 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1555 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1556 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1557 SrvOpen
->NodeReferenceCount
= 1;
1559 RxReferenceVNetRoot(VNetRoot
);
1560 RxReferenceNetFcb(Fcb
);
1562 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1563 ++Fcb
->SrvOpenListVersion
;
1565 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1566 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1567 InitializeListHead(&SrvOpen
->FobxList
);
1568 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1573 if (_SEH2_AbnormalTermination())
1575 if (SrvOpen
!= NULL
)
1577 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1583 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1596 IN PRX_CONTEXT RxContext
,
1597 IN PNET_ROOT NetRoot
,
1598 IN PUNICODE_STRING CanonicalName
,
1599 IN PUNICODE_STRING LocalNetRootName
,
1600 IN PUNICODE_STRING FilePath
,
1601 IN PRX_CONNECTION_ID RxConnectionId
)
1604 PV_NET_ROOT VNetRoot
;
1605 USHORT CaseInsensitiveLength
;
1609 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
1610 LocalNetRootName
, FilePath
, RxConnectionId
);
1612 /* Lock must be held exclusively */
1613 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1615 /* Check for overflow */
1616 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
1621 /* Get name length and allocate VNetRoot */
1622 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1623 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
1624 CaseInsensitiveLength
);
1625 if (VNetRoot
== NULL
)
1630 /* Initialize its connection parameters */
1631 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
1632 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
1633 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1634 if (!NT_SUCCESS(Status
))
1636 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
1637 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1638 RxFreeObject(VNetRoot
);
1644 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
1646 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1647 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
1648 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1649 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1651 InitializeListHead(&VNetRoot
->TransitionWaitList
);
1652 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
1654 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
1658 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1660 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
1664 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1667 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
1669 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
1675 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
1678 /* Insert in prefix table */
1679 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
1680 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1683 RxReferenceNetRoot(NetRoot
);
1684 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
1687 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
1688 VNetRoot
->UpperFinalizationDone
= FALSE
;
1689 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
1690 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
1692 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
1693 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
1700 IN OUT PVOID Instance
,
1701 IN LOCK_HOLDING_STATE LockHoldingState
)
1704 NODE_TYPE_CODE NodeType
;
1705 PNODE_TYPE_AND_SIZE Node
;
1709 RxAcquireScavengerMutex();
1711 /* Check we have a node we can handle */
1712 NodeType
= NodeType(Instance
);
1713 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
1714 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
1715 (NodeType
== RDBSS_NTC_FOBX
));
1717 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
1718 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
1719 ASSERT(RefCount
>= 0);
1724 case RDBSS_NTC_SRVCALL
:
1725 case RDBSS_NTC_NETROOT
:
1726 case RDBSS_NTC_V_NETROOT
:
1727 case RDBSS_NTC_SRVOPEN
:
1728 case RDBSS_NTC_FOBX
:
1736 /* No need to free - still in use */
1739 RxReleaseScavengerMutex();
1743 /* We have to be locked exclusively */
1744 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
1747 RxReleaseScavengerMutex();
1751 RxReleaseScavengerMutex();
1753 /* TODO: Really deallocate stuff - we're leaking as hell! */
1756 case RDBSS_NTC_SRVCALL
:
1760 SrvCall
= (PSRV_CALL
)Instance
;
1762 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
1763 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
1764 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
1768 case RDBSS_NTC_NETROOT
:
1772 case RDBSS_NTC_V_NETROOT
:
1776 case RDBSS_NTC_SRVOPEN
:
1780 case RDBSS_NTC_FOBX
:
1791 RxDereferenceAndDeleteRxContext_Real(
1792 IN PRX_CONTEXT RxContext
)
1797 PRX_CONTEXT StopContext
= NULL
;
1799 /* Make sure we really have a context */
1800 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1801 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
1802 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
1803 /* If refcount is 0, start releasing stuff that needs spinlock held */
1806 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1808 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
1810 /* If that's stop context from DO, remove it */
1811 RxDeviceObject
= RxContext
->RxDeviceObject
;
1812 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
1814 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
1818 /* Remove it from the list */
1819 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
1820 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
1821 RemoveEntryList(&RxContext
->ContextListEntry
);
1823 /* If that was the last active context, save the stop context */
1824 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
1826 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
1828 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
1833 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1835 /* Now, deal with what can be done without spinlock held */
1838 /* Refcount shouldn't have changed */
1839 ASSERT(RxContext
->ReferenceCount
== 0);
1840 /* Reset everything that can be */
1841 RxPrepareContextForReuse(RxContext
);
1843 #ifdef RDBSS_TRACKER
1844 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
1846 /* If that was the last active, set the event */
1847 if (StopContext
!= NULL
)
1849 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
1850 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
1853 /* Is ShadowCrit still owned? Shouldn't happen! */
1854 if (RxContext
->ShadowCritOwner
!= 0)
1856 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
1860 /* If it was allocated, free it */
1863 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
1873 RxDispatchToWorkerThread(
1874 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
1875 IN WORK_QUEUE_TYPE WorkQueueType
,
1876 IN PRX_WORKERTHREAD_ROUTINE Routine
,
1880 PRX_WORK_DISPATCH_ITEM DispatchItem
;
1882 /* Allocate a bit of context */
1883 DispatchItem
= ExAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
1884 if (DispatchItem
== NULL
)
1886 return STATUS_INSUFFICIENT_RESOURCES
;
1889 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
1890 DispatchItem
->DispatchRoutine
= Routine
;
1891 DispatchItem
->DispatchRoutineParameter
= pContext
;
1892 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
1893 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
1896 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, DispatchItem
);
1897 if (!NT_SUCCESS(Status
))
1899 ExFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
1900 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
1903 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
1912 RxExclusivePrefixTableLockToShared(
1913 PRX_PREFIX_TABLE Table
)
1917 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
1924 RxExtractServerName(
1925 IN PUNICODE_STRING FilePathName
,
1926 OUT PUNICODE_STRING SrvCallName
,
1927 OUT PUNICODE_STRING RestOfName
)
1933 ASSERT(SrvCallName
!= NULL
);
1935 /* SrvCall name will start from the begin up to the first separator */
1936 SrvCallName
->Buffer
= FilePathName
->Buffer
;
1937 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
1939 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
1945 /* Compute length */
1946 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
1947 SrvCallName
->MaximumLength
= Length
;
1948 SrvCallName
->Length
= Length
;
1950 /* Return the rest if asked */
1951 if (RestOfName
!= NULL
)
1953 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
1954 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
1955 RestOfName
->MaximumLength
= Length
;
1956 RestOfName
->Length
= Length
;
1964 RxFcbTableInsertFcb(
1965 IN OUT PRX_FCB_TABLE FcbTable
,
1970 /* We deal with the table, make sure it's locked */
1971 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
1973 /* Compute the hash */
1974 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
1976 RxReferenceNetFcb(Fcb
);
1978 /* If no length, it will be our null entry */
1979 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
1981 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
1983 /* Otherwise, insert in the appropriate bucket */
1986 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
1987 &Fcb
->FcbTableEntry
.HashLinks
);
1990 /* Propagate the change by incrementing the version number */
1991 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
1993 return STATUS_SUCCESS
;
2000 RxFcbTableLookupFcb(
2001 IN PRX_FCB_TABLE FcbTable
,
2002 IN PUNICODE_STRING Path
)
2005 PRX_FCB_TABLE_ENTRY TableEntry
;
2009 /* No path - easy, that's null entry */
2012 TableEntry
= FcbTable
->TableEntryForNull
;
2017 PLIST_ENTRY HashBucket
, ListEntry
;
2019 /* Otherwise, compute the hash value and find the associated bucket */
2020 Hash
= RxTableComputePathHashValue(Path
);
2021 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2022 /* If the bucket is empty, it means there's no entry yet */
2023 if (IsListEmpty(HashBucket
))
2029 /* Otherwise, browse all the entry */
2030 for (ListEntry
= HashBucket
->Flink
;
2031 ListEntry
!= HashBucket
;
2032 ListEntry
= ListEntry
->Flink
)
2034 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2035 InterlockedIncrement(&FcbTable
->Compares
);
2037 /* If entry hash and string are equal, thatt's the one! */
2038 if (TableEntry
->HashValue
== Hash
&&
2039 TableEntry
->Path
.Length
== Path
->Length
&&
2040 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2046 /* We reached the end? Not found */
2047 if (ListEntry
== HashBucket
)
2054 InterlockedIncrement(&FcbTable
->Lookups
);
2056 /* If table entry isn't null, return the FCB */
2057 if (TableEntry
!= NULL
)
2059 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2060 RxReferenceNetFcb(Fcb
);
2065 InterlockedIncrement(&FcbTable
->FailedLookups
);
2075 RxFcbTableRemoveFcb(
2076 IN OUT PRX_FCB_TABLE FcbTable
,
2081 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2083 /* If no path, then remove entry for null */
2084 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2086 FcbTable
->TableEntryForNull
= NULL
;
2088 /* Otherwise, remove from the bucket */
2091 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2094 /* Reset its list entry */
2095 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2097 /* Propagate the change by incrementing the version number */
2098 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2100 return STATUS_SUCCESS
;
2109 IN BOOLEAN RecursiveFinalize
,
2110 IN BOOLEAN ForceFinalize
,
2111 IN LONG ReferenceCount
)
2115 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2116 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2118 /* Make sure we have an exclusively acquired FCB */
2119 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2120 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2122 /* We shouldn't force finalization... */
2123 ASSERT(!ForceFinalize
);
2125 /* If recurisve, finalize all the associated SRV_OPEN */
2126 if (RecursiveFinalize
)
2128 PLIST_ENTRY ListEntry
;
2130 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2131 ListEntry
!= &ThisFcb
->SrvOpenList
;
2132 ListEntry
= ListEntry
->Flink
)
2136 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2137 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2140 /* If FCB is still in use, that's over */
2143 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2145 ASSERT(ReferenceCount
> 0);
2151 ASSERT(ReferenceCount
>= 1);
2153 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2154 if (ReferenceCount
!= 1 && !ForceFinalize
)
2159 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2161 DPRINT("Finalizing FCB open: %d (%d)", ThisFcb
->OpenCount
, ForceFinalize
);
2163 /* If finalization was not already initiated, go ahead */
2164 if (!ThisFcb
->UpperFinalizationDone
)
2166 /* Free any FCB_LOCK */
2167 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2169 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2171 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2175 Entry
= ThisFcb
->BufferedLocks
.List
;
2176 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2182 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2183 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2187 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2189 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2191 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2193 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2197 ThisFcb
->UpperFinalizationDone
= TRUE
;
2200 ASSERT(ReferenceCount
>= 1);
2202 /* Even if forced, don't allow broken free */
2203 if (ReferenceCount
!= 1)
2208 /* Now, release everything */
2209 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2211 ExFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2214 if (ThisFcb
->MRxDispatch
!= NULL
)
2216 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2219 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2220 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2221 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2223 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2224 RxDereferenceNetRoot(ThisFcb
->pNetRoot
, LHS_LockNotHeld
);
2226 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2227 ASSERT(!ThisFcb
->fMiniInited
);
2229 /* And free the object */
2230 RxFreeFcbObject(ThisFcb
);
2237 OUT PNET_ROOT ThisNetRoot
,
2238 IN BOOLEAN RecursiveFinalize
,
2239 IN BOOLEAN ForceFinalize
2248 OUT PSRV_CALL ThisSrvCall
,
2249 IN BOOLEAN RecursiveFinalize
,
2250 IN BOOLEAN ForceFinalize
)
2258 OUT PSRV_OPEN ThisSrvOpen
,
2259 IN BOOLEAN RecursiveFinalize
,
2260 IN BOOLEAN ForceFinalize
)
2267 RxFindOrConstructVirtualNetRoot(
2268 IN PRX_CONTEXT RxContext
,
2269 IN PUNICODE_STRING CanonicalName
,
2270 IN NET_ROOT_TYPE NetRootType
,
2271 IN PUNICODE_STRING RemainingName
)
2277 PV_NET_ROOT VNetRoot
;
2278 RX_CONNECTION_ID ConnectionID
;
2279 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2280 LOCK_HOLDING_STATE LockHoldingState
;
2284 RxDeviceObject
= RxContext
->RxDeviceObject
;
2285 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
2286 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
2288 /* Ask the mini-rdr for connection ID */
2289 ConnectionID
.SessionID
= 0;
2290 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
2292 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
2293 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
2295 /* mini-rdr is expected not to fail - unless it's not implemented */
2296 DPRINT1("Failed to initialize connection ID\n");
2301 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
2303 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2304 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
2305 LockHoldingState
= LHS_SharedLockHeld
;
2309 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
2313 PV_NET_ROOT SavedVNetRoot
;
2315 /* Look in prefix table */
2316 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
2317 if (Container
!= NULL
)
2319 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
2320 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
2322 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
2323 RxDereferenceSrvCall(Container
, LockHoldingState
);
2327 VNetRoot
= Container
;
2328 NetRoot
= VNetRoot
->NetRoot
;
2330 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
2331 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
2332 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
2334 Status
= STATUS_BAD_NETWORK_PATH
;
2335 SavedVNetRoot
= NULL
;
2341 PUNICODE_STRING UserName
, UserDomain
, Password
;
2343 /* We can reuse if we use same credentials */
2344 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
2345 &SessionId
, &UserName
,
2346 &UserDomain
, &Password
,
2348 if (NT_SUCCESS(Status
))
2350 SavedVNetRoot
= VNetRoot
;
2351 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
2353 UserDomain
, Password
,
2355 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
2357 PLIST_ENTRY ListEntry
;
2359 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
2360 ListEntry
!= &NetRoot
->VirtualNetRoots
;
2361 ListEntry
= ListEntry
->Flink
)
2363 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
2364 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
2366 UserDomain
, Password
,
2368 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2374 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
2376 SavedVNetRoot
= NULL
;
2380 if (!NT_SUCCESS(Status
))
2382 SavedVNetRoot
= NULL
;
2385 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
2389 /* We'll fail, if we had referenced a VNetRoot, dereference it */
2390 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
2392 if (SavedVNetRoot
== NULL
)
2394 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
2397 /* Reference VNetRoot we'll keep, and dereference current */
2398 else if (SavedVNetRoot
!= VNetRoot
)
2400 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
2401 if (SavedVNetRoot
!= NULL
)
2403 RxReferenceVNetRoot(SavedVNetRoot
);
2408 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
2409 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2416 /* If we're locked exclusive, we won't loop again, it was the second pass */
2417 if (LockHoldingState
!= LHS_SharedLockHeld
)
2422 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
2423 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
2425 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2426 LockHoldingState
= LHS_ExclusiveLockHeld
;
2430 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2431 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
2432 LockHoldingState
= LHS_ExclusiveLockHeld
;
2435 /* We didn't fail, and didn't find any VNetRoot, construct one */
2438 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
2440 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
2441 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
2443 if (Status
== STATUS_SUCCESS
)
2445 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
2446 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2447 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
2449 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2450 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
2451 RemainingName
->MaximumLength
= RemainingName
->Length
;
2453 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
2455 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
2457 VNetRoot
->Flags
|= Flags
;
2461 /* Release the prefix table - caller expects it to be released */
2462 if (LockHoldingState
!= LHS_LockNotHeld
)
2464 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2467 /* If we failed creating, quit */
2468 if (Status
!= STATUS_SUCCESS
)
2470 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
2474 /* Otherwise, wait until the VNetRoot is stable */
2475 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
2476 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
2477 /* It's all good, update the RX_CONTEXT with all our structs */
2478 if (VNetRoot
->Condition
== Condition_Good
)
2482 NetRoot
= VNetRoot
->NetRoot
;
2483 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2484 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2485 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
2489 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2490 RxContext
->Create
.pVNetRoot
= NULL
;
2491 Status
= STATUS_BAD_NETWORK_PATH
;
2501 RxFindOrCreateConnections(
2502 _In_ PRX_CONTEXT RxContext
,
2503 _In_ PUNICODE_STRING CanonicalName
,
2504 _In_ NET_ROOT_TYPE NetRootType
,
2505 _Out_ PUNICODE_STRING LocalNetRootName
,
2506 _Out_ PUNICODE_STRING FilePathName
,
2507 _Inout_ PLOCK_HOLDING_STATE LockState
,
2508 _In_ PRX_CONNECTION_ID RxConnectionId
)
2513 PV_NET_ROOT VNetRoot
;
2514 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
2515 PRX_PREFIX_TABLE PrefixTable
;
2516 UNICODE_STRING RemainingName
, NetRootName
;
2520 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
2521 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
2522 FilePathName
, LockState
, RxConnectionId
);
2524 *FilePathName
= *CanonicalName
;
2525 LocalNetRootName
->Length
= 0;
2526 LocalNetRootName
->MaximumLength
= 0;
2527 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
2529 /* UNC path, split it */
2530 if (FilePathName
->Buffer
[1] == ';')
2536 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2538 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2547 return STATUS_OBJECT_NAME_INVALID
;
2550 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
2551 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
2552 LocalNetRootName
->Length
= Length
;
2553 LocalNetRootName
->MaximumLength
= Length
;
2554 FilePathName
->Length
-= Length
;
2556 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
2557 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
2558 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
2562 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
2567 ASSERT(*LockState
!= LHS_LockNotHeld
);
2569 /* If previous lookup left something, dereference it */
2570 if (Container
!= NULL
)
2572 switch (NodeType(Container
))
2574 case RDBSS_NTC_SRVCALL
:
2575 RxDereferenceSrvCall(Container
, *LockState
);
2578 case RDBSS_NTC_NETROOT
:
2579 RxDereferenceNetRoot(Container
, *LockState
);
2582 case RDBSS_NTC_V_NETROOT
:
2583 RxDereferenceVNetRoot(Container
, *LockState
);
2587 /* Should never happen */
2593 /* Look for our NetRoot in prefix table */
2594 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
2595 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
2599 UNICODE_STRING SrvCallName
;
2605 /* Assume we didn't succeed */
2606 RxContext
->Create
.pVNetRoot
= NULL
;
2607 RxContext
->Create
.pNetRoot
= NULL
;
2608 RxContext
->Create
.pSrvCall
= NULL
;
2609 RxContext
->Create
.Type
= NetRootType
;
2611 /* If we found something */
2612 if (Container
!= NULL
)
2615 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
2617 VNetRoot
= Container
;
2618 /* Use its NetRoot */
2619 NetRoot
= VNetRoot
->NetRoot
;
2621 /* If it's not stable, wait for it to be stable */
2622 if (NetRoot
->Condition
== Condition_InTransition
)
2624 RxReleasePrefixTableLock(PrefixTable
);
2625 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
2626 RxWaitForStableNetRoot(NetRoot
, RxContext
);
2627 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2628 *LockState
= LHS_ExclusiveLockHeld
;
2630 /* Now that's it's ok, retry lookup to find what we want */
2631 if (NetRoot
->Condition
== Condition_Good
)
2637 /* Is the associated netroot good? */
2638 if (NetRoot
->Condition
== Condition_Good
)
2640 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
2642 /* If it is, and SrvCall as well, then, we have our active connection */
2643 if (SrvCall
->Condition
== Condition_Good
&&
2644 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
2646 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2647 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2648 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
2650 Status
= STATUS_CONNECTION_ACTIVE
;
2655 /* If VNetRoot was well constructed, it means the connection is active */
2656 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
2658 Status
= STATUS_CONNECTION_ACTIVE
;
2662 Status
= VNetRoot
->ConstructionStatus
;
2665 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
2668 /* Can only be a SrvCall */
2671 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
2672 SrvCall
= Container
;
2674 /* Wait for the SRV_CALL to be stable */
2675 if (SrvCall
->Condition
== Condition_InTransition
)
2677 RxReleasePrefixTableLock(PrefixTable
);
2678 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
2679 RxWaitForStableSrvCall(SrvCall
, RxContext
);
2680 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2681 *LockState
= LHS_ExclusiveLockHeld
;
2683 /* It went good, loop again to find what we look for */
2684 if (SrvCall
->Condition
== Condition_Good
)
2690 /* If it's not good... */
2691 if (SrvCall
->Condition
!= Condition_Good
)
2693 /* But SRV_CALL was well constructed, assume a connection was active */
2694 if (SrvCall
->Status
== STATUS_SUCCESS
)
2696 Status
= STATUS_CONNECTION_ACTIVE
;
2700 Status
= SrvCall
->Status
;
2703 RxDereferenceSrvCall(SrvCall
, *LockState
);
2709 /* If we found a SRV_CALL not matching our DO, quit */
2710 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
2711 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
2713 RxDereferenceSrvCall(SrvCall
, *LockState
);
2714 Status
= STATUS_BAD_NETWORK_NAME
;
2718 /* Now, we want exclusive lock */
2719 if (*LockState
== LHS_SharedLockHeld
)
2721 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
2723 RxReleasePrefixTableLock(PrefixTable
);
2724 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2725 *LockState
= LHS_ExclusiveLockHeld
;
2729 RxReleasePrefixTableLock(PrefixTable
);
2730 *LockState
= LHS_ExclusiveLockHeld
;
2733 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
2735 /* If we reach that point, we found something, no need to create something */
2736 if (Container
!= NULL
)
2741 /* Get the name for the SRV_CALL */
2742 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
2743 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
2744 /* And create the SRV_CALL */
2745 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
2746 if (SrvCall
== NULL
)
2748 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2752 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
2753 RxReferenceSrvCall(SrvCall
);
2754 RxContext
->Create
.pVNetRoot
= NULL
;
2755 RxContext
->Create
.pNetRoot
= NULL
;
2756 RxContext
->Create
.pSrvCall
= NULL
;
2757 RxContext
->Create
.Type
= NetRootType
;
2758 Container
= SrvCall
;
2760 /* Construct SRV_CALL, ie, use mini-rdr */
2761 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
2762 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
2763 if (Status
!= STATUS_SUCCESS
)
2765 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
2766 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2767 RxDereferenceSrvCall(SrvCall
, *LockState
);
2768 RxReleasePrefixTableLock(PrefixTable
);
2772 /* Loop again to make use of SRV_CALL stable condition wait */
2775 /* At that point, we have a stable SRV_CALL (either found or constructed) */
2776 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
2777 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
2778 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
2780 /* Call mini-rdr to get NetRoot name */
2781 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
2782 /* And create the NetRoot with that name */
2783 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
2784 if (NetRoot
== NULL
)
2786 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2789 NetRoot
->Type
= NetRootType
;
2791 RxDereferenceSrvCall(SrvCall
, *LockState
);
2793 /* Finally, create the associated VNetRoot */
2794 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
2795 if (VNetRoot
== NULL
)
2797 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2798 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2801 RxReferenceVNetRoot(VNetRoot
);
2803 /* We're get closer! */
2804 NetRoot
->Condition
= Condition_InTransition
;
2805 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
2806 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2807 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2809 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
2810 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
2811 if (!NT_SUCCESS(Status
))
2813 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
2814 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
2815 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
2817 RxContext
->Create
.pNetRoot
= NULL
;
2818 RxContext
->Create
.pVNetRoot
= NULL
;
2822 PIO_STACK_LOCATION Stack
;
2824 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
2826 Stack
= RxContext
->CurrentIrpSp
;
2827 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2829 RxExclusivePrefixTableLockToShared(PrefixTable
);
2830 *LockState
= LHS_SharedLockHeld
;
2836 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
2838 if (*LockState
!= LHS_LockNotHeld
)
2840 RxReleasePrefixTableLock(PrefixTable
);
2841 *LockState
= LHS_LockNotHeld
;
2847 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
2856 RxFinishFcbInitialization(
2857 IN OUT PMRX_FCB Fcb
,
2858 IN RX_FILE_TYPE FileType
,
2859 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
2861 NODE_TYPE_CODE OldType
;
2865 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
2867 OldType
= Fcb
->Header
.NodeTypeCode
;
2868 Fcb
->Header
.NodeTypeCode
= FileType
;
2869 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
2870 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
2872 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2874 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
2875 else if (InitPacket
!= NULL
)
2877 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
2878 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
2879 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
2880 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
2881 InitPacket
->pValidDataLength
->QuadPart
);
2884 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2885 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2887 /* If our FCB newly points to a file, initiliaz everything related */
2888 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
&&
2889 !OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
2891 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
2892 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, &RxLockOperationCompletion
,
2893 &RxUnlockOperation
);
2895 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
2896 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
2898 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
2902 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
2911 RxFinishSrvCallConstruction(
2912 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
2916 PRX_CONTEXT Context
;
2917 RX_BLOCK_CONDITION Condition
;
2918 PRX_PREFIX_TABLE PrefixTable
;
2920 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
2922 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
2923 Context
= Calldown
->RxContext
;
2924 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
2926 /* We have a winner, notify him */
2927 if (Calldown
->BestFinisher
!= NULL
)
2929 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
2931 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
2933 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
2934 MRxSrvCallWinnerNotify
,
2935 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
2936 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
2937 if (Status
!= STATUS_SUCCESS
)
2939 Condition
= Condition_Bad
;
2943 Condition
= Condition_Good
;
2946 /* Otherwise, just fail our SRV_CALL */
2949 Status
= Calldown
->CallbackContexts
[0].Status
;
2950 Condition
= Condition_Bad
;
2953 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2954 RxTransitionSrvCall(SrvCall
, Condition
);
2955 ExFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
2957 /* If async, finish it here, otherwise, caller has already finished the stuff */
2958 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
2960 DPRINT("Finishing async call\n");
2962 RxReleasePrefixTableLock(PrefixTable
);
2964 /* Make sure we weren't cancelled in-between */
2965 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
2967 Status
= STATUS_CANCELLED
;
2970 /* In case that was a create, context can be reused */
2971 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
2973 RxpPrepareCreateContextForReuse(Context
);
2976 /* If that's a failure, reset everything and return failure */
2977 if (Status
!= STATUS_SUCCESS
)
2979 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
2980 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
2982 if (Context
->Info
.Buffer
!= NULL
)
2984 ExFreePool(Context
->Info
.Buffer
);
2985 Context
->Info
.Buffer
= NULL
;
2988 Context
->CurrentIrp
->IoStatus
.Information
= 0;
2989 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
2990 RxCompleteRequest(Context
, Status
);
2992 /* Otherwise, call resume routine and done! */
2995 Status
= Context
->ResumeRoutine(Context
);
2996 if (Status
!= STATUS_PENDING
)
2998 RxCompleteRequest(Context
, Status
);
3001 DPRINT("Not completing, pending\n");
3005 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
3014 RxFinishSrvCallConstructionDispatcher(
3018 BOOLEAN Direct
, KeepLoop
;
3020 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
3022 /* In case of failure of starting dispatcher, context is not set
3023 * We keep track of it to fail associated SRV_CALL
3025 Direct
= (Context
== NULL
);
3027 /* Separated thread, loop forever */
3030 PLIST_ENTRY ListEntry
;
3031 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
3033 /* If there are no SRV_CALL to finalize left, just finish thread */
3034 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
3035 if (IsListEmpty(&RxSrvCalldownList
))
3038 RxSrvCallConstructionDispatcherActive
= FALSE
;
3040 /* Otherwise, get the SRV_CALL to finish construction */
3043 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
3046 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
3054 /* If direct is set, reset the finisher to avoid electing a winner
3055 * and fail SRV_CALL (see upper comment)
3057 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
3060 Calldown
->BestFinisher
= NULL
;
3062 /* Finish SRV_CALL construction */
3063 RxFinishSrvCallConstruction(Calldown
);
3085 RxGetFileSizeWithLock(
3087 OUT PLONGLONG FileSize
)
3091 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
3102 return RxData
.OurProcess
;
3109 RxInitializeBufferingManager(
3112 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
3113 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
3114 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
3115 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
3116 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
3117 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
3118 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
3119 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
3120 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
3121 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
3123 return STATUS_SUCCESS
;
3131 RxInitializeContext(
3133 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
3134 IN ULONG InitialContextFlags
,
3135 IN OUT PRX_CONTEXT RxContext
)
3137 PIO_STACK_LOCATION Stack
;
3139 /* Initialize our various fields */
3140 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
3141 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
3142 RxContext
->ReferenceCount
= 1;
3143 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
3144 RxContext
->RxDeviceObject
= RxDeviceObject
;
3145 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
3146 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
3147 InitializeListHead(&RxContext
->BlockedOperations
);
3148 RxContext
->MRxCancelRoutine
= NULL
;
3149 RxContext
->ResumeRoutine
= NULL
;
3150 RxContext
->Flags
|= InitialContextFlags
;
3151 RxContext
->CurrentIrp
= Irp
;
3152 RxContext
->LastExecutionThread
= PsGetCurrentThread();
3153 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
3155 /* If've got no IRP, mark RX_CONTEXT */
3158 RxContext
->CurrentIrpSp
= NULL
;
3159 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
3160 RxContext
->MinorFunction
= 0;
3164 /* Otherwise, first determine whether we are performing async operation */
3165 Stack
= IoGetCurrentIrpStackLocation(Irp
);
3166 if (Stack
->FileObject
!= NULL
)
3170 Fcb
= Stack
->FileObject
->FsContext
;
3171 if (!IoIsOperationSynchronous(Irp
) ||
3172 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
3173 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
3174 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
3176 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3180 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
3182 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3184 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3186 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3189 /* Set proper flags if TopLevl IRP/Device */
3190 if (!RxIsThisTheTopLevelIrp(Irp
))
3192 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
3194 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
3196 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
3199 /* Copy stack information */
3200 RxContext
->MajorFunction
= Stack
->MajorFunction
;
3201 RxContext
->MinorFunction
= Stack
->MinorFunction
;
3202 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
3203 RxContext
->CurrentIrpSp
= Stack
;
3205 /* If we have a FO associated, learn for more */
3206 if (Stack
->FileObject
!= NULL
)
3211 /* Get the FCB and CCB (FOBX) */
3212 Fcb
= Stack
->FileObject
->FsContext
;
3213 Fobx
= Stack
->FileObject
->FsContext2
;
3214 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
3215 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
3217 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
3220 /* We have a FOBX, this not a DFS opening, keep track of it */
3221 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
3223 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
3224 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
3225 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
3227 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
3232 RxContext
->pFobx
= NULL
;
3235 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
3236 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
3239 PV_NET_ROOT VNetRoot
= NULL
;
3241 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
3243 VNetRoot
= Fcb
->VNetRoot
;
3245 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
3247 VNetRoot
= (PV_NET_ROOT
)Fobx
;
3250 if (VNetRoot
!= NULL
)
3252 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3256 /* Remember if that's a write through file */
3257 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
3258 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
3260 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
3265 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
3267 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
3268 RxContext
, RxContext
->MinorFunction
, Irp
,
3269 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
3270 RxContext
->SerialNumber
);
3279 RxInitializeDispatcher(
3283 HANDLE ThreadHandle
;
3287 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
3288 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
3290 /* Set appropriate timeouts: 10s & 60s */
3291 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3292 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3293 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3294 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
3296 RxDispatcher
.NumberOfProcessors
= 1;
3297 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
3298 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
3300 /* Initialize our dispatchers */
3301 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
3302 if (!NT_SUCCESS(Status
))
3307 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
3308 if (!NT_SUCCESS(Status
))
3313 /* And start them */
3314 RxDispatcher
.State
= RxDispatcherActive
;
3315 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
3316 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
3317 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
3318 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
3319 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
3320 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
3321 if (NT_SUCCESS(Status
))
3323 ZwClose(ThreadHandle
);
3333 RxInitializeFcbTable(
3334 IN OUT PRX_FCB_TABLE FcbTable
,
3335 IN BOOLEAN CaseInsensitiveMatch
)
3341 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
3342 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
3344 ExInitializeResourceLite(&FcbTable
->TableLock
);
3345 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
3346 FcbTable
->Version
= 0;
3347 FcbTable
->TableEntryForNull
= NULL
;
3349 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
3350 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
3352 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
3355 FcbTable
->Lookups
= 0;
3356 FcbTable
->FailedLookups
= 0;
3357 FcbTable
->Compares
= 0;
3365 RxInitializeLowIoContext(
3366 OUT PLOWIO_CONTEXT LowIoContext
,
3369 PRX_CONTEXT RxContext
;
3370 PIO_STACK_LOCATION Stack
;
3374 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
3375 ASSERT(LowIoContext
= &RxContext
->LowIoContext
);
3377 Stack
= RxContext
->CurrentIrpSp
;
3379 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
3380 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
3381 RxContext
->LowIoContext
.Operation
= Operation
;
3386 case LOWIO_OP_WRITE
:
3387 /* In case of RW, set a canary, to make sure these fields are properly set
3388 * they will be asserted when lowio request will be submit to mini-rdr
3391 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
3392 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
3393 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
3395 /* Keep track of paging IOs */
3396 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
3398 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
3402 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
3407 case LOWIO_OP_FSCTL
:
3408 case LOWIO_OP_IOCTL
:
3409 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
3410 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
3411 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
3412 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
3413 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
3414 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
3415 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
3418 /* Nothing to do for these */
3419 case LOWIO_OP_SHAREDLOCK
:
3420 case LOWIO_OP_EXCLUSIVELOCK
:
3421 case LOWIO_OP_UNLOCK
:
3422 case LOWIO_OP_UNLOCK_MULTIPLE
:
3423 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
3424 case LOWIO_OP_CLEAROUT
:
3428 /* Should never happen */
3438 RxInitializeLowIoPerFcbInfo(
3439 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
3443 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
3444 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
3451 RxInitializeMRxDispatcher(
3452 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
3456 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
3457 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
3459 return STATUS_SUCCESS
;
3466 RxInitializePrefixTable(
3467 IN OUT PRX_PREFIX_TABLE ThisTable
,
3468 IN ULONG TableSize OPTIONAL
,
3469 IN BOOLEAN CaseInsensitiveMatch
)
3475 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
3478 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
3479 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
3480 InitializeListHead(&ThisTable
->MemberQueue
);
3481 ThisTable
->Version
= 0;
3482 ThisTable
->TableEntryForNull
= NULL
;
3483 ThisTable
->IsNetNameTable
= FALSE
;
3484 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
3485 ThisTable
->TableSize
= TableSize
;
3491 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
3493 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
3502 RxInitializePurgeSyncronizationContext(
3503 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
3507 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
3508 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
3512 RxInitializeSrvCallParameters(
3513 IN PRX_CONTEXT RxContext
,
3514 IN OUT PSRV_CALL SrvCall
)
3518 SrvCall
->pPrincipalName
= NULL
;
3520 /* We only have stuff to initialize for file opening from DFS */
3521 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
3523 return STATUS_SUCCESS
;
3526 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
3529 return STATUS_NOT_IMPLEMENTED
;
3533 RxInitializeVNetRootParameters(
3534 PRX_CONTEXT RxContext
,
3536 OUT PULONG SessionId
,
3537 OUT PUNICODE_STRING
*UserNamePtr
,
3538 OUT PUNICODE_STRING
*UserDomainNamePtr
,
3539 OUT PUNICODE_STRING
*PasswordPtr
,
3543 PACCESS_TOKEN Token
;
3547 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
3548 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
3550 *UserNamePtr
= NULL
;
3551 *UserDomainNamePtr
= NULL
;
3552 *PasswordPtr
= NULL
;
3553 /* By default, that's not CSC instance */
3554 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
3556 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
3557 if (SeTokenIsRestricted(Token
))
3559 return STATUS_ACCESS_DENIED
;
3563 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
3564 if (!NT_SUCCESS(Status
))
3570 Status
= SeQuerySessionIdToken(Token
, SessionId
);
3571 if (!NT_SUCCESS(Status
))
3576 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
3579 Status
= STATUS_NOT_IMPLEMENTED
;
3583 /* Deal with connection credentials */
3584 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
3587 Status
= STATUS_NOT_IMPLEMENTED
;
3591 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
3594 Status
= STATUS_NOT_IMPLEMENTED
;
3599 if (NT_SUCCESS(Status
))
3601 /* If that's a CSC instance, mark it as such */
3602 if (RxIsThisACscAgentOpen(RxContext
))
3604 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
3616 RxInitializeWorkQueue(
3617 PRX_WORK_QUEUE WorkQueue
,
3618 WORK_QUEUE_TYPE WorkQueueType
,
3619 ULONG MaximumNumberOfWorkerThreads
,
3620 ULONG MinimumNumberOfWorkerThreads
)
3624 WorkQueue
->Type
= WorkQueueType
;
3625 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
3626 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
3628 WorkQueue
->State
= RxWorkQueueActive
;
3629 WorkQueue
->SpinUpRequestPending
= FALSE
;
3630 WorkQueue
->pRundownContext
= NULL
;
3631 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
3632 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
3633 WorkQueue
->CumulativeQueueLength
= 0;
3634 WorkQueue
->NumberOfSpinUpRequests
= 0;
3635 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
3636 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
3637 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
3638 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
3639 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
3640 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
3641 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
3642 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
3643 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
3644 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
3645 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
3646 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
3647 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
3648 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
3649 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
3650 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
3652 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
3653 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
3660 RxInitializeWorkQueueDispatcher(
3661 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
3664 ULONG MaximumNumberOfWorkerThreads
;
3668 /* Number of threads will depend on system capacity */
3669 if (MmQuerySystemSize() != MmLargeSystem
)
3671 MaximumNumberOfWorkerThreads
= 5;
3675 MaximumNumberOfWorkerThreads
= 10;
3678 /* Initialize the work queues */
3679 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
3680 MaximumNumberOfWorkerThreads
, 1);
3681 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
3682 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
3684 /* And start the worker threads */
3685 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
3686 RxBootstrapWorkerThreadDispatcher
,
3687 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
3688 if (!NT_SUCCESS(Status
))
3693 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
3694 RxBootstrapWorkerThreadDispatcher
,
3695 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
3696 if (!NT_SUCCESS(Status
))
3701 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
3702 RxBootstrapWorkerThreadDispatcher
,
3703 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
3708 RxInitiateSrvOpenKeyAssociation (
3709 IN OUT PSRV_OPEN SrvOpen
3719 RxInsertWorkQueueItem(
3720 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
3721 WORK_QUEUE_TYPE WorkQueueType
,
3722 PRX_WORK_DISPATCH_ITEM DispatchItem
)
3726 BOOLEAN SpinUpThreads
;
3727 PRX_WORK_QUEUE WorkQueue
;
3729 /* No dispatcher, nothing to insert */
3730 if (RxDispatcher
.State
!= RxDispatcherActive
)
3732 return STATUS_UNSUCCESSFUL
;
3735 /* Get the work queue */
3736 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
3738 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
3739 /* Only insert if the work queue is in decent state */
3740 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
3742 Status
= STATUS_UNSUCCESSFUL
;
3746 SpinUpThreads
= FALSE
;
3747 DispatchItem
->WorkQueueItem
.pDeviceObject
= pMRxDeviceObject
;
3748 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
3749 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
3750 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
3752 /* If required (and possible!), spin up a new worker thread */
3753 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
3754 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
3755 !WorkQueue
->SpinUpRequestPending
)
3757 WorkQueue
->SpinUpRequestPending
= TRUE
;
3758 SpinUpThreads
= TRUE
;
3761 Status
= STATUS_SUCCESS
;
3763 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
3765 /* If we failed, return and still not insert item */
3766 if (!NT_SUCCESS(Status
))
3771 /* All fine, insert the item */
3772 KeInsertQueue(&WorkQueue
->Queue
, &DispatchItem
->WorkQueueItem
.List
);
3774 /* And start a new worker thread if needed */
3777 RxSpinUpWorkerThreads(WorkQueue
);
3784 RxIsThisACscAgentOpen(
3785 IN PRX_CONTEXT RxContext
)
3791 /* Client Side Caching is DFS stuff - we don't support it */
3792 if (RxContext
->Create
.EaLength
!= 0)
3797 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
3798 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
3808 IN PRX_CONTEXT RxContext
,
3809 IN LOCK_OPERATION Operation
,
3810 IN ULONG BufferLength
)
3819 Irp
= RxContext
->CurrentIrp
;
3820 /* If we already have a MDL, make sure it's locked */
3821 if (Irp
->MdlAddress
!= NULL
)
3823 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
3827 /* That likely means the driver asks for buffered IOs - we don't support it! */
3828 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
3830 /* If we have a real length */
3831 if (BufferLength
> 0)
3833 /* Allocate a MDL and lock it */
3834 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
3837 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
3838 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
3841 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
3845 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3849 Status
= _SEH2_GetExceptionCode();
3851 /* Free the possible MDL we have allocated */
3853 Irp
->MdlAddress
= NULL
;
3855 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
3858 if (!FsRtlIsNtstatusExpected(Status
))
3860 Status
= STATUS_INVALID_USER_BUFFER
;
3863 RxContext
->IoStatusBlock
.Status
= Status
;
3864 ExRaiseStatus(Status
);
3870 RxLowIoCompletionTail(
3871 IN PRX_CONTEXT RxContext
)
3878 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
3880 /* Only continue if we're at APC_LEVEL or lower */
3881 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
&&
3882 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
3884 return STATUS_MORE_PROCESSING_REQUIRED
;
3887 /* Call the completion routine */
3888 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
3889 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
3890 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
3895 /* If it was a RW operation, for a paging file ... */
3896 Operation
= RxContext
->LowIoContext
.Operation
;
3897 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
3899 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
3902 Status
= STATUS_NOT_IMPLEMENTED
;
3907 /* Sanity check: we had known operation */
3908 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
3911 /* If not sync operation, complete now. Otherwise, caller has already completed */
3912 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
3914 RxCompleteRequest(RxContext
, Status
);
3917 DPRINT("Status: %x\n", Status
);
3926 RxLowIoPopulateFsctlInfo(
3927 IN PRX_CONTEXT RxContext
)
3932 PIO_STACK_LOCATION Stack
;
3936 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
3938 Irp
= RxContext
->CurrentIrp
;
3939 Stack
= RxContext
->CurrentIrpSp
;
3941 /* Copy stack parameters */
3942 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
3943 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
3944 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
3945 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
3946 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
3948 /* Same buffer in case of buffered */
3949 if (Method
== METHOD_BUFFERED
)
3951 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3952 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3954 return STATUS_SUCCESS
;
3957 /* Two buffers for neither */
3958 if (Method
== METHOD_NEITHER
)
3960 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
3961 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
3963 return STATUS_SUCCESS
;
3966 /* Only IN/OUT remain */
3967 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
3969 /* Use system buffer for input */
3970 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3971 /* And MDL for output */
3972 Mdl
= Irp
->MdlAddress
;
3975 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
3976 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
3978 return STATUS_INSUFFICIENT_RESOURCES
;
3983 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
3986 return STATUS_SUCCESS
;
3992 IN PRX_CONTEXT RxContext
,
3993 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
3997 BOOLEAN Synchronous
;
3998 PLOWIO_CONTEXT LowIoContext
;
4000 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
4004 LowIoContext
= &RxContext
->LowIoContext
;
4005 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4007 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
4009 Status
= STATUS_SUCCESS
;
4010 Operation
= LowIoContext
->Operation
;
4014 case LOWIO_OP_WRITE
:
4015 /* Check that the parameters were properly set by caller
4016 * See comment in RxInitializeLowIoContext()
4018 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
4019 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
4021 /* Lock the buffer */
4022 RxLockUserBuffer(RxContext
,
4023 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
4024 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
4025 if (RxNewMapUserBuffer(RxContext
) == NULL
)
4027 return STATUS_INSUFFICIENT_RESOURCES
;
4029 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
4031 /* If that's a paging IO, initialize serial operation */
4032 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
4036 Fcb
= (PFCB
)RxContext
->pFcb
;
4038 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
4039 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
4040 if (Operation
== LOWIO_OP_READ
)
4042 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
4046 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
4049 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
4054 case LOWIO_OP_FSCTL
:
4055 case LOWIO_OP_IOCTL
:
4056 /* Set FSCTL/IOCTL parameters */
4057 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
4058 /* Check whether we're consistent: a length means a buffer */
4059 if (NT_SUCCESS(Status
))
4061 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
4062 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
4063 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
4064 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
4066 Status
= STATUS_INVALID_PARAMETER
;
4072 case LOWIO_OP_SHAREDLOCK
:
4073 case LOWIO_OP_EXCLUSIVELOCK
:
4074 case LOWIO_OP_UNLOCK
:
4075 case LOWIO_OP_UNLOCK_MULTIPLE
:
4076 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4077 case LOWIO_OP_CLEAROUT
:
4082 Status
= STATUS_INVALID_PARAMETER
;
4086 /* No need to perform extra init in case of posting */
4087 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
4089 /* Preflight checks were OK, time to submit */
4090 if (NT_SUCCESS(Status
))
4092 PMINIRDR_DISPATCH Dispatch
;
4096 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4097 /* If not synchronous, we're likely to return before the operation is finished */
4098 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
4100 IoMarkIrpPending(RxContext
->CurrentIrp
);
4104 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
4105 if (Dispatch
!= NULL
)
4107 /* We'll try to execute until the mini-rdr doesn't return pending */
4110 RxContext
->IoStatusBlock
.Information
= 0;
4112 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
4113 if (Status
== STATUS_PENDING
)
4115 /* Unless it's not synchronous, caller will be happy with pending op */
4121 RxWaitSync(RxContext
);
4122 Status
= RxContext
->IoStatusBlock
.Status
;
4128 /* We had marked the IRP pending, whereas the operation finished, drop that */
4129 if (Status
!= STATUS_RETRY
)
4131 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
4133 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
4136 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
4140 } while (Status
== STATUS_PENDING
);
4144 Status
= STATUS_INVALID_PARAMETER
;
4148 /* Call completion and return */
4149 RxContext
->IoStatusBlock
.Status
= Status
;
4150 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
4151 return RxLowIoCompletionTail(RxContext
);
4159 IN PRX_CONTEXT RxContext
)
4165 Irp
= RxContext
->CurrentIrp
;
4166 /* We should have a MDL (buffered IOs are not supported!) */
4167 if (Irp
->MdlAddress
!= NULL
)
4170 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
4173 /* Just return system buffer */
4174 return Irp
->AssociatedIrp
.SystemBuffer
;
4178 RxMarkFobxOnCleanup(
4197 PRX_CONTEXT RxContext
)
4203 Irp
= RxContext
->CurrentIrp
;
4204 if (Irp
->MdlAddress
!= NULL
)
4206 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
4209 return Irp
->UserBuffer
;
4241 RxpAcquirePrefixTableLockShared(
4242 PRX_PREFIX_TABLE pTable
,
4244 BOOLEAN ProcessBufferingStateChangeRequests
)
4248 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
4249 pTable
->TableLock
.ActiveEntries
);
4251 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
4258 RxpAcquirePrefixTableLockExclusive(
4259 PRX_PREFIX_TABLE pTable
,
4261 BOOLEAN ProcessBufferingStateChangeRequests
)
4265 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
4266 pTable
->TableLock
.ActiveEntries
);
4268 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
4275 RxpDereferenceAndFinalizeNetFcb(
4277 IN PRX_CONTEXT RxContext
,
4278 IN BOOLEAN RecursiveFinalize
,
4279 IN BOOLEAN ForceFinalize
)
4284 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
4288 ASSERT(!ForceFinalize
);
4289 ASSERT(NodeTypeIsFcb(ThisFcb
));
4290 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
4292 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
4293 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
4294 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
4300 Status
= STATUS_SUCCESS
;
4301 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
4302 ResourceAcquired
= FALSE
;
4303 NetRootReferenced
= FALSE
;
4304 /* If FCB isn't orphaned, it still have context attached */
4305 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
4307 /* Don't let NetRoot go away before we're done */
4308 RxReferenceNetRoot(NetRoot
);
4309 NetRootReferenced
= TRUE
;
4311 /* Try to acquire the table lock exclusively */
4312 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
4314 RxReferenceNetFcb(ThisFcb
);
4316 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
4318 if (RxContext
!= NULL
&& RxContext
!= (PVOID
)-1 && RxContext
!= (PVOID
)-2)
4320 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
4323 RxReleaseFcb(RxContext
, ThisFcb
);
4325 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
4327 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
4330 References
= RxDereferenceNetFcb(ThisFcb
);
4332 ResourceAcquired
= TRUE
;
4336 /* If locking was OK (or not needed!), attempt finalization */
4337 if (NT_SUCCESS(Status
))
4339 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
4342 /* Release table lock if acquired */
4343 if (ResourceAcquired
)
4345 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
4348 /* We don't need the NetRoot anylonger */
4349 if (NetRootReferenced
)
4351 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
4358 RxpDereferenceNetFcb(
4369 RxPrefixTableInsertName(
4370 IN OUT PRX_PREFIX_TABLE ThisTable
,
4371 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
4373 IN PULONG ContainerRefCount
,
4374 IN USHORT CaseInsensitiveLength
,
4375 IN PRX_CONNECTION_ID ConnectionId
4380 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
4382 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
4383 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
4385 /* Copy parameters and compute hash */
4386 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
4387 ThisEntry
->ContainingRecord
= Container
;
4388 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
4389 InterlockedIncrement((volatile long *)ContainerRefCount
);
4390 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
4391 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
4393 /* If no path length: this is entry for null path */
4394 if (ThisEntry
->Prefix
.Length
== 0)
4396 ThisTable
->TableEntryForNull
= ThisEntry
;
4398 /* Otherwise, insert in the appropriate bucket */
4401 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
4404 /* If we had a connection ID, keep track of it */
4405 if (ConnectionId
!= NULL
)
4407 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
4411 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
4412 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
4415 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
4416 /* Reflect the changes */
4417 ++ThisTable
->Version
;
4419 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
4428 RxPrefixTableLookupName(
4429 IN PRX_PREFIX_TABLE ThisTable
,
4430 IN PUNICODE_STRING CanonicalName
,
4431 OUT PUNICODE_STRING RemainingName
,
4432 IN PRX_CONNECTION_ID ConnectionId
)
4438 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
4439 ASSERT(CanonicalName
->Length
> 0);
4441 /* Call the internal helper */
4442 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
4443 if (Container
== NULL
)
4448 /* Reference our container before returning it */
4449 if (RdbssReferenceTracingValue
!= 0)
4451 NODE_TYPE_CODE Type
;
4453 Type
= NodeType(Container
);
4456 case RDBSS_NTC_SRVCALL
:
4457 RxReferenceSrvCall(Container
);
4460 case RDBSS_NTC_NETROOT
:
4461 RxReferenceNetRoot(Container
);
4464 case RDBSS_NTC_V_NETROOT
:
4465 RxReferenceVNetRoot(Container
);
4475 RxReference(Container
);
4493 RxpReleasePrefixTableLock(
4494 PRX_PREFIX_TABLE pTable
,
4495 BOOLEAN ProcessBufferingStateChangeRequests
)
4499 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
4500 pTable
->TableLock
.ActiveEntries
);
4502 ExReleaseResourceLite(&pTable
->TableLock
);
4510 RxPrepareContextForReuse(
4511 IN OUT PRX_CONTEXT RxContext
)
4515 /* When we reach that point, make sure mandatory parts are null-ed */
4516 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
4518 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
4519 RxContext
->Create
.RdrFlags
= 0;
4521 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
4523 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
4524 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
4527 RxContext
->ReferenceCount
= 0;
4531 RxProcessFcbChangeBufferingStateRequest(
4538 RxpTrackDereference(
4539 _In_ ULONG TraceType
,
4540 _In_ PCSTR FileName
,
4542 _In_ PVOID Instance
)
4550 _In_ ULONG TraceType
,
4551 _In_ PCSTR FileName
,
4553 _In_ PVOID Instance
)
4559 RxpUndoScavengerFinalizationMarking(
4566 RxPurgeFcbInSystemCache(
4568 IN PLARGE_INTEGER FileOffset OPTIONAL
,
4570 IN BOOLEAN UninitializeCacheMaps
,
4571 IN BOOLEAN FlushFile
)
4574 return STATUS_NOT_IMPLEMENTED
;
4581 RxpWorkerThreadDispatcher(
4582 IN PRX_WORK_QUEUE WorkQueue
,
4583 IN PLARGE_INTEGER WaitInterval
)
4587 PETHREAD CurrentThread
;
4588 BOOLEAN KillThread
, Dereference
;
4589 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
4590 PWORKER_THREAD_ROUTINE WorkerRoutine
;
4592 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4594 /* Reference ourselves */
4595 CurrentThread
= PsGetCurrentThread();
4596 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, PsThreadType
, KernelMode
);
4597 ASSERT(NT_SUCCESS(Status
));
4599 /* Infinite loop for worker */
4601 Dereference
= FALSE
;
4605 PLIST_ENTRY ListEntry
;
4607 /* Remove an entry from the work queue */
4608 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
4609 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
4611 PRDBSS_DEVICE_OBJECT DeviceObject
;
4613 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
4615 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
4616 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
4617 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4619 /* Get the parameters, and null-them in the struct */
4620 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
4621 Parameter
= WorkQueueItem
->Parameter
;
4622 DeviceObject
= WorkQueueItem
->pDeviceObject
;
4624 WorkQueueItem
->List
.Flink
= NULL
;
4625 WorkQueueItem
->WorkerRoutine
= NULL
;
4626 WorkQueueItem
->Parameter
= NULL
;
4627 WorkQueueItem
->pDeviceObject
= NULL
;
4629 /* Call the routine */
4630 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
4631 WorkerRoutine(Parameter
);
4633 /* Are we going down now? */
4634 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
4636 PKEVENT TearDownEvent
;
4638 TearDownEvent
= InterlockedExchangePointer((volatile PVOID
)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
4639 if (TearDownEvent
!= NULL
)
4641 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
4645 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4648 /* Shall we shutdown... */
4649 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
4650 switch (WorkQueue
->State
)
4652 /* Our queue is active, kill it if we have no more items to dispatch
4653 * and more threads than the required minimum
4655 case RxWorkQueueActive
:
4656 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
4658 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
4659 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
4663 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
4668 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4673 /* The queue is inactive: kill it we have more threads than the required minimum */
4674 case RxWorkQueueInactive
:
4675 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
4676 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
4680 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
4685 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4689 /* Rundown in progress..., kill it for sure! */
4690 case RxWorkQueueRundownInProgress
:
4692 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
4694 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
4696 RundownContext
= WorkQueue
->pRundownContext
;
4697 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
4699 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
4701 Dereference
= FALSE
;
4703 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
4705 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
4708 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4715 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
4716 } while (!KillThread
);
4718 DPRINT("Killed worker thread\n");
4720 /* Do we have to dereference ourselves? */
4723 ObDereferenceObject(CurrentThread
);
4726 /* Dump last executed routine */
4727 if (DumpDispatchRoutine
)
4729 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
4732 PsTerminateSystemThread(STATUS_SUCCESS
);
4737 IN OUT PVOID Instance
)
4739 NODE_TYPE_CODE NodeType
;
4740 PNODE_TYPE_AND_SIZE Node
;
4744 RxAcquireScavengerMutex();
4746 /* We can only reference a few structs */
4747 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
4748 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
4749 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
4750 (NodeType
== RDBSS_NTC_FOBX
));
4752 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
4753 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
4755 /* And that's not implemented! (yay, we leak :-D) */
4758 case RDBSS_NTC_SRVCALL
:
4759 case RDBSS_NTC_NETROOT
:
4760 case RDBSS_NTC_V_NETROOT
:
4761 case RDBSS_NTC_SRVOPEN
:
4762 case RDBSS_NTC_FOBX
:
4770 RxpUndoScavengerFinalizationMarking(Instance
);
4771 RxReleaseScavengerMutex();
4776 RxResumeBlockedOperations_Serially(
4777 IN OUT PRX_CONTEXT RxContext
,
4778 IN OUT PLIST_ENTRY BlockingIoQ
)
4782 RxAcquireSerializationMutex();
4784 /* This can only happen on pipes */
4785 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
4787 RxReleaseSerializationMutex();
4793 RxReleaseSerializationMutex();
4797 RxScavengeRelatedFobxs(
4805 RxScavengeVNetRoots(
4806 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
4817 RxSpinUpRequestsDispatcher(
4821 PRX_DISPATCHER RxDispatcher
;
4823 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, PsThreadType
, KernelMode
);
4824 if (!NT_SUCCESS(Status
))
4826 PsTerminateSystemThread(STATUS_SUCCESS
);
4829 RxDispatcher
= Dispatcher
;
4834 PLIST_ENTRY ListEntry
;
4836 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
4837 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
4838 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
4840 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
4841 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
4843 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
4847 ListEntry
= &RxDispatcher
->SpinUpRequests
;
4849 KeResetEvent(&RxDispatcher
->SpinUpRequestsEvent
);
4850 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
4852 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
4854 PWORK_QUEUE_ITEM WorkItem
;
4855 PRX_WORK_QUEUE WorkQueue
;
4857 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
4858 WorkQueue
= WorkItem
->Parameter
;
4860 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
4862 DPRINT1("WORKQ:SR %lx %lx\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
4863 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
4865 } while (RxDispatcher
->State
== RxDispatcherActive
);
4867 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
4868 PsTerminateSystemThread(STATUS_SUCCESS
);
4875 RxSpinUpWorkerThread(
4876 PRX_WORK_QUEUE WorkQueue
,
4877 PRX_WORKERTHREAD_ROUTINE Routine
,
4882 HANDLE ThreadHandle
;
4886 /* If work queue is inactive, that cannot work */
4887 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
4888 if (WorkQueue
->State
!= RxWorkQueueActive
)
4890 Status
= STATUS_UNSUCCESSFUL
;
4891 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
4895 ++WorkQueue
->NumberOfActiveWorkerThreads
;
4896 Status
= STATUS_SUCCESS
;
4898 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
4900 /* Quit on failure */
4901 if (!NT_SUCCESS(Status
))
4906 /* Spin up the worker thread */
4907 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
4908 if (NT_SUCCESS(Status
))
4910 ZwClose(ThreadHandle
);
4913 /* Read well: we reached that point because it failed! */
4914 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
4916 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
4917 --WorkQueue
->NumberOfActiveWorkerThreads
;
4918 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
4920 /* Rundown, no more active threads, set the event! */
4921 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
4922 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
4924 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
4927 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
4929 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
4935 RxSpinUpWorkerThreads(
4936 PRX_WORK_QUEUE WorkQueue
)
4942 RxSynchronizeWithScavenger(
4943 IN PRX_CONTEXT RxContext
)
4952 RxTableComputeHashValue(
4953 IN PUNICODE_STRING Name
)
4961 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
4964 Loops
[1] = MaxChar
- 1;
4965 Loops
[2] = MaxChar
- 2;
4966 Loops
[3] = MaxChar
- 3;
4967 Loops
[4] = MaxChar
- 4;
4968 Loops
[5] = MaxChar
/ 4;
4969 Loops
[6] = 2 * MaxChar
/ 4;
4970 Loops
[7] = 3 * MaxChar
/ 4;
4973 for (i
= 0; i
< 8; ++i
)
4978 if (Idx
>= 0 && Idx
< MaxChar
)
4980 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
4991 RxTableComputePathHashValue(
4992 IN PUNICODE_STRING Name
)
5000 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
5003 Loops
[1] = MaxChar
- 1;
5004 Loops
[2] = MaxChar
- 2;
5005 Loops
[3] = MaxChar
- 3;
5006 Loops
[4] = MaxChar
- 4;
5007 Loops
[5] = MaxChar
/ 4;
5008 Loops
[6] = 2 * MaxChar
/ 4;
5009 Loops
[7] = 3 * MaxChar
/ 4;
5012 for (i
= 0; i
< 8; ++i
)
5017 if (Idx
>= 0 && Idx
< MaxChar
)
5019 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
5028 IN PRX_PREFIX_TABLE ThisTable
,
5029 IN PUNICODE_STRING Name
,
5030 OUT PUNICODE_STRING RemainingName
,
5031 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
5035 PRX_PREFIX_ENTRY Entry
;
5036 RX_CONNECTION_ID NullId
;
5037 UNICODE_STRING LookupString
;
5041 /* If caller didn't provide a connection ID, setup one */
5042 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
5044 NullId
.Luid
.LowPart
= 0;
5045 NullId
.Luid
.HighPart
= 0;
5046 RxConnectionId
= &NullId
;
5050 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
5054 LookupString
.Buffer
= Name
->Buffer
;
5055 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
5056 /* We'll perform the lookup, path component after another */
5057 for (i
= 1; i
< MaxChar
; ++i
)
5060 PRX_PREFIX_ENTRY CurEntry
;
5062 /* Don't cut in the middle of a path element */
5063 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
5068 /* Perform lookup in the table */
5069 LookupString
.Length
= i
* sizeof(WCHAR
);
5070 Hash
= RxTableComputeHashValue(&LookupString
);
5071 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
5073 ++ThisTable
->Lookups
;
5075 /* Entry not found, move to the next component */
5076 if (CurEntry
== NULL
)
5079 ++ThisTable
->FailedLookups
;
5085 ASSERT(Entry
->ContainingRecord
!= NULL
);
5086 Container
= Entry
->ContainingRecord
;
5088 /* Need to handle NetRoot specific case... */
5089 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
5094 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
5100 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
5104 /* Entry was found */
5109 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
5111 /* Setup remaining name */
5112 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
5113 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
5114 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
5118 /* Otherwise, that's the whole name */
5119 RemainingName
= Name
;
5129 RxTableLookupName_ExactLengthMatch(
5130 IN PRX_PREFIX_TABLE ThisTable
,
5131 IN PUNICODE_STRING Name
,
5133 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
5135 PLIST_ENTRY ListEntry
, HashBucket
;
5139 ASSERT(RxConnectionId
!= NULL
);
5141 /* Select the right bucket */
5142 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
5143 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
5144 /* If bucket is empty, no match */
5145 if (IsListEmpty(HashBucket
))
5150 /* Browse all the entries in the bucket */
5151 for (ListEntry
= HashBucket
->Flink
;
5152 ListEntry
!= HashBucket
;
5153 ListEntry
= ListEntry
->Flink
)
5156 PRX_PREFIX_ENTRY Entry
;
5157 BOOLEAN CaseInsensitive
;
5158 PUNICODE_STRING CmpName
, CmpPrefix
;
5159 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
5161 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
5162 ++ThisTable
->Considers
;
5163 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
5165 Container
= Entry
->ContainingRecord
;
5166 ASSERT(Container
!= NULL
);
5168 /* Not the same hash, not the same length, move on */
5169 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
5174 ++ThisTable
->Compares
;
5175 /* If we have to perform a case insensitive compare on a portion... */
5176 if (Entry
->CaseInsensitiveLength
!= 0)
5178 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
5180 /* Perform the case insensitive check on the asked length */
5181 InsensitiveName
.Buffer
= Name
->Buffer
;
5182 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
5183 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
5184 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
5185 /* No match, move to the next entry */
5186 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
5191 /* Was the case insensitive covering the whole name? */
5192 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
5194 /* If connection ID also matches, that a complete match! */
5195 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
5201 /* Otherwise, we have to continue with the sensitive match.... */
5202 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
5203 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
5204 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
5205 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
5207 CmpName
= &InsensitiveName
;
5208 CmpPrefix
= &InsensitivePrefix
;
5209 CaseInsensitive
= FALSE
;
5214 CmpPrefix
= &Entry
->Prefix
;
5215 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
5218 /* Perform the compare, if there's a match, also check for connection ID */
5219 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
5221 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
5232 RxTrackerUpdateHistory(
5233 _Inout_opt_ PRX_CONTEXT RxContext
,
5234 _Inout_ PMRX_FCB MrxFcb
,
5235 _In_ ULONG Operation
,
5236 _In_ ULONG LineNumber
,
5237 _In_ PCSTR FileName
,
5238 _In_ ULONG SerialNumber
)
5244 RxTrackPagingIoResource(
5245 _Inout_ PVOID Instance
,
5257 RxUninitializeVNetRootParameters(
5258 IN PUNICODE_STRING UserName
,
5259 IN PUNICODE_STRING UserDomainName
,
5260 IN PUNICODE_STRING Password
,
5265 /* Only free what could have been allocated */
5266 if (UserName
!= NULL
)
5268 ExFreePool(UserName
);
5271 if (UserDomainName
!= NULL
)
5273 ExFreePool(UserDomainName
);
5276 if (Password
!= NULL
)
5278 ExFreePool(Password
);
5281 /* And remove the possibly set CSC agent flag */
5284 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
5293 IN RX_BLOCK_CONDITION NewConditionValue
,
5294 OUT PRX_BLOCK_CONDITION Condition
,
5295 IN OUT PLIST_ENTRY TransitionWaitList
)
5297 PRX_CONTEXT Context
;
5298 LIST_ENTRY SerializationQueue
;
5302 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
5304 /* Set the new condition */
5305 RxAcquireSerializationMutex();
5306 ASSERT(NewConditionValue
!= Condition_InTransition
);
5307 *Condition
= NewConditionValue
;
5308 /* And get the serialization queue for treatment */
5309 RxTransferList(&SerializationQueue
, TransitionWaitList
);
5310 RxReleaseSerializationMutex();
5312 /* Handle the serialization queue */
5313 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
5314 while (Context
!= NULL
)
5316 /* If the caller asked for post, post the request */
5317 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
5319 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
5320 RxFsdPostRequest(Context
);
5322 /* Otherwise, wake up sleeping waiters */
5325 RxSignalSynchronousWaiter(Context
);
5328 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
5333 RxVerifyOperationIsLegal(
5334 IN PRX_CONTEXT RxContext
)
5343 RxWaitForStableCondition(
5344 IN PRX_BLOCK_CONDITION Condition
,
5345 IN OUT PLIST_ENTRY TransitionWaitList
,
5346 IN OUT PRX_CONTEXT RxContext
,
5347 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
5350 NTSTATUS LocalStatus
;
5354 /* Make sure to always get status */
5355 if (AsyncStatus
== NULL
)
5357 AsyncStatus
= &LocalStatus
;
5360 /* By default, it's a success */
5361 *AsyncStatus
= STATUS_SUCCESS
;
5364 /* If it's not stable, we've to wait */
5365 if (!StableCondition(*Condition
))
5367 /* Lock the mutex */
5368 RxAcquireSerializationMutex();
5369 /* Still not stable? */
5370 if (!StableCondition(*Condition
))
5372 /* Insert us in the wait list for processing on stable condition */
5373 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
5375 /* If we're asked to post on stable, don't wait, and just return pending */
5376 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
5378 *AsyncStatus
= STATUS_PENDING
;
5385 RxReleaseSerializationMutex();
5387 /* We don't post on stable, so, just wait... */
5390 RxWaitSync(RxContext
);
5400 RxWorkItemDispatcher(
5403 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
5405 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
5407 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
5409 ExFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
5415 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
5417 #ifdef RDBSS_TRACKER
5419 _In_ ULONG LineNumber
,
5420 _In_ PCSTR FileName
,
5421 _In_ ULONG SerialNumber
5426 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
5430 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
5432 SpecialContext
= FALSE
;
5433 ContextIsPresent
= FALSE
;
5434 /* Check for special context */
5435 if ((ULONG_PTR
)RxContext
== -1 || (ULONG_PTR
)RxContext
== -2)
5437 SpecialContext
= TRUE
;
5440 /* We don't handle buffering state change yet... */
5441 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
5442 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
5447 /* Nor special contexts */
5453 /* Nor missing contexts... */
5454 if (RxContext
== NULL
)
5459 /* That said: we have a real context! */
5460 ContextIsPresent
= TRUE
;
5462 /* If we've been cancelled in between, give up */
5463 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
5464 if (!NT_SUCCESS(Status
))
5470 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
5474 /* Assume we cannot lock */
5475 Status
= STATUS_LOCK_NOT_GRANTED
;
5477 /* Lock according to what the caller asked */
5480 case FCB_MODE_EXCLUSIVE
:
5481 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
5484 case FCB_MODE_SHARED
:
5485 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
5488 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
5489 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
5493 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
5494 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
5501 Status
= STATUS_SUCCESS
;
5502 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
5504 /* Handle paging write - not implemented */
5505 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
5511 /* And break, that cool! */
5517 /* If it failed, return immediately */
5518 if (!NT_SUCCESS(Status
))
5524 /* If we don't have to check for valid operation, job done, nothing more to do */
5525 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
5527 if (NT_SUCCESS(Status
))
5529 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
5535 /* Verify operation */
5538 RxVerifyOperationIsLegal(RxContext
);
5542 /* If it failed, release lock and fail */
5543 if (_SEH2_AbnormalTermination())
5545 ExReleaseResourceLite(Fcb
->Header
.Resource
);
5546 Status
= STATUS_LOCK_NOT_GRANTED
;
5551 if (NT_SUCCESS(Status
))
5553 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
5556 DPRINT("Status: %x\n", Status
);
5564 __RxItsTheSameContext(
5565 _In_ PRX_CONTEXT RxContext
,
5566 _In_ ULONG CapturedRxContextSerialNumber
,
5570 /* Check we have a context with the same serial number */
5571 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
5572 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
5575 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
5581 _Inout_opt_ PRX_CONTEXT RxContext
,
5582 _Inout_ PMRX_FCB MrxFcb
5583 #ifdef RDBSS_TRACKER
5585 _In_ ULONG LineNumber
,
5586 _In_ PCSTR FileName
,
5587 _In_ ULONG SerialNumber
5591 BOOLEAN IsExclusive
, BufferingPending
;
5593 RxAcquireSerializationMutex();
5595 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
5596 IsExclusive
= BooleanFlagOn(MrxFcb
->Header
.Resource
->Flag
, ResourceOwnedExclusive
);
5598 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
5599 * then just release the FCB
5601 if (!BufferingPending
|| !IsExclusive
)
5603 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
5604 LineNumber
, FileName
, SerialNumber
);
5605 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
5608 RxReleaseSerializationMutex();
5610 /* And finally leave */
5611 if (!BufferingPending
|| !IsExclusive
)
5616 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
5618 /* Otherwise, handle buffering state and release */
5619 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
5621 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
5622 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
5626 __RxReleaseFcbForThread(
5627 _Inout_opt_ PRX_CONTEXT RxContext
,
5628 _Inout_ PMRX_FCB MrxFcb
,
5629 _In_ ERESOURCE_THREAD ResourceThreadId
5630 #ifdef RDBSS_TRACKER
5632 _In_ ULONG LineNumber
,
5633 _In_ PCSTR FileName
,
5634 _In_ ULONG SerialNumber
5638 BOOLEAN IsExclusive
, BufferingPending
;
5640 RxAcquireSerializationMutex();
5642 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
5643 IsExclusive
= BooleanFlagOn(MrxFcb
->Header
.Resource
->Flag
, ResourceOwnedExclusive
);
5645 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
5646 * then just release the FCB
5648 if (!BufferingPending
|| !IsExclusive
)
5650 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
5651 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
5652 LineNumber
, FileName
, SerialNumber
);
5653 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
5656 RxReleaseSerializationMutex();
5658 /* And finally leave */
5659 if (!BufferingPending
|| !IsExclusive
)
5664 /* Otherwise, handle buffering state and release */
5665 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
5666 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
5667 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);