3 * Copyright (C) 2017 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rxce/rxce.c
23 * PURPOSE: RXCE library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
);
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown
);
54 RxFinishSrvCallConstructionDispatcher(
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
60 WORK_QUEUE_TYPE WorkQueueType
,
61 PRX_WORK_DISPATCH_ITEM DispatchItem
);
65 PRX_CONTEXT RxContext
);
74 _RxAllocatePoolWithTag(
75 _In_ POOL_TYPE PoolType
,
76 _In_ SIZE_T NumberOfBytes
,
90 extern ULONG ReadAheadGranularity
;
92 volatile LONG RxNumberOfActiveFcbs
= 0;
93 ULONG SerialNumber
= 1;
95 volatile ULONG RxContextSerialNumberCounter
;
96 BOOLEAN RxStopOnLoudCompletion
= TRUE
;
97 BOOLEAN RxSrvCallConstructionDispatcherActive
= FALSE
;
98 LIST_ENTRY RxSrvCalldownList
;
99 RX_SPIN_LOCK RxStrucSupSpinLock
;
100 ULONG RdbssReferenceTracingValue
;
101 LARGE_INTEGER RxWorkQueueWaitInterval
[RxMaximumWorkQueue
];
102 LARGE_INTEGER RxSpinUpDispatcherWaitInterval
;
103 RX_DISPATCHER RxDispatcher
;
104 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues
;
105 FAST_MUTEX RxLowIoPagingIoSyncMutex
;
106 BOOLEAN RxContinueFromAssert
= TRUE
;
107 ULONG RxExplodePoolTags
= 1;
109 BOOLEAN DumpDispatchRoutine
= TRUE
;
111 BOOLEAN DumpDispatchRoutine
= FALSE
;
119 #define ASSERT(exp) \
122 RxAssert(#exp, __FILE__, __LINE__, NULL); \
127 #undef RxAllocatePool
128 #undef RxAllocatePoolWithTag
131 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
132 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
133 #define RxFreePool _RxFreePool
134 #define RxFreePoolWithTag _RxFreePoolWithTag
137 /* FUNCTIONS ****************************************************************/
143 RxAddVirtualNetRootToNetRoot(
145 PV_NET_ROOT VNetRoot
)
149 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
151 /* Insert in the VNetRoot list - make sure lock is held */
152 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
154 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
155 ++NetRoot
->NumberOfVirtualNetRoots
;
156 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
164 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
165 NODE_TYPE_CODE NodeType
,
168 PVOID AlreadyAllocatedObject
)
173 PVOID Buffer
, PAPNBuffer
;
174 PNON_PAGED_FCB NonPagedFcb
;
175 PMINIRDR_DISPATCH Dispatch
;
176 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
180 Dispatch
= RxDeviceObject
->Dispatch
;
193 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
194 if (NodeType
== RDBSS_NTC_FOBX
)
196 FobxSize
= sizeof(FOBX
);
197 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
199 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
202 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
203 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
205 SrvOpenSize
= sizeof(SRV_OPEN
);
206 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
208 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
211 FobxSize
= sizeof(FOBX
);
212 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
214 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
217 /* Otherwise, we're asked to allocate a FCB */
220 /* So, allocate the FCB and its extension if asked */
221 FcbSize
= sizeof(FCB
);
222 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
224 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
227 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
228 * Otherwise, it will be allocated later on, specifically
230 if (PoolType
== NonPagedPool
)
232 NonPagedSize
= sizeof(NON_PAGED_FCB
);
235 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
236 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
238 SrvOpenSize
= sizeof(SRV_OPEN
);
239 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
241 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
244 FobxSize
= sizeof(FOBX
);
245 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
247 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
252 /* If we already have a buffer, go ahead */
253 if (AlreadyAllocatedObject
!= NULL
)
255 Buffer
= AlreadyAllocatedObject
;
257 /* Otherwise, allocate it */
260 Buffer
= RxAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
267 /* Now, get the pointers - FOBX is easy */
268 if (NodeType
== RDBSS_NTC_FOBX
)
272 /* SRV_OPEN first, FOBX next */
273 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
276 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
278 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
284 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
286 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
288 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
289 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
292 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
293 if (PoolType
!= NonPagedPool
)
295 NonPagedFcb
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
296 if (NonPagedFcb
== NULL
)
298 RxFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
302 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
304 /* Otherwise, just point at the right place in what has been allocated previously */
307 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
308 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
312 /* If we have allocated a SRV_OPEN, initialize it */
315 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
317 if (NodeType
== RDBSS_NTC_SRVOPEN
)
319 SrvOpen
->InternalFobx
= Fobx
;
323 SrvOpen
->InternalFobx
= NULL
;
324 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
327 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
329 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
332 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
335 /* If we have allocated a FOBX, initialize it */
338 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
340 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
342 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
346 /* If we have allocated a FCB, initialize it */
349 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
351 Fcb
->NonPaged
= NonPagedFcb
;
352 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
353 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
354 NonPagedFcb
->FcbBackPointer
= Fcb
;
356 Fcb
->InternalSrvOpen
= SrvOpen
;
357 Fcb
->InternalFobx
= Fobx
;
359 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
360 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
361 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
363 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
365 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
368 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
370 InterlockedIncrement(&RxNumberOfActiveFcbs
);
371 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
373 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
374 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
385 NODE_TYPE_CODE NodeType
,
386 PMINIRDR_DISPATCH MRxDispatch
,
389 ULONG Tag
, ObjectSize
;
390 PVOID Object
, *Extension
;
391 PRX_PREFIX_ENTRY PrefixEntry
;
392 USHORT StructSize
, ExtensionSize
;
396 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
400 case RDBSS_NTC_SRVCALL
:
401 Tag
= RX_SRVCALL_POOLTAG
;
402 StructSize
= sizeof(SRV_CALL
);
403 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
405 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
409 case RDBSS_NTC_NETROOT
:
410 Tag
= RX_NETROOT_POOLTAG
;
411 StructSize
= sizeof(NET_ROOT
);
412 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
414 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
418 case RDBSS_NTC_V_NETROOT
:
419 Tag
= RX_V_NETROOT_POOLTAG
;
420 StructSize
= sizeof(V_NET_ROOT
);
421 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
423 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
432 /* Now, allocate the object */
433 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
434 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
440 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
442 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
445 case RDBSS_NTC_SRVCALL
:
446 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
447 Extension
= &((PSRV_CALL
)Object
)->Context
;
448 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
451 case RDBSS_NTC_NETROOT
:
452 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
453 Extension
= &((PNET_ROOT
)Object
)->Context
;
454 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
457 case RDBSS_NTC_V_NETROOT
:
458 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
459 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
467 /* Set the prefix table unicode string */
468 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
469 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
470 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
471 PrefixEntry
->Prefix
.Length
= NameLength
;
472 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
473 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
475 /* Return the extension if we are asked to manage it */
476 if (ExtensionSize
!= 0)
478 *Extension
= Add2Ptr(Object
, StructSize
);
497 /* If we're not asked to continue, just stop the system */
498 if (!RxContinueFromAssert
)
500 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
503 /* Otherwise, capture context to offer the user to dump it */
504 RtlCaptureContext(&Context
);
506 /* Loop until the user hits 'i' */
509 /* If no file provided, use empty name */
515 /* If no message provided, use empty one */
521 /* Display the message */
522 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
523 /* And ask the user */
524 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
525 /* If he asks for ignore, quit
526 * In case of invalid input, ask again
528 if (Response
[0] != 'B' && Response
[0] != 'b')
530 if (Response
[0] == 'I' || Response
[0] == 'i')
538 /* Break: offer the user to dump the context and break */
539 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
542 /* Continue looping, so that after dump, execution can continue (with ignore) */
551 RxBootstrapWorkerThreadDispatcher(
554 PRX_WORK_QUEUE RxWorkQueue
;
558 RxWorkQueue
= WorkQueue
;
559 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
563 RxCheckVNetRootCredentials(
564 PRX_CONTEXT RxContext
,
565 PV_NET_ROOT VNetRoot
,
567 PUNICODE_STRING UserName
,
568 PUNICODE_STRING UserDomain
,
569 PUNICODE_STRING Password
,
574 /* If that's a UNC name, there's nothing to process */
575 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
576 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
579 return STATUS_MORE_PROCESSING_REQUIRED
;
582 /* Compare the logon ID in the VNetRoot with the one provided */
583 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
585 return STATUS_MORE_PROCESSING_REQUIRED
;
588 /* No credential provided? That's OK */
589 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
591 return STATUS_SUCCESS
;
596 return STATUS_NOT_IMPLEMENTED
;
608 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
610 ASSERT(Context
!= NULL
);
611 ASSERT(Context
->CurrentIrp
!= NULL
);
612 Irp
= Context
->CurrentIrp
;
614 /* Debug what the caller asks for */
615 if (Context
->LoudCompletionString
!= NULL
)
617 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
618 /* Does the user asks to stop on failed completion */
619 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
621 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
625 /* Complete for real */
626 Context
->CurrentIrp
= NULL
;
627 RxCompleteRequest_Real(Context
, Irp
, Status
);
629 DPRINT("Status: %lx\n", Status
);
637 RxCompleteRequest_Real(
638 IN PRX_CONTEXT RxContext
,
644 PIO_STACK_LOCATION Stack
;
646 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
648 /* Nothing to complete, just free context */
651 DPRINT("NULL IRP for %p\n", RxContext
);
652 if (RxContext
!= NULL
)
654 RxDereferenceAndDeleteRxContext_Real(RxContext
);
660 /* Remove cancel routine */
661 IoAcquireCancelSpinLock(&OldIrql
);
662 IoSetCancelRoutine(Irp
, NULL
);
663 IoReleaseCancelSpinLock(OldIrql
);
665 /* Select the boost, given the success/paging operation */
666 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
668 Boost
= IO_DISK_INCREMENT
;
672 Irp
->IoStatus
.Information
= 0;
673 Boost
= IO_NO_INCREMENT
;
675 Irp
->IoStatus
.Status
= Status
;
677 if (RxContext
!= NULL
)
679 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
680 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
682 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
683 RxContext
->MinorFunction
, RxContext
, Irp
,
684 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
688 /* If that's an opening, there might be a canonical name allocated,
689 * if completion isn't pending, release it
691 Stack
= IoGetCurrentIrpStackLocation(Irp
);
692 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
695 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
697 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
700 RxpPrepareCreateContextForReuse(RxContext
);
701 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
704 /* If it's a write, validate the correct behavior of the operation */
705 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
707 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
709 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
713 /* If it's pending, make sure IRP is marked as such */
714 if (RxContext
!= NULL
)
716 if (RxContext
->PendingReturned
)
718 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
723 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
724 IoCompleteRequest(Irp
, Boost
);
726 /* If there's a context, dereference it */
727 if (RxContext
!= NULL
)
729 RxDereferenceAndDeleteRxContext_Real(RxContext
);
734 RxCompleteSrvOpenKeyAssociation(
735 IN OUT PSRV_OPEN SrvOpen
)
745 IN PRX_CONTEXT RxContext
,
746 IN PSRV_CALL SrvCall
,
747 IN PNET_ROOT NetRoot
,
748 IN PV_NET_ROOT VirtualNetRoot
,
749 OUT PLOCK_HOLDING_STATE LockHoldingState
)
752 PRX_PREFIX_TABLE PrefixTable
;
753 PMRX_CREATENETROOT_CONTEXT Context
;
754 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
758 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
759 VirtualNetRoot
, LockHoldingState
);
761 /* Validate the lock is exclusively held */
762 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
763 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
765 /* Allocate the context */
766 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
769 return STATUS_INSUFFICIENT_RESOURCES
;
772 /* We can release lock now */
773 RxReleasePrefixTableLock(PrefixTable
);
774 *LockHoldingState
= LHS_LockNotHeld
;
776 RootCondition
= Condition_Bad
;
777 VRootCondition
= Condition_Bad
;
779 /* Initialize the context */
780 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
781 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
782 Context
->RxContext
= RxContext
;
783 Context
->pVNetRoot
= VirtualNetRoot
;
784 Context
->Callback
= RxCreateNetRootCallBack
;
786 /* And call the mini-rdr */
787 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
788 if (Status
== STATUS_PENDING
)
790 /* Wait for the mini-rdr to be done */
791 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
792 /* Update the structures condition according to mini-rdr return */
793 if (NT_SUCCESS(Context
->NetRootStatus
))
795 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
797 RootCondition
= Condition_Good
;
798 VRootCondition
= Condition_Good
;
799 Status
= STATUS_SUCCESS
;
803 RootCondition
= Condition_Good
;
804 Status
= Context
->VirtualNetRootStatus
;
809 Status
= Context
->VirtualNetRootStatus
;
810 if (NT_SUCCESS(Status
))
812 Status
= Context
->NetRootStatus
;
818 /* It has to return STATUS_PENDING! */
822 /* Acquire lock again - for caller lock status will remain unchanged */
823 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
824 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
825 *LockHoldingState
= LHS_ExclusiveLockHeld
;
827 /* Do the transition to the condition got from mini-rdr */
828 RxTransitionNetRoot(NetRoot
, RootCondition
);
829 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
831 /* Context is not longer needed */
832 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
834 DPRINT("Status: %x\n", Status
);
844 IN PRX_CONTEXT RxContext
,
845 IN PSRV_CALL SrvCall
,
846 OUT PLOCK_HOLDING_STATE LockHoldingState
)
849 PRX_PREFIX_TABLE PrefixTable
;
850 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
851 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
852 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
856 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
858 /* Validate the lock is exclusively held */
859 RxDeviceObject
= RxContext
->RxDeviceObject
;
860 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
861 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
863 /* Allocate the context for mini-rdr */
864 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
865 if (Calldown
== NULL
)
867 SrvCall
->Context
= NULL
;
868 SrvCall
->Condition
= Condition_Bad
;
869 RxReleasePrefixTableLock(PrefixTable
);
870 *LockHoldingState
= LHS_LockNotHeld
;
871 return STATUS_INSUFFICIENT_RESOURCES
;
875 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
877 SrvCall
->Context
= NULL
;
878 SrvCall
->Condition
= Condition_InTransition
;
880 RxReleasePrefixTableLock(PrefixTable
);
881 *LockHoldingState
= LHS_LockNotHeld
;
883 CallbackContext
= &Calldown
->CallbackContexts
[0];
884 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
885 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
886 CallbackContext
->SrvCalldownStructure
= Calldown
;
887 CallbackContext
->CallbackContextOrdinal
= 0;
888 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
890 RxReferenceSrvCall(SrvCall
);
892 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
893 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
895 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
899 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
902 Calldown
->NumberToWait
= 1;
903 Calldown
->NumberRemaining
= 1;
904 Calldown
->RxContext
= RxContext
;
905 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
906 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
907 Calldown
->BestFinisher
= NULL
;
908 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
909 InitializeListHead(&Calldown
->SrvCalldownList
);
911 /* Call the mini-rdr */
912 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
913 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
914 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
915 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
916 /* It has to return STATUS_PENDING! */
917 ASSERT(Status
== STATUS_PENDING
);
919 /* No async, start completion */
920 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
922 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
924 /* Finish construction - we'll notify mini-rdr it's the winner */
925 Status
= RxFinishSrvCallConstruction(Calldown
);
926 if (!NT_SUCCESS(Status
))
928 RxReleasePrefixTableLock(PrefixTable
);
929 *LockHoldingState
= LHS_LockNotHeld
;
933 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
934 *LockHoldingState
= LHS_ExclusiveLockHeld
;
938 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
946 RxConstructVirtualNetRoot(
947 IN PRX_CONTEXT RxContext
,
948 IN PUNICODE_STRING CanonicalName
,
949 IN NET_ROOT_TYPE NetRootType
,
950 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
951 OUT PLOCK_HOLDING_STATE LockHoldingState
,
952 OUT PRX_CONNECTION_ID RxConnectionId
)
955 PV_NET_ROOT VNetRoot
;
956 RX_BLOCK_CONDITION Condition
;
957 UNICODE_STRING LocalNetRootName
, FilePathName
;
961 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
964 Condition
= Condition_Bad
;
965 /* Before creating the VNetRoot, try to find the appropriate connection */
966 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
967 &LocalNetRootName
, &FilePathName
,
968 LockHoldingState
, RxConnectionId
);
969 /* Found and active */
970 if (Status
== STATUS_CONNECTION_ACTIVE
)
972 /* We need a new VNetRoot */
973 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
974 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
975 if (VNetRoot
!= NULL
)
977 RxReferenceVNetRoot(VNetRoot
);
980 /* Dereference previous VNetRoot */
981 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
982 /* Reset and start construct (new structures will replace old ones) */
983 RxContext
->Create
.pSrvCall
= NULL
;
984 RxContext
->Create
.pNetRoot
= NULL
;
985 RxContext
->Create
.pVNetRoot
= NULL
;
987 /* Construct new NetRoot */
988 if (VNetRoot
!= NULL
)
990 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
991 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
992 if (NT_SUCCESS(Status
))
994 Condition
= Condition_Good
;
999 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1004 /* If it failed creating the connection, leave */
1005 if (Status
!= STATUS_SUCCESS
)
1007 if (*LockHoldingState
!= LHS_LockNotHeld
)
1009 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1010 *LockHoldingState
= LHS_LockNotHeld
;
1013 *VirtualNetRootPointer
= VNetRoot
;
1014 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1018 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1020 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1021 Condition
= Condition_Good
;
1024 /* We have a non stable VNetRoot - transition it */
1025 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1027 RxTransitionVNetRoot(VNetRoot
, Condition
);
1030 /* If recreation failed */
1031 if (Status
!= STATUS_SUCCESS
)
1033 /* Dereference potential VNetRoot */
1034 if (VNetRoot
!= NULL
)
1036 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1037 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1042 if (*LockHoldingState
!= LHS_LockNotHeld
)
1044 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1045 *LockHoldingState
= LHS_LockNotHeld
;
1049 *VirtualNetRootPointer
= VNetRoot
;
1053 /* Return the allocated VNetRoot */
1054 *VirtualNetRootPointer
= VNetRoot
;
1063 IN PRX_CONTEXT RxContext
,
1064 IN PV_NET_ROOT VNetRoot
,
1065 IN PUNICODE_STRING Name
)
1071 NODE_TYPE_CODE NodeType
;
1072 PIO_STACK_LOCATION Stack
;
1073 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1077 /* We need a decent VNetRoot */
1078 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1080 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1081 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1082 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1084 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1085 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1087 Stack
= RxContext
->CurrentIrpSp
;
1089 /* Do we need to create a fake FCB? Like for renaming */
1090 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1091 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1092 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1094 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1095 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1097 /* Allocate the FCB */
1098 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1099 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1105 /* Initialize the FCB */
1106 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1107 Fcb
->RxDeviceObject
= RxDeviceObject
;
1108 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1109 Fcb
->VNetRoot
= VNetRoot
;
1110 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1112 InitializeListHead(&Fcb
->SrvOpenList
);
1113 Fcb
->SrvOpenListVersion
= 0;
1115 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1116 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1117 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1118 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1119 NetRoot
->InnerNamePrefix
.Length
);
1120 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1122 /* Copy back parameters from RxContext */
1123 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1125 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1128 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1130 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1132 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1135 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1137 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1140 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1141 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1143 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1144 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1146 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1147 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1149 /* Fake FCB doesn't go in prefix table */
1152 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1153 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1154 DPRINT("Fake FCB: %p\n", Fcb
);
1158 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1161 RxReferenceVNetRoot(VNetRoot
);
1162 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1164 Fcb
->ulFileSizeVersion
= 0;
1166 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1167 RxReferenceNetFcb(Fcb
);
1178 OUT PRX_CONTEXT RxContext
,
1179 IN PMRX_SRV_OPEN MrxSrvOpen
)
1190 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1191 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1192 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1193 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1196 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1197 /* Can we use pre-allocated FOBX? */
1198 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1200 Fobx
= Fcb
->InternalFobx
;
1201 /* Call allocate to initialize the FOBX */
1202 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1203 /* Mark it used now */
1204 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1205 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1207 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1209 Fobx
= SrvOpen
->InternalFobx
;
1210 /* Call allocate to initialize the FOBX */
1211 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1212 /* Mark it used now */
1213 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1214 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1218 /* Last case, we cannot, allocate a FOBX */
1219 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1223 /* Allocation failed! */
1230 Fobx
->Flags
= Flags
;
1232 /* Initialize throttling */
1233 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1234 if (NetRoot
!= NULL
)
1236 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1238 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1239 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1240 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1242 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1244 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1245 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1246 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1250 /* Propagate flags fron RxContext */
1251 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1253 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1256 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1258 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1262 Fobx
->FobxSerialNumber
= 0;
1263 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1264 Fobx
->NodeReferenceCount
= 1;
1265 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1267 RxReferenceSrvOpen(SrvOpen
);
1268 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1270 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1271 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1272 InitializeListHead(&Fobx
->ClosePendingList
);
1274 Fobx
->CloseTime
.QuadPart
= 0;
1275 Fobx
->fOpenCountDecremented
= FALSE
;
1277 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1279 return (PMRX_FOBX
)Fobx
;
1287 IN PSRV_CALL SrvCall
,
1288 IN PUNICODE_STRING Name
,
1289 IN ULONG NetRootFlags
,
1290 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1293 USHORT CaseInsensitiveLength
;
1294 PRX_PREFIX_TABLE PrefixTable
;
1296 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1300 /* We need a SRV_CALL */
1301 ASSERT(SrvCall
!= NULL
);
1303 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1304 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1306 /* Get name length */
1307 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1308 if (CaseInsensitiveLength
> MAXUSHORT
)
1313 /* Allocate the NetRoot */
1314 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1315 CaseInsensitiveLength
);
1316 if (NetRoot
== NULL
)
1321 /* Construct name */
1322 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1323 Name
->Buffer
, Name
->Length
);
1324 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1326 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1327 SrvCall
->PrefixEntry
.Prefix
.Length
);
1330 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1332 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1334 /* Inisert in prefix table */
1335 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1336 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1339 /* Prepare the FCB table */
1340 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1342 InitializeListHead(&NetRoot
->TransitionWaitList
);
1343 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1344 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1346 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1348 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1349 NetRoot
->Flags
|= NetRootFlags
;
1350 NetRoot
->DiskParameters
.ClusterSize
= 1;
1351 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1352 NetRoot
->SrvCall
= SrvCall
;
1354 RxReferenceSrvCall(SrvCall
);
1356 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1365 RxCreateNetRootCallBack(
1366 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1370 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1380 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1381 IN ULONG InitialContextFlags
)
1384 PRX_CONTEXT Context
;
1386 ASSERT(RxDeviceObject
!= NULL
);
1388 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1390 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1391 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1393 /* Allocate the context from our lookaside list */
1394 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1395 if (Context
== NULL
)
1400 /* And initialize it */
1401 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1402 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1403 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1405 /* Add it to our global list */
1406 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1407 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1408 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1410 DPRINT("Context: %p\n", Context
);
1419 IN PRX_CONTEXT RxContext
,
1420 IN PUNICODE_STRING Name
,
1421 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1422 IN PRX_CONNECTION_ID RxConnectionId
)
1429 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1431 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1433 /* Get the name length */
1434 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1435 if (InnerNamePrefix
!= NULL
)
1437 NameLength
+= InnerNamePrefix
->Length
;
1440 /* Allocate the object */
1441 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1442 if (SrvCall
== NULL
)
1448 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1449 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1450 RxInitializeBufferingManager(SrvCall
);
1451 InitializeListHead(&SrvCall
->TransitionWaitList
);
1452 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1453 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1454 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1455 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1456 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1457 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1458 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1459 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1461 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1470 RxCreateSrvCallCallBack(
1471 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1475 PRX_CONTEXT RxContext
;
1476 ULONG NumberRemaining
;
1477 BOOLEAN StartDispatcher
;
1478 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1480 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1482 /* Get our context structures */
1483 Calldown
= Context
->SrvCalldownStructure
;
1484 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1486 /* If it is a success, that's the winner */
1487 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1488 if (Context
->Status
== STATUS_SUCCESS
)
1490 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1491 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1493 NumberRemaining
= --Calldown
->NumberRemaining
;
1494 SrvCall
->Status
= Context
->Status
;
1495 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1497 /* Still some to ask, keep going */
1498 if (NumberRemaining
!= 0)
1503 /* If that's not async, signal we're done */
1504 RxContext
= Calldown
->RxContext
;
1505 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1507 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1510 /* If that's a mailslot, finish construction, no more to do */
1511 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1513 RxFinishSrvCallConstruction(Calldown
);
1517 /* Queue our finish call for delayed completion */
1518 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1519 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1520 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1521 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1522 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1524 /* If we have to start dispatcher, go ahead */
1525 if (StartDispatcher
)
1529 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1530 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1531 if (!NT_SUCCESS(Status
))
1533 /* It failed - run it manually.... */
1534 RxFinishSrvCallConstructionDispatcher(NULL
);
1544 IN PV_NET_ROOT VNetRoot
,
1553 ASSERT(NodeTypeIsFcb(Fcb
));
1554 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1556 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1560 SrvOpen
= Fcb
->InternalSrvOpen
;
1561 /* Check whethet we have to allocate a new SRV_OPEN */
1562 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1563 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1564 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1567 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1568 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1573 /* Otherwise, just use internal one and initialize it */
1574 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1575 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1576 Fcb
->InternalSrvOpen
);
1577 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1578 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1581 /* If SrvOpen was properly allocated, initialize it */
1582 if (SrvOpen
!= NULL
)
1584 SrvOpen
->Flags
= Flags
;
1585 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1586 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1587 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1588 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1589 SrvOpen
->NodeReferenceCount
= 1;
1591 RxReferenceVNetRoot(VNetRoot
);
1592 RxReferenceNetFcb(Fcb
);
1594 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1595 ++Fcb
->SrvOpenListVersion
;
1597 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1598 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1599 InitializeListHead(&SrvOpen
->FobxList
);
1600 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1605 if (_SEH2_AbnormalTermination())
1607 if (SrvOpen
!= NULL
)
1609 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1615 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1628 IN PRX_CONTEXT RxContext
,
1629 IN PNET_ROOT NetRoot
,
1630 IN PUNICODE_STRING CanonicalName
,
1631 IN PUNICODE_STRING LocalNetRootName
,
1632 IN PUNICODE_STRING FilePath
,
1633 IN PRX_CONNECTION_ID RxConnectionId
)
1636 PV_NET_ROOT VNetRoot
;
1637 USHORT CaseInsensitiveLength
;
1641 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
1642 LocalNetRootName
, FilePath
, RxConnectionId
);
1644 /* Lock must be held exclusively */
1645 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1647 /* Check for overflow */
1648 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
1653 /* Get name length and allocate VNetRoot */
1654 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1655 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
1656 CaseInsensitiveLength
);
1657 if (VNetRoot
== NULL
)
1662 /* Initialize its connection parameters */
1663 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
1664 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
1665 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1666 if (!NT_SUCCESS(Status
))
1668 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
1669 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1670 RxFreeObject(VNetRoot
);
1676 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
1678 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1679 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
1680 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1681 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1683 InitializeListHead(&VNetRoot
->TransitionWaitList
);
1684 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
1686 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
1690 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1692 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
1696 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1699 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
1701 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
1707 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
1710 /* Insert in prefix table */
1711 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
1712 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1715 RxReferenceNetRoot(NetRoot
);
1716 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
1719 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
1720 VNetRoot
->UpperFinalizationDone
= FALSE
;
1721 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
1722 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
1724 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
1725 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
1732 IN OUT PVOID Instance
,
1733 IN LOCK_HOLDING_STATE LockHoldingState
)
1736 NODE_TYPE_CODE NodeType
;
1737 PNODE_TYPE_AND_SIZE Node
;
1741 RxAcquireScavengerMutex();
1743 /* Check we have a node we can handle */
1744 NodeType
= NodeType(Instance
);
1745 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
1746 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
1747 (NodeType
== RDBSS_NTC_FOBX
));
1749 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
1750 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
1751 ASSERT(RefCount
>= 0);
1753 /* Trace refcount */
1756 case RDBSS_NTC_SRVCALL
:
1757 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
1760 case RDBSS_NTC_NETROOT
:
1761 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
1764 case RDBSS_NTC_V_NETROOT
:
1765 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
1768 case RDBSS_NTC_SRVOPEN
:
1769 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
1772 case RDBSS_NTC_FOBX
:
1773 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
1781 /* No need to free - still in use */
1784 RxReleaseScavengerMutex();
1788 /* We have to be locked exclusively */
1789 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
1792 RxReleaseScavengerMutex();
1796 RxReleaseScavengerMutex();
1798 /* TODO: Really deallocate stuff - we're leaking as hell! */
1801 case RDBSS_NTC_SRVCALL
:
1805 SrvCall
= (PSRV_CALL
)Instance
;
1807 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
1808 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
1809 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
1813 case RDBSS_NTC_NETROOT
:
1817 case RDBSS_NTC_V_NETROOT
:
1821 case RDBSS_NTC_SRVOPEN
:
1825 case RDBSS_NTC_FOBX
:
1836 RxDereferenceAndDeleteRxContext_Real(
1837 IN PRX_CONTEXT RxContext
)
1842 PRX_CONTEXT StopContext
= NULL
;
1844 /* Make sure we really have a context */
1845 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1846 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
1847 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
1848 /* If refcount is 0, start releasing stuff that needs spinlock held */
1851 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1853 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
1855 /* If that's stop context from DO, remove it */
1856 RxDeviceObject
= RxContext
->RxDeviceObject
;
1857 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
1859 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
1863 /* Remove it from the list */
1864 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
1865 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
1866 RemoveEntryList(&RxContext
->ContextListEntry
);
1868 /* If that was the last active context, save the stop context */
1869 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
1871 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
1873 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
1878 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1880 /* Now, deal with what can be done without spinlock held */
1883 /* Refcount shouldn't have changed */
1884 ASSERT(RxContext
->ReferenceCount
== 0);
1885 /* Reset everything that can be */
1886 RxPrepareContextForReuse(RxContext
);
1888 #ifdef RDBSS_TRACKER
1889 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
1891 /* If that was the last active, set the event */
1892 if (StopContext
!= NULL
)
1894 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
1895 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
1898 /* Is ShadowCrit still owned? Shouldn't happen! */
1899 if (RxContext
->ShadowCritOwner
!= 0)
1901 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
1905 /* If it was allocated, free it */
1908 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
1918 RxDispatchToWorkerThread(
1919 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
1920 IN WORK_QUEUE_TYPE WorkQueueType
,
1921 IN PRX_WORKERTHREAD_ROUTINE Routine
,
1925 PRX_WORK_DISPATCH_ITEM DispatchItem
;
1927 /* Allocate a bit of context */
1928 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
1929 if (DispatchItem
== NULL
)
1931 return STATUS_INSUFFICIENT_RESOURCES
;
1934 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
1935 DispatchItem
->DispatchRoutine
= Routine
;
1936 DispatchItem
->DispatchRoutineParameter
= pContext
;
1937 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
1938 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
1941 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, DispatchItem
);
1942 if (!NT_SUCCESS(Status
))
1944 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
1945 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
1948 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
1957 RxExclusivePrefixTableLockToShared(
1958 PRX_PREFIX_TABLE Table
)
1962 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
1969 RxExtractServerName(
1970 IN PUNICODE_STRING FilePathName
,
1971 OUT PUNICODE_STRING SrvCallName
,
1972 OUT PUNICODE_STRING RestOfName
)
1978 ASSERT(SrvCallName
!= NULL
);
1980 /* SrvCall name will start from the begin up to the first separator */
1981 SrvCallName
->Buffer
= FilePathName
->Buffer
;
1982 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
1984 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
1990 /* Compute length */
1991 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
1992 SrvCallName
->MaximumLength
= Length
;
1993 SrvCallName
->Length
= Length
;
1995 /* Return the rest if asked */
1996 if (RestOfName
!= NULL
)
1998 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
1999 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2000 RestOfName
->MaximumLength
= Length
;
2001 RestOfName
->Length
= Length
;
2009 RxFcbTableInsertFcb(
2010 IN OUT PRX_FCB_TABLE FcbTable
,
2015 /* We deal with the table, make sure it's locked */
2016 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2018 /* Compute the hash */
2019 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2021 RxReferenceNetFcb(Fcb
);
2023 /* If no length, it will be our null entry */
2024 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2026 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2028 /* Otherwise, insert in the appropriate bucket */
2031 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2032 &Fcb
->FcbTableEntry
.HashLinks
);
2035 /* Propagate the change by incrementing the version number */
2036 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2038 return STATUS_SUCCESS
;
2045 RxFcbTableLookupFcb(
2046 IN PRX_FCB_TABLE FcbTable
,
2047 IN PUNICODE_STRING Path
)
2050 PRX_FCB_TABLE_ENTRY TableEntry
;
2054 /* No path - easy, that's null entry */
2057 TableEntry
= FcbTable
->TableEntryForNull
;
2062 PLIST_ENTRY HashBucket
, ListEntry
;
2064 /* Otherwise, compute the hash value and find the associated bucket */
2065 Hash
= RxTableComputePathHashValue(Path
);
2066 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2067 /* If the bucket is empty, it means there's no entry yet */
2068 if (IsListEmpty(HashBucket
))
2074 /* Otherwise, browse all the entry */
2075 for (ListEntry
= HashBucket
->Flink
;
2076 ListEntry
!= HashBucket
;
2077 ListEntry
= ListEntry
->Flink
)
2079 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2080 InterlockedIncrement(&FcbTable
->Compares
);
2082 /* If entry hash and string are equal, thatt's the one! */
2083 if (TableEntry
->HashValue
== Hash
&&
2084 TableEntry
->Path
.Length
== Path
->Length
&&
2085 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2091 /* We reached the end? Not found */
2092 if (ListEntry
== HashBucket
)
2099 InterlockedIncrement(&FcbTable
->Lookups
);
2101 /* If table entry isn't null, return the FCB */
2102 if (TableEntry
!= NULL
)
2104 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2105 RxReferenceNetFcb(Fcb
);
2110 InterlockedIncrement(&FcbTable
->FailedLookups
);
2120 RxFcbTableRemoveFcb(
2121 IN OUT PRX_FCB_TABLE FcbTable
,
2126 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2128 /* If no path, then remove entry for null */
2129 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2131 FcbTable
->TableEntryForNull
= NULL
;
2133 /* Otherwise, remove from the bucket */
2136 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2139 /* Reset its list entry */
2140 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2142 /* Propagate the change by incrementing the version number */
2143 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2145 return STATUS_SUCCESS
;
2154 IN BOOLEAN RecursiveFinalize
,
2155 IN BOOLEAN ForceFinalize
,
2156 IN LONG ReferenceCount
)
2160 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2161 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2163 /* Make sure we have an exclusively acquired FCB */
2164 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2165 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2167 /* We shouldn't force finalization... */
2168 ASSERT(!ForceFinalize
);
2170 /* If recurisve, finalize all the associated SRV_OPEN */
2171 if (RecursiveFinalize
)
2173 PLIST_ENTRY ListEntry
;
2175 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2176 ListEntry
!= &ThisFcb
->SrvOpenList
;
2177 ListEntry
= ListEntry
->Flink
)
2181 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2182 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2185 /* If FCB is still in use, that's over */
2188 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2190 ASSERT(ReferenceCount
> 0);
2196 ASSERT(ReferenceCount
>= 1);
2198 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2199 if (ReferenceCount
!= 1 && !ForceFinalize
)
2204 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2206 DPRINT("Finalizing FCB open: %d (%d)", ThisFcb
->OpenCount
, ForceFinalize
);
2208 /* If finalization was not already initiated, go ahead */
2209 if (!ThisFcb
->UpperFinalizationDone
)
2211 /* Free any FCB_LOCK */
2212 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2214 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2216 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2220 Entry
= ThisFcb
->BufferedLocks
.List
;
2221 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2227 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2228 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2232 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2234 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2236 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2238 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2242 ThisFcb
->UpperFinalizationDone
= TRUE
;
2245 ASSERT(ReferenceCount
>= 1);
2247 /* Even if forced, don't allow broken free */
2248 if (ReferenceCount
!= 1)
2253 /* Now, release everything */
2254 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2256 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2259 if (ThisFcb
->MRxDispatch
!= NULL
)
2261 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2264 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2265 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2266 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2268 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2269 RxDereferenceNetRoot(ThisFcb
->pNetRoot
, LHS_LockNotHeld
);
2271 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2272 ASSERT(!ThisFcb
->fMiniInited
);
2274 /* And free the object */
2275 RxFreeFcbObject(ThisFcb
);
2282 OUT PNET_ROOT ThisNetRoot
,
2283 IN BOOLEAN RecursiveFinalize
,
2284 IN BOOLEAN ForceFinalize
2293 OUT PSRV_CALL ThisSrvCall
,
2294 IN BOOLEAN RecursiveFinalize
,
2295 IN BOOLEAN ForceFinalize
)
2303 OUT PSRV_OPEN ThisSrvOpen
,
2304 IN BOOLEAN RecursiveFinalize
,
2305 IN BOOLEAN ForceFinalize
)
2312 RxFindOrConstructVirtualNetRoot(
2313 IN PRX_CONTEXT RxContext
,
2314 IN PUNICODE_STRING CanonicalName
,
2315 IN NET_ROOT_TYPE NetRootType
,
2316 IN PUNICODE_STRING RemainingName
)
2322 PV_NET_ROOT VNetRoot
;
2323 RX_CONNECTION_ID ConnectionID
;
2324 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2325 LOCK_HOLDING_STATE LockHoldingState
;
2329 RxDeviceObject
= RxContext
->RxDeviceObject
;
2330 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
2331 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
2333 /* Ask the mini-rdr for connection ID */
2334 ConnectionID
.SessionID
= 0;
2335 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
2337 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
2338 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
2340 /* mini-rdr is expected not to fail - unless it's not implemented */
2341 DPRINT1("Failed to initialize connection ID\n");
2346 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
2348 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
2349 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
2350 LockHoldingState
= LHS_SharedLockHeld
;
2354 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
2358 PV_NET_ROOT SavedVNetRoot
;
2360 /* Look in prefix table */
2361 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
2362 if (Container
!= NULL
)
2364 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
2365 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
2367 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
2368 RxDereferenceSrvCall(Container
, LockHoldingState
);
2372 VNetRoot
= Container
;
2373 NetRoot
= VNetRoot
->NetRoot
;
2375 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
2376 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
2377 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
2379 Status
= STATUS_BAD_NETWORK_PATH
;
2380 SavedVNetRoot
= NULL
;
2386 PUNICODE_STRING UserName
, UserDomain
, Password
;
2388 /* We can reuse if we use same credentials */
2389 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
2390 &SessionId
, &UserName
,
2391 &UserDomain
, &Password
,
2393 if (NT_SUCCESS(Status
))
2395 SavedVNetRoot
= VNetRoot
;
2396 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
2398 UserDomain
, Password
,
2400 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
2402 PLIST_ENTRY ListEntry
;
2404 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
2405 ListEntry
!= &NetRoot
->VirtualNetRoots
;
2406 ListEntry
= ListEntry
->Flink
)
2408 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
2409 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
2411 UserDomain
, Password
,
2413 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2419 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
2421 SavedVNetRoot
= NULL
;
2425 if (!NT_SUCCESS(Status
))
2427 SavedVNetRoot
= NULL
;
2430 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
2434 /* We'll fail, if we had referenced a VNetRoot, dereference it */
2435 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
2437 if (SavedVNetRoot
== NULL
)
2439 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
2442 /* Reference VNetRoot we'll keep, and dereference current */
2443 else if (SavedVNetRoot
!= VNetRoot
)
2445 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
2446 if (SavedVNetRoot
!= NULL
)
2448 RxReferenceVNetRoot(SavedVNetRoot
);
2453 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
2454 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
2461 /* If we're locked exclusive, we won't loop again, it was the second pass */
2462 if (LockHoldingState
!= LHS_SharedLockHeld
)
2467 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
2468 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
2470 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2471 LockHoldingState
= LHS_ExclusiveLockHeld
;
2475 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2476 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
2477 LockHoldingState
= LHS_ExclusiveLockHeld
;
2480 /* We didn't fail, and didn't find any VNetRoot, construct one */
2483 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
2485 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
2486 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
2488 if (Status
== STATUS_SUCCESS
)
2490 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
2491 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2492 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
2494 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2495 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
2496 RemainingName
->MaximumLength
= RemainingName
->Length
;
2498 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
2500 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
2502 VNetRoot
->Flags
|= Flags
;
2506 /* Release the prefix table - caller expects it to be released */
2507 if (LockHoldingState
!= LHS_LockNotHeld
)
2509 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
2512 /* If we failed creating, quit */
2513 if (Status
!= STATUS_SUCCESS
)
2515 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
2519 /* Otherwise, wait until the VNetRoot is stable */
2520 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
2521 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
2522 /* It's all good, update the RX_CONTEXT with all our structs */
2523 if (VNetRoot
->Condition
== Condition_Good
)
2527 NetRoot
= VNetRoot
->NetRoot
;
2528 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2529 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2530 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
2534 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2535 RxContext
->Create
.pVNetRoot
= NULL
;
2536 Status
= STATUS_BAD_NETWORK_PATH
;
2546 RxFindOrCreateConnections(
2547 _In_ PRX_CONTEXT RxContext
,
2548 _In_ PUNICODE_STRING CanonicalName
,
2549 _In_ NET_ROOT_TYPE NetRootType
,
2550 _Out_ PUNICODE_STRING LocalNetRootName
,
2551 _Out_ PUNICODE_STRING FilePathName
,
2552 _Inout_ PLOCK_HOLDING_STATE LockState
,
2553 _In_ PRX_CONNECTION_ID RxConnectionId
)
2558 PV_NET_ROOT VNetRoot
;
2559 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
2560 PRX_PREFIX_TABLE PrefixTable
;
2561 UNICODE_STRING RemainingName
, NetRootName
;
2565 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
2566 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
2567 FilePathName
, LockState
, RxConnectionId
);
2569 *FilePathName
= *CanonicalName
;
2570 LocalNetRootName
->Length
= 0;
2571 LocalNetRootName
->MaximumLength
= 0;
2572 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
2574 /* UNC path, split it */
2575 if (FilePathName
->Buffer
[1] == ';')
2581 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2583 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2592 return STATUS_OBJECT_NAME_INVALID
;
2595 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
2596 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
2597 LocalNetRootName
->Length
= Length
;
2598 LocalNetRootName
->MaximumLength
= Length
;
2599 FilePathName
->Length
-= Length
;
2601 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
2602 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
2603 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
2607 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
2612 ASSERT(*LockState
!= LHS_LockNotHeld
);
2614 /* If previous lookup left something, dereference it */
2615 if (Container
!= NULL
)
2617 switch (NodeType(Container
))
2619 case RDBSS_NTC_SRVCALL
:
2620 RxDereferenceSrvCall(Container
, *LockState
);
2623 case RDBSS_NTC_NETROOT
:
2624 RxDereferenceNetRoot(Container
, *LockState
);
2627 case RDBSS_NTC_V_NETROOT
:
2628 RxDereferenceVNetRoot(Container
, *LockState
);
2632 /* Should never happen */
2638 /* Look for our NetRoot in prefix table */
2639 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
2640 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
2644 UNICODE_STRING SrvCallName
;
2650 /* Assume we didn't succeed */
2651 RxContext
->Create
.pVNetRoot
= NULL
;
2652 RxContext
->Create
.pNetRoot
= NULL
;
2653 RxContext
->Create
.pSrvCall
= NULL
;
2654 RxContext
->Create
.Type
= NetRootType
;
2656 /* If we found something */
2657 if (Container
!= NULL
)
2660 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
2662 VNetRoot
= Container
;
2663 /* Use its NetRoot */
2664 NetRoot
= VNetRoot
->NetRoot
;
2666 /* If it's not stable, wait for it to be stable */
2667 if (NetRoot
->Condition
== Condition_InTransition
)
2669 RxReleasePrefixTableLock(PrefixTable
);
2670 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
2671 RxWaitForStableNetRoot(NetRoot
, RxContext
);
2672 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2673 *LockState
= LHS_ExclusiveLockHeld
;
2675 /* Now that's it's ok, retry lookup to find what we want */
2676 if (NetRoot
->Condition
== Condition_Good
)
2682 /* Is the associated netroot good? */
2683 if (NetRoot
->Condition
== Condition_Good
)
2685 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
2687 /* If it is, and SrvCall as well, then, we have our active connection */
2688 if (SrvCall
->Condition
== Condition_Good
&&
2689 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
2691 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2692 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2693 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
2695 Status
= STATUS_CONNECTION_ACTIVE
;
2700 /* If VNetRoot was well constructed, it means the connection is active */
2701 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
2703 Status
= STATUS_CONNECTION_ACTIVE
;
2707 Status
= VNetRoot
->ConstructionStatus
;
2710 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
2713 /* Can only be a SrvCall */
2716 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
2717 SrvCall
= Container
;
2719 /* Wait for the SRV_CALL to be stable */
2720 if (SrvCall
->Condition
== Condition_InTransition
)
2722 RxReleasePrefixTableLock(PrefixTable
);
2723 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
2724 RxWaitForStableSrvCall(SrvCall
, RxContext
);
2725 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2726 *LockState
= LHS_ExclusiveLockHeld
;
2728 /* It went good, loop again to find what we look for */
2729 if (SrvCall
->Condition
== Condition_Good
)
2735 /* If it's not good... */
2736 if (SrvCall
->Condition
!= Condition_Good
)
2738 /* But SRV_CALL was well constructed, assume a connection was active */
2739 if (SrvCall
->Status
== STATUS_SUCCESS
)
2741 Status
= STATUS_CONNECTION_ACTIVE
;
2745 Status
= SrvCall
->Status
;
2748 RxDereferenceSrvCall(SrvCall
, *LockState
);
2754 /* If we found a SRV_CALL not matching our DO, quit */
2755 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
2756 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
2758 RxDereferenceSrvCall(SrvCall
, *LockState
);
2759 Status
= STATUS_BAD_NETWORK_NAME
;
2763 /* Now, we want exclusive lock */
2764 if (*LockState
== LHS_SharedLockHeld
)
2766 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
2768 RxReleasePrefixTableLock(PrefixTable
);
2769 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2770 *LockState
= LHS_ExclusiveLockHeld
;
2774 RxReleasePrefixTableLock(PrefixTable
);
2775 *LockState
= LHS_ExclusiveLockHeld
;
2778 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
2780 /* If we reach that point, we found something, no need to create something */
2781 if (Container
!= NULL
)
2786 /* Get the name for the SRV_CALL */
2787 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
2788 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
2789 /* And create the SRV_CALL */
2790 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
2791 if (SrvCall
== NULL
)
2793 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2797 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
2798 RxReferenceSrvCall(SrvCall
);
2799 RxContext
->Create
.pVNetRoot
= NULL
;
2800 RxContext
->Create
.pNetRoot
= NULL
;
2801 RxContext
->Create
.pSrvCall
= NULL
;
2802 RxContext
->Create
.Type
= NetRootType
;
2803 Container
= SrvCall
;
2805 /* Construct SRV_CALL, ie, use mini-rdr */
2806 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
2807 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
2808 if (Status
!= STATUS_SUCCESS
)
2810 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
2811 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2812 RxDereferenceSrvCall(SrvCall
, *LockState
);
2813 RxReleasePrefixTableLock(PrefixTable
);
2817 /* Loop again to make use of SRV_CALL stable condition wait */
2820 /* At that point, we have a stable SRV_CALL (either found or constructed) */
2821 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
2822 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
2823 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
2825 /* Call mini-rdr to get NetRoot name */
2826 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
2827 /* And create the NetRoot with that name */
2828 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
2829 if (NetRoot
== NULL
)
2831 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2834 NetRoot
->Type
= NetRootType
;
2836 RxDereferenceSrvCall(SrvCall
, *LockState
);
2838 /* Finally, create the associated VNetRoot */
2839 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
2840 if (VNetRoot
== NULL
)
2842 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2843 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2846 RxReferenceVNetRoot(VNetRoot
);
2848 /* We're get closer! */
2849 NetRoot
->Condition
= Condition_InTransition
;
2850 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
2851 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
2852 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2854 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
2855 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
2856 if (!NT_SUCCESS(Status
))
2858 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
2859 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
2860 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
2862 RxContext
->Create
.pNetRoot
= NULL
;
2863 RxContext
->Create
.pVNetRoot
= NULL
;
2867 PIO_STACK_LOCATION Stack
;
2869 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
2871 Stack
= RxContext
->CurrentIrpSp
;
2872 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
2874 RxExclusivePrefixTableLockToShared(PrefixTable
);
2875 *LockState
= LHS_SharedLockHeld
;
2881 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
2883 if (*LockState
!= LHS_LockNotHeld
)
2885 RxReleasePrefixTableLock(PrefixTable
);
2886 *LockState
= LHS_LockNotHeld
;
2892 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
2901 RxFinishFcbInitialization(
2902 IN OUT PMRX_FCB Fcb
,
2903 IN RX_FILE_TYPE FileType
,
2904 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
2906 NODE_TYPE_CODE OldType
;
2910 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
2912 OldType
= Fcb
->Header
.NodeTypeCode
;
2913 Fcb
->Header
.NodeTypeCode
= FileType
;
2914 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
2915 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
2917 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2919 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
2920 else if (InitPacket
!= NULL
)
2922 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
2923 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
2924 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
2925 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
2926 InitPacket
->pValidDataLength
->QuadPart
);
2929 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
2930 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2932 /* If our FCB newly points to a file, initiliaz everything related */
2933 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
&&
2934 OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
2936 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
2937 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, &RxLockOperationCompletion
,
2938 &RxUnlockOperation
);
2940 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
2941 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
2943 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
2947 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
2956 RxFinishSrvCallConstruction(
2957 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
2961 PRX_CONTEXT Context
;
2962 RX_BLOCK_CONDITION Condition
;
2963 PRX_PREFIX_TABLE PrefixTable
;
2965 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
2967 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
2968 Context
= Calldown
->RxContext
;
2969 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
2971 /* We have a winner, notify him */
2972 if (Calldown
->BestFinisher
!= NULL
)
2974 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
2976 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
2978 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
2979 MRxSrvCallWinnerNotify
,
2980 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
2981 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
2982 if (Status
!= STATUS_SUCCESS
)
2984 Condition
= Condition_Bad
;
2988 Condition
= Condition_Good
;
2991 /* Otherwise, just fail our SRV_CALL */
2994 Status
= Calldown
->CallbackContexts
[0].Status
;
2995 Condition
= Condition_Bad
;
2998 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2999 RxTransitionSrvCall(SrvCall
, Condition
);
3000 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
3002 /* If async, finish it here, otherwise, caller has already finished the stuff */
3003 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
3005 DPRINT("Finishing async call\n");
3007 RxReleasePrefixTableLock(PrefixTable
);
3009 /* Make sure we weren't cancelled in-between */
3010 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
3012 Status
= STATUS_CANCELLED
;
3015 /* In case that was a create, context can be reused */
3016 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
3018 RxpPrepareCreateContextForReuse(Context
);
3021 /* If that's a failure, reset everything and return failure */
3022 if (Status
!= STATUS_SUCCESS
)
3024 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
3025 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3027 if (Context
->Info
.Buffer
!= NULL
)
3029 RxFreePool(Context
->Info
.Buffer
);
3030 Context
->Info
.Buffer
= NULL
;
3033 Context
->CurrentIrp
->IoStatus
.Information
= 0;
3034 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
3035 RxCompleteRequest(Context
, Status
);
3037 /* Otherwise, call resume routine and done! */
3040 Status
= Context
->ResumeRoutine(Context
);
3041 if (Status
!= STATUS_PENDING
)
3043 RxCompleteRequest(Context
, Status
);
3046 DPRINT("Not completing, pending\n");
3050 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
3059 RxFinishSrvCallConstructionDispatcher(
3063 BOOLEAN Direct
, KeepLoop
;
3065 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
3067 /* In case of failure of starting dispatcher, context is not set
3068 * We keep track of it to fail associated SRV_CALL
3070 Direct
= (Context
== NULL
);
3072 /* Separated thread, loop forever */
3075 PLIST_ENTRY ListEntry
;
3076 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
3078 /* If there are no SRV_CALL to finalize left, just finish thread */
3079 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
3080 if (IsListEmpty(&RxSrvCalldownList
))
3083 RxSrvCallConstructionDispatcherActive
= FALSE
;
3085 /* Otherwise, get the SRV_CALL to finish construction */
3088 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
3091 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
3099 /* If direct is set, reset the finisher to avoid electing a winner
3100 * and fail SRV_CALL (see upper comment)
3102 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
3105 Calldown
->BestFinisher
= NULL
;
3107 /* Finish SRV_CALL construction */
3108 RxFinishSrvCallConstruction(Calldown
);
3130 RxGetFileSizeWithLock(
3132 OUT PLONGLONG FileSize
)
3136 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
3147 return RxData
.OurProcess
;
3154 RxInitializeBufferingManager(
3157 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
3158 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
3159 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
3160 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
3161 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
3162 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
3163 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
3164 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
3165 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
3166 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
3168 return STATUS_SUCCESS
;
3176 RxInitializeContext(
3178 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
3179 IN ULONG InitialContextFlags
,
3180 IN OUT PRX_CONTEXT RxContext
)
3182 PIO_STACK_LOCATION Stack
;
3184 /* Initialize our various fields */
3185 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
3186 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
3187 RxContext
->ReferenceCount
= 1;
3188 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
3189 RxContext
->RxDeviceObject
= RxDeviceObject
;
3190 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
3191 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
3192 InitializeListHead(&RxContext
->BlockedOperations
);
3193 RxContext
->MRxCancelRoutine
= NULL
;
3194 RxContext
->ResumeRoutine
= NULL
;
3195 RxContext
->Flags
|= InitialContextFlags
;
3196 RxContext
->CurrentIrp
= Irp
;
3197 RxContext
->LastExecutionThread
= PsGetCurrentThread();
3198 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
3200 /* If've got no IRP, mark RX_CONTEXT */
3203 RxContext
->CurrentIrpSp
= NULL
;
3204 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
3205 RxContext
->MinorFunction
= 0;
3209 /* Otherwise, first determine whether we are performing async operation */
3210 Stack
= IoGetCurrentIrpStackLocation(Irp
);
3211 if (Stack
->FileObject
!= NULL
)
3215 Fcb
= Stack
->FileObject
->FsContext
;
3216 if (!IoIsOperationSynchronous(Irp
) ||
3217 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
3218 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
3219 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
3221 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3225 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
3227 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3229 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3231 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
3234 /* Set proper flags if TopLevl IRP/Device */
3235 if (!RxIsThisTheTopLevelIrp(Irp
))
3237 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
3239 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
3241 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
3244 /* Copy stack information */
3245 RxContext
->MajorFunction
= Stack
->MajorFunction
;
3246 RxContext
->MinorFunction
= Stack
->MinorFunction
;
3247 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
3248 RxContext
->CurrentIrpSp
= Stack
;
3250 /* If we have a FO associated, learn for more */
3251 if (Stack
->FileObject
!= NULL
)
3256 /* Get the FCB and CCB (FOBX) */
3257 Fcb
= Stack
->FileObject
->FsContext
;
3258 Fobx
= Stack
->FileObject
->FsContext2
;
3259 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
3260 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
3262 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
3265 /* We have a FOBX, this not a DFS opening, keep track of it */
3266 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
3268 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
3269 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
3270 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
3272 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
3277 RxContext
->pFobx
= NULL
;
3280 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
3281 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
3284 PV_NET_ROOT VNetRoot
= NULL
;
3286 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
3288 VNetRoot
= Fcb
->VNetRoot
;
3290 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
3292 VNetRoot
= (PV_NET_ROOT
)Fobx
;
3295 if (VNetRoot
!= NULL
)
3297 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3301 /* Remember if that's a write through file */
3302 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
3303 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
3305 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
3310 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
3312 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
3313 RxContext
, RxContext
->MinorFunction
, Irp
,
3314 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
3315 RxContext
->SerialNumber
);
3324 RxInitializeDispatcher(
3328 HANDLE ThreadHandle
;
3332 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
3333 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
3335 /* Set appropriate timeouts: 10s & 60s */
3336 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3337 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3338 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
3339 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
3341 RxDispatcher
.NumberOfProcessors
= 1;
3342 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
3343 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
3345 /* Initialize our dispatchers */
3346 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
3347 if (!NT_SUCCESS(Status
))
3352 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
3353 if (!NT_SUCCESS(Status
))
3358 /* And start them */
3359 RxDispatcher
.State
= RxDispatcherActive
;
3360 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
3361 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
3362 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
3363 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
3364 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
3365 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
3366 if (NT_SUCCESS(Status
))
3368 ZwClose(ThreadHandle
);
3378 RxInitializeFcbTable(
3379 IN OUT PRX_FCB_TABLE FcbTable
,
3380 IN BOOLEAN CaseInsensitiveMatch
)
3386 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
3387 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
3389 ExInitializeResourceLite(&FcbTable
->TableLock
);
3390 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
3391 FcbTable
->Version
= 0;
3392 FcbTable
->TableEntryForNull
= NULL
;
3394 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
3395 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
3397 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
3400 FcbTable
->Lookups
= 0;
3401 FcbTable
->FailedLookups
= 0;
3402 FcbTable
->Compares
= 0;
3410 RxInitializeLowIoContext(
3411 OUT PLOWIO_CONTEXT LowIoContext
,
3414 PRX_CONTEXT RxContext
;
3415 PIO_STACK_LOCATION Stack
;
3419 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
3420 ASSERT(LowIoContext
== &RxContext
->LowIoContext
);
3422 Stack
= RxContext
->CurrentIrpSp
;
3424 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
3425 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
3426 RxContext
->LowIoContext
.Operation
= Operation
;
3431 case LOWIO_OP_WRITE
:
3432 /* In case of RW, set a canary, to make sure these fields are properly set
3433 * they will be asserted when lowio request will be submit to mini-rdr
3436 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
3437 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
3438 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
3440 /* Keep track of paging IOs */
3441 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
3443 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
3447 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
3452 case LOWIO_OP_FSCTL
:
3453 case LOWIO_OP_IOCTL
:
3454 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
3455 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
3456 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
3457 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
3458 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
3459 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
3460 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
3463 /* Nothing to do for these */
3464 case LOWIO_OP_SHAREDLOCK
:
3465 case LOWIO_OP_EXCLUSIVELOCK
:
3466 case LOWIO_OP_UNLOCK
:
3467 case LOWIO_OP_UNLOCK_MULTIPLE
:
3468 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
3469 case LOWIO_OP_CLEAROUT
:
3473 /* Should never happen */
3483 RxInitializeLowIoPerFcbInfo(
3484 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
3488 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
3489 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
3496 RxInitializeMRxDispatcher(
3497 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
3501 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
3502 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
3504 return STATUS_SUCCESS
;
3511 RxInitializePrefixTable(
3512 IN OUT PRX_PREFIX_TABLE ThisTable
,
3513 IN ULONG TableSize OPTIONAL
,
3514 IN BOOLEAN CaseInsensitiveMatch
)
3520 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
3523 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
3524 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
3525 InitializeListHead(&ThisTable
->MemberQueue
);
3526 ThisTable
->Version
= 0;
3527 ThisTable
->TableEntryForNull
= NULL
;
3528 ThisTable
->IsNetNameTable
= FALSE
;
3529 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
3530 ThisTable
->TableSize
= TableSize
;
3536 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
3538 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
3547 RxInitializePurgeSyncronizationContext(
3548 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
3552 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
3553 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
3557 RxInitializeSrvCallParameters(
3558 IN PRX_CONTEXT RxContext
,
3559 IN OUT PSRV_CALL SrvCall
)
3563 SrvCall
->pPrincipalName
= NULL
;
3565 /* We only have stuff to initialize for file opening from DFS */
3566 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
3568 return STATUS_SUCCESS
;
3571 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
3574 return STATUS_NOT_IMPLEMENTED
;
3578 RxInitializeVNetRootParameters(
3579 PRX_CONTEXT RxContext
,
3581 OUT PULONG SessionId
,
3582 OUT PUNICODE_STRING
*UserNamePtr
,
3583 OUT PUNICODE_STRING
*UserDomainNamePtr
,
3584 OUT PUNICODE_STRING
*PasswordPtr
,
3588 PACCESS_TOKEN Token
;
3592 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
3593 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
3595 *UserNamePtr
= NULL
;
3596 *UserDomainNamePtr
= NULL
;
3597 *PasswordPtr
= NULL
;
3598 /* By default, that's not CSC instance */
3599 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
3601 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
3602 if (SeTokenIsRestricted(Token
))
3604 return STATUS_ACCESS_DENIED
;
3608 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
3609 if (!NT_SUCCESS(Status
))
3615 Status
= SeQuerySessionIdToken(Token
, SessionId
);
3616 if (!NT_SUCCESS(Status
))
3621 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
3624 Status
= STATUS_NOT_IMPLEMENTED
;
3628 /* Deal with connection credentials */
3629 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
3632 Status
= STATUS_NOT_IMPLEMENTED
;
3636 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
3639 Status
= STATUS_NOT_IMPLEMENTED
;
3644 if (NT_SUCCESS(Status
))
3646 /* If that's a CSC instance, mark it as such */
3647 if (RxIsThisACscAgentOpen(RxContext
))
3649 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
3661 RxInitializeWorkQueue(
3662 PRX_WORK_QUEUE WorkQueue
,
3663 WORK_QUEUE_TYPE WorkQueueType
,
3664 ULONG MaximumNumberOfWorkerThreads
,
3665 ULONG MinimumNumberOfWorkerThreads
)
3669 WorkQueue
->Type
= WorkQueueType
;
3670 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
3671 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
3673 WorkQueue
->State
= RxWorkQueueActive
;
3674 WorkQueue
->SpinUpRequestPending
= FALSE
;
3675 WorkQueue
->pRundownContext
= NULL
;
3676 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
3677 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
3678 WorkQueue
->CumulativeQueueLength
= 0;
3679 WorkQueue
->NumberOfSpinUpRequests
= 0;
3680 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
3681 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
3682 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
3683 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
3684 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
3685 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
3686 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
3687 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
3688 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
3689 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
3690 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
3691 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
3692 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
3693 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
3694 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
3695 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
3697 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
3698 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
3705 RxInitializeWorkQueueDispatcher(
3706 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
3709 ULONG MaximumNumberOfWorkerThreads
;
3713 /* Number of threads will depend on system capacity */
3714 if (MmQuerySystemSize() != MmLargeSystem
)
3716 MaximumNumberOfWorkerThreads
= 5;
3720 MaximumNumberOfWorkerThreads
= 10;
3723 /* Initialize the work queues */
3724 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
3725 MaximumNumberOfWorkerThreads
, 1);
3726 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
3727 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
3729 /* And start the worker threads */
3730 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
3731 RxBootstrapWorkerThreadDispatcher
,
3732 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
3733 if (!NT_SUCCESS(Status
))
3738 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
3739 RxBootstrapWorkerThreadDispatcher
,
3740 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
3741 if (!NT_SUCCESS(Status
))
3746 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
3747 RxBootstrapWorkerThreadDispatcher
,
3748 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
3753 RxInitiateSrvOpenKeyAssociation (
3754 IN OUT PSRV_OPEN SrvOpen
3764 RxInsertWorkQueueItem(
3765 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
3766 WORK_QUEUE_TYPE WorkQueueType
,
3767 PRX_WORK_DISPATCH_ITEM DispatchItem
)
3771 BOOLEAN SpinUpThreads
;
3772 PRX_WORK_QUEUE WorkQueue
;
3774 /* No dispatcher, nothing to insert */
3775 if (RxDispatcher
.State
!= RxDispatcherActive
)
3777 return STATUS_UNSUCCESSFUL
;
3780 /* Get the work queue */
3781 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
3783 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
3784 /* Only insert if the work queue is in decent state */
3785 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
3787 Status
= STATUS_UNSUCCESSFUL
;
3791 SpinUpThreads
= FALSE
;
3792 DispatchItem
->WorkQueueItem
.pDeviceObject
= pMRxDeviceObject
;
3793 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
3794 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
3795 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
3797 /* If required (and possible!), spin up a new worker thread */
3798 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
3799 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
3800 !WorkQueue
->SpinUpRequestPending
)
3802 WorkQueue
->SpinUpRequestPending
= TRUE
;
3803 SpinUpThreads
= TRUE
;
3806 Status
= STATUS_SUCCESS
;
3808 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
3810 /* If we failed, return and still not insert item */
3811 if (!NT_SUCCESS(Status
))
3816 /* All fine, insert the item */
3817 KeInsertQueue(&WorkQueue
->Queue
, &DispatchItem
->WorkQueueItem
.List
);
3819 /* And start a new worker thread if needed */
3822 RxSpinUpWorkerThreads(WorkQueue
);
3829 RxIsThisACscAgentOpen(
3830 IN PRX_CONTEXT RxContext
)
3836 /* Client Side Caching is DFS stuff - we don't support it */
3837 if (RxContext
->Create
.EaLength
!= 0)
3842 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
3843 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
3853 IN PRX_CONTEXT RxContext
,
3854 IN LOCK_OPERATION Operation
,
3855 IN ULONG BufferLength
)
3864 Irp
= RxContext
->CurrentIrp
;
3865 /* If we already have a MDL, make sure it's locked */
3866 if (Irp
->MdlAddress
!= NULL
)
3868 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
3872 /* That likely means the driver asks for buffered IOs - we don't support it! */
3873 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
3875 /* If we have a real length */
3876 if (BufferLength
> 0)
3878 /* Allocate a MDL and lock it */
3879 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
3882 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
3883 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
3886 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
3890 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3894 Status
= _SEH2_GetExceptionCode();
3896 /* Free the possible MDL we have allocated */
3898 Irp
->MdlAddress
= NULL
;
3900 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
3903 if (!FsRtlIsNtstatusExpected(Status
))
3905 Status
= STATUS_INVALID_USER_BUFFER
;
3908 RxContext
->IoStatusBlock
.Status
= Status
;
3909 ExRaiseStatus(Status
);
3915 RxLowIoCompletionTail(
3916 IN PRX_CONTEXT RxContext
)
3923 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
3925 /* Only continue if we're at APC_LEVEL or lower */
3926 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
&&
3927 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
3929 return STATUS_MORE_PROCESSING_REQUIRED
;
3932 /* Call the completion routine */
3933 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
3934 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
3935 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
3940 /* If it was a RW operation, for a paging file ... */
3941 Operation
= RxContext
->LowIoContext
.Operation
;
3942 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
3944 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
3947 Status
= STATUS_NOT_IMPLEMENTED
;
3952 /* Sanity check: we had known operation */
3953 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
3956 /* If not sync operation, complete now. Otherwise, caller has already completed */
3957 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
3959 RxCompleteRequest(RxContext
, Status
);
3962 DPRINT("Status: %x\n", Status
);
3971 RxLowIoPopulateFsctlInfo(
3972 IN PRX_CONTEXT RxContext
)
3977 PIO_STACK_LOCATION Stack
;
3981 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
3983 Irp
= RxContext
->CurrentIrp
;
3984 Stack
= RxContext
->CurrentIrpSp
;
3986 /* Copy stack parameters */
3987 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
3988 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
3989 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
3990 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
3991 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
3993 /* Same buffer in case of buffered */
3994 if (Method
== METHOD_BUFFERED
)
3996 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3997 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
3999 return STATUS_SUCCESS
;
4002 /* Two buffers for neither */
4003 if (Method
== METHOD_NEITHER
)
4005 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
4006 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
4008 return STATUS_SUCCESS
;
4011 /* Only IN/OUT remain */
4012 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
4014 /* Use system buffer for input */
4015 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
4016 /* And MDL for output */
4017 Mdl
= Irp
->MdlAddress
;
4020 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
4021 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
4023 return STATUS_INSUFFICIENT_RESOURCES
;
4028 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
4031 return STATUS_SUCCESS
;
4037 IN PRX_CONTEXT RxContext
,
4038 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
4042 BOOLEAN Synchronous
;
4043 PLOWIO_CONTEXT LowIoContext
;
4045 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
4049 LowIoContext
= &RxContext
->LowIoContext
;
4050 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
4052 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
4054 Status
= STATUS_SUCCESS
;
4055 Operation
= LowIoContext
->Operation
;
4059 case LOWIO_OP_WRITE
:
4060 /* Check that the parameters were properly set by caller
4061 * See comment in RxInitializeLowIoContext()
4063 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
4064 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
4066 /* Lock the buffer */
4067 RxLockUserBuffer(RxContext
,
4068 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
4069 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
4070 if (RxNewMapUserBuffer(RxContext
) == NULL
)
4072 return STATUS_INSUFFICIENT_RESOURCES
;
4074 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
4076 /* If that's a paging IO, initialize serial operation */
4077 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
4081 Fcb
= (PFCB
)RxContext
->pFcb
;
4083 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
4084 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
4085 if (Operation
== LOWIO_OP_READ
)
4087 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
4091 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
4094 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
4099 case LOWIO_OP_FSCTL
:
4100 case LOWIO_OP_IOCTL
:
4101 /* Set FSCTL/IOCTL parameters */
4102 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
4103 /* Check whether we're consistent: a length means a buffer */
4104 if (NT_SUCCESS(Status
))
4106 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
4107 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
4108 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
4109 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
4111 Status
= STATUS_INVALID_PARAMETER
;
4117 case LOWIO_OP_SHAREDLOCK
:
4118 case LOWIO_OP_EXCLUSIVELOCK
:
4119 case LOWIO_OP_UNLOCK
:
4120 case LOWIO_OP_UNLOCK_MULTIPLE
:
4121 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4122 case LOWIO_OP_CLEAROUT
:
4127 Status
= STATUS_INVALID_PARAMETER
;
4131 /* No need to perform extra init in case of posting */
4132 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
4134 /* Preflight checks were OK, time to submit */
4135 if (NT_SUCCESS(Status
))
4137 PMINIRDR_DISPATCH Dispatch
;
4141 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
4142 /* If not synchronous, we're likely to return before the operation is finished */
4143 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
4145 IoMarkIrpPending(RxContext
->CurrentIrp
);
4149 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
4150 if (Dispatch
!= NULL
)
4152 /* We'll try to execute until the mini-rdr doesn't return pending */
4155 RxContext
->IoStatusBlock
.Information
= 0;
4157 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
4158 if (Status
== STATUS_PENDING
)
4160 /* Unless it's not synchronous, caller will be happy with pending op */
4166 RxWaitSync(RxContext
);
4167 Status
= RxContext
->IoStatusBlock
.Status
;
4173 /* We had marked the IRP pending, whereas the operation finished, drop that */
4174 if (Status
!= STATUS_RETRY
)
4176 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
4178 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
4181 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
4185 } while (Status
== STATUS_PENDING
);
4189 Status
= STATUS_INVALID_PARAMETER
;
4193 /* Call completion and return */
4194 RxContext
->IoStatusBlock
.Status
= Status
;
4195 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
4196 return RxLowIoCompletionTail(RxContext
);
4204 IN PRX_CONTEXT RxContext
)
4210 Irp
= RxContext
->CurrentIrp
;
4211 /* We should have a MDL (buffered IOs are not supported!) */
4212 if (Irp
->MdlAddress
!= NULL
)
4215 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
4218 /* Just return system buffer */
4219 return Irp
->AssociatedIrp
.SystemBuffer
;
4223 RxMarkFobxOnCleanup(
4242 PRX_CONTEXT RxContext
)
4248 Irp
= RxContext
->CurrentIrp
;
4249 if (Irp
->MdlAddress
!= NULL
)
4251 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
4254 return Irp
->UserBuffer
;
4286 RxpAcquirePrefixTableLockShared(
4287 PRX_PREFIX_TABLE pTable
,
4289 BOOLEAN ProcessBufferingStateChangeRequests
)
4293 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
4294 pTable
->TableLock
.ActiveEntries
);
4296 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
4303 RxpAcquirePrefixTableLockExclusive(
4304 PRX_PREFIX_TABLE pTable
,
4306 BOOLEAN ProcessBufferingStateChangeRequests
)
4310 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
4311 pTable
->TableLock
.ActiveEntries
);
4313 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
4320 RxpDereferenceAndFinalizeNetFcb(
4322 IN PRX_CONTEXT RxContext
,
4323 IN BOOLEAN RecursiveFinalize
,
4324 IN BOOLEAN ForceFinalize
)
4329 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
4333 ASSERT(!ForceFinalize
);
4334 ASSERT(NodeTypeIsFcb(ThisFcb
));
4335 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
4337 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
4338 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
4339 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
4345 Status
= STATUS_SUCCESS
;
4346 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
4347 ResourceAcquired
= FALSE
;
4348 NetRootReferenced
= FALSE
;
4349 /* If FCB isn't orphaned, it still have context attached */
4350 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
4352 /* Don't let NetRoot go away before we're done */
4353 RxReferenceNetRoot(NetRoot
);
4354 NetRootReferenced
= TRUE
;
4356 /* Try to acquire the table lock exclusively */
4357 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
4359 RxReferenceNetFcb(ThisFcb
);
4361 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
4363 if (RxContext
!= NULL
&& RxContext
!= (PVOID
)-1 && RxContext
!= (PVOID
)-2)
4365 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
4368 RxReleaseFcb(RxContext
, ThisFcb
);
4370 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
4372 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
4375 References
= RxDereferenceNetFcb(ThisFcb
);
4377 ResourceAcquired
= TRUE
;
4381 /* If locking was OK (or not needed!), attempt finalization */
4382 if (NT_SUCCESS(Status
))
4384 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
4387 /* Release table lock if acquired */
4388 if (ResourceAcquired
)
4390 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
4393 /* We don't need the NetRoot anylonger */
4394 if (NetRootReferenced
)
4396 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
4406 RxpDereferenceNetFcb(
4413 ASSERT(NodeTypeIsFcb(Fcb
));
4415 NewCount
= InterlockedDecrement((volatile long *)&Fcb
->NodeReferenceCount
);
4416 ASSERT(NewCount
>= 0);
4418 PRINT_REF_COUNT(NETFCB
, NewCount
);
4427 RxPrefixTableInsertName(
4428 IN OUT PRX_PREFIX_TABLE ThisTable
,
4429 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
4431 IN PULONG ContainerRefCount
,
4432 IN USHORT CaseInsensitiveLength
,
4433 IN PRX_CONNECTION_ID ConnectionId
4438 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
4440 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
4441 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
4443 /* Copy parameters and compute hash */
4444 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
4445 ThisEntry
->ContainingRecord
= Container
;
4446 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
4447 InterlockedIncrement((volatile long *)ContainerRefCount
);
4448 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
4449 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
4451 /* If no path length: this is entry for null path */
4452 if (ThisEntry
->Prefix
.Length
== 0)
4454 ThisTable
->TableEntryForNull
= ThisEntry
;
4456 /* Otherwise, insert in the appropriate bucket */
4459 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
4462 /* If we had a connection ID, keep track of it */
4463 if (ConnectionId
!= NULL
)
4465 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
4469 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
4470 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
4473 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
4474 /* Reflect the changes */
4475 ++ThisTable
->Version
;
4477 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
4486 RxPrefixTableLookupName(
4487 IN PRX_PREFIX_TABLE ThisTable
,
4488 IN PUNICODE_STRING CanonicalName
,
4489 OUT PUNICODE_STRING RemainingName
,
4490 IN PRX_CONNECTION_ID ConnectionId
)
4496 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
4497 ASSERT(CanonicalName
->Length
> 0);
4499 /* Call the internal helper */
4500 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
4501 if (Container
== NULL
)
4506 /* Reference our container before returning it */
4507 if (RdbssReferenceTracingValue
!= 0)
4509 NODE_TYPE_CODE Type
;
4511 Type
= NodeType(Container
);
4514 case RDBSS_NTC_SRVCALL
:
4515 RxReferenceSrvCall(Container
);
4518 case RDBSS_NTC_NETROOT
:
4519 RxReferenceNetRoot(Container
);
4522 case RDBSS_NTC_V_NETROOT
:
4523 RxReferenceVNetRoot(Container
);
4533 RxReference(Container
);
4550 ASSERT(NodeTypeIsFcb(Fcb
));
4552 NewCount
= InterlockedIncrement((volatile long *)&Fcb
->NodeReferenceCount
);
4554 PRINT_REF_COUNT(NETFCB
, Fcb
->NodeReferenceCount
);
4563 RxpReleasePrefixTableLock(
4564 PRX_PREFIX_TABLE pTable
,
4565 BOOLEAN ProcessBufferingStateChangeRequests
)
4569 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
4570 pTable
->TableLock
.ActiveEntries
);
4572 ExReleaseResourceLite(&pTable
->TableLock
);
4580 RxPrepareContextForReuse(
4581 IN OUT PRX_CONTEXT RxContext
)
4585 /* When we reach that point, make sure mandatory parts are null-ed */
4586 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
4588 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
4589 RxContext
->Create
.RdrFlags
= 0;
4591 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
4593 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
4594 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
4597 RxContext
->ReferenceCount
= 0;
4601 RxProcessFcbChangeBufferingStateRequest(
4608 RxpTrackDereference(
4609 _In_ ULONG TraceType
,
4610 _In_ PCSTR FileName
,
4612 _In_ PVOID Instance
)
4616 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
4627 _In_ ULONG TraceType
,
4628 _In_ PCSTR FileName
,
4630 _In_ PVOID Instance
)
4632 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
4641 RxpUndoScavengerFinalizationMarking(
4644 PNODE_TYPE_AND_SIZE Node
;
4648 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
4649 /* There's no marking - nothing to do */
4650 if (!BooleanFlagOn(Node
->NodeTypeCode
, RX_SCAVENGER_MASK
))
4659 RxPurgeFcbInSystemCache(
4661 IN PLARGE_INTEGER FileOffset OPTIONAL
,
4663 IN BOOLEAN UninitializeCacheMaps
,
4664 IN BOOLEAN FlushFile
)
4667 return STATUS_NOT_IMPLEMENTED
;
4674 RxpWorkerThreadDispatcher(
4675 IN PRX_WORK_QUEUE WorkQueue
,
4676 IN PLARGE_INTEGER WaitInterval
)
4680 PETHREAD CurrentThread
;
4681 BOOLEAN KillThread
, Dereference
;
4682 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
4683 PWORKER_THREAD_ROUTINE WorkerRoutine
;
4685 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4687 /* Reference ourselves */
4688 CurrentThread
= PsGetCurrentThread();
4689 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, PsThreadType
, KernelMode
);
4690 ASSERT(NT_SUCCESS(Status
));
4692 /* Infinite loop for worker */
4694 Dereference
= FALSE
;
4698 PLIST_ENTRY ListEntry
;
4700 /* Remove an entry from the work queue */
4701 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
4702 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
4704 PRDBSS_DEVICE_OBJECT DeviceObject
;
4706 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
4708 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
4709 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
4710 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4712 /* Get the parameters, and null-them in the struct */
4713 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
4714 Parameter
= WorkQueueItem
->Parameter
;
4715 DeviceObject
= WorkQueueItem
->pDeviceObject
;
4717 WorkQueueItem
->List
.Flink
= NULL
;
4718 WorkQueueItem
->WorkerRoutine
= NULL
;
4719 WorkQueueItem
->Parameter
= NULL
;
4720 WorkQueueItem
->pDeviceObject
= NULL
;
4722 /* Call the routine */
4723 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
4724 WorkerRoutine(Parameter
);
4726 /* Are we going down now? */
4727 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
4729 PKEVENT TearDownEvent
;
4731 TearDownEvent
= InterlockedExchangePointer((void * volatile*)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
4732 if (TearDownEvent
!= NULL
)
4734 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
4738 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4741 /* Shall we shutdown... */
4742 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
4743 switch (WorkQueue
->State
)
4745 /* Our queue is active, kill it if we have no more items to dispatch
4746 * and more threads than the required minimum
4748 case RxWorkQueueActive
:
4749 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
4751 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
4752 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
4756 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
4761 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4766 /* The queue is inactive: kill it we have more threads than the required minimum */
4767 case RxWorkQueueInactive
:
4768 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
4769 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
4773 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
4778 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4782 /* Rundown in progress..., kill it for sure! */
4783 case RxWorkQueueRundownInProgress
:
4785 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
4787 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
4789 RundownContext
= WorkQueue
->pRundownContext
;
4790 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
4792 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
4794 Dereference
= FALSE
;
4796 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
4798 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
4801 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
4808 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
4809 } while (!KillThread
);
4811 DPRINT("Killed worker thread\n");
4813 /* Do we have to dereference ourselves? */
4816 ObDereferenceObject(CurrentThread
);
4819 /* Dump last executed routine */
4820 if (DumpDispatchRoutine
)
4822 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
4825 PsTerminateSystemThread(STATUS_SUCCESS
);
4830 IN OUT PVOID Instance
)
4832 NODE_TYPE_CODE NodeType
;
4833 PNODE_TYPE_AND_SIZE Node
;
4837 RxAcquireScavengerMutex();
4839 /* We can only reference a few structs */
4840 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
4841 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
4842 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
4843 (NodeType
== RDBSS_NTC_FOBX
));
4845 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
4846 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
4848 /* Trace refcount if asked */
4851 case RDBSS_NTC_SRVCALL
:
4852 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
4855 case RDBSS_NTC_NETROOT
:
4856 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
4859 case RDBSS_NTC_V_NETROOT
:
4860 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
4863 case RDBSS_NTC_SRVOPEN
:
4864 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
4867 case RDBSS_NTC_FOBX
:
4868 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
4876 RxpUndoScavengerFinalizationMarking(Instance
);
4877 RxReleaseScavengerMutex();
4882 RxResumeBlockedOperations_Serially(
4883 IN OUT PRX_CONTEXT RxContext
,
4884 IN OUT PLIST_ENTRY BlockingIoQ
)
4888 RxAcquireSerializationMutex();
4890 /* This can only happen on pipes */
4891 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
4893 RxReleaseSerializationMutex();
4899 RxReleaseSerializationMutex();
4903 RxScavengeRelatedFobxs(
4911 RxScavengeVNetRoots(
4912 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
4923 RxSpinUpRequestsDispatcher(
4927 PRX_DISPATCHER RxDispatcher
;
4929 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, PsThreadType
, KernelMode
);
4930 if (!NT_SUCCESS(Status
))
4932 PsTerminateSystemThread(STATUS_SUCCESS
);
4935 RxDispatcher
= Dispatcher
;
4940 PLIST_ENTRY ListEntry
;
4942 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
4943 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
4944 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
4946 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
4947 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
4949 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
4953 ListEntry
= &RxDispatcher
->SpinUpRequests
;
4955 KeResetEvent(&RxDispatcher
->SpinUpRequestsEvent
);
4956 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
4958 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
4960 PWORK_QUEUE_ITEM WorkItem
;
4961 PRX_WORK_QUEUE WorkQueue
;
4963 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
4964 WorkQueue
= WorkItem
->Parameter
;
4966 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
4968 DPRINT1("WORKQ:SR %lx %lx\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
4969 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
4971 } while (RxDispatcher
->State
== RxDispatcherActive
);
4973 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
4974 PsTerminateSystemThread(STATUS_SUCCESS
);
4981 RxSpinUpWorkerThread(
4982 PRX_WORK_QUEUE WorkQueue
,
4983 PRX_WORKERTHREAD_ROUTINE Routine
,
4988 HANDLE ThreadHandle
;
4992 /* If work queue is inactive, that cannot work */
4993 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
4994 if (WorkQueue
->State
!= RxWorkQueueActive
)
4996 Status
= STATUS_UNSUCCESSFUL
;
4997 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
5001 ++WorkQueue
->NumberOfActiveWorkerThreads
;
5002 Status
= STATUS_SUCCESS
;
5004 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5006 /* Quit on failure */
5007 if (!NT_SUCCESS(Status
))
5012 /* Spin up the worker thread */
5013 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
5014 if (NT_SUCCESS(Status
))
5016 ZwClose(ThreadHandle
);
5019 /* Read well: we reached that point because it failed! */
5020 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
5022 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
5023 --WorkQueue
->NumberOfActiveWorkerThreads
;
5024 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
5026 /* Rundown, no more active threads, set the event! */
5027 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
5028 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
5030 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
5033 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
5035 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5041 RxSpinUpWorkerThreads(
5042 PRX_WORK_QUEUE WorkQueue
)
5048 RxSynchronizeWithScavenger(
5049 IN PRX_CONTEXT RxContext
)
5058 RxTableComputeHashValue(
5059 IN PUNICODE_STRING Name
)
5067 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
5070 Loops
[1] = MaxChar
- 1;
5071 Loops
[2] = MaxChar
- 2;
5072 Loops
[3] = MaxChar
- 3;
5073 Loops
[4] = MaxChar
- 4;
5074 Loops
[5] = MaxChar
/ 4;
5075 Loops
[6] = 2 * MaxChar
/ 4;
5076 Loops
[7] = 3 * MaxChar
/ 4;
5079 for (i
= 0; i
< 8; ++i
)
5084 if (Idx
>= 0 && Idx
< MaxChar
)
5086 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
5097 RxTableComputePathHashValue(
5098 IN PUNICODE_STRING Name
)
5106 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
5109 Loops
[1] = MaxChar
- 1;
5110 Loops
[2] = MaxChar
- 2;
5111 Loops
[3] = MaxChar
- 3;
5112 Loops
[4] = MaxChar
- 4;
5113 Loops
[5] = MaxChar
/ 4;
5114 Loops
[6] = 2 * MaxChar
/ 4;
5115 Loops
[7] = 3 * MaxChar
/ 4;
5118 for (i
= 0; i
< 8; ++i
)
5123 if (Idx
>= 0 && Idx
< MaxChar
)
5125 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
5134 IN PRX_PREFIX_TABLE ThisTable
,
5135 IN PUNICODE_STRING Name
,
5136 OUT PUNICODE_STRING RemainingName
,
5137 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
5141 PRX_PREFIX_ENTRY Entry
;
5142 RX_CONNECTION_ID NullId
;
5143 UNICODE_STRING LookupString
;
5147 /* If caller didn't provide a connection ID, setup one */
5148 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
5150 NullId
.Luid
.LowPart
= 0;
5151 NullId
.Luid
.HighPart
= 0;
5152 RxConnectionId
= &NullId
;
5156 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
5160 LookupString
.Buffer
= Name
->Buffer
;
5161 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
5162 /* We'll perform the lookup, path component after another */
5163 for (i
= 1; i
< MaxChar
; ++i
)
5166 PRX_PREFIX_ENTRY CurEntry
;
5168 /* Don't cut in the middle of a path element */
5169 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
5174 /* Perform lookup in the table */
5175 LookupString
.Length
= i
* sizeof(WCHAR
);
5176 Hash
= RxTableComputeHashValue(&LookupString
);
5177 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
5179 ++ThisTable
->Lookups
;
5181 /* Entry not found, move to the next component */
5182 if (CurEntry
== NULL
)
5185 ++ThisTable
->FailedLookups
;
5191 ASSERT(Entry
->ContainingRecord
!= NULL
);
5192 Container
= Entry
->ContainingRecord
;
5194 /* Need to handle NetRoot specific case... */
5195 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
5200 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
5206 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
5210 /* Entry was found */
5215 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
5217 /* Setup remaining name */
5218 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
5219 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
5220 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
5224 /* Otherwise, that's the whole name */
5225 RemainingName
= Name
;
5235 RxTableLookupName_ExactLengthMatch(
5236 IN PRX_PREFIX_TABLE ThisTable
,
5237 IN PUNICODE_STRING Name
,
5239 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
5241 PLIST_ENTRY ListEntry
, HashBucket
;
5245 ASSERT(RxConnectionId
!= NULL
);
5247 /* Select the right bucket */
5248 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
5249 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
5250 /* If bucket is empty, no match */
5251 if (IsListEmpty(HashBucket
))
5256 /* Browse all the entries in the bucket */
5257 for (ListEntry
= HashBucket
->Flink
;
5258 ListEntry
!= HashBucket
;
5259 ListEntry
= ListEntry
->Flink
)
5262 PRX_PREFIX_ENTRY Entry
;
5263 BOOLEAN CaseInsensitive
;
5264 PUNICODE_STRING CmpName
, CmpPrefix
;
5265 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
5267 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
5268 ++ThisTable
->Considers
;
5269 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
5271 Container
= Entry
->ContainingRecord
;
5272 ASSERT(Container
!= NULL
);
5274 /* Not the same hash, not the same length, move on */
5275 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
5280 ++ThisTable
->Compares
;
5281 /* If we have to perform a case insensitive compare on a portion... */
5282 if (Entry
->CaseInsensitiveLength
!= 0)
5284 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
5286 /* Perform the case insensitive check on the asked length */
5287 InsensitiveName
.Buffer
= Name
->Buffer
;
5288 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
5289 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
5290 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
5291 /* No match, move to the next entry */
5292 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
5297 /* Was the case insensitive covering the whole name? */
5298 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
5300 /* If connection ID also matches, that a complete match! */
5301 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
5307 /* Otherwise, we have to continue with the sensitive match.... */
5308 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
5309 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
5310 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
5311 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
5313 CmpName
= &InsensitiveName
;
5314 CmpPrefix
= &InsensitivePrefix
;
5315 CaseInsensitive
= FALSE
;
5320 CmpPrefix
= &Entry
->Prefix
;
5321 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
5324 /* Perform the compare, if there's a match, also check for connection ID */
5325 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
5327 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
5341 RxTrackerUpdateHistory(
5342 _Inout_opt_ PRX_CONTEXT RxContext
,
5343 _Inout_ PMRX_FCB MrxFcb
,
5344 _In_ ULONG Operation
,
5345 _In_ ULONG LineNumber
,
5346 _In_ PCSTR FileName
,
5347 _In_ ULONG SerialNumber
)
5350 RX_FCBTRACKER_CASES Case
;
5352 /* Check for null or special context */
5353 if (RxContext
== NULL
)
5355 Case
= RX_FCBTRACKER_CASE_NULLCONTEXT
;
5357 else if ((ULONG_PTR
)RxContext
== -1)
5359 Case
= RX_FCBTRACKER_CASE_CBS_CONTEXT
;
5361 else if ((ULONG_PTR
)RxContext
== -2)
5363 Case
= RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT
;
5367 ASSERT(NodeType(RxContext
) == RDBSS_NTC_RX_CONTEXT
);
5368 Case
= RX_FCBTRACKER_CASE_NORMAL
;
5371 /* If caller provided a FCB, update its history */
5375 ASSERT(NodeTypeIsFcb(Fcb
));
5377 /* Only one acquire operation, so many release operations... */
5378 if (Operation
== TRACKER_ACQUIRE_FCB
)
5380 ++Fcb
->FcbAcquires
[Case
];
5384 ++Fcb
->FcbReleases
[Case
];
5388 /* If we have a normal context, update its history about this function calls */
5389 if (Case
== RX_FCBTRACKER_CASE_NORMAL
)
5391 ULONG TrackerHistoryPointer
;
5393 /* Only one acquire operation, so many release operations... */
5394 if (Operation
== TRACKER_ACQUIRE_FCB
)
5396 InterlockedIncrement(&RxContext
->AcquireReleaseFcbTrackerX
);
5400 InterlockedDecrement(&RxContext
->AcquireReleaseFcbTrackerX
);
5403 /* We only keep track of the 32 first calls */
5404 TrackerHistoryPointer
= InterlockedExchangeAdd((volatile long *)&RxContext
->TrackerHistoryPointer
, 1);
5405 if (TrackerHistoryPointer
< RDBSS_TRACKER_HISTORY_SIZE
)
5407 RxContext
->TrackerHistory
[TrackerHistoryPointer
].AcquireRelease
= Operation
;
5408 RxContext
->TrackerHistory
[TrackerHistoryPointer
].LineNumber
= LineNumber
;
5409 RxContext
->TrackerHistory
[TrackerHistoryPointer
].FileName
= (PSZ
)FileName
;
5410 RxContext
->TrackerHistory
[TrackerHistoryPointer
].SavedTrackerValue
= RxContext
->AcquireReleaseFcbTrackerX
;
5411 RxContext
->TrackerHistory
[TrackerHistoryPointer
].Flags
= RxContext
->Flags
;
5414 /* If it's negative, then we released once more than we acquired it?! */
5415 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
>= 0);
5420 RxTrackPagingIoResource(
5421 _Inout_ PVOID Instance
,
5433 RxUninitializeVNetRootParameters(
5434 IN PUNICODE_STRING UserName
,
5435 IN PUNICODE_STRING UserDomainName
,
5436 IN PUNICODE_STRING Password
,
5441 /* Only free what could have been allocated */
5442 if (UserName
!= NULL
)
5444 RxFreePool(UserName
);
5447 if (UserDomainName
!= NULL
)
5449 RxFreePool(UserDomainName
);
5452 if (Password
!= NULL
)
5454 RxFreePool(Password
);
5457 /* And remove the possibly set CSC agent flag */
5460 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
5469 IN RX_BLOCK_CONDITION NewConditionValue
,
5470 OUT PRX_BLOCK_CONDITION Condition
,
5471 IN OUT PLIST_ENTRY TransitionWaitList
)
5473 PRX_CONTEXT Context
;
5474 LIST_ENTRY SerializationQueue
;
5478 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
5480 /* Set the new condition */
5481 RxAcquireSerializationMutex();
5482 ASSERT(NewConditionValue
!= Condition_InTransition
);
5483 *Condition
= NewConditionValue
;
5484 /* And get the serialization queue for treatment */
5485 RxTransferList(&SerializationQueue
, TransitionWaitList
);
5486 RxReleaseSerializationMutex();
5488 /* Handle the serialization queue */
5489 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
5490 while (Context
!= NULL
)
5492 /* If the caller asked for post, post the request */
5493 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
5495 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
5496 RxFsdPostRequest(Context
);
5498 /* Otherwise, wake up sleeping waiters */
5501 RxSignalSynchronousWaiter(Context
);
5504 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
5512 RxVerifyOperationIsLegal(
5513 IN PRX_CONTEXT RxContext
)
5518 PFILE_OBJECT FileObject
;
5519 PIO_STACK_LOCATION Stack
;
5523 Irp
= RxContext
->CurrentIrp
;
5524 Stack
= RxContext
->CurrentIrpSp
;
5525 FileObject
= Stack
->FileObject
;
5527 /* We'll only check stuff on opened files, this requires an IRP and a FO */
5528 if (Irp
== NULL
|| FileObject
== NULL
)
5533 /* Set no exception for breakpoint - remember whether is was already set */
5534 FlagSet
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
5535 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
5537 /* If we have a CCB, perform a few checks on opened file */
5538 Fobx
= RxContext
->pFobx
;
5541 PMRX_SRV_OPEN SrvOpen
;
5543 SrvOpen
= Fobx
->pSrvOpen
;
5544 if (SrvOpen
!= NULL
)
5546 UCHAR MajorFunction
;
5548 MajorFunction
= RxContext
->MajorFunction
;
5549 /* Only allow closing/cleanup operations on renamed files */
5550 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
5551 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
5553 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_RENAMED
;
5554 ExRaiseStatus(STATUS_FILE_RENAMED
);
5557 /* Only allow closing/cleanup operations on deleted files */
5558 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
5559 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
))
5561 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_DELETED
;
5562 ExRaiseStatus(STATUS_FILE_DELETED
);
5567 /* If that's an open operation */
5568 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
5570 PFILE_OBJECT RelatedFileObject
;
5572 /* We won't allow an open operation relative to a file to be deleted */
5573 RelatedFileObject
= FileObject
->RelatedFileObject
;
5574 if (RelatedFileObject
!= NULL
)
5578 Fcb
= RelatedFileObject
->FsContext
;
5579 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
5581 RxContext
->IoStatusBlock
.Status
= STATUS_DELETE_PENDING
;
5582 ExRaiseStatus(STATUS_DELETE_PENDING
);
5587 /* If cleanup was completed */
5588 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
5590 if (!BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
))
5592 UCHAR MajorFunction
;
5594 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
5595 MajorFunction
= Stack
->MajorFunction
;
5596 if (MajorFunction
!= IRP_MJ_CLOSE
&& MajorFunction
!= IRP_MJ_QUERY_INFORMATION
&&
5597 MajorFunction
!= IRP_MJ_SET_INFORMATION
)
5599 if ((MajorFunction
!= IRP_MJ_READ
&& MajorFunction
!= IRP_MJ_WRITE
) ||
5600 !BooleanFlagOn(Stack
->MinorFunction
, IRP_MN_COMPLETE
))
5602 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_CLOSED
;
5603 ExRaiseStatus(STATUS_FILE_CLOSED
);
5609 /* If flag was already set, don't clear it */
5612 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
5620 RxWaitForStableCondition(
5621 IN PRX_BLOCK_CONDITION Condition
,
5622 IN OUT PLIST_ENTRY TransitionWaitList
,
5623 IN OUT PRX_CONTEXT RxContext
,
5624 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
5627 NTSTATUS LocalStatus
;
5631 /* Make sure to always get status */
5632 if (AsyncStatus
== NULL
)
5634 AsyncStatus
= &LocalStatus
;
5637 /* By default, it's a success */
5638 *AsyncStatus
= STATUS_SUCCESS
;
5641 /* If it's not stable, we've to wait */
5642 if (!StableCondition(*Condition
))
5644 /* Lock the mutex */
5645 RxAcquireSerializationMutex();
5646 /* Still not stable? */
5647 if (!StableCondition(*Condition
))
5649 /* Insert us in the wait list for processing on stable condition */
5650 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
5652 /* If we're asked to post on stable, don't wait, and just return pending */
5653 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
5655 *AsyncStatus
= STATUS_PENDING
;
5662 RxReleaseSerializationMutex();
5664 /* We don't post on stable, so, just wait... */
5667 RxWaitSync(RxContext
);
5677 RxWorkItemDispatcher(
5680 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
5682 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
5684 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
5686 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
5694 _RxAllocatePoolWithTag(
5695 _In_ POOL_TYPE PoolType
,
5696 _In_ SIZE_T NumberOfBytes
,
5699 return ExAllocatePoolWithTagPriority(PoolType
, NumberOfBytes
, Tag
, LowPoolPriority
);
5710 ExFreePoolWithTag(Buffer
, 0);
5722 ExFreePoolWithTag(Buffer
, Tag
);
5728 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
5730 #ifdef RDBSS_TRACKER
5732 _In_ ULONG LineNumber
,
5733 _In_ PCSTR FileName
,
5734 _In_ ULONG SerialNumber
5739 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
5743 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
5745 SpecialContext
= FALSE
;
5746 ContextIsPresent
= FALSE
;
5747 /* Check for special context */
5748 if ((ULONG_PTR
)RxContext
== -1 || (ULONG_PTR
)RxContext
== -2)
5750 SpecialContext
= TRUE
;
5753 /* We don't handle buffering state change yet... */
5754 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
5755 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
5760 /* Nor special contexts */
5766 /* Nor missing contexts... */
5767 if (RxContext
== NULL
)
5772 /* That said: we have a real context! */
5773 ContextIsPresent
= TRUE
;
5775 /* If we've been cancelled in between, give up */
5776 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
5777 if (!NT_SUCCESS(Status
))
5783 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
5787 /* Assume we cannot lock */
5788 Status
= STATUS_LOCK_NOT_GRANTED
;
5790 /* Lock according to what the caller asked */
5793 case FCB_MODE_EXCLUSIVE
:
5794 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
5797 case FCB_MODE_SHARED
:
5798 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
5801 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
5802 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
5806 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
5807 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
5814 Status
= STATUS_SUCCESS
;
5815 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
5817 /* Handle paging write - not implemented */
5818 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
5824 /* And break, that cool! */
5830 /* If it failed, return immediately */
5831 if (!NT_SUCCESS(Status
))
5837 /* If we don't have to check for valid operation, job done, nothing more to do */
5838 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
5840 if (NT_SUCCESS(Status
))
5842 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
5848 /* Verify operation */
5851 RxVerifyOperationIsLegal(RxContext
);
5855 /* If it failed, release lock and fail */
5856 if (_SEH2_AbnormalTermination())
5858 ExReleaseResourceLite(Fcb
->Header
.Resource
);
5859 Status
= STATUS_LOCK_NOT_GRANTED
;
5864 if (NT_SUCCESS(Status
))
5866 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
5869 DPRINT("Status: %x\n", Status
);
5877 __RxItsTheSameContext(
5878 _In_ PRX_CONTEXT RxContext
,
5879 _In_ ULONG CapturedRxContextSerialNumber
,
5883 /* Check we have a context with the same serial number */
5884 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
5885 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
5888 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
5894 _Inout_opt_ PRX_CONTEXT RxContext
,
5895 _Inout_ PMRX_FCB MrxFcb
5896 #ifdef RDBSS_TRACKER
5898 _In_ ULONG LineNumber
,
5899 _In_ PCSTR FileName
,
5900 _In_ ULONG SerialNumber
5904 BOOLEAN IsExclusive
, BufferingPending
;
5906 RxAcquireSerializationMutex();
5908 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
5909 IsExclusive
= BooleanFlagOn(MrxFcb
->Header
.Resource
->Flag
, ResourceOwnedExclusive
);
5911 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
5912 * then just release the FCB
5914 if (!BufferingPending
|| !IsExclusive
)
5916 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
5917 LineNumber
, FileName
, SerialNumber
);
5918 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
5921 RxReleaseSerializationMutex();
5923 /* And finally leave */
5924 if (!BufferingPending
|| !IsExclusive
)
5929 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
5931 /* Otherwise, handle buffering state and release */
5932 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
5934 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
5935 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
5939 __RxReleaseFcbForThread(
5940 _Inout_opt_ PRX_CONTEXT RxContext
,
5941 _Inout_ PMRX_FCB MrxFcb
,
5942 _In_ ERESOURCE_THREAD ResourceThreadId
5943 #ifdef RDBSS_TRACKER
5945 _In_ ULONG LineNumber
,
5946 _In_ PCSTR FileName
,
5947 _In_ ULONG SerialNumber
5951 BOOLEAN IsExclusive
, BufferingPending
;
5953 RxAcquireSerializationMutex();
5955 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
5956 IsExclusive
= BooleanFlagOn(MrxFcb
->Header
.Resource
->Flag
, ResourceOwnedExclusive
);
5958 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
5959 * then just release the FCB
5961 if (!BufferingPending
|| !IsExclusive
)
5963 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
5964 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
5965 LineNumber
, FileName
, SerialNumber
);
5966 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
5969 RxReleaseSerializationMutex();
5971 /* And finally leave */
5972 if (!BufferingPending
|| !IsExclusive
)
5977 /* Otherwise, handle buffering state and release */
5978 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
5979 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
5980 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);