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_QUEUE_ITEM WorkQueueItem
);
65 PRX_CONTEXT RxContext
);
73 RxpDispatchChangeBufferingStateRequests(
76 PLIST_ENTRY DiscardedRequests
);
85 _RxAllocatePoolWithTag(
86 _In_ POOL_TYPE PoolType
,
87 _In_ SIZE_T NumberOfBytes
,
101 extern ULONG ReadAheadGranularity
;
103 volatile LONG RxNumberOfActiveFcbs
= 0;
104 ULONG SerialNumber
= 1;
106 volatile ULONG RxContextSerialNumberCounter
;
107 BOOLEAN RxStopOnLoudCompletion
= TRUE
;
108 BOOLEAN RxSrvCallConstructionDispatcherActive
= FALSE
;
109 LIST_ENTRY RxSrvCalldownList
;
110 RX_SPIN_LOCK RxStrucSupSpinLock
;
111 ULONG RdbssReferenceTracingValue
;
112 LARGE_INTEGER RxWorkQueueWaitInterval
[RxMaximumWorkQueue
];
113 LARGE_INTEGER RxSpinUpDispatcherWaitInterval
;
114 RX_DISPATCHER RxDispatcher
;
115 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues
;
116 FAST_MUTEX RxLowIoPagingIoSyncMutex
;
117 BOOLEAN RxContinueFromAssert
= TRUE
;
118 ULONG RxExplodePoolTags
= 1;
120 BOOLEAN DumpDispatchRoutine
= TRUE
;
122 BOOLEAN DumpDispatchRoutine
= FALSE
;
130 #define ASSERT(exp) \
133 RxAssert(#exp, __FILE__, __LINE__, NULL); \
138 #undef RxAllocatePool
139 #undef RxAllocatePoolWithTag
142 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
143 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
144 #define RxFreePool _RxFreePool
145 #define RxFreePoolWithTag _RxFreePoolWithTag
148 /* FUNCTIONS ****************************************************************/
154 RxAddVirtualNetRootToNetRoot(
156 PV_NET_ROOT VNetRoot
)
160 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
162 /* Insert in the VNetRoot list - make sure lock is held */
163 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
165 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
166 ++NetRoot
->NumberOfVirtualNetRoots
;
167 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
175 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
176 NODE_TYPE_CODE NodeType
,
179 PVOID AlreadyAllocatedObject
)
184 PVOID Buffer
, PAPNBuffer
;
185 PNON_PAGED_FCB NonPagedFcb
;
186 PMINIRDR_DISPATCH Dispatch
;
187 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
191 Dispatch
= RxDeviceObject
->Dispatch
;
204 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
205 if (NodeType
== RDBSS_NTC_FOBX
)
207 FobxSize
= sizeof(FOBX
);
208 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
210 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
213 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
214 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
216 SrvOpenSize
= sizeof(SRV_OPEN
);
217 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
219 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
222 FobxSize
= sizeof(FOBX
);
223 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
225 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
228 /* Otherwise, we're asked to allocate a FCB */
231 /* So, allocate the FCB and its extension if asked */
232 FcbSize
= sizeof(FCB
);
233 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
235 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
238 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
239 * Otherwise, it will be allocated later on, specifically
241 if (PoolType
== NonPagedPool
)
243 NonPagedSize
= sizeof(NON_PAGED_FCB
);
246 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
247 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
249 SrvOpenSize
= sizeof(SRV_OPEN
);
250 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
252 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
255 FobxSize
= sizeof(FOBX
);
256 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
258 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
263 /* If we already have a buffer, go ahead */
264 if (AlreadyAllocatedObject
!= NULL
)
266 Buffer
= AlreadyAllocatedObject
;
268 /* Otherwise, allocate it */
271 Buffer
= RxAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
278 /* Now, get the pointers - FOBX is easy */
279 if (NodeType
== RDBSS_NTC_FOBX
)
283 /* SRV_OPEN first, FOBX next */
284 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
287 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
289 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
295 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
297 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
299 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
300 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
303 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
304 if (PoolType
!= NonPagedPool
)
306 NonPagedFcb
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
307 if (NonPagedFcb
== NULL
)
309 RxFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
313 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
315 /* Otherwise, just point at the right place in what has been allocated previously */
318 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
319 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
323 /* If we have allocated a SRV_OPEN, initialize it */
326 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
328 if (NodeType
== RDBSS_NTC_SRVOPEN
)
330 SrvOpen
->InternalFobx
= Fobx
;
334 SrvOpen
->InternalFobx
= NULL
;
335 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
338 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
340 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
343 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
346 /* If we have allocated a FOBX, initialize it */
349 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
351 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
353 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
357 /* If we have allocated a FCB, initialize it */
360 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
362 Fcb
->NonPaged
= NonPagedFcb
;
363 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
364 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
365 NonPagedFcb
->FcbBackPointer
= Fcb
;
367 Fcb
->InternalSrvOpen
= SrvOpen
;
368 Fcb
->InternalFobx
= Fobx
;
370 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
371 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
372 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
374 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
376 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
379 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
381 InterlockedIncrement(&RxNumberOfActiveFcbs
);
382 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
384 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
385 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
396 NODE_TYPE_CODE NodeType
,
397 PMINIRDR_DISPATCH MRxDispatch
,
400 ULONG Tag
, ObjectSize
;
401 PVOID Object
, *Extension
;
402 PRX_PREFIX_ENTRY PrefixEntry
;
403 USHORT StructSize
, ExtensionSize
;
407 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
411 case RDBSS_NTC_SRVCALL
:
412 Tag
= RX_SRVCALL_POOLTAG
;
413 StructSize
= sizeof(SRV_CALL
);
414 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
416 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
420 case RDBSS_NTC_NETROOT
:
421 Tag
= RX_NETROOT_POOLTAG
;
422 StructSize
= sizeof(NET_ROOT
);
423 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
425 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
429 case RDBSS_NTC_V_NETROOT
:
430 Tag
= RX_V_NETROOT_POOLTAG
;
431 StructSize
= sizeof(V_NET_ROOT
);
432 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
434 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
443 /* Now, allocate the object */
444 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
445 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
451 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
453 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
456 case RDBSS_NTC_SRVCALL
:
457 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
458 Extension
= &((PSRV_CALL
)Object
)->Context
;
459 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
462 case RDBSS_NTC_NETROOT
:
463 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
464 Extension
= &((PNET_ROOT
)Object
)->Context
;
465 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
468 case RDBSS_NTC_V_NETROOT
:
469 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
470 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
478 /* Set the prefix table unicode string */
479 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
480 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
481 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
482 PrefixEntry
->Prefix
.Length
= NameLength
;
483 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
484 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
486 /* Return the extension if we are asked to manage it */
487 if (ExtensionSize
!= 0)
489 *Extension
= Add2Ptr(Object
, StructSize
);
508 /* If we're not asked to continue, just stop the system */
509 if (!RxContinueFromAssert
)
511 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
514 /* Otherwise, capture context to offer the user to dump it */
515 RtlCaptureContext(&Context
);
517 /* Loop until the user hits 'i' */
520 /* If no file provided, use empty name */
526 /* If no message provided, use empty one */
532 /* Display the message */
533 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
534 /* And ask the user */
535 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
536 /* If he asks for ignore, quit
537 * In case of invalid input, ask again
539 if (Response
[0] != 'B' && Response
[0] != 'b')
541 if (Response
[0] == 'I' || Response
[0] == 'i')
549 /* Break: offer the user to dump the context and break */
550 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
553 /* Continue looping, so that after dump, execution can continue (with ignore) */
562 RxBootstrapWorkerThreadDispatcher(
565 PRX_WORK_QUEUE RxWorkQueue
;
569 RxWorkQueue
= WorkQueue
;
570 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
574 RxCheckVNetRootCredentials(
575 PRX_CONTEXT RxContext
,
576 PV_NET_ROOT VNetRoot
,
578 PUNICODE_STRING UserName
,
579 PUNICODE_STRING UserDomain
,
580 PUNICODE_STRING Password
,
585 /* If that's a UNC name, there's nothing to process */
586 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
587 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
590 return STATUS_MORE_PROCESSING_REQUIRED
;
593 /* Compare the logon ID in the VNetRoot with the one provided */
594 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
596 return STATUS_MORE_PROCESSING_REQUIRED
;
599 /* No credential provided? That's OK */
600 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
602 return STATUS_SUCCESS
;
607 return STATUS_NOT_IMPLEMENTED
;
619 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
621 ASSERT(Context
!= NULL
);
622 ASSERT(Context
->CurrentIrp
!= NULL
);
623 Irp
= Context
->CurrentIrp
;
625 /* Debug what the caller asks for */
626 if (Context
->LoudCompletionString
!= NULL
)
628 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
629 /* Does the user asks to stop on failed completion */
630 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
632 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
636 /* Complete for real */
637 Context
->CurrentIrp
= NULL
;
638 RxCompleteRequest_Real(Context
, Irp
, Status
);
640 DPRINT("Status: %lx\n", Status
);
648 RxCompleteRequest_Real(
649 IN PRX_CONTEXT RxContext
,
655 PIO_STACK_LOCATION Stack
;
657 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
659 /* Nothing to complete, just free context */
662 DPRINT("NULL IRP for %p\n", RxContext
);
663 if (RxContext
!= NULL
)
665 RxDereferenceAndDeleteRxContext_Real(RxContext
);
671 /* Remove cancel routine */
672 IoAcquireCancelSpinLock(&OldIrql
);
673 IoSetCancelRoutine(Irp
, NULL
);
674 IoReleaseCancelSpinLock(OldIrql
);
676 /* Select the boost, given the success/paging operation */
677 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
679 Boost
= IO_DISK_INCREMENT
;
683 Irp
->IoStatus
.Information
= 0;
684 Boost
= IO_NO_INCREMENT
;
686 Irp
->IoStatus
.Status
= Status
;
688 if (RxContext
!= NULL
)
690 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
691 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
693 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
694 RxContext
->MinorFunction
, RxContext
, Irp
,
695 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
699 /* If that's an opening, there might be a canonical name allocated,
700 * if completion isn't pending, release it
702 Stack
= IoGetCurrentIrpStackLocation(Irp
);
703 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
706 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
708 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
711 RxpPrepareCreateContextForReuse(RxContext
);
712 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
715 /* If it's a write, validate the correct behavior of the operation */
716 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
718 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
720 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
724 /* If it's pending, make sure IRP is marked as such */
725 if (RxContext
!= NULL
)
727 if (RxContext
->PendingReturned
)
729 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
734 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
735 IoCompleteRequest(Irp
, Boost
);
737 /* If there's a context, dereference it */
738 if (RxContext
!= NULL
)
740 RxDereferenceAndDeleteRxContext_Real(RxContext
);
748 RxCompleteSrvOpenKeyAssociation(
749 IN OUT PSRV_OPEN SrvOpen
)
753 SrvCall
= (PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
;
754 /* Only handle requests if opening was a success */
755 if (SrvOpen
->Condition
== Condition_Good
)
758 BOOLEAN ProcessChange
;
759 LIST_ENTRY DiscardedRequests
;
761 /* Initialize our discarded requests list */
762 InitializeListHead(&DiscardedRequests
);
764 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
766 /* Transfer our requests in the SRV_CALL */
767 RxTransferList(&SrvCall
->BufferingManager
.SrvOpenLists
[0], &SrvOpen
->SrvOpenKeyList
);
769 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
770 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
772 /* Dispatch requests and get the discarded ones */
773 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &DiscardedRequests
);
775 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
777 /* Is there still anything to process? */
778 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
779 if (IsListEmpty(&SrvCall
->BufferingManager
.HandlerList
))
781 ProcessChange
= FALSE
;
785 ProcessChange
= (SrvCall
->BufferingManager
.HandlerInactive
== FALSE
);
788 SrvCall
->BufferingManager
.HandlerInactive
= TRUE
;
791 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
796 RxReferenceSrvCall(SrvCall
);
797 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
798 &SrvCall
->BufferingManager
.HandlerWorkItem
,
799 RxProcessChangeBufferingStateRequests
, SrvCall
);
802 /* And discard left requests */
803 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests
);
807 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
816 IN PRX_CONTEXT RxContext
,
817 IN PSRV_CALL SrvCall
,
818 IN PNET_ROOT NetRoot
,
819 IN PV_NET_ROOT VirtualNetRoot
,
820 OUT PLOCK_HOLDING_STATE LockHoldingState
)
823 PRX_PREFIX_TABLE PrefixTable
;
824 PMRX_CREATENETROOT_CONTEXT Context
;
825 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
829 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
830 VirtualNetRoot
, LockHoldingState
);
832 /* Validate the lock is exclusively held */
833 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
834 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
836 /* Allocate the context */
837 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
840 return STATUS_INSUFFICIENT_RESOURCES
;
843 /* We can release lock now */
844 RxReleasePrefixTableLock(PrefixTable
);
845 *LockHoldingState
= LHS_LockNotHeld
;
847 RootCondition
= Condition_Bad
;
848 VRootCondition
= Condition_Bad
;
850 /* Initialize the context */
851 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
852 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
853 Context
->RxContext
= RxContext
;
854 Context
->pVNetRoot
= VirtualNetRoot
;
855 Context
->Callback
= RxCreateNetRootCallBack
;
857 /* And call the mini-rdr */
858 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
859 if (Status
== STATUS_PENDING
)
861 /* Wait for the mini-rdr to be done */
862 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
863 /* Update the structures condition according to mini-rdr return */
864 if (NT_SUCCESS(Context
->NetRootStatus
))
866 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
868 RootCondition
= Condition_Good
;
869 VRootCondition
= Condition_Good
;
870 Status
= STATUS_SUCCESS
;
874 RootCondition
= Condition_Good
;
875 Status
= Context
->VirtualNetRootStatus
;
880 Status
= Context
->VirtualNetRootStatus
;
881 if (NT_SUCCESS(Status
))
883 Status
= Context
->NetRootStatus
;
889 /* It has to return STATUS_PENDING! */
893 /* Acquire lock again - for caller lock status will remain unchanged */
894 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
895 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
896 *LockHoldingState
= LHS_ExclusiveLockHeld
;
898 /* Do the transition to the condition got from mini-rdr */
899 RxTransitionNetRoot(NetRoot
, RootCondition
);
900 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
902 /* Context is not longer needed */
903 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
905 DPRINT("Status: %x\n", Status
);
915 IN PRX_CONTEXT RxContext
,
916 IN PSRV_CALL SrvCall
,
917 OUT PLOCK_HOLDING_STATE LockHoldingState
)
920 PRX_PREFIX_TABLE PrefixTable
;
921 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
922 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
923 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
927 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
929 /* Validate the lock is exclusively held */
930 RxDeviceObject
= RxContext
->RxDeviceObject
;
931 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
932 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
934 /* Allocate the context for mini-rdr */
935 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
936 if (Calldown
== NULL
)
938 SrvCall
->Context
= NULL
;
939 SrvCall
->Condition
= Condition_Bad
;
940 RxReleasePrefixTableLock(PrefixTable
);
941 *LockHoldingState
= LHS_LockNotHeld
;
942 return STATUS_INSUFFICIENT_RESOURCES
;
946 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
948 SrvCall
->Context
= NULL
;
949 SrvCall
->Condition
= Condition_InTransition
;
951 RxReleasePrefixTableLock(PrefixTable
);
952 *LockHoldingState
= LHS_LockNotHeld
;
954 CallbackContext
= &Calldown
->CallbackContexts
[0];
955 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
956 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
957 CallbackContext
->SrvCalldownStructure
= Calldown
;
958 CallbackContext
->CallbackContextOrdinal
= 0;
959 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
961 RxReferenceSrvCall(SrvCall
);
963 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
964 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
966 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
970 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
973 Calldown
->NumberToWait
= 1;
974 Calldown
->NumberRemaining
= 1;
975 Calldown
->RxContext
= RxContext
;
976 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
977 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
978 Calldown
->BestFinisher
= NULL
;
979 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
980 InitializeListHead(&Calldown
->SrvCalldownList
);
982 /* Call the mini-rdr */
983 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
984 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
985 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
986 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
987 /* It has to return STATUS_PENDING! */
988 ASSERT(Status
== STATUS_PENDING
);
990 /* No async, start completion */
991 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
993 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
995 /* Finish construction - we'll notify mini-rdr it's the winner */
996 Status
= RxFinishSrvCallConstruction(Calldown
);
997 if (!NT_SUCCESS(Status
))
999 RxReleasePrefixTableLock(PrefixTable
);
1000 *LockHoldingState
= LHS_LockNotHeld
;
1004 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
1005 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1009 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
1017 RxConstructVirtualNetRoot(
1018 IN PRX_CONTEXT RxContext
,
1019 IN PUNICODE_STRING CanonicalName
,
1020 IN NET_ROOT_TYPE NetRootType
,
1021 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
1022 OUT PLOCK_HOLDING_STATE LockHoldingState
,
1023 OUT PRX_CONNECTION_ID RxConnectionId
)
1026 PV_NET_ROOT VNetRoot
;
1027 RX_BLOCK_CONDITION Condition
;
1028 UNICODE_STRING LocalNetRootName
, FilePathName
;
1032 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1035 Condition
= Condition_Bad
;
1036 /* Before creating the VNetRoot, try to find the appropriate connection */
1037 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
1038 &LocalNetRootName
, &FilePathName
,
1039 LockHoldingState
, RxConnectionId
);
1040 /* Found and active */
1041 if (Status
== STATUS_CONNECTION_ACTIVE
)
1043 /* We need a new VNetRoot */
1044 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
1045 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
1046 if (VNetRoot
!= NULL
)
1048 RxReferenceVNetRoot(VNetRoot
);
1051 /* Dereference previous VNetRoot */
1052 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
1053 /* Reset and start construct (new structures will replace old ones) */
1054 RxContext
->Create
.pSrvCall
= NULL
;
1055 RxContext
->Create
.pNetRoot
= NULL
;
1056 RxContext
->Create
.pVNetRoot
= NULL
;
1058 /* Construct new NetRoot */
1059 if (VNetRoot
!= NULL
)
1061 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
1062 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
1063 if (NT_SUCCESS(Status
))
1065 Condition
= Condition_Good
;
1070 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1075 /* If it failed creating the connection, leave */
1076 if (Status
!= STATUS_SUCCESS
)
1078 if (*LockHoldingState
!= LHS_LockNotHeld
)
1080 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1081 *LockHoldingState
= LHS_LockNotHeld
;
1084 *VirtualNetRootPointer
= VNetRoot
;
1085 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1089 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1091 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1092 Condition
= Condition_Good
;
1095 /* We have a non stable VNetRoot - transition it */
1096 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1098 RxTransitionVNetRoot(VNetRoot
, Condition
);
1101 /* If recreation failed */
1102 if (Status
!= STATUS_SUCCESS
)
1104 /* Dereference potential VNetRoot */
1105 if (VNetRoot
!= NULL
)
1107 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1108 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1113 if (*LockHoldingState
!= LHS_LockNotHeld
)
1115 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1116 *LockHoldingState
= LHS_LockNotHeld
;
1120 *VirtualNetRootPointer
= VNetRoot
;
1124 /* Return the allocated VNetRoot */
1125 *VirtualNetRootPointer
= VNetRoot
;
1134 IN PRX_CONTEXT RxContext
,
1135 IN PV_NET_ROOT VNetRoot
,
1136 IN PUNICODE_STRING Name
)
1142 NODE_TYPE_CODE NodeType
;
1143 PIO_STACK_LOCATION Stack
;
1144 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1148 /* We need a decent VNetRoot */
1149 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1151 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1152 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1153 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1155 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1156 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1158 Stack
= RxContext
->CurrentIrpSp
;
1160 /* Do we need to create a fake FCB? Like for renaming */
1161 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1162 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1163 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1165 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1166 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1168 /* Allocate the FCB */
1169 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1170 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1176 /* Initialize the FCB */
1177 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1178 Fcb
->RxDeviceObject
= RxDeviceObject
;
1179 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1180 Fcb
->VNetRoot
= VNetRoot
;
1181 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1183 InitializeListHead(&Fcb
->SrvOpenList
);
1184 Fcb
->SrvOpenListVersion
= 0;
1186 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1187 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1188 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1189 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1190 NetRoot
->InnerNamePrefix
.Length
);
1191 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1193 /* Copy back parameters from RxContext */
1194 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1196 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1199 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1201 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1203 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1206 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1208 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1211 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1212 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1214 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1215 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1217 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1218 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1220 /* Fake FCB doesn't go in prefix table */
1223 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1224 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1225 DPRINT("Fake FCB: %p\n", Fcb
);
1229 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1232 RxReferenceVNetRoot(VNetRoot
);
1233 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1235 Fcb
->ulFileSizeVersion
= 0;
1237 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1238 RxReferenceNetFcb(Fcb
);
1249 OUT PRX_CONTEXT RxContext
,
1250 IN PMRX_SRV_OPEN MrxSrvOpen
)
1261 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1262 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1263 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1264 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1267 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1268 /* Can we use pre-allocated FOBX? */
1269 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1271 Fobx
= Fcb
->InternalFobx
;
1272 /* Call allocate to initialize the FOBX */
1273 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1274 /* Mark it used now */
1275 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1276 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1278 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1280 Fobx
= SrvOpen
->InternalFobx
;
1281 /* Call allocate to initialize the FOBX */
1282 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1283 /* Mark it used now */
1284 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1285 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1289 /* Last case, we cannot, allocate a FOBX */
1290 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1294 /* Allocation failed! */
1301 Fobx
->Flags
= Flags
;
1303 /* Initialize throttling */
1304 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1305 if (NetRoot
!= NULL
)
1307 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1309 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1310 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1311 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1313 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1315 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1316 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1317 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1321 /* Propagate flags fron RxContext */
1322 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1324 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1327 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1329 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1333 Fobx
->FobxSerialNumber
= 0;
1334 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1335 Fobx
->NodeReferenceCount
= 1;
1336 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1338 RxReferenceSrvOpen(SrvOpen
);
1339 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1341 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1342 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1343 InitializeListHead(&Fobx
->ClosePendingList
);
1345 Fobx
->CloseTime
.QuadPart
= 0;
1346 Fobx
->fOpenCountDecremented
= FALSE
;
1348 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1350 return (PMRX_FOBX
)Fobx
;
1358 IN PSRV_CALL SrvCall
,
1359 IN PUNICODE_STRING Name
,
1360 IN ULONG NetRootFlags
,
1361 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1364 USHORT CaseInsensitiveLength
;
1365 PRX_PREFIX_TABLE PrefixTable
;
1367 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1371 /* We need a SRV_CALL */
1372 ASSERT(SrvCall
!= NULL
);
1374 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1375 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1377 /* Get name length */
1378 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1379 if (CaseInsensitiveLength
> MAXUSHORT
)
1384 /* Allocate the NetRoot */
1385 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1386 CaseInsensitiveLength
);
1387 if (NetRoot
== NULL
)
1392 /* Construct name */
1393 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1394 Name
->Buffer
, Name
->Length
);
1395 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1397 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1398 SrvCall
->PrefixEntry
.Prefix
.Length
);
1401 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1403 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1405 /* Inisert in prefix table */
1406 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1407 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1410 /* Prepare the FCB table */
1411 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1413 InitializeListHead(&NetRoot
->TransitionWaitList
);
1414 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1415 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1417 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1419 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1420 NetRoot
->Flags
|= NetRootFlags
;
1421 NetRoot
->DiskParameters
.ClusterSize
= 1;
1422 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1423 NetRoot
->SrvCall
= SrvCall
;
1425 RxReferenceSrvCall(SrvCall
);
1427 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1436 RxCreateNetRootCallBack(
1437 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1441 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1451 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1452 IN ULONG InitialContextFlags
)
1455 PRX_CONTEXT Context
;
1457 ASSERT(RxDeviceObject
!= NULL
);
1459 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1461 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1462 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1464 /* Allocate the context from our lookaside list */
1465 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1466 if (Context
== NULL
)
1471 /* And initialize it */
1472 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1473 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1474 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1476 /* Add it to our global list */
1477 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1478 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1479 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1481 DPRINT("Context: %p\n", Context
);
1490 IN PRX_CONTEXT RxContext
,
1491 IN PUNICODE_STRING Name
,
1492 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1493 IN PRX_CONNECTION_ID RxConnectionId
)
1500 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1502 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1504 /* Get the name length */
1505 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1506 if (InnerNamePrefix
!= NULL
)
1508 NameLength
+= InnerNamePrefix
->Length
;
1511 /* Allocate the object */
1512 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1513 if (SrvCall
== NULL
)
1519 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1520 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1521 RxInitializeBufferingManager(SrvCall
);
1522 InitializeListHead(&SrvCall
->TransitionWaitList
);
1523 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1524 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1525 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1526 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1527 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1528 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1529 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1530 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1532 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1541 RxCreateSrvCallCallBack(
1542 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1546 PRX_CONTEXT RxContext
;
1547 ULONG NumberRemaining
;
1548 BOOLEAN StartDispatcher
;
1549 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1551 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1553 /* Get our context structures */
1554 Calldown
= Context
->SrvCalldownStructure
;
1555 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1557 /* If it is a success, that's the winner */
1558 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1559 if (Context
->Status
== STATUS_SUCCESS
)
1561 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1562 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1564 NumberRemaining
= --Calldown
->NumberRemaining
;
1565 SrvCall
->Status
= Context
->Status
;
1566 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1568 /* Still some to ask, keep going */
1569 if (NumberRemaining
!= 0)
1574 /* If that's not async, signal we're done */
1575 RxContext
= Calldown
->RxContext
;
1576 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1578 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1581 /* If that's a mailslot, finish construction, no more to do */
1582 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1584 RxFinishSrvCallConstruction(Calldown
);
1588 /* Queue our finish call for delayed completion */
1589 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1590 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1591 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1592 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1593 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1595 /* If we have to start dispatcher, go ahead */
1596 if (StartDispatcher
)
1600 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1601 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1602 if (!NT_SUCCESS(Status
))
1604 /* It failed - run it manually.... */
1605 RxFinishSrvCallConstructionDispatcher(NULL
);
1615 IN PV_NET_ROOT VNetRoot
,
1624 ASSERT(NodeTypeIsFcb(Fcb
));
1625 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1627 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1631 SrvOpen
= Fcb
->InternalSrvOpen
;
1632 /* Check whethet we have to allocate a new SRV_OPEN */
1633 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1634 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1635 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1638 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1639 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1644 /* Otherwise, just use internal one and initialize it */
1645 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1646 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1647 Fcb
->InternalSrvOpen
);
1648 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1649 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1652 /* If SrvOpen was properly allocated, initialize it */
1653 if (SrvOpen
!= NULL
)
1655 SrvOpen
->Flags
= Flags
;
1656 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1657 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1658 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1659 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1660 SrvOpen
->NodeReferenceCount
= 1;
1662 RxReferenceVNetRoot(VNetRoot
);
1663 RxReferenceNetFcb(Fcb
);
1665 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1666 ++Fcb
->SrvOpenListVersion
;
1668 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1669 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1670 InitializeListHead(&SrvOpen
->FobxList
);
1671 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1676 if (_SEH2_AbnormalTermination())
1678 if (SrvOpen
!= NULL
)
1680 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1686 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1699 IN PRX_CONTEXT RxContext
,
1700 IN PNET_ROOT NetRoot
,
1701 IN PUNICODE_STRING CanonicalName
,
1702 IN PUNICODE_STRING LocalNetRootName
,
1703 IN PUNICODE_STRING FilePath
,
1704 IN PRX_CONNECTION_ID RxConnectionId
)
1707 PV_NET_ROOT VNetRoot
;
1708 USHORT CaseInsensitiveLength
;
1712 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
1713 LocalNetRootName
, FilePath
, RxConnectionId
);
1715 /* Lock must be held exclusively */
1716 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1718 /* Check for overflow */
1719 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
1724 /* Get name length and allocate VNetRoot */
1725 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1726 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
1727 CaseInsensitiveLength
);
1728 if (VNetRoot
== NULL
)
1733 /* Initialize its connection parameters */
1734 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
1735 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
1736 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1737 if (!NT_SUCCESS(Status
))
1739 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
1740 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1741 RxFreeObject(VNetRoot
);
1747 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
1749 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1750 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
1751 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1752 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1754 InitializeListHead(&VNetRoot
->TransitionWaitList
);
1755 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
1757 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
1761 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1763 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
1767 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1770 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
1772 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
1778 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
1781 /* Insert in prefix table */
1782 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
1783 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1786 RxReferenceNetRoot(NetRoot
);
1787 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
1790 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
1791 VNetRoot
->UpperFinalizationDone
= FALSE
;
1792 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
1793 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
1795 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
1796 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
1803 IN OUT PVOID Instance
,
1804 IN LOCK_HOLDING_STATE LockHoldingState
)
1807 NODE_TYPE_CODE NodeType
;
1808 PNODE_TYPE_AND_SIZE Node
;
1812 RxAcquireScavengerMutex();
1814 /* Check we have a node we can handle */
1815 NodeType
= NodeType(Instance
);
1816 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
1817 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
1818 (NodeType
== RDBSS_NTC_FOBX
));
1820 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
1821 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
1822 ASSERT(RefCount
>= 0);
1824 /* Trace refcount */
1827 case RDBSS_NTC_SRVCALL
:
1828 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
1831 case RDBSS_NTC_NETROOT
:
1832 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
1835 case RDBSS_NTC_V_NETROOT
:
1836 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
1839 case RDBSS_NTC_SRVOPEN
:
1840 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
1843 case RDBSS_NTC_FOBX
:
1844 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
1852 /* No need to free - still in use */
1855 RxReleaseScavengerMutex();
1859 /* We have to be locked exclusively */
1860 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
1863 RxReleaseScavengerMutex();
1867 RxReleaseScavengerMutex();
1869 /* Now, deallocate the memory */
1872 case RDBSS_NTC_SRVCALL
:
1876 SrvCall
= (PSRV_CALL
)Instance
;
1878 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
1879 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
1880 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
1884 case RDBSS_NTC_NETROOT
:
1888 NetRoot
= (PNET_ROOT
)Instance
;
1890 ASSERT(NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
1891 ASSERT(RxIsPrefixTableLockAcquired(NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
1892 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
1896 case RDBSS_NTC_V_NETROOT
:
1898 PV_NET_ROOT VNetRoot
;
1900 VNetRoot
= (PV_NET_ROOT
)Instance
;
1902 ASSERT(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
1903 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
1904 RxFinalizeVNetRoot(VNetRoot
, TRUE
, TRUE
);
1908 case RDBSS_NTC_SRVOPEN
:
1912 SrvOpen
= (PSRV_OPEN
)Instance
;
1914 ASSERT(RxIsFcbAcquired(SrvOpen
->Fcb
));
1915 if (SrvOpen
->OpenCount
== 0)
1917 RxFinalizeSrvOpen(SrvOpen
, FALSE
, FALSE
);
1922 case RDBSS_NTC_FOBX
:
1926 Fobx
= (PFOBX
)Instance
;
1928 ASSERT(RxIsFcbAcquired(Fobx
->SrvOpen
->Fcb
));
1929 RxFinalizeNetFobx(Fobx
, TRUE
, FALSE
);
1940 RxDereferenceAndDeleteRxContext_Real(
1941 IN PRX_CONTEXT RxContext
)
1946 PRX_CONTEXT StopContext
= NULL
;
1948 /* Make sure we really have a context */
1949 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1950 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
1951 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
1952 /* If refcount is 0, start releasing stuff that needs spinlock held */
1955 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1957 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
1959 /* If that's stop context from DO, remove it */
1960 RxDeviceObject
= RxContext
->RxDeviceObject
;
1961 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
1963 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
1967 /* Remove it from the list */
1968 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
1969 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
1970 RemoveEntryList(&RxContext
->ContextListEntry
);
1972 /* If that was the last active context, save the stop context */
1973 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
1975 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
1977 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
1982 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1984 /* Now, deal with what can be done without spinlock held */
1987 /* Refcount shouldn't have changed */
1988 ASSERT(RxContext
->ReferenceCount
== 0);
1989 /* Reset everything that can be */
1990 RxPrepareContextForReuse(RxContext
);
1992 #ifdef RDBSS_TRACKER
1993 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
1995 /* If that was the last active, set the event */
1996 if (StopContext
!= NULL
)
1998 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
1999 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
2002 /* Is ShadowCrit still owned? Shouldn't happen! */
2003 if (RxContext
->ShadowCritOwner
!= 0)
2005 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
2009 /* If it was allocated, free it */
2012 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
2022 RxDispatchToWorkerThread(
2023 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
2024 IN WORK_QUEUE_TYPE WorkQueueType
,
2025 IN PRX_WORKERTHREAD_ROUTINE Routine
,
2029 PRX_WORK_DISPATCH_ITEM DispatchItem
;
2031 /* Allocate a bit of context */
2032 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
2033 if (DispatchItem
== NULL
)
2035 return STATUS_INSUFFICIENT_RESOURCES
;
2038 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2039 DispatchItem
->DispatchRoutine
= Routine
;
2040 DispatchItem
->DispatchRoutineParameter
= pContext
;
2041 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
2042 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
2045 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, &DispatchItem
->WorkQueueItem
);
2046 if (!NT_SUCCESS(Status
))
2048 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
2049 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
2052 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
2061 RxExclusivePrefixTableLockToShared(
2062 PRX_PREFIX_TABLE Table
)
2066 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
2073 RxExtractServerName(
2074 IN PUNICODE_STRING FilePathName
,
2075 OUT PUNICODE_STRING SrvCallName
,
2076 OUT PUNICODE_STRING RestOfName
)
2082 ASSERT(SrvCallName
!= NULL
);
2084 /* SrvCall name will start from the begin up to the first separator */
2085 SrvCallName
->Buffer
= FilePathName
->Buffer
;
2086 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2088 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2094 /* Compute length */
2095 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
2096 SrvCallName
->MaximumLength
= Length
;
2097 SrvCallName
->Length
= Length
;
2099 /* Return the rest if asked */
2100 if (RestOfName
!= NULL
)
2102 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
2103 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2104 RestOfName
->MaximumLength
= Length
;
2105 RestOfName
->Length
= Length
;
2113 RxFcbTableInsertFcb(
2114 IN OUT PRX_FCB_TABLE FcbTable
,
2119 /* We deal with the table, make sure it's locked */
2120 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2122 /* Compute the hash */
2123 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2125 RxReferenceNetFcb(Fcb
);
2127 /* If no length, it will be our null entry */
2128 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2130 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2132 /* Otherwise, insert in the appropriate bucket */
2135 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2136 &Fcb
->FcbTableEntry
.HashLinks
);
2139 /* Propagate the change by incrementing the version number */
2140 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2142 return STATUS_SUCCESS
;
2149 RxFcbTableLookupFcb(
2150 IN PRX_FCB_TABLE FcbTable
,
2151 IN PUNICODE_STRING Path
)
2154 PRX_FCB_TABLE_ENTRY TableEntry
;
2158 /* No path - easy, that's null entry */
2161 TableEntry
= FcbTable
->TableEntryForNull
;
2166 PLIST_ENTRY HashBucket
, ListEntry
;
2168 /* Otherwise, compute the hash value and find the associated bucket */
2169 Hash
= RxTableComputePathHashValue(Path
);
2170 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2171 /* If the bucket is empty, it means there's no entry yet */
2172 if (IsListEmpty(HashBucket
))
2178 /* Otherwise, browse all the entry */
2179 for (ListEntry
= HashBucket
->Flink
;
2180 ListEntry
!= HashBucket
;
2181 ListEntry
= ListEntry
->Flink
)
2183 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2184 InterlockedIncrement(&FcbTable
->Compares
);
2186 /* If entry hash and string are equal, thatt's the one! */
2187 if (TableEntry
->HashValue
== Hash
&&
2188 TableEntry
->Path
.Length
== Path
->Length
&&
2189 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2195 /* We reached the end? Not found */
2196 if (ListEntry
== HashBucket
)
2203 InterlockedIncrement(&FcbTable
->Lookups
);
2205 /* If table entry isn't null, return the FCB */
2206 if (TableEntry
!= NULL
)
2208 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2209 RxReferenceNetFcb(Fcb
);
2214 InterlockedIncrement(&FcbTable
->FailedLookups
);
2224 RxFcbTableRemoveFcb(
2225 IN OUT PRX_FCB_TABLE FcbTable
,
2230 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2232 /* If no path, then remove entry for null */
2233 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2235 FcbTable
->TableEntryForNull
= NULL
;
2237 /* Otherwise, remove from the bucket */
2240 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2243 /* Reset its list entry */
2244 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2246 /* Propagate the change by incrementing the version number */
2247 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2249 return STATUS_SUCCESS
;
2257 IN OUT PRX_FCB_TABLE FcbTable
)
2263 /* Just delete the lock */
2264 ExDeleteResourceLite(&FcbTable
->TableLock
);
2266 /* And make sure (checked) that the table is really empty... */
2267 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2269 ASSERT(IsListEmpty(&FcbTable
->HashBuckets
[Bucket
]));
2279 IN BOOLEAN RecursiveFinalize
,
2280 IN BOOLEAN ForceFinalize
,
2281 IN LONG ReferenceCount
)
2285 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2286 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2288 /* Make sure we have an exclusively acquired FCB */
2289 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2290 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2292 /* We shouldn't force finalization... */
2293 ASSERT(!ForceFinalize
);
2295 /* If recurisve, finalize all the associated SRV_OPEN */
2296 if (RecursiveFinalize
)
2298 PLIST_ENTRY ListEntry
;
2300 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2301 ListEntry
!= &ThisFcb
->SrvOpenList
;
2302 ListEntry
= ListEntry
->Flink
)
2306 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2307 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2310 /* If FCB is still in use, that's over */
2313 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2315 ASSERT(ReferenceCount
> 0);
2321 ASSERT(ReferenceCount
>= 1);
2323 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2324 if (ReferenceCount
!= 1 && !ForceFinalize
)
2329 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2331 DPRINT("Finalizing FCB open: %d (%d)", ThisFcb
->OpenCount
, ForceFinalize
);
2333 /* If finalization was not already initiated, go ahead */
2334 if (!ThisFcb
->UpperFinalizationDone
)
2336 /* Free any FCB_LOCK */
2337 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2339 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2341 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2345 Entry
= ThisFcb
->BufferedLocks
.List
;
2346 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2352 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2353 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2357 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2359 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2361 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2363 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2367 ThisFcb
->UpperFinalizationDone
= TRUE
;
2370 ASSERT(ReferenceCount
>= 1);
2372 /* Even if forced, don't allow broken free */
2373 if (ReferenceCount
!= 1)
2378 /* Now, release everything */
2379 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2381 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2384 if (ThisFcb
->MRxDispatch
!= NULL
)
2386 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2389 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2390 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2391 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2393 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2394 RxDereferenceNetRoot(ThisFcb
->pNetRoot
, LHS_LockNotHeld
);
2396 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2397 ASSERT(!ThisFcb
->fMiniInited
);
2399 /* And free the object */
2400 RxFreeFcbObject(ThisFcb
);
2410 _Out_ PFOBX ThisFobx
,
2411 _In_ BOOLEAN RecursiveFinalize
,
2412 _In_ BOOLEAN ForceFinalize
)
2419 ASSERT(NodeType(ThisFobx
) == RDBSS_NTC_FOBX
);
2421 /* Only finalize if forced or if there's no ref left */
2422 if (ThisFobx
->NodeReferenceCount
!= 0 &&
2428 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx
, ThisFobx
->NodeReferenceCount
, ForceFinalize
);
2430 SrvOpen
= ThisFobx
->SrvOpen
;
2432 /* If it wasn't finalized yet, do it */
2433 if (!ThisFobx
->UpperFinalizationDone
)
2435 ASSERT(NodeType(SrvOpen
->Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
2436 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
2438 /* Remove it from the SRV_OPEN */
2439 RemoveEntryList(&ThisFobx
->FobxQLinks
);
2441 /* If we were used to browse a directory, free the query buffer */
2442 if (BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_FREE_UNICODE
))
2444 RxFreePoolWithTag(ThisFobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
2447 /* Notify the mini-rdr */
2448 if (Fcb
->MRxDispatch
!= NULL
&& Fcb
->MRxDispatch
->MRxDeallocateForFobx
!= NULL
)
2450 Fcb
->MRxDispatch
->MRxDeallocateForFobx((PMRX_FOBX
)ThisFobx
);
2453 /* If the SRV_OPEN wasn't closed yet, do it */
2454 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
2458 Status
= RxCloseAssociatedSrvOpen(ThisFobx
, FALSE
);
2459 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen
, ThisFobx
, Status
);
2462 /* Finalization done */
2463 ThisFobx
->UpperFinalizationDone
= TRUE
;
2466 /* If we're still referenced, don't go any further! */
2467 if (ThisFobx
->NodeReferenceCount
!= 0)
2472 /* At that point, everything should be closed */
2473 ASSERT(IsListEmpty(&ThisFobx
->ClosePendingList
));
2475 /* Was the FOBX allocated with another object?
2476 * If so, mark the buffer free in said object
2478 if (ThisFobx
== Fcb
->InternalFobx
)
2480 ClearFlag(Fcb
->FcbState
, FCB_STATE_FOBX_USED
);
2482 else if (ThisFobx
== SrvOpen
->InternalFobx
)
2484 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
);
2487 ThisFobx
->pSrvOpen
= NULL
;
2490 InterlockedDecrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
2492 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
2494 /* If it wasn't allocated with another object, free the FOBX */
2495 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_ENCLOSED_ALLOCATED
))
2497 RxFreeFcbObject(ThisFobx
);
2508 OUT PNET_ROOT ThisNetRoot
,
2509 IN BOOLEAN RecursiveFinalize
,
2510 IN BOOLEAN ForceFinalize
)
2513 PRX_FCB_TABLE FcbTable
;
2514 PRX_PREFIX_TABLE PrefixTable
;
2518 ASSERT(NodeType(ThisNetRoot
) == RDBSS_NTC_NETROOT
);
2520 PrefixTable
= ThisNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2521 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
2523 /* If sme finalization is already ongoing, leave */
2524 if (BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
))
2529 /* Mark we're finalizing */
2530 SetFlag(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
);
2532 FcbTable
= &ThisNetRoot
->FcbTable
;
2533 /* Did caller asked us to finalize any associated FCB? */
2534 if (RecursiveFinalize
)
2538 /* Browse all the FCBs in our FCB table */
2539 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
2540 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2542 PLIST_ENTRY HashBucket
, ListEntry
;
2544 HashBucket
= &FcbTable
->HashBuckets
[Bucket
];
2545 ListEntry
= HashBucket
->Flink
;
2546 while (ListEntry
!= HashBucket
)
2550 Fcb
= CONTAINING_RECORD(ListEntry
, FCB
, FcbTableEntry
.HashLinks
);
2551 ASSERT(NodeTypeIsFcb(Fcb
));
2553 ListEntry
= ListEntry
->Flink
;
2555 /* If the FCB isn't orphaned, then, it's time to purge it */
2556 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
2560 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
2561 ASSERT(Status
== STATUS_SUCCESS
);
2566 RxReleaseFcbTableLock(FcbTable
);
2569 /* Only finalize if forced or if there's a single ref left */
2570 if (ThisNetRoot
->NodeReferenceCount
!= 1 && !ForceFinalize
)
2575 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot
, &ThisNetRoot
->PrefixEntry
.Prefix
);
2577 /* If we're still referenced, don't go any further! */
2578 if (ThisNetRoot
->NodeReferenceCount
!= 1)
2583 /* Finalize the FCB table (and make sure it's empty!) */
2584 RxFinalizeFcbTable(FcbTable
);
2586 /* If name wasn't remove already, do it now */
2587 if (!BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
2589 RxRemovePrefixTableEntry(PrefixTable
, &ThisNetRoot
->PrefixEntry
);
2592 /* Delete the object */
2593 SrvCall
= (PSRV_CALL
)ThisNetRoot
->pSrvCall
;
2594 RxFreeObject(ThisNetRoot
);
2596 /* And dereference the associated SRV_CALL */
2597 if (SrvCall
!= NULL
)
2599 RxDereferenceSrvCall(SrvCall
, LHS_ExclusiveLockHeld
);
2610 OUT PSRV_CALL ThisSrvCall
,
2611 IN BOOLEAN RecursiveFinalize
,
2612 IN BOOLEAN ForceFinalize
)
2614 PRX_PREFIX_TABLE PrefixTable
;
2618 ASSERT(NodeType(ThisSrvCall
) == RDBSS_NTC_SRVCALL
);
2620 PrefixTable
= ThisSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2621 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
2623 /* Only finalize if forced or if there's a single ref left */
2624 if (ThisSrvCall
->NodeReferenceCount
!= 1 &&
2630 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall
, &ThisSrvCall
->PrefixEntry
.Prefix
);
2632 /* If it wasn't finalized yet, do it */
2633 if (!ThisSrvCall
->UpperFinalizationDone
)
2637 /* Remove ourselves from prefix table */
2638 RxRemovePrefixTableEntry(PrefixTable
, &ThisSrvCall
->PrefixEntry
);
2640 /* Remember our third arg, in case we get queued for later execution */
2643 SetFlag(ThisSrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
2647 ThisSrvCall
->UpperFinalizationDone
= TRUE
;
2649 /* Would defered execution free the object? */
2650 WillFree
= (ThisSrvCall
->NodeReferenceCount
== 1);
2652 /* If we have a device object */
2653 if (ThisSrvCall
->RxDeviceObject
!= NULL
)
2657 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
2658 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
2660 /* Extra ref, as usual */
2661 InterlockedIncrement((volatile long *)&ThisSrvCall
->NodeReferenceCount
);
2663 RxDispatchToWorkerThread(ThisSrvCall
->RxDeviceObject
, DelayedWorkQueue
, RxpDestroySrvCall
, ThisSrvCall
);
2665 /* Return to the caller, in advance, whether we're freeing the object or not */
2669 /* If in the right thread already, call the mini-rdr */
2670 MINIRDR_CALL_THROUGH(Status
, ThisSrvCall
->RxDeviceObject
->Dispatch
,
2671 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)ThisSrvCall
, ForceFinalize
));
2676 /* If we're still referenced, don't go any further! */
2677 if (ThisSrvCall
->NodeReferenceCount
!= 1)
2683 if (ThisSrvCall
->pDomainName
!= NULL
)
2685 RxFreePool(ThisSrvCall
->pDomainName
);
2689 RxTearDownBufferingManager(ThisSrvCall
);
2690 RxFreeObject(ThisSrvCall
);
2697 OUT PSRV_OPEN ThisSrvOpen
,
2698 IN BOOLEAN RecursiveFinalize
,
2699 IN BOOLEAN ForceFinalize
)
2710 OUT PV_NET_ROOT ThisVNetRoot
,
2711 IN BOOLEAN RecursiveFinalize
,
2712 IN BOOLEAN ForceFinalize
)
2715 PRX_PREFIX_TABLE PrefixTable
;
2719 ASSERT(NodeType(ThisVNetRoot
) == RDBSS_NTC_V_NETROOT
);
2721 PrefixTable
= ThisVNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2722 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
2724 /* Only finalize if forced or if there's a single ref left */
2725 if (ThisVNetRoot
->NodeReferenceCount
!= 1 &&
2731 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot
, &ThisVNetRoot
->PrefixEntry
.Prefix
);
2733 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
2734 /* If it wasn't finalized yet, do it */
2735 if (!ThisVNetRoot
->UpperFinalizationDone
)
2737 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
2739 /* Reference the NetRoot so that it doesn't disappear */
2740 RxReferenceNetRoot(NetRoot
);
2741 RxOrphanSrvOpens(ThisVNetRoot
);
2742 /* Remove us from the available VNetRoot for NetRoot */
2743 RxRemoveVirtualNetRootFromNetRoot(NetRoot
, ThisVNetRoot
);
2744 /* Remove extra ref */
2745 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2747 /* Remove ourselves from prefix table */
2748 RxRemovePrefixTableEntry(PrefixTable
, &ThisVNetRoot
->PrefixEntry
);
2750 /* Finalization done */
2751 ThisVNetRoot
->UpperFinalizationDone
= TRUE
;
2754 /* If we're still referenced, don't go any further! */
2755 if (ThisVNetRoot
->NodeReferenceCount
!= 1)
2760 /* If there's an associated device, notify mini-rdr */
2761 if (NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
2765 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
2766 MRxFinalizeVNetRoot
, ((PMRX_V_NET_ROOT
)ThisVNetRoot
, FALSE
));
2770 /* Free parameters */
2771 RxUninitializeVNetRootParameters(ThisVNetRoot
->pUserName
, ThisVNetRoot
->pUserDomainName
,
2772 ThisVNetRoot
->pPassword
, &ThisVNetRoot
->Flags
);
2773 /* Dereference our NetRoot, we won't reference it anymore */
2774 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2776 /* And free the object! */
2777 RxFreePoolWithTag(ThisVNetRoot
, RX_V_NETROOT_POOLTAG
);
2783 RxFindOrConstructVirtualNetRoot(
2784 IN PRX_CONTEXT RxContext
,
2785 IN PUNICODE_STRING CanonicalName
,
2786 IN NET_ROOT_TYPE NetRootType
,
2787 IN PUNICODE_STRING RemainingName
)
2793 PV_NET_ROOT VNetRoot
;
2794 RX_CONNECTION_ID ConnectionID
;
2795 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2796 LOCK_HOLDING_STATE LockHoldingState
;
2800 RxDeviceObject
= RxContext
->RxDeviceObject
;
2801 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
2802 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
2804 /* Ask the mini-rdr for connection ID */
2805 ConnectionID
.SessionID
= 0;
2806 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
2808 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
2809 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
2811 /* mini-rdr is expected not to fail - unless it's not implemented */
2812 DPRINT1("Failed to initialize connection ID\n");
2817 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
2819 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2820 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
2821 LockHoldingState
= LHS_SharedLockHeld
;
2825 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
2829 PV_NET_ROOT SavedVNetRoot
;
2831 /* Look in prefix table */
2832 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
2833 if (Container
!= NULL
)
2835 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
2836 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
2838 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
2839 RxDereferenceSrvCall(Container
, LockHoldingState
);
2843 VNetRoot
= Container
;
2844 NetRoot
= VNetRoot
->NetRoot
;
2846 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
2847 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
2848 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
2850 Status
= STATUS_BAD_NETWORK_PATH
;
2851 SavedVNetRoot
= NULL
;
2857 PUNICODE_STRING UserName
, UserDomain
, Password
;
2859 /* We can reuse if we use same credentials */
2860 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
2861 &SessionId
, &UserName
,
2862 &UserDomain
, &Password
,
2864 if (NT_SUCCESS(Status
))
2866 SavedVNetRoot
= VNetRoot
;
2867 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
2869 UserDomain
, Password
,
2871 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
2873 PLIST_ENTRY ListEntry
;
2875 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
2876 ListEntry
!= &NetRoot
->VirtualNetRoots
;
2877 ListEntry
= ListEntry
->Flink
)
2879 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
2880 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
2882 UserDomain
, Password
,
2884 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2890 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
2892 SavedVNetRoot
= NULL
;
2896 if (!NT_SUCCESS(Status
))
2898 SavedVNetRoot
= NULL
;
2901 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
2905 /* We'll fail, if we had referenced a VNetRoot, dereference it */
2906 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
2908 if (SavedVNetRoot
== NULL
)
2910 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
2913 /* Reference VNetRoot we'll keep, and dereference current */
2914 else if (SavedVNetRoot
!= VNetRoot
)
2916 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
2917 if (SavedVNetRoot
!= NULL
)
2919 RxReferenceVNetRoot(SavedVNetRoot
);
2924 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
2925 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2932 /* If we're locked exclusive, we won't loop again, it was the second pass */
2933 if (LockHoldingState
!= LHS_SharedLockHeld
)
2938 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
2939 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
2941 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2942 LockHoldingState
= LHS_ExclusiveLockHeld
;
2946 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2947 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
2948 LockHoldingState
= LHS_ExclusiveLockHeld
;
2951 /* We didn't fail, and didn't find any VNetRoot, construct one */
2954 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
2956 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
2957 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
2959 if (Status
== STATUS_SUCCESS
)
2961 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
2962 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2963 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
2965 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2966 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
2967 RemainingName
->MaximumLength
= RemainingName
->Length
;
2969 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
2971 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
2973 VNetRoot
->Flags
|= Flags
;
2977 /* Release the prefix table - caller expects it to be released */
2978 if (LockHoldingState
!= LHS_LockNotHeld
)
2980 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2983 /* If we failed creating, quit */
2984 if (Status
!= STATUS_SUCCESS
)
2986 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
2990 /* Otherwise, wait until the VNetRoot is stable */
2991 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
2992 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
2993 /* It's all good, update the RX_CONTEXT with all our structs */
2994 if (VNetRoot
->Condition
== Condition_Good
)
2998 NetRoot
= VNetRoot
->NetRoot
;
2999 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3000 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3001 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
3005 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3006 RxContext
->Create
.pVNetRoot
= NULL
;
3007 Status
= STATUS_BAD_NETWORK_PATH
;
3017 RxFindOrCreateConnections(
3018 _In_ PRX_CONTEXT RxContext
,
3019 _In_ PUNICODE_STRING CanonicalName
,
3020 _In_ NET_ROOT_TYPE NetRootType
,
3021 _Out_ PUNICODE_STRING LocalNetRootName
,
3022 _Out_ PUNICODE_STRING FilePathName
,
3023 _Inout_ PLOCK_HOLDING_STATE LockState
,
3024 _In_ PRX_CONNECTION_ID RxConnectionId
)
3029 PV_NET_ROOT VNetRoot
;
3030 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
3031 PRX_PREFIX_TABLE PrefixTable
;
3032 UNICODE_STRING RemainingName
, NetRootName
;
3036 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3037 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
3038 FilePathName
, LockState
, RxConnectionId
);
3040 *FilePathName
= *CanonicalName
;
3041 LocalNetRootName
->Length
= 0;
3042 LocalNetRootName
->MaximumLength
= 0;
3043 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
3045 /* UNC path, split it */
3046 if (FilePathName
->Buffer
[1] == ';')
3052 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
3054 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
3063 return STATUS_OBJECT_NAME_INVALID
;
3066 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
3067 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
3068 LocalNetRootName
->Length
= Length
;
3069 LocalNetRootName
->MaximumLength
= Length
;
3070 FilePathName
->Length
-= Length
;
3072 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
3073 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
3074 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
3078 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
3083 ASSERT(*LockState
!= LHS_LockNotHeld
);
3085 /* If previous lookup left something, dereference it */
3086 if (Container
!= NULL
)
3088 switch (NodeType(Container
))
3090 case RDBSS_NTC_SRVCALL
:
3091 RxDereferenceSrvCall(Container
, *LockState
);
3094 case RDBSS_NTC_NETROOT
:
3095 RxDereferenceNetRoot(Container
, *LockState
);
3098 case RDBSS_NTC_V_NETROOT
:
3099 RxDereferenceVNetRoot(Container
, *LockState
);
3103 /* Should never happen */
3109 /* Look for our NetRoot in prefix table */
3110 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
3111 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
3115 UNICODE_STRING SrvCallName
;
3121 /* Assume we didn't succeed */
3122 RxContext
->Create
.pVNetRoot
= NULL
;
3123 RxContext
->Create
.pNetRoot
= NULL
;
3124 RxContext
->Create
.pSrvCall
= NULL
;
3125 RxContext
->Create
.Type
= NetRootType
;
3127 /* If we found something */
3128 if (Container
!= NULL
)
3131 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
3133 VNetRoot
= Container
;
3134 /* Use its NetRoot */
3135 NetRoot
= VNetRoot
->NetRoot
;
3137 /* If it's not stable, wait for it to be stable */
3138 if (NetRoot
->Condition
== Condition_InTransition
)
3140 RxReleasePrefixTableLock(PrefixTable
);
3141 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
3142 RxWaitForStableNetRoot(NetRoot
, RxContext
);
3143 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3144 *LockState
= LHS_ExclusiveLockHeld
;
3146 /* Now that's it's ok, retry lookup to find what we want */
3147 if (NetRoot
->Condition
== Condition_Good
)
3153 /* Is the associated netroot good? */
3154 if (NetRoot
->Condition
== Condition_Good
)
3156 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
3158 /* If it is, and SrvCall as well, then, we have our active connection */
3159 if (SrvCall
->Condition
== Condition_Good
&&
3160 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
3162 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3163 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3164 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3166 Status
= STATUS_CONNECTION_ACTIVE
;
3171 /* If VNetRoot was well constructed, it means the connection is active */
3172 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
3174 Status
= STATUS_CONNECTION_ACTIVE
;
3178 Status
= VNetRoot
->ConstructionStatus
;
3181 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3184 /* Can only be a SrvCall */
3187 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3188 SrvCall
= Container
;
3190 /* Wait for the SRV_CALL to be stable */
3191 if (SrvCall
->Condition
== Condition_InTransition
)
3193 RxReleasePrefixTableLock(PrefixTable
);
3194 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
3195 RxWaitForStableSrvCall(SrvCall
, RxContext
);
3196 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3197 *LockState
= LHS_ExclusiveLockHeld
;
3199 /* It went good, loop again to find what we look for */
3200 if (SrvCall
->Condition
== Condition_Good
)
3206 /* If it's not good... */
3207 if (SrvCall
->Condition
!= Condition_Good
)
3209 /* But SRV_CALL was well constructed, assume a connection was active */
3210 if (SrvCall
->Status
== STATUS_SUCCESS
)
3212 Status
= STATUS_CONNECTION_ACTIVE
;
3216 Status
= SrvCall
->Status
;
3219 RxDereferenceSrvCall(SrvCall
, *LockState
);
3225 /* If we found a SRV_CALL not matching our DO, quit */
3226 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
3227 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3229 RxDereferenceSrvCall(SrvCall
, *LockState
);
3230 Status
= STATUS_BAD_NETWORK_NAME
;
3234 /* Now, we want exclusive lock */
3235 if (*LockState
== LHS_SharedLockHeld
)
3237 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
3239 RxReleasePrefixTableLock(PrefixTable
);
3240 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3241 *LockState
= LHS_ExclusiveLockHeld
;
3245 RxReleasePrefixTableLock(PrefixTable
);
3246 *LockState
= LHS_ExclusiveLockHeld
;
3249 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3251 /* If we reach that point, we found something, no need to create something */
3252 if (Container
!= NULL
)
3257 /* Get the name for the SRV_CALL */
3258 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
3259 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
3260 /* And create the SRV_CALL */
3261 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
3262 if (SrvCall
== NULL
)
3264 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3268 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3269 RxReferenceSrvCall(SrvCall
);
3270 RxContext
->Create
.pVNetRoot
= NULL
;
3271 RxContext
->Create
.pNetRoot
= NULL
;
3272 RxContext
->Create
.pSrvCall
= NULL
;
3273 RxContext
->Create
.Type
= NetRootType
;
3274 Container
= SrvCall
;
3276 /* Construct SRV_CALL, ie, use mini-rdr */
3277 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
3278 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
3279 if (Status
!= STATUS_SUCCESS
)
3281 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
3282 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3283 RxDereferenceSrvCall(SrvCall
, *LockState
);
3284 RxReleasePrefixTableLock(PrefixTable
);
3288 /* Loop again to make use of SRV_CALL stable condition wait */
3291 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3292 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
3293 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
3294 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
3296 /* Call mini-rdr to get NetRoot name */
3297 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
3298 /* And create the NetRoot with that name */
3299 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
3300 if (NetRoot
== NULL
)
3302 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3305 NetRoot
->Type
= NetRootType
;
3307 RxDereferenceSrvCall(SrvCall
, *LockState
);
3309 /* Finally, create the associated VNetRoot */
3310 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
3311 if (VNetRoot
== NULL
)
3313 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
3314 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3317 RxReferenceVNetRoot(VNetRoot
);
3319 /* We're get closer! */
3320 NetRoot
->Condition
= Condition_InTransition
;
3321 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3322 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3323 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3325 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3326 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
3327 if (!NT_SUCCESS(Status
))
3329 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
3330 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
3331 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3333 RxContext
->Create
.pNetRoot
= NULL
;
3334 RxContext
->Create
.pVNetRoot
= NULL
;
3338 PIO_STACK_LOCATION Stack
;
3340 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3342 Stack
= RxContext
->CurrentIrpSp
;
3343 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
3345 RxExclusivePrefixTableLockToShared(PrefixTable
);
3346 *LockState
= LHS_SharedLockHeld
;
3352 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
3354 if (*LockState
!= LHS_LockNotHeld
)
3356 RxReleasePrefixTableLock(PrefixTable
);
3357 *LockState
= LHS_LockNotHeld
;
3363 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
3372 RxFinishFcbInitialization(
3373 IN OUT PMRX_FCB Fcb
,
3374 IN RX_FILE_TYPE FileType
,
3375 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
3377 NODE_TYPE_CODE OldType
;
3381 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
3383 OldType
= Fcb
->Header
.NodeTypeCode
;
3384 Fcb
->Header
.NodeTypeCode
= FileType
;
3385 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
3386 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
3388 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3390 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
3391 else if (InitPacket
!= NULL
)
3393 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
3394 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
3395 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
3396 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
3397 InitPacket
->pValidDataLength
->QuadPart
);
3400 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3401 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3403 /* If our FCB newly points to a file, initiliaz everything related */
3404 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
&&
3405 OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
3407 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
3408 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, &RxLockOperationCompletion
,
3409 &RxUnlockOperation
);
3411 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
3412 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
3414 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
3418 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
3427 RxFinishSrvCallConstruction(
3428 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
3432 PRX_CONTEXT Context
;
3433 RX_BLOCK_CONDITION Condition
;
3434 PRX_PREFIX_TABLE PrefixTable
;
3436 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
3438 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
3439 Context
= Calldown
->RxContext
;
3440 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
3442 /* We have a winner, notify him */
3443 if (Calldown
->BestFinisher
!= NULL
)
3445 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
3447 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
3449 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
3450 MRxSrvCallWinnerNotify
,
3451 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
3452 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
3453 if (Status
!= STATUS_SUCCESS
)
3455 Condition
= Condition_Bad
;
3459 Condition
= Condition_Good
;
3462 /* Otherwise, just fail our SRV_CALL */
3465 Status
= Calldown
->CallbackContexts
[0].Status
;
3466 Condition
= Condition_Bad
;
3469 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3470 RxTransitionSrvCall(SrvCall
, Condition
);
3471 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
3473 /* If async, finish it here, otherwise, caller has already finished the stuff */
3474 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
3476 DPRINT("Finishing async call\n");
3478 RxReleasePrefixTableLock(PrefixTable
);
3480 /* Make sure we weren't cancelled in-between */
3481 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
3483 Status
= STATUS_CANCELLED
;
3486 /* In case that was a create, context can be reused */
3487 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
3489 RxpPrepareCreateContextForReuse(Context
);
3492 /* If that's a failure, reset everything and return failure */
3493 if (Status
!= STATUS_SUCCESS
)
3495 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
3496 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3498 if (Context
->Info
.Buffer
!= NULL
)
3500 RxFreePool(Context
->Info
.Buffer
);
3501 Context
->Info
.Buffer
= NULL
;
3504 Context
->CurrentIrp
->IoStatus
.Information
= 0;
3505 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
3506 RxCompleteRequest(Context
, Status
);
3508 /* Otherwise, call resume routine and done! */
3511 Status
= Context
->ResumeRoutine(Context
);
3512 if (Status
!= STATUS_PENDING
)
3514 RxCompleteRequest(Context
, Status
);
3517 DPRINT("Not completing, pending\n");
3521 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
3530 RxFinishSrvCallConstructionDispatcher(
3534 BOOLEAN Direct
, KeepLoop
;
3536 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
3538 /* In case of failure of starting dispatcher, context is not set
3539 * We keep track of it to fail associated SRV_CALL
3541 Direct
= (Context
== NULL
);
3543 /* Separated thread, loop forever */
3546 PLIST_ENTRY ListEntry
;
3547 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
3549 /* If there are no SRV_CALL to finalize left, just finish thread */
3550 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
3551 if (IsListEmpty(&RxSrvCalldownList
))
3554 RxSrvCallConstructionDispatcherActive
= FALSE
;
3556 /* Otherwise, get the SRV_CALL to finish construction */
3559 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
3562 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
3570 /* If direct is set, reset the finisher to avoid electing a winner
3571 * and fail SRV_CALL (see upper comment)
3573 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
3576 Calldown
->BestFinisher
= NULL
;
3578 /* Finish SRV_CALL construction */
3579 RxFinishSrvCallConstruction(Calldown
);
3587 RxFlushFcbInSystemCache(
3589 IN BOOLEAN SynchronizeWithLazyWriter
)
3591 IO_STATUS_BLOCK IoStatus
;
3596 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &IoStatus
);
3597 /* If we're asked to sync with LW, do it in case of success */
3598 if (SynchronizeWithLazyWriter
&& NT_SUCCESS(IoStatus
.Status
))
3600 RxAcquirePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
3601 RxReleasePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
3604 DPRINT("Flushing for FCB %p returns %lx\n", Fcb
, IoStatus
.Status
);
3605 return IoStatus
.Status
;
3624 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
3625 if (NodeType(pObject
) == RDBSS_NTC_SRVCALL
)
3628 PRDBSS_DEVICE_OBJECT DeviceObject
;
3630 SrvCall
= (PSRV_CALL
)pObject
;
3631 DeviceObject
= SrvCall
->RxDeviceObject
;
3632 if (DeviceObject
!= NULL
)
3634 if (!BooleanFlagOn(DeviceObject
->Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
3636 ASSERT(SrvCall
->Context
== NULL
);
3639 ASSERT(SrvCall
->Context2
== NULL
);
3641 SrvCall
->RxDeviceObject
= NULL
;
3644 else if (NodeType(pObject
) == RDBSS_NTC_NETROOT
)
3648 NetRoot
= (PNET_ROOT
)pObject
;
3649 NetRoot
->pSrvCall
= NULL
;
3650 NetRoot
->NodeTypeCode
= NodeType(pObject
) | 0xF000;
3653 /* And just free the object */
3654 RxFreePool(pObject
);
3661 RxGetFileSizeWithLock(
3663 OUT PLONGLONG FileSize
)
3667 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
3678 return RxData
.OurProcess
;
3685 RxInitializeBufferingManager(
3688 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
3689 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
3690 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
3691 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
3692 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
3693 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
3694 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
3695 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
3696 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
3697 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
3699 return STATUS_SUCCESS
;
3707 RxInitializeContext(
3709 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
3710 IN ULONG InitialContextFlags
,
3711 IN OUT PRX_CONTEXT RxContext
)
3713 PIO_STACK_LOCATION Stack
;
3715 /* Initialize our various fields */
3716 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
3717 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
3718 RxContext
->ReferenceCount
= 1;
3719 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
3720 RxContext
->RxDeviceObject
= RxDeviceObject
;
3721 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
3722 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
3723 InitializeListHead(&RxContext
->BlockedOperations
);
3724 RxContext
->MRxCancelRoutine
= NULL
;
3725 RxContext
->ResumeRoutine
= NULL
;
3726 RxContext
->Flags
|= InitialContextFlags
;
3727 RxContext
->CurrentIrp
= Irp
;
3728 RxContext
->LastExecutionThread
= PsGetCurrentThread();
3729 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
3731 /* If've got no IRP, mark RX_CONTEXT */
3734 RxContext
->CurrentIrpSp
= NULL
;
3735 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
3736 RxContext
->MinorFunction
= 0;
3740 /* Otherwise, first determine whether we are performing async operation */
3741 Stack
= IoGetCurrentIrpStackLocation(Irp
);
3742 if (Stack
->FileObject
!= NULL
)
3746 Fcb
= Stack
->FileObject
->FsContext
;
3747 if (!IoIsOperationSynchronous(Irp
) ||
3748 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
3749 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
3750 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
3752 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3756 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
3758 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3760 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3762 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3765 /* Set proper flags if TopLevl IRP/Device */
3766 if (!RxIsThisTheTopLevelIrp(Irp
))
3768 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
3770 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
3772 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
3775 /* Copy stack information */
3776 RxContext
->MajorFunction
= Stack
->MajorFunction
;
3777 RxContext
->MinorFunction
= Stack
->MinorFunction
;
3778 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
3779 RxContext
->CurrentIrpSp
= Stack
;
3781 /* If we have a FO associated, learn for more */
3782 if (Stack
->FileObject
!= NULL
)
3787 /* Get the FCB and CCB (FOBX) */
3788 Fcb
= Stack
->FileObject
->FsContext
;
3789 Fobx
= Stack
->FileObject
->FsContext2
;
3790 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
3791 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
3793 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
3796 /* We have a FOBX, this not a DFS opening, keep track of it */
3797 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
3799 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
3800 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
3801 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
3803 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
3808 RxContext
->pFobx
= NULL
;
3811 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
3812 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
3815 PV_NET_ROOT VNetRoot
= NULL
;
3817 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
3819 VNetRoot
= Fcb
->VNetRoot
;
3821 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
3823 VNetRoot
= (PV_NET_ROOT
)Fobx
;
3826 if (VNetRoot
!= NULL
)
3828 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3832 /* Remember if that's a write through file */
3833 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
3834 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
3836 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
3841 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
3843 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
3844 RxContext
, RxContext
->MinorFunction
, Irp
,
3845 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
3846 RxContext
->SerialNumber
);
3855 RxInitializeDispatcher(
3859 HANDLE ThreadHandle
;
3863 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
3864 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
3866 /* Set appropriate timeouts: 10s & 60s */
3867 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3868 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3869 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3870 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
3872 RxDispatcher
.NumberOfProcessors
= 1;
3873 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
3874 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
3876 /* Initialize our dispatchers */
3877 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
3878 if (!NT_SUCCESS(Status
))
3883 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
3884 if (!NT_SUCCESS(Status
))
3889 /* And start them */
3890 RxDispatcher
.State
= RxDispatcherActive
;
3891 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
3892 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
3893 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
3894 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
3895 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
3896 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
3897 if (NT_SUCCESS(Status
))
3899 ZwClose(ThreadHandle
);
3909 RxInitializeFcbTable(
3910 IN OUT PRX_FCB_TABLE FcbTable
,
3911 IN BOOLEAN CaseInsensitiveMatch
)
3917 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
3918 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
3920 ExInitializeResourceLite(&FcbTable
->TableLock
);
3921 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
3922 FcbTable
->Version
= 0;
3923 FcbTable
->TableEntryForNull
= NULL
;
3925 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
3926 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
3928 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
3931 FcbTable
->Lookups
= 0;
3932 FcbTable
->FailedLookups
= 0;
3933 FcbTable
->Compares
= 0;
3941 RxInitializeLowIoContext(
3942 OUT PLOWIO_CONTEXT LowIoContext
,
3945 PRX_CONTEXT RxContext
;
3946 PIO_STACK_LOCATION Stack
;
3950 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
3951 ASSERT(LowIoContext
== &RxContext
->LowIoContext
);
3953 Stack
= RxContext
->CurrentIrpSp
;
3955 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
3956 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
3957 RxContext
->LowIoContext
.Operation
= Operation
;
3962 case LOWIO_OP_WRITE
:
3963 /* In case of RW, set a canary, to make sure these fields are properly set
3964 * they will be asserted when lowio request will be submit to mini-rdr
3967 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
3968 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
3969 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
3971 /* Keep track of paging IOs */
3972 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
3974 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
3978 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
3983 case LOWIO_OP_FSCTL
:
3984 case LOWIO_OP_IOCTL
:
3985 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
3986 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
3987 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
3988 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
3989 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
3990 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
3991 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
3994 /* Nothing to do for these */
3995 case LOWIO_OP_SHAREDLOCK
:
3996 case LOWIO_OP_EXCLUSIVELOCK
:
3997 case LOWIO_OP_UNLOCK
:
3998 case LOWIO_OP_UNLOCK_MULTIPLE
:
3999 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4000 case LOWIO_OP_CLEAROUT
:
4004 /* Should never happen */
4014 RxInitializeLowIoPerFcbInfo(
4015 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
4019 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
4020 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
4027 RxInitializeMRxDispatcher(
4028 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
4032 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4033 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4035 return STATUS_SUCCESS
;
4042 RxInitializePrefixTable(
4043 IN OUT PRX_PREFIX_TABLE ThisTable
,
4044 IN ULONG TableSize OPTIONAL
,
4045 IN BOOLEAN CaseInsensitiveMatch
)
4051 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
4054 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
4055 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
4056 InitializeListHead(&ThisTable
->MemberQueue
);
4057 ThisTable
->Version
= 0;
4058 ThisTable
->TableEntryForNull
= NULL
;
4059 ThisTable
->IsNetNameTable
= FALSE
;
4060 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4061 ThisTable
->TableSize
= TableSize
;
4067 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
4069 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
4078 RxInitializePurgeSyncronizationContext(
4079 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
4083 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
4084 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
4088 RxInitializeSrvCallParameters(
4089 IN PRX_CONTEXT RxContext
,
4090 IN OUT PSRV_CALL SrvCall
)
4094 SrvCall
->pPrincipalName
= NULL
;
4096 /* We only have stuff to initialize for file opening from DFS */
4097 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
4099 return STATUS_SUCCESS
;
4102 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
4105 return STATUS_NOT_IMPLEMENTED
;
4109 RxInitializeVNetRootParameters(
4110 PRX_CONTEXT RxContext
,
4112 OUT PULONG SessionId
,
4113 OUT PUNICODE_STRING
*UserNamePtr
,
4114 OUT PUNICODE_STRING
*UserDomainNamePtr
,
4115 OUT PUNICODE_STRING
*PasswordPtr
,
4119 PACCESS_TOKEN Token
;
4123 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
4124 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
4126 *UserNamePtr
= NULL
;
4127 *UserDomainNamePtr
= NULL
;
4128 *PasswordPtr
= NULL
;
4129 /* By default, that's not CSC instance */
4130 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4132 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
4133 if (SeTokenIsRestricted(Token
))
4135 return STATUS_ACCESS_DENIED
;
4139 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
4140 if (!NT_SUCCESS(Status
))
4146 Status
= SeQuerySessionIdToken(Token
, SessionId
);
4147 if (!NT_SUCCESS(Status
))
4152 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
4155 Status
= STATUS_NOT_IMPLEMENTED
;
4159 /* Deal with connection credentials */
4160 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
4163 Status
= STATUS_NOT_IMPLEMENTED
;
4167 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
4170 Status
= STATUS_NOT_IMPLEMENTED
;
4175 if (NT_SUCCESS(Status
))
4177 /* If that's a CSC instance, mark it as such */
4178 if (RxIsThisACscAgentOpen(RxContext
))
4180 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4192 RxInitializeWorkQueue(
4193 PRX_WORK_QUEUE WorkQueue
,
4194 WORK_QUEUE_TYPE WorkQueueType
,
4195 ULONG MaximumNumberOfWorkerThreads
,
4196 ULONG MinimumNumberOfWorkerThreads
)
4200 WorkQueue
->Type
= WorkQueueType
;
4201 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
4202 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
4204 WorkQueue
->State
= RxWorkQueueActive
;
4205 WorkQueue
->SpinUpRequestPending
= FALSE
;
4206 WorkQueue
->pRundownContext
= NULL
;
4207 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
4208 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
4209 WorkQueue
->CumulativeQueueLength
= 0;
4210 WorkQueue
->NumberOfSpinUpRequests
= 0;
4211 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
4212 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
4213 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
4214 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
4215 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
4216 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
4217 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
4218 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
4219 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
4220 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
4221 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
4222 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
4223 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
4224 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
4225 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
4226 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
4228 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
4229 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
4236 RxInitializeWorkQueueDispatcher(
4237 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
4240 ULONG MaximumNumberOfWorkerThreads
;
4244 /* Number of threads will depend on system capacity */
4245 if (MmQuerySystemSize() != MmLargeSystem
)
4247 MaximumNumberOfWorkerThreads
= 5;
4251 MaximumNumberOfWorkerThreads
= 10;
4254 /* Initialize the work queues */
4255 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
4256 MaximumNumberOfWorkerThreads
, 1);
4257 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
4258 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
4260 /* And start the worker threads */
4261 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
4262 RxBootstrapWorkerThreadDispatcher
,
4263 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
4264 if (!NT_SUCCESS(Status
))
4269 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
4270 RxBootstrapWorkerThreadDispatcher
,
4271 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
4272 if (!NT_SUCCESS(Status
))
4277 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
4278 RxBootstrapWorkerThreadDispatcher
,
4279 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
4287 RxInitiateSrvOpenKeyAssociation(
4288 IN OUT PSRV_OPEN SrvOpen
)
4290 PRX_BUFFERING_MANAGER BufferingManager
;
4294 SrvOpen
->Key
= NULL
;
4296 /* Just keep track of the opening request */
4297 BufferingManager
= &((PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
;
4298 InterlockedIncrement(&BufferingManager
->NumberOfOutstandingOpens
);
4300 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
4307 RxInsertWorkQueueItem(
4308 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
4309 WORK_QUEUE_TYPE WorkQueueType
,
4310 PRX_WORK_QUEUE_ITEM WorkQueueItem
)
4314 BOOLEAN SpinUpThreads
;
4315 PRX_WORK_QUEUE WorkQueue
;
4317 /* No dispatcher, nothing to insert */
4318 if (RxDispatcher
.State
!= RxDispatcherActive
)
4320 return STATUS_UNSUCCESSFUL
;
4323 /* Get the work queue */
4324 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
4326 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
4327 /* Only insert if the work queue is in decent state */
4328 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
4330 Status
= STATUS_UNSUCCESSFUL
;
4334 SpinUpThreads
= FALSE
;
4335 WorkQueueItem
->pDeviceObject
= pMRxDeviceObject
;
4336 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
4337 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
4338 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
4340 /* If required (and possible!), spin up a new worker thread */
4341 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
4342 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
4343 !WorkQueue
->SpinUpRequestPending
)
4345 WorkQueue
->SpinUpRequestPending
= TRUE
;
4346 SpinUpThreads
= TRUE
;
4349 Status
= STATUS_SUCCESS
;
4351 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
4353 /* If we failed, return and still not insert item */
4354 if (!NT_SUCCESS(Status
))
4359 /* All fine, insert the item */
4360 KeInsertQueue(&WorkQueue
->Queue
, &WorkQueueItem
->List
);
4362 /* And start a new worker thread if needed */
4365 RxSpinUpWorkerThreads(WorkQueue
);
4372 RxIsThisACscAgentOpen(
4373 IN PRX_CONTEXT RxContext
)
4379 /* Client Side Caching is DFS stuff - we don't support it */
4380 if (RxContext
->Create
.EaLength
!= 0)
4385 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
4386 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
4396 IN PRX_CONTEXT RxContext
,
4397 IN LOCK_OPERATION Operation
,
4398 IN ULONG BufferLength
)
4407 Irp
= RxContext
->CurrentIrp
;
4408 /* If we already have a MDL, make sure it's locked */
4409 if (Irp
->MdlAddress
!= NULL
)
4411 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
4415 /* That likely means the driver asks for buffered IOs - we don't support it! */
4416 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
4418 /* If we have a real length */
4419 if (BufferLength
> 0)
4421 /* Allocate a MDL and lock it */
4422 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
4425 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
4426 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
4429 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
4433 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4437 Status
= _SEH2_GetExceptionCode();
4439 /* Free the possible MDL we have allocated */
4441 Irp
->MdlAddress
= NULL
;
4443 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
4446 if (!FsRtlIsNtstatusExpected(Status
))
4448 Status
= STATUS_INVALID_USER_BUFFER
;
4451 RxContext
->IoStatusBlock
.Status
= Status
;
4452 ExRaiseStatus(Status
);
4458 RxLowIoCompletionTail(
4459 IN PRX_CONTEXT RxContext
)
4466 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
4468 /* Only continue if we're at APC_LEVEL or lower */
4469 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
&&
4470 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
4472 return STATUS_MORE_PROCESSING_REQUIRED
;
4475 /* Call the completion routine */
4476 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
4477 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
4478 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
4483 /* If it was a RW operation, for a paging file ... */
4484 Operation
= RxContext
->LowIoContext
.Operation
;
4485 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
4487 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
4490 Status
= STATUS_NOT_IMPLEMENTED
;
4495 /* Sanity check: we had known operation */
4496 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
4499 /* If not sync operation, complete now. Otherwise, caller has already completed */
4500 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
4502 RxCompleteRequest(RxContext
, Status
);
4505 DPRINT("Status: %x\n", Status
);
4514 RxLowIoPopulateFsctlInfo(
4515 IN PRX_CONTEXT RxContext
)
4520 PIO_STACK_LOCATION Stack
;
4524 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
4526 Irp
= RxContext
->CurrentIrp
;
4527 Stack
= RxContext
->CurrentIrpSp
;
4529 /* Copy stack parameters */
4530 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
4531 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
4532 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
4533 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
4534 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
4536 /* Same buffer in case of buffered */
4537 if (Method
== METHOD_BUFFERED
)
4539 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4540 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4542 return STATUS_SUCCESS
;
4545 /* Two buffers for neither */
4546 if (Method
== METHOD_NEITHER
)
4548 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
4549 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
4551 return STATUS_SUCCESS
;
4554 /* Only IN/OUT remain */
4555 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
4557 /* Use system buffer for input */
4558 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4559 /* And MDL for output */
4560 Mdl
= Irp
->MdlAddress
;
4563 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
4564 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
4566 return STATUS_INSUFFICIENT_RESOURCES
;
4571 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
4574 return STATUS_SUCCESS
;
4580 IN PRX_CONTEXT RxContext
,
4581 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
4585 BOOLEAN Synchronous
;
4586 PLOWIO_CONTEXT LowIoContext
;
4588 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
4592 LowIoContext
= &RxContext
->LowIoContext
;
4593 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4595 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
4597 Status
= STATUS_SUCCESS
;
4598 Operation
= LowIoContext
->Operation
;
4602 case LOWIO_OP_WRITE
:
4603 /* Check that the parameters were properly set by caller
4604 * See comment in RxInitializeLowIoContext()
4606 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
4607 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
4609 /* Lock the buffer */
4610 RxLockUserBuffer(RxContext
,
4611 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
4612 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
4613 if (RxNewMapUserBuffer(RxContext
) == NULL
)
4615 return STATUS_INSUFFICIENT_RESOURCES
;
4617 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
4619 /* If that's a paging IO, initialize serial operation */
4620 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
4624 Fcb
= (PFCB
)RxContext
->pFcb
;
4626 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
4627 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
4628 if (Operation
== LOWIO_OP_READ
)
4630 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
4634 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
4637 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
4642 case LOWIO_OP_FSCTL
:
4643 case LOWIO_OP_IOCTL
:
4644 /* Set FSCTL/IOCTL parameters */
4645 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
4646 /* Check whether we're consistent: a length means a buffer */
4647 if (NT_SUCCESS(Status
))
4649 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
4650 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
4651 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
4652 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
4654 Status
= STATUS_INVALID_PARAMETER
;
4660 case LOWIO_OP_SHAREDLOCK
:
4661 case LOWIO_OP_EXCLUSIVELOCK
:
4662 case LOWIO_OP_UNLOCK
:
4663 case LOWIO_OP_UNLOCK_MULTIPLE
:
4664 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4665 case LOWIO_OP_CLEAROUT
:
4670 Status
= STATUS_INVALID_PARAMETER
;
4674 /* No need to perform extra init in case of posting */
4675 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
4677 /* Preflight checks were OK, time to submit */
4678 if (NT_SUCCESS(Status
))
4680 PMINIRDR_DISPATCH Dispatch
;
4684 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4685 /* If not synchronous, we're likely to return before the operation is finished */
4686 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
4688 IoMarkIrpPending(RxContext
->CurrentIrp
);
4692 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
4693 if (Dispatch
!= NULL
)
4695 /* We'll try to execute until the mini-rdr doesn't return pending */
4698 RxContext
->IoStatusBlock
.Information
= 0;
4700 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
4701 if (Status
== STATUS_PENDING
)
4703 /* Unless it's not synchronous, caller will be happy with pending op */
4709 RxWaitSync(RxContext
);
4710 Status
= RxContext
->IoStatusBlock
.Status
;
4716 /* We had marked the IRP pending, whereas the operation finished, drop that */
4717 if (Status
!= STATUS_RETRY
)
4719 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
4721 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
4724 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
4728 } while (Status
== STATUS_PENDING
);
4732 Status
= STATUS_INVALID_PARAMETER
;
4736 /* Call completion and return */
4737 RxContext
->IoStatusBlock
.Status
= Status
;
4738 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
4739 return RxLowIoCompletionTail(RxContext
);
4747 IN PRX_CONTEXT RxContext
)
4753 Irp
= RxContext
->CurrentIrp
;
4754 /* We should have a MDL (buffered IOs are not supported!) */
4755 if (Irp
->MdlAddress
!= NULL
)
4758 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
4761 /* Just return system buffer */
4762 return Irp
->AssociatedIrp
.SystemBuffer
;
4766 RxMarkFobxOnCleanup(
4785 PRX_CONTEXT RxContext
)
4791 Irp
= RxContext
->CurrentIrp
;
4792 if (Irp
->MdlAddress
!= NULL
)
4794 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
4797 return Irp
->UserBuffer
;
4827 IN PV_NET_ROOT ThisVNetRoot
)
4836 RxpAcquirePrefixTableLockShared(
4837 PRX_PREFIX_TABLE pTable
,
4839 BOOLEAN ProcessBufferingStateChangeRequests
)
4843 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
4844 pTable
->TableLock
.ActiveEntries
);
4846 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
4853 RxpAcquirePrefixTableLockExclusive(
4854 PRX_PREFIX_TABLE pTable
,
4856 BOOLEAN ProcessBufferingStateChangeRequests
)
4860 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
4861 pTable
->TableLock
.ActiveEntries
);
4863 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
4870 RxpDereferenceAndFinalizeNetFcb(
4872 IN PRX_CONTEXT RxContext
,
4873 IN BOOLEAN RecursiveFinalize
,
4874 IN BOOLEAN ForceFinalize
)
4879 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
4883 ASSERT(!ForceFinalize
);
4884 ASSERT(NodeTypeIsFcb(ThisFcb
));
4885 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
4887 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
4888 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
4889 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
4895 Status
= STATUS_SUCCESS
;
4896 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
4897 ResourceAcquired
= FALSE
;
4898 NetRootReferenced
= FALSE
;
4899 /* If FCB isn't orphaned, it still have context attached */
4900 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
4902 /* Don't let NetRoot go away before we're done */
4903 RxReferenceNetRoot(NetRoot
);
4904 NetRootReferenced
= TRUE
;
4906 /* Try to acquire the table lock exclusively */
4907 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
4909 RxReferenceNetFcb(ThisFcb
);
4911 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
4913 if (RxContext
!= NULL
&& RxContext
!= (PVOID
)-1 && RxContext
!= (PVOID
)-2)
4915 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
4918 RxReleaseFcb(RxContext
, ThisFcb
);
4920 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
4922 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
4925 References
= RxDereferenceNetFcb(ThisFcb
);
4927 ResourceAcquired
= TRUE
;
4931 /* If locking was OK (or not needed!), attempt finalization */
4932 if (NT_SUCCESS(Status
))
4934 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
4937 /* Release table lock if acquired */
4938 if (ResourceAcquired
)
4940 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
4943 /* We don't need the NetRoot anylonger */
4944 if (NetRootReferenced
)
4946 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
4956 RxpDereferenceNetFcb(
4963 ASSERT(NodeTypeIsFcb(Fcb
));
4965 NewCount
= InterlockedDecrement((volatile long *)&Fcb
->NodeReferenceCount
);
4966 ASSERT(NewCount
>= 0);
4968 PRINT_REF_COUNT(NETFCB
, NewCount
);
4983 BOOLEAN ForceFinalize
;
4984 PRX_PREFIX_TABLE PrefixTable
;
4986 SrvCall
= (PSRV_CALL
)Context
;
4987 /* At this step, RxFinalizeSrvCall already cleaned some fields */
4988 ASSERT(SrvCall
->UpperFinalizationDone
);
4990 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
4991 /* Were we called with ForceFinalize? */
4992 ForceFinalize
= BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
4994 /* Notify mini-rdr */
4995 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
,
4996 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)SrvCall
,
5000 /* Dereference our extra reference (set before queueing) */
5001 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
5002 InterlockedDecrement((volatile long *)&SrvCall
->NodeReferenceCount
);
5003 /* And finalize for real, with the right context */
5004 RxFinalizeSrvCall(SrvCall
, FALSE
, ForceFinalize
);
5005 RxReleasePrefixTableLock(PrefixTable
);
5009 RxpDiscardChangeBufferingStateRequests(
5010 _Inout_ PLIST_ENTRY DiscardedRequests
)
5016 RxpDispatchChangeBufferingStateRequests(
5019 PLIST_ENTRY DiscardedRequests
)
5029 RxPostToWorkerThread(
5030 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
5031 _In_ WORK_QUEUE_TYPE WorkQueueType
,
5032 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem
,
5033 _In_ PRX_WORKERTHREAD_ROUTINE Routine
,
5034 _In_ PVOID pContext
)
5036 /* Initialize work queue item */
5037 pWorkQueueItem
->List
.Flink
= NULL
;
5038 pWorkQueueItem
->WorkerRoutine
= Routine
;
5039 pWorkQueueItem
->Parameter
= pContext
;
5041 /* And insert it in the work queue */
5042 return RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, pWorkQueueItem
);
5046 RxpProcessChangeBufferingStateRequests(
5048 BOOLEAN UpdateHandlerState
)
5057 RxPrefixTableInsertName(
5058 IN OUT PRX_PREFIX_TABLE ThisTable
,
5059 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
5061 IN PULONG ContainerRefCount
,
5062 IN USHORT CaseInsensitiveLength
,
5063 IN PRX_CONNECTION_ID ConnectionId
5068 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
5070 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
5071 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
5073 /* Copy parameters and compute hash */
5074 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
5075 ThisEntry
->ContainingRecord
= Container
;
5076 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
5077 InterlockedIncrement((volatile long *)ContainerRefCount
);
5078 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
5079 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
5081 /* If no path length: this is entry for null path */
5082 if (ThisEntry
->Prefix
.Length
== 0)
5084 ThisTable
->TableEntryForNull
= ThisEntry
;
5086 /* Otherwise, insert in the appropriate bucket */
5089 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
5092 /* If we had a connection ID, keep track of it */
5093 if (ConnectionId
!= NULL
)
5095 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
5099 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
5100 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
5103 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
5104 /* Reflect the changes */
5105 ++ThisTable
->Version
;
5107 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
5116 RxPrefixTableLookupName(
5117 IN PRX_PREFIX_TABLE ThisTable
,
5118 IN PUNICODE_STRING CanonicalName
,
5119 OUT PUNICODE_STRING RemainingName
,
5120 IN PRX_CONNECTION_ID ConnectionId
)
5126 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
5127 ASSERT(CanonicalName
->Length
> 0);
5129 /* Call the internal helper */
5130 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
5131 if (Container
== NULL
)
5136 /* Reference our container before returning it */
5137 if (RdbssReferenceTracingValue
!= 0)
5139 NODE_TYPE_CODE Type
;
5141 Type
= NodeType(Container
);
5144 case RDBSS_NTC_SRVCALL
:
5145 RxReferenceSrvCall(Container
);
5148 case RDBSS_NTC_NETROOT
:
5149 RxReferenceNetRoot(Container
);
5152 case RDBSS_NTC_V_NETROOT
:
5153 RxReferenceVNetRoot(Container
);
5163 RxReference(Container
);
5180 ASSERT(NodeTypeIsFcb(Fcb
));
5182 NewCount
= InterlockedIncrement((volatile long *)&Fcb
->NodeReferenceCount
);
5184 PRINT_REF_COUNT(NETFCB
, Fcb
->NodeReferenceCount
);
5193 RxpReleasePrefixTableLock(
5194 PRX_PREFIX_TABLE pTable
,
5195 BOOLEAN ProcessBufferingStateChangeRequests
)
5199 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
5200 pTable
->TableLock
.ActiveEntries
);
5202 ExReleaseResourceLite(&pTable
->TableLock
);
5210 RxPrepareContextForReuse(
5211 IN OUT PRX_CONTEXT RxContext
)
5215 /* When we reach that point, make sure mandatory parts are null-ed */
5216 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
5218 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
5219 RxContext
->Create
.RdrFlags
= 0;
5221 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
5223 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
5224 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
5227 RxContext
->ReferenceCount
= 0;
5235 RxProcessChangeBufferingStateRequests(
5238 /* Call internal routine */
5239 RxUndoScavengerFinalizationMarking(SrvCall
);
5240 RxpProcessChangeBufferingStateRequests(SrvCall
, TRUE
);
5244 RxProcessFcbChangeBufferingStateRequest(
5251 RxpTrackDereference(
5252 _In_ ULONG TraceType
,
5253 _In_ PCSTR FileName
,
5255 _In_ PVOID Instance
)
5259 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
5270 _In_ ULONG TraceType
,
5271 _In_ PCSTR FileName
,
5273 _In_ PVOID Instance
)
5275 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
5284 RxpUndoScavengerFinalizationMarking(
5287 PNODE_TYPE_AND_SIZE Node
;
5291 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
5292 /* There's no marking - nothing to do */
5293 if (!BooleanFlagOn(Node
->NodeTypeCode
, RX_SCAVENGER_MASK
))
5310 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
5312 /* Reference our FCB so that it doesn't disappear */
5313 RxReferenceNetFcb(Fcb
);
5314 /* Purge Cc if required */
5315 if (Fcb
->OpenCount
!= 0)
5317 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
5320 /* If it wasn't freed, release the lock */
5321 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
5323 RxReleaseFcb(NULL
, Fcb
);
5331 RxPurgeFcbInSystemCache(
5333 IN PLARGE_INTEGER FileOffset OPTIONAL
,
5335 IN BOOLEAN UninitializeCacheMaps
,
5336 IN BOOLEAN FlushFile
)
5343 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
5345 /* Try to flush first, if asked */
5348 /* If flushing failed, just make some noise */
5349 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
5350 if (!NT_SUCCESS(Status
))
5352 PVOID CallersAddress
, CallersCaller
;
5354 RtlGetCallersAddress(&CallersAddress
, &CallersCaller
);
5355 DPRINT1("Flush failed with status %lx for FCB %p\n", Status
, Fcb
);
5356 DPRINT1("Caller was %p %p\n", CallersAddress
, CallersCaller
);
5360 /* Deal with Cc for purge */
5361 Purged
= CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, FileOffset
,
5362 Length
, UninitializeCacheMaps
);
5363 /* If purge failed, force section closing */
5366 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
5368 RxReleaseFcb(NULL
, Fcb
);
5369 Purged
= MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
5370 RxAcquireExclusiveFcb(NULL
, Fcb
);
5373 /* Return appropriate status */
5374 Status
= (Purged
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
5375 DPRINT("Purge for FCB %p returns %lx\n", Fcb
, Status
);
5384 RxpWorkerThreadDispatcher(
5385 IN PRX_WORK_QUEUE WorkQueue
,
5386 IN PLARGE_INTEGER WaitInterval
)
5390 PETHREAD CurrentThread
;
5391 BOOLEAN KillThread
, Dereference
;
5392 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
5393 PWORKER_THREAD_ROUTINE WorkerRoutine
;
5395 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
5397 /* Reference ourselves */
5398 CurrentThread
= PsGetCurrentThread();
5399 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
5400 ASSERT(NT_SUCCESS(Status
));
5402 /* Infinite loop for worker */
5404 Dereference
= FALSE
;
5408 PLIST_ENTRY ListEntry
;
5410 /* Remove an entry from the work queue */
5411 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
5412 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
5414 PRDBSS_DEVICE_OBJECT DeviceObject
;
5416 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
5418 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
5419 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
5420 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
5422 /* Get the parameters, and null-them in the struct */
5423 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
5424 Parameter
= WorkQueueItem
->Parameter
;
5425 DeviceObject
= WorkQueueItem
->pDeviceObject
;
5427 WorkQueueItem
->List
.Flink
= NULL
;
5428 WorkQueueItem
->WorkerRoutine
= NULL
;
5429 WorkQueueItem
->Parameter
= NULL
;
5430 WorkQueueItem
->pDeviceObject
= NULL
;
5432 /* Call the routine */
5433 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
5434 WorkerRoutine(Parameter
);
5436 /* Are we going down now? */
5437 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
5439 PKEVENT TearDownEvent
;
5441 TearDownEvent
= InterlockedExchangePointer((void * volatile*)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
5442 if (TearDownEvent
!= NULL
)
5444 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
5448 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
5451 /* Shall we shutdown... */
5452 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
5453 switch (WorkQueue
->State
)
5455 /* Our queue is active, kill it if we have no more items to dispatch
5456 * and more threads than the required minimum
5458 case RxWorkQueueActive
:
5459 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
5461 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
5462 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
5466 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
5471 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
5476 /* The queue is inactive: kill it we have more threads than the required minimum */
5477 case RxWorkQueueInactive
:
5478 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
5479 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
5483 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
5488 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
5492 /* Rundown in progress..., kill it for sure! */
5493 case RxWorkQueueRundownInProgress
:
5495 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
5497 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
5499 RundownContext
= WorkQueue
->pRundownContext
;
5500 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
5502 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
5504 Dereference
= FALSE
;
5506 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
5508 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
5511 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
5518 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5519 } while (!KillThread
);
5521 DPRINT("Killed worker thread\n");
5523 /* Do we have to dereference ourselves? */
5526 ObDereferenceObject(CurrentThread
);
5529 /* Dump last executed routine */
5530 if (DumpDispatchRoutine
)
5532 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
5535 PsTerminateSystemThread(STATUS_SUCCESS
);
5540 IN OUT PVOID Instance
)
5542 NODE_TYPE_CODE NodeType
;
5543 PNODE_TYPE_AND_SIZE Node
;
5547 RxAcquireScavengerMutex();
5549 /* We can only reference a few structs */
5550 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
5551 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
5552 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
5553 (NodeType
== RDBSS_NTC_FOBX
));
5555 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
5556 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
5558 /* Trace refcount if asked */
5561 case RDBSS_NTC_SRVCALL
:
5562 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
5565 case RDBSS_NTC_NETROOT
:
5566 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
5569 case RDBSS_NTC_V_NETROOT
:
5570 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
5573 case RDBSS_NTC_SRVOPEN
:
5574 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
5577 case RDBSS_NTC_FOBX
:
5578 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
5586 RxpUndoScavengerFinalizationMarking(Instance
);
5587 RxReleaseScavengerMutex();
5594 RxRemovePrefixTableEntry(
5595 IN OUT PRX_PREFIX_TABLE ThisTable
,
5596 IN OUT PRX_PREFIX_ENTRY Entry
)
5600 ASSERT(NodeType(Entry
) == RDBSS_NTC_PREFIX_ENTRY
);
5601 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
5603 /* Check whether we're asked to remove null entry */
5604 if (Entry
->Prefix
.Length
== 0)
5606 ThisTable
->TableEntryForNull
= NULL
;
5610 RemoveEntryList(&Entry
->HashLinks
);
5613 Entry
->ContainingRecord
= NULL
;
5615 /* Also remove it from global list */
5616 RemoveEntryList(&Entry
->MemberQLinks
);
5618 ++ThisTable
->Version
;
5625 RxRemoveVirtualNetRootFromNetRoot(
5627 PV_NET_ROOT VNetRoot
)
5629 PRX_PREFIX_TABLE PrefixTable
;
5633 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
5634 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
5636 /* Remove the VNetRoot from the list in the NetRoot */
5637 --NetRoot
->NumberOfVirtualNetRoots
;
5638 RemoveEntryList(&VNetRoot
->NetRootListEntry
);
5640 /* Fix the NetRoot if we were the default VNetRoot */
5641 if (NetRoot
->DefaultVNetRoot
== VNetRoot
)
5643 /* Put the first one available */
5644 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
5646 NetRoot
->DefaultVNetRoot
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
5648 /* Otherwise, none */
5651 NetRoot
->DefaultVNetRoot
= NULL
;
5655 /* If there are still other VNetRoot available, we're done */
5656 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
5661 /* Otherwise, initiate NetRoot finalization */
5662 if (!BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
5664 RxRemovePrefixTableEntry(PrefixTable
, &NetRoot
->PrefixEntry
);
5665 SetFlag(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
);
5668 /* Notify mini-rdr */
5669 if (NetRoot
->pSrvCall
!= NULL
&& NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
5673 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
5674 MRxFinalizeNetRoot
, ((PMRX_NET_ROOT
)NetRoot
, FALSE
));
5681 RxResumeBlockedOperations_Serially(
5682 IN OUT PRX_CONTEXT RxContext
,
5683 IN OUT PLIST_ENTRY BlockingIoQ
)
5687 RxAcquireSerializationMutex();
5689 /* This can only happen on pipes */
5690 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
5692 RxReleaseSerializationMutex();
5698 RxReleaseSerializationMutex();
5705 RxScavengeRelatedFobxs(
5709 LIST_ENTRY LocalList
;
5710 PLIST_ENTRY NextEntry
;
5711 PRDBSS_SCAVENGER Scavenger
;
5715 /* First of all, check whether there are FOBX to scavenge */
5716 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5717 RxAcquireScavengerMutex();
5718 if (Scavenger
->FobxsToBeFinalized
<= 0)
5720 RxReleaseScavengerMutex();
5724 /* Initialize our local list which will hold all the FOBX to scavenge so
5725 * that we don't acquire the scavenger mutex too long
5727 InitializeListHead(&LocalList
);
5729 /* Technically, that condition should all be true... */
5730 if (!IsListEmpty(&Scavenger
->FobxFinalizationList
))
5732 PLIST_ENTRY NextEntry
, LastEntry
;
5734 /* Browse all the FCBs to find the matching ones */
5735 NextEntry
= Scavenger
->FobxFinalizationList
.Flink
;
5736 LastEntry
= &Scavenger
->FobxFinalizationList
;
5737 while (NextEntry
!= LastEntry
)
5739 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
5740 NextEntry
= NextEntry
->Flink
;
5741 /* Matching our FCB? Let's finalize it */
5742 if (Fobx
->pSrvOpen
!= NULL
&& Fobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
5744 RxpUndoScavengerFinalizationMarking(Fobx
);
5745 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
5746 InsertTailList(&LocalList
, &Fobx
->ScavengerFinalizationList
);
5751 RxReleaseScavengerMutex();
5753 /* Nothing to scavenge? Quit */
5754 if (IsListEmpty(&LocalList
))
5759 /* Now, finalize all the extracted FOBX */
5760 while (!IsListEmpty(&LocalList
))
5762 NextEntry
= RemoveHeadList(&LocalList
);
5763 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
5764 RxFinalizeNetFobx(Fobx
, TRUE
, TRUE
);
5771 RxScavengeVNetRoots(
5772 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
5783 RxSpinUpRequestsDispatcher(
5787 PRX_DISPATCHER RxDispatcher
;
5789 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
5790 if (!NT_SUCCESS(Status
))
5792 PsTerminateSystemThread(STATUS_SUCCESS
);
5795 RxDispatcher
= Dispatcher
;
5800 PLIST_ENTRY ListEntry
;
5802 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
5803 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
5804 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
5806 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
5807 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
5809 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
5813 ListEntry
= &RxDispatcher
->SpinUpRequests
;
5815 KeResetEvent(&RxDispatcher
->SpinUpRequestsEvent
);
5816 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
5818 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
5820 PWORK_QUEUE_ITEM WorkItem
;
5821 PRX_WORK_QUEUE WorkQueue
;
5823 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
5824 WorkQueue
= WorkItem
->Parameter
;
5826 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
5828 DPRINT("Workqueue: calling %p(%p)\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
5829 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
5831 } while (RxDispatcher
->State
== RxDispatcherActive
);
5833 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
5834 PsTerminateSystemThread(STATUS_SUCCESS
);
5841 RxSpinUpWorkerThread(
5842 PRX_WORK_QUEUE WorkQueue
,
5843 PRX_WORKERTHREAD_ROUTINE Routine
,
5848 HANDLE ThreadHandle
;
5852 /* If work queue is inactive, that cannot work */
5853 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
5854 if (WorkQueue
->State
!= RxWorkQueueActive
)
5856 Status
= STATUS_UNSUCCESSFUL
;
5857 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
5861 ++WorkQueue
->NumberOfActiveWorkerThreads
;
5862 Status
= STATUS_SUCCESS
;
5864 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5866 /* Quit on failure */
5867 if (!NT_SUCCESS(Status
))
5872 /* Spin up the worker thread */
5873 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
5874 if (NT_SUCCESS(Status
))
5876 ZwClose(ThreadHandle
);
5879 /* Read well: we reached that point because it failed! */
5880 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
5882 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
5883 --WorkQueue
->NumberOfActiveWorkerThreads
;
5884 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
5886 /* Rundown, no more active threads, set the event! */
5887 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
5888 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
5890 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
5893 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
5895 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5901 RxSpinUpWorkerThreads(
5902 PRX_WORK_QUEUE WorkQueue
)
5908 RxSynchronizeWithScavenger(
5909 IN PRX_CONTEXT RxContext
)
5918 RxTableComputeHashValue(
5919 IN PUNICODE_STRING Name
)
5927 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
5930 Loops
[1] = MaxChar
- 1;
5931 Loops
[2] = MaxChar
- 2;
5932 Loops
[3] = MaxChar
- 3;
5933 Loops
[4] = MaxChar
- 4;
5934 Loops
[5] = MaxChar
/ 4;
5935 Loops
[6] = 2 * MaxChar
/ 4;
5936 Loops
[7] = 3 * MaxChar
/ 4;
5939 for (i
= 0; i
< 8; ++i
)
5944 if (Idx
>= 0 && Idx
< MaxChar
)
5946 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
5957 RxTableComputePathHashValue(
5958 IN PUNICODE_STRING Name
)
5966 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
5969 Loops
[1] = MaxChar
- 1;
5970 Loops
[2] = MaxChar
- 2;
5971 Loops
[3] = MaxChar
- 3;
5972 Loops
[4] = MaxChar
- 4;
5973 Loops
[5] = MaxChar
/ 4;
5974 Loops
[6] = 2 * MaxChar
/ 4;
5975 Loops
[7] = 3 * MaxChar
/ 4;
5978 for (i
= 0; i
< 8; ++i
)
5983 if (Idx
>= 0 && Idx
< MaxChar
)
5985 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
5997 IN PRX_PREFIX_TABLE ThisTable
,
5998 IN PUNICODE_STRING Name
,
5999 OUT PUNICODE_STRING RemainingName
,
6000 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
6004 PRX_PREFIX_ENTRY Entry
;
6005 RX_CONNECTION_ID NullId
;
6006 UNICODE_STRING LookupString
;
6010 /* If caller didn't provide a connection ID, setup one */
6011 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
6013 NullId
.Luid
.LowPart
= 0;
6014 NullId
.Luid
.HighPart
= 0;
6015 RxConnectionId
= &NullId
;
6019 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
6023 LookupString
.Buffer
= Name
->Buffer
;
6024 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
6025 /* We'll perform the lookup, path component after another */
6026 for (i
= 1; i
< MaxChar
; ++i
)
6029 PRX_PREFIX_ENTRY CurEntry
;
6031 /* Don't cut in the middle of a path element */
6032 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
6037 /* Perform lookup in the table */
6038 LookupString
.Length
= i
* sizeof(WCHAR
);
6039 Hash
= RxTableComputeHashValue(&LookupString
);
6040 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
6042 ++ThisTable
->Lookups
;
6044 /* Entry not found, move to the next component */
6045 if (CurEntry
== NULL
)
6048 ++ThisTable
->FailedLookups
;
6054 ASSERT(Entry
->ContainingRecord
!= NULL
);
6055 Container
= Entry
->ContainingRecord
;
6057 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
6058 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
6062 NetRoot
= (PNET_ROOT
)Entry
->ContainingRecord
;
6063 /* If there's a default one, perfect, that's a match */
6064 if (NetRoot
->DefaultVNetRoot
!= NULL
)
6066 Container
= NetRoot
->DefaultVNetRoot
;
6068 /* If none (that shouldn't happen!), try to find one */
6071 /* Use the first one in the list */
6072 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
6074 Container
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
6076 /* Really, really, shouldn't happen */
6087 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
6093 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
6097 /* Entry was found */
6102 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
6104 /* Setup remaining name */
6105 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
6106 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
6107 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
6111 /* Otherwise, that's the whole name */
6112 RemainingName
= Name
;
6122 RxTableLookupName_ExactLengthMatch(
6123 IN PRX_PREFIX_TABLE ThisTable
,
6124 IN PUNICODE_STRING Name
,
6126 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
6128 PLIST_ENTRY ListEntry
, HashBucket
;
6132 ASSERT(RxConnectionId
!= NULL
);
6134 /* Select the right bucket */
6135 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
6136 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
6137 /* If bucket is empty, no match */
6138 if (IsListEmpty(HashBucket
))
6143 /* Browse all the entries in the bucket */
6144 for (ListEntry
= HashBucket
->Flink
;
6145 ListEntry
!= HashBucket
;
6146 ListEntry
= ListEntry
->Flink
)
6149 PRX_PREFIX_ENTRY Entry
;
6150 BOOLEAN CaseInsensitive
;
6151 PUNICODE_STRING CmpName
, CmpPrefix
;
6152 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
6154 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
6155 ++ThisTable
->Considers
;
6156 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
6158 Container
= Entry
->ContainingRecord
;
6159 ASSERT(Container
!= NULL
);
6161 /* Not the same hash, not the same length, move on */
6162 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
6167 ++ThisTable
->Compares
;
6168 /* If we have to perform a case insensitive compare on a portion... */
6169 if (Entry
->CaseInsensitiveLength
!= 0)
6171 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
6173 /* Perform the case insensitive check on the asked length */
6174 InsensitiveName
.Buffer
= Name
->Buffer
;
6175 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
6176 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
6177 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
6178 /* No match, move to the next entry */
6179 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
6184 /* Was the case insensitive covering the whole name? */
6185 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
6187 /* If connection ID also matches, that a complete match! */
6188 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
6194 /* Otherwise, we have to continue with the sensitive match.... */
6195 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
6196 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
6197 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
6198 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
6200 CmpName
= &InsensitiveName
;
6201 CmpPrefix
= &InsensitivePrefix
;
6202 CaseInsensitive
= FALSE
;
6207 CmpPrefix
= &Entry
->Prefix
;
6208 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
6211 /* Perform the compare, if there's a match, also check for connection ID */
6212 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
6214 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
6228 RxTearDownBufferingManager(
6234 return STATUS_SUCCESS
;
6241 RxTrackerUpdateHistory(
6242 _Inout_opt_ PRX_CONTEXT RxContext
,
6243 _Inout_ PMRX_FCB MrxFcb
,
6244 _In_ ULONG Operation
,
6245 _In_ ULONG LineNumber
,
6246 _In_ PCSTR FileName
,
6247 _In_ ULONG SerialNumber
)
6250 RX_FCBTRACKER_CASES Case
;
6252 /* Check for null or special context */
6253 if (RxContext
== NULL
)
6255 Case
= RX_FCBTRACKER_CASE_NULLCONTEXT
;
6257 else if ((ULONG_PTR
)RxContext
== -1)
6259 Case
= RX_FCBTRACKER_CASE_CBS_CONTEXT
;
6261 else if ((ULONG_PTR
)RxContext
== -2)
6263 Case
= RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT
;
6267 ASSERT(NodeType(RxContext
) == RDBSS_NTC_RX_CONTEXT
);
6268 Case
= RX_FCBTRACKER_CASE_NORMAL
;
6271 /* If caller provided a FCB, update its history */
6275 ASSERT(NodeTypeIsFcb(Fcb
));
6277 /* Only one acquire operation, so many release operations... */
6278 if (Operation
== TRACKER_ACQUIRE_FCB
)
6280 ++Fcb
->FcbAcquires
[Case
];
6284 ++Fcb
->FcbReleases
[Case
];
6288 /* If we have a normal context, update its history about this function calls */
6289 if (Case
== RX_FCBTRACKER_CASE_NORMAL
)
6291 ULONG TrackerHistoryPointer
;
6293 /* Only one acquire operation, so many release operations... */
6294 if (Operation
== TRACKER_ACQUIRE_FCB
)
6296 InterlockedIncrement(&RxContext
->AcquireReleaseFcbTrackerX
);
6300 InterlockedDecrement(&RxContext
->AcquireReleaseFcbTrackerX
);
6303 /* We only keep track of the 32 first calls */
6304 TrackerHistoryPointer
= InterlockedExchangeAdd((volatile long *)&RxContext
->TrackerHistoryPointer
, 1);
6305 if (TrackerHistoryPointer
< RDBSS_TRACKER_HISTORY_SIZE
)
6307 RxContext
->TrackerHistory
[TrackerHistoryPointer
].AcquireRelease
= Operation
;
6308 RxContext
->TrackerHistory
[TrackerHistoryPointer
].LineNumber
= LineNumber
;
6309 RxContext
->TrackerHistory
[TrackerHistoryPointer
].FileName
= (PSZ
)FileName
;
6310 RxContext
->TrackerHistory
[TrackerHistoryPointer
].SavedTrackerValue
= RxContext
->AcquireReleaseFcbTrackerX
;
6311 RxContext
->TrackerHistory
[TrackerHistoryPointer
].Flags
= RxContext
->Flags
;
6314 /* If it's negative, then we released once more than we acquired it?! */
6315 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
>= 0);
6320 RxTrackPagingIoResource(
6321 _Inout_ PVOID Instance
,
6333 RxUndoScavengerFinalizationMarking(
6336 /* Just call internal routine with mutex held */
6337 RxAcquireScavengerMutex();
6338 RxpUndoScavengerFinalizationMarking(Instance
);
6339 RxReleaseScavengerMutex();
6346 RxUninitializeVNetRootParameters(
6347 IN PUNICODE_STRING UserName
,
6348 IN PUNICODE_STRING UserDomainName
,
6349 IN PUNICODE_STRING Password
,
6354 /* Only free what could have been allocated */
6355 if (UserName
!= NULL
)
6357 RxFreePool(UserName
);
6360 if (UserDomainName
!= NULL
)
6362 RxFreePool(UserDomainName
);
6365 if (Password
!= NULL
)
6367 RxFreePool(Password
);
6370 /* And remove the possibly set CSC agent flag */
6373 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
6382 IN RX_BLOCK_CONDITION NewConditionValue
,
6383 OUT PRX_BLOCK_CONDITION Condition
,
6384 IN OUT PLIST_ENTRY TransitionWaitList
)
6386 PRX_CONTEXT Context
;
6387 LIST_ENTRY SerializationQueue
;
6391 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
6393 /* Set the new condition */
6394 RxAcquireSerializationMutex();
6395 ASSERT(NewConditionValue
!= Condition_InTransition
);
6396 *Condition
= NewConditionValue
;
6397 /* And get the serialization queue for treatment */
6398 RxTransferList(&SerializationQueue
, TransitionWaitList
);
6399 RxReleaseSerializationMutex();
6401 /* Handle the serialization queue */
6402 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
6403 while (Context
!= NULL
)
6405 /* If the caller asked for post, post the request */
6406 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
6408 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
6409 RxFsdPostRequest(Context
);
6411 /* Otherwise, wake up sleeping waiters */
6414 RxSignalSynchronousWaiter(Context
);
6417 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
6425 RxVerifyOperationIsLegal(
6426 IN PRX_CONTEXT RxContext
)
6431 PFILE_OBJECT FileObject
;
6432 PIO_STACK_LOCATION Stack
;
6436 Irp
= RxContext
->CurrentIrp
;
6437 Stack
= RxContext
->CurrentIrpSp
;
6438 FileObject
= Stack
->FileObject
;
6440 /* We'll only check stuff on opened files, this requires an IRP and a FO */
6441 if (Irp
== NULL
|| FileObject
== NULL
)
6446 /* Set no exception for breakpoint - remember whether is was already set */
6447 FlagSet
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
6448 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
6450 /* If we have a CCB, perform a few checks on opened file */
6451 Fobx
= RxContext
->pFobx
;
6454 PMRX_SRV_OPEN SrvOpen
;
6456 SrvOpen
= Fobx
->pSrvOpen
;
6457 if (SrvOpen
!= NULL
)
6459 UCHAR MajorFunction
;
6461 MajorFunction
= RxContext
->MajorFunction
;
6462 /* Only allow closing/cleanup operations on renamed files */
6463 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
6464 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
6466 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_RENAMED
;
6467 ExRaiseStatus(STATUS_FILE_RENAMED
);
6470 /* Only allow closing/cleanup operations on deleted files */
6471 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
6472 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
))
6474 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_DELETED
;
6475 ExRaiseStatus(STATUS_FILE_DELETED
);
6480 /* If that's an open operation */
6481 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
6483 PFILE_OBJECT RelatedFileObject
;
6485 /* We won't allow an open operation relative to a file to be deleted */
6486 RelatedFileObject
= FileObject
->RelatedFileObject
;
6487 if (RelatedFileObject
!= NULL
)
6491 Fcb
= RelatedFileObject
->FsContext
;
6492 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
6494 RxContext
->IoStatusBlock
.Status
= STATUS_DELETE_PENDING
;
6495 ExRaiseStatus(STATUS_DELETE_PENDING
);
6500 /* If cleanup was completed */
6501 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
6503 if (!BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
))
6505 UCHAR MajorFunction
;
6507 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
6508 MajorFunction
= Stack
->MajorFunction
;
6509 if (MajorFunction
!= IRP_MJ_CLOSE
&& MajorFunction
!= IRP_MJ_QUERY_INFORMATION
&&
6510 MajorFunction
!= IRP_MJ_SET_INFORMATION
)
6512 if ((MajorFunction
!= IRP_MJ_READ
&& MajorFunction
!= IRP_MJ_WRITE
) ||
6513 !BooleanFlagOn(Stack
->MinorFunction
, IRP_MN_COMPLETE
))
6515 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_CLOSED
;
6516 ExRaiseStatus(STATUS_FILE_CLOSED
);
6522 /* If flag was already set, don't clear it */
6525 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
6533 RxWaitForStableCondition(
6534 IN PRX_BLOCK_CONDITION Condition
,
6535 IN OUT PLIST_ENTRY TransitionWaitList
,
6536 IN OUT PRX_CONTEXT RxContext
,
6537 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
6540 NTSTATUS LocalStatus
;
6544 /* Make sure to always get status */
6545 if (AsyncStatus
== NULL
)
6547 AsyncStatus
= &LocalStatus
;
6550 /* By default, it's a success */
6551 *AsyncStatus
= STATUS_SUCCESS
;
6554 /* If it's not stable, we've to wait */
6555 if (!StableCondition(*Condition
))
6557 /* Lock the mutex */
6558 RxAcquireSerializationMutex();
6559 /* Still not stable? */
6560 if (!StableCondition(*Condition
))
6562 /* Insert us in the wait list for processing on stable condition */
6563 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
6565 /* If we're asked to post on stable, don't wait, and just return pending */
6566 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
6568 *AsyncStatus
= STATUS_PENDING
;
6575 RxReleaseSerializationMutex();
6577 /* We don't post on stable, so, just wait... */
6580 RxWaitSync(RxContext
);
6590 RxWorkItemDispatcher(
6593 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
6595 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
6597 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
6599 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
6607 _RxAllocatePoolWithTag(
6608 _In_ POOL_TYPE PoolType
,
6609 _In_ SIZE_T NumberOfBytes
,
6612 return ExAllocatePoolWithTagPriority(PoolType
, NumberOfBytes
, Tag
, LowPoolPriority
);
6623 ExFreePoolWithTag(Buffer
, 0);
6635 ExFreePoolWithTag(Buffer
, Tag
);
6641 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
6643 #ifdef RDBSS_TRACKER
6645 _In_ ULONG LineNumber
,
6646 _In_ PCSTR FileName
,
6647 _In_ ULONG SerialNumber
6652 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
6656 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
6658 SpecialContext
= FALSE
;
6659 ContextIsPresent
= FALSE
;
6660 /* Check for special context */
6661 if ((ULONG_PTR
)RxContext
== -1 || (ULONG_PTR
)RxContext
== -2)
6663 SpecialContext
= TRUE
;
6666 /* We don't handle buffering state change yet... */
6667 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
6668 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
6673 /* Nor special contexts */
6679 /* Nor missing contexts... */
6680 if (RxContext
== NULL
)
6685 /* That said: we have a real context! */
6686 ContextIsPresent
= TRUE
;
6688 /* If we've been cancelled in between, give up */
6689 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
6690 if (!NT_SUCCESS(Status
))
6696 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
6700 /* Assume we cannot lock */
6701 Status
= STATUS_LOCK_NOT_GRANTED
;
6703 /* Lock according to what the caller asked */
6706 case FCB_MODE_EXCLUSIVE
:
6707 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
6710 case FCB_MODE_SHARED
:
6711 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
6714 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
6715 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
6719 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
6720 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
6727 Status
= STATUS_SUCCESS
;
6728 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
6730 /* Handle paging write - not implemented */
6731 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
6737 /* And break, that cool! */
6743 /* If it failed, return immediately */
6744 if (!NT_SUCCESS(Status
))
6750 /* If we don't have to check for valid operation, job done, nothing more to do */
6751 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
6753 if (NT_SUCCESS(Status
))
6755 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
6761 /* Verify operation */
6764 RxVerifyOperationIsLegal(RxContext
);
6768 /* If it failed, release lock and fail */
6769 if (_SEH2_AbnormalTermination())
6771 ExReleaseResourceLite(Fcb
->Header
.Resource
);
6772 Status
= STATUS_LOCK_NOT_GRANTED
;
6777 if (NT_SUCCESS(Status
))
6779 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
6782 DPRINT("Status: %x\n", Status
);
6790 __RxItsTheSameContext(
6791 _In_ PRX_CONTEXT RxContext
,
6792 _In_ ULONG CapturedRxContextSerialNumber
,
6796 /* Check we have a context with the same serial number */
6797 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
6798 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
6801 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
6807 _Inout_opt_ PRX_CONTEXT RxContext
,
6808 _Inout_ PMRX_FCB MrxFcb
6809 #ifdef RDBSS_TRACKER
6811 _In_ ULONG LineNumber
,
6812 _In_ PCSTR FileName
,
6813 _In_ ULONG SerialNumber
6817 BOOLEAN IsExclusive
, BufferingPending
;
6819 RxAcquireSerializationMutex();
6821 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
6822 IsExclusive
= BooleanFlagOn(MrxFcb
->Header
.Resource
->Flag
, ResourceOwnedExclusive
);
6824 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
6825 * then just release the FCB
6827 if (!BufferingPending
|| !IsExclusive
)
6829 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
6830 LineNumber
, FileName
, SerialNumber
);
6831 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
6834 RxReleaseSerializationMutex();
6836 /* And finally leave */
6837 if (!BufferingPending
|| !IsExclusive
)
6842 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
6844 /* Otherwise, handle buffering state and release */
6845 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
6847 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
6848 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
6852 __RxReleaseFcbForThread(
6853 _Inout_opt_ PRX_CONTEXT RxContext
,
6854 _Inout_ PMRX_FCB MrxFcb
,
6855 _In_ ERESOURCE_THREAD ResourceThreadId
6856 #ifdef RDBSS_TRACKER
6858 _In_ ULONG LineNumber
,
6859 _In_ PCSTR FileName
,
6860 _In_ ULONG SerialNumber
6864 BOOLEAN IsExclusive
, BufferingPending
;
6866 RxAcquireSerializationMutex();
6868 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
6869 IsExclusive
= BooleanFlagOn(MrxFcb
->Header
.Resource
->Flag
, ResourceOwnedExclusive
);
6871 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
6872 * then just release the FCB
6874 if (!BufferingPending
|| !IsExclusive
)
6876 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
6877 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
6878 LineNumber
, FileName
, SerialNumber
);
6879 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
6882 RxReleaseSerializationMutex();
6884 /* And finally leave */
6885 if (!BufferingPending
|| !IsExclusive
)
6890 /* Otherwise, handle buffering state and release */
6891 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
6892 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
6893 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);