3 * Copyright (C) 2017 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rxce/rxce.c
23 * PURPOSE: RXCE library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
);
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown
);
54 RxFinishSrvCallConstructionDispatcher(
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
60 WORK_QUEUE_TYPE WorkQueueType
,
61 PRX_WORK_QUEUE_ITEM WorkQueueItem
);
65 PRX_CONTEXT RxContext
);
73 RxpDispatchChangeBufferingStateRequests(
76 PLIST_ENTRY DiscardedRequests
);
80 RxScavengerTimerRoutine(
86 _In_
struct _KDPC
*Dpc
,
87 _In_opt_ PVOID DeferredContext
,
88 _In_opt_ PVOID SystemArgument1
,
89 _In_opt_ PVOID SystemArgument2
);
98 _RxAllocatePoolWithTag(
99 _In_ POOL_TYPE PoolType
,
100 _In_ SIZE_T NumberOfBytes
,
114 extern ULONG ReadAheadGranularity
;
116 volatile LONG RxNumberOfActiveFcbs
= 0;
117 ULONG SerialNumber
= 1;
119 volatile ULONG RxContextSerialNumberCounter
;
120 BOOLEAN RxStopOnLoudCompletion
= TRUE
;
121 BOOLEAN RxSrvCallConstructionDispatcherActive
= FALSE
;
122 LIST_ENTRY RxSrvCalldownList
;
123 RX_SPIN_LOCK RxStrucSupSpinLock
;
124 ULONG RdbssReferenceTracingValue
;
125 LARGE_INTEGER RxWorkQueueWaitInterval
[RxMaximumWorkQueue
];
126 LARGE_INTEGER RxSpinUpDispatcherWaitInterval
;
127 RX_DISPATCHER RxDispatcher
;
128 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues
;
129 FAST_MUTEX RxLowIoPagingIoSyncMutex
;
130 BOOLEAN RxContinueFromAssert
= TRUE
;
131 ULONG RxExplodePoolTags
= 1;
132 LARGE_INTEGER RxTimerInterval
;
133 RX_SPIN_LOCK RxTimerLock
;
134 LIST_ENTRY RxTimerQueueHead
;
135 LIST_ENTRY RxRecurrentWorkItemsList
;
138 ULONG RxTimerTickCount
;
140 BOOLEAN DumpDispatchRoutine
= TRUE
;
142 BOOLEAN DumpDispatchRoutine
= FALSE
;
150 #define ASSERT(exp) \
153 RxAssert(#exp, __FILE__, __LINE__, NULL); \
158 #undef RxAllocatePool
159 #undef RxAllocatePoolWithTag
162 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
163 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
164 #define RxFreePool _RxFreePool
165 #define RxFreePoolWithTag _RxFreePoolWithTag
168 /* FUNCTIONS ****************************************************************/
174 RxAddVirtualNetRootToNetRoot(
176 PV_NET_ROOT VNetRoot
)
180 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
182 /* Insert in the VNetRoot list - make sure lock is held */
183 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
185 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
186 ++NetRoot
->NumberOfVirtualNetRoots
;
187 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
195 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
196 NODE_TYPE_CODE NodeType
,
199 PVOID AlreadyAllocatedObject
)
204 PVOID Buffer
, PAPNBuffer
;
205 PNON_PAGED_FCB NonPagedFcb
;
206 PMINIRDR_DISPATCH Dispatch
;
207 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
211 Dispatch
= RxDeviceObject
->Dispatch
;
224 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
225 if (NodeType
== RDBSS_NTC_FOBX
)
227 FobxSize
= sizeof(FOBX
);
228 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
230 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
233 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
234 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
236 SrvOpenSize
= sizeof(SRV_OPEN
);
237 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
239 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
242 FobxSize
= sizeof(FOBX
);
243 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
245 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
248 /* Otherwise, we're asked to allocate a FCB */
251 /* So, allocate the FCB and its extension if asked */
252 FcbSize
= sizeof(FCB
);
253 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
255 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
258 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
259 * Otherwise, it will be allocated later on, specifically
261 if (PoolType
== NonPagedPool
)
263 NonPagedSize
= sizeof(NON_PAGED_FCB
);
266 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
267 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
269 SrvOpenSize
= sizeof(SRV_OPEN
);
270 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
272 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
275 FobxSize
= sizeof(FOBX
);
276 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
278 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
283 /* If we already have a buffer, go ahead */
284 if (AlreadyAllocatedObject
!= NULL
)
286 Buffer
= AlreadyAllocatedObject
;
288 /* Otherwise, allocate it */
291 Buffer
= RxAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
298 /* Now, get the pointers - FOBX is easy */
299 if (NodeType
== RDBSS_NTC_FOBX
)
303 /* SRV_OPEN first, FOBX next */
304 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
307 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
309 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
315 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
317 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
319 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
320 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
323 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
324 if (PoolType
!= NonPagedPool
)
326 NonPagedFcb
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
327 if (NonPagedFcb
== NULL
)
329 RxFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
333 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
335 /* Otherwise, just point at the right place in what has been allocated previously */
338 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
339 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
343 /* If we have allocated a SRV_OPEN, initialize it */
346 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
348 if (NodeType
== RDBSS_NTC_SRVOPEN
)
350 SrvOpen
->InternalFobx
= Fobx
;
354 SrvOpen
->InternalFobx
= NULL
;
355 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
358 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
360 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
363 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
366 /* If we have allocated a FOBX, initialize it */
369 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
371 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
373 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
377 /* If we have allocated a FCB, initialize it */
380 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
382 Fcb
->NonPaged
= NonPagedFcb
;
383 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
384 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
385 NonPagedFcb
->FcbBackPointer
= Fcb
;
387 Fcb
->InternalSrvOpen
= SrvOpen
;
388 Fcb
->InternalFobx
= Fobx
;
390 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
391 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
392 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
394 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
396 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
399 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
401 InterlockedIncrement(&RxNumberOfActiveFcbs
);
402 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
404 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
405 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
416 NODE_TYPE_CODE NodeType
,
417 PMINIRDR_DISPATCH MRxDispatch
,
420 ULONG Tag
, ObjectSize
;
421 PVOID Object
, *Extension
;
422 PRX_PREFIX_ENTRY PrefixEntry
;
423 USHORT StructSize
, ExtensionSize
;
427 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
431 case RDBSS_NTC_SRVCALL
:
432 Tag
= RX_SRVCALL_POOLTAG
;
433 StructSize
= sizeof(SRV_CALL
);
434 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
436 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
440 case RDBSS_NTC_NETROOT
:
441 Tag
= RX_NETROOT_POOLTAG
;
442 StructSize
= sizeof(NET_ROOT
);
443 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
445 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
449 case RDBSS_NTC_V_NETROOT
:
450 Tag
= RX_V_NETROOT_POOLTAG
;
451 StructSize
= sizeof(V_NET_ROOT
);
452 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
454 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
463 /* Now, allocate the object */
464 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
465 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
471 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
473 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
476 case RDBSS_NTC_SRVCALL
:
477 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
478 Extension
= &((PSRV_CALL
)Object
)->Context
;
479 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
482 case RDBSS_NTC_NETROOT
:
483 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
484 Extension
= &((PNET_ROOT
)Object
)->Context
;
485 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
488 case RDBSS_NTC_V_NETROOT
:
489 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
490 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
498 /* Set the prefix table unicode string */
499 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
500 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
501 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
502 PrefixEntry
->Prefix
.Length
= NameLength
;
503 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
504 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
506 /* Return the extension if we are asked to manage it */
507 if (ExtensionSize
!= 0)
509 *Extension
= Add2Ptr(Object
, StructSize
);
528 /* If we're not asked to continue, just stop the system */
529 if (!RxContinueFromAssert
)
531 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
534 /* Otherwise, capture context to offer the user to dump it */
535 RtlCaptureContext(&Context
);
537 /* Loop until the user hits 'i' */
540 /* If no file provided, use empty name */
546 /* If no message provided, use empty one */
552 /* Display the message */
553 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
554 /* And ask the user */
555 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
556 /* If he asks for ignore, quit
557 * In case of invalid input, ask again
559 if (Response
[0] != 'B' && Response
[0] != 'b')
561 if (Response
[0] == 'I' || Response
[0] == 'i')
569 /* Break: offer the user to dump the context and break */
570 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
573 /* Continue looping, so that after dump, execution can continue (with ignore) */
582 RxBootstrapWorkerThreadDispatcher(
585 PRX_WORK_QUEUE RxWorkQueue
;
589 RxWorkQueue
= WorkQueue
;
590 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
598 RxChangeBufferingState(
601 BOOLEAN ComputeNewState
)
604 NTSTATUS Status
, MiniStatus
;
605 ULONG NewBufferingState
, OldBufferingState
;
609 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen
, Context
, ComputeNewState
);
611 Fcb
= (PFCB
)SrvOpen
->pFcb
;
612 ASSERT(NodeTypeIsFcb(Fcb
));
613 /* First of all, mark that buffering state is changing */
614 SetFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
617 Status
= STATUS_SUCCESS
;
620 /* If we're asked to compute a new state, ask the mini-rdr for it */
623 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxComputeNewBufferingState
,
624 ((PMRX_SRV_OPEN
)SrvOpen
, Context
, &NewBufferingState
));
625 if (MiniStatus
!= STATUS_SUCCESS
)
627 NewBufferingState
= 0;
632 /* If not, use SRV_OPEN state */
633 NewBufferingState
= SrvOpen
->BufferingFlags
;
636 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
637 if ((Fcb
->ShareAccess
.SharedRead
+ Fcb
->ShareAccess
.SharedWrite
+ Fcb
->ShareAccess
.SharedDelete
) == 0 && !ComputeNewState
)
639 SetFlag(NewBufferingState
, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES
);
642 /* If there's a lock operation to complete, clear that flag */
643 if (Fcb
->OutstandingLockOperationsCount
!= 0)
645 ClearFlag(NewBufferingState
, FCB_STATE_LOCK_BUFFERING_ENABLED
);
648 /* Get the old state */
649 OldBufferingState
= Fcb
->FcbState
& FCB_STATE_BUFFERING_STATE_MASK
;
650 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState
, NewBufferingState
, SrvOpen
->BufferingFlags
);
652 /* If we're dropping write cache, then flush the FCB */
653 if (BooleanFlagOn(OldBufferingState
, FCB_STATE_WRITECACHING_ENABLED
) &&
654 !BooleanFlagOn(NewBufferingState
, FCB_STATE_WRITECACHING_ENABLED
))
656 DPRINT("Flushing\n");
658 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
661 /* If we're dropping read cache, then purge */
662 if (Fcb
->UncleanCount
== 0 ||
663 (BooleanFlagOn(OldBufferingState
, FCB_STATE_READCACHING_ENABLED
) &&
664 !BooleanFlagOn(NewBufferingState
, FCB_STATE_READCACHING_ENABLED
)) ||
665 BooleanFlagOn(NewBufferingState
, FCB_STATE_DELETE_ON_CLOSE
))
669 if (!NT_SUCCESS(Status
))
671 DPRINT("Previous flush failed with status: %lx\n", Status
);
674 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, TRUE
);
677 /* If there's already a change pending in SRV_OPEN */
678 if (ComputeNewState
&& BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
680 /* If there's a FOBX at least */
681 if (!IsListEmpty(&SrvOpen
->FobxList
))
683 PRX_CONTEXT RxContext
;
685 /* Create a fake context to pass to the mini-rdr */
686 RxContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
687 if (RxContext
!= NULL
)
691 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
693 /* Give the first FOBX */
694 Fobx
= CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
);
695 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
696 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
698 /* If there was a delayed close, perform it */
699 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
701 DPRINT("Oplock break close for %p\n", SrvOpen
);
703 RxCloseAssociatedSrvOpen(Fobx
, RxContext
);
705 /* Otherwise, inform the mini-rdr about completion */
708 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxCompleteBufferingStateChangeRequest
,
709 (RxContext
, (PMRX_SRV_OPEN
)SrvOpen
, Context
));
713 RxDereferenceAndDeleteRxContext(RxContext
);
718 /* Set the new state */
719 Fcb
->FcbState
^= (NewBufferingState
^ Fcb
->FcbState
) & FCB_STATE_BUFFERING_STATE_MASK
;
723 /* Job done, clear the flag */
724 ClearFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
726 if (!BooleanFlagOn(NewBufferingState
, FCB_STATE_FILETIMECACHEING_ENABLED
))
728 ClearFlag(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
);
737 RxCheckVNetRootCredentials(
738 PRX_CONTEXT RxContext
,
739 PV_NET_ROOT VNetRoot
,
741 PUNICODE_STRING UserName
,
742 PUNICODE_STRING UserDomain
,
743 PUNICODE_STRING Password
,
748 /* If that's a UNC name, there's nothing to process */
749 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
750 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
753 return STATUS_MORE_PROCESSING_REQUIRED
;
756 /* Compare the logon ID in the VNetRoot with the one provided */
757 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
759 return STATUS_MORE_PROCESSING_REQUIRED
;
762 /* No credential provided? That's OK */
763 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
765 return STATUS_SUCCESS
;
770 return STATUS_NOT_IMPLEMENTED
;
782 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
784 ASSERT(Context
!= NULL
);
785 ASSERT(Context
->CurrentIrp
!= NULL
);
786 Irp
= Context
->CurrentIrp
;
788 /* Debug what the caller asks for */
789 if (Context
->LoudCompletionString
!= NULL
)
791 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
792 /* Does the user asks to stop on failed completion */
793 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
795 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
799 /* Complete for real */
800 Context
->CurrentIrp
= NULL
;
801 RxCompleteRequest_Real(Context
, Irp
, Status
);
803 DPRINT("Status: %lx\n", Status
);
811 RxCompleteRequest_Real(
812 IN PRX_CONTEXT RxContext
,
818 PIO_STACK_LOCATION Stack
;
820 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
822 /* Nothing to complete, just free context */
825 DPRINT("NULL IRP for %p\n", RxContext
);
826 if (RxContext
!= NULL
)
828 RxDereferenceAndDeleteRxContext_Real(RxContext
);
834 /* Remove cancel routine */
835 IoAcquireCancelSpinLock(&OldIrql
);
836 IoSetCancelRoutine(Irp
, NULL
);
837 IoReleaseCancelSpinLock(OldIrql
);
839 /* Select the boost, given the success/paging operation */
840 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
842 Boost
= IO_DISK_INCREMENT
;
846 Irp
->IoStatus
.Information
= 0;
847 Boost
= IO_NO_INCREMENT
;
849 Irp
->IoStatus
.Status
= Status
;
851 if (RxContext
!= NULL
)
853 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
854 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
856 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
857 RxContext
->MinorFunction
, RxContext
, Irp
,
858 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
862 /* If that's an opening, there might be a canonical name allocated,
863 * if completion isn't pending, release it
865 Stack
= IoGetCurrentIrpStackLocation(Irp
);
866 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
869 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
871 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
874 RxpPrepareCreateContextForReuse(RxContext
);
875 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
878 /* If it's a write, validate the correct behavior of the operation */
879 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
881 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
883 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
887 /* If it's pending, make sure IRP is marked as such */
888 if (RxContext
!= NULL
)
890 if (RxContext
->PendingReturned
)
892 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
897 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
898 IoCompleteRequest(Irp
, Boost
);
900 /* If there's a context, dereference it */
901 if (RxContext
!= NULL
)
903 RxDereferenceAndDeleteRxContext_Real(RxContext
);
911 RxCompleteSrvOpenKeyAssociation(
912 IN OUT PSRV_OPEN SrvOpen
)
916 SrvCall
= (PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
;
917 /* Only handle requests if opening was a success */
918 if (SrvOpen
->Condition
== Condition_Good
)
921 BOOLEAN ProcessChange
;
922 LIST_ENTRY DiscardedRequests
;
924 /* Initialize our discarded requests list */
925 InitializeListHead(&DiscardedRequests
);
927 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
929 /* Transfer our requests in the SRV_CALL */
930 RxTransferList(&SrvCall
->BufferingManager
.SrvOpenLists
[0], &SrvOpen
->SrvOpenKeyList
);
932 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
933 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
935 /* Dispatch requests and get the discarded ones */
936 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &DiscardedRequests
);
938 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
940 /* Is there still anything to process? */
941 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
942 if (IsListEmpty(&SrvCall
->BufferingManager
.HandlerList
))
944 ProcessChange
= FALSE
;
948 ProcessChange
= (SrvCall
->BufferingManager
.HandlerInactive
== FALSE
);
951 SrvCall
->BufferingManager
.HandlerInactive
= TRUE
;
954 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
959 RxReferenceSrvCall(SrvCall
);
960 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
961 &SrvCall
->BufferingManager
.HandlerWorkItem
,
962 RxProcessChangeBufferingStateRequests
, SrvCall
);
965 /* And discard left requests */
966 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests
);
970 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
979 IN PRX_CONTEXT RxContext
,
980 IN PSRV_CALL SrvCall
,
981 IN PNET_ROOT NetRoot
,
982 IN PV_NET_ROOT VirtualNetRoot
,
983 OUT PLOCK_HOLDING_STATE LockHoldingState
)
986 PRX_PREFIX_TABLE PrefixTable
;
987 PMRX_CREATENETROOT_CONTEXT Context
;
988 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
992 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
993 VirtualNetRoot
, LockHoldingState
);
995 /* Validate the lock is exclusively held */
996 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
997 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
999 /* Allocate the context */
1000 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
1001 if (Context
== NULL
)
1003 return STATUS_INSUFFICIENT_RESOURCES
;
1006 /* We can release lock now */
1007 RxReleasePrefixTableLock(PrefixTable
);
1008 *LockHoldingState
= LHS_LockNotHeld
;
1010 RootCondition
= Condition_Bad
;
1011 VRootCondition
= Condition_Bad
;
1013 /* Initialize the context */
1014 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
1015 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
1016 Context
->RxContext
= RxContext
;
1017 Context
->pVNetRoot
= VirtualNetRoot
;
1018 Context
->Callback
= RxCreateNetRootCallBack
;
1020 /* And call the mini-rdr */
1021 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
1022 if (Status
== STATUS_PENDING
)
1024 /* Wait for the mini-rdr to be done */
1025 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1026 /* Update the structures condition according to mini-rdr return */
1027 if (NT_SUCCESS(Context
->NetRootStatus
))
1029 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
1031 RootCondition
= Condition_Good
;
1032 VRootCondition
= Condition_Good
;
1033 Status
= STATUS_SUCCESS
;
1037 RootCondition
= Condition_Good
;
1038 Status
= Context
->VirtualNetRootStatus
;
1043 Status
= Context
->VirtualNetRootStatus
;
1044 if (NT_SUCCESS(Status
))
1046 Status
= Context
->NetRootStatus
;
1052 /* It has to return STATUS_PENDING! */
1056 /* Acquire lock again - for caller lock status will remain unchanged */
1057 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
1058 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
1059 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1061 /* Do the transition to the condition got from mini-rdr */
1062 RxTransitionNetRoot(NetRoot
, RootCondition
);
1063 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
1065 /* Context is not longer needed */
1066 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
1068 DPRINT("Status: %x\n", Status
);
1078 IN PRX_CONTEXT RxContext
,
1079 IN PSRV_CALL SrvCall
,
1080 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1083 PRX_PREFIX_TABLE PrefixTable
;
1084 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1085 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1086 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
1090 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
1092 /* Validate the lock is exclusively held */
1093 RxDeviceObject
= RxContext
->RxDeviceObject
;
1094 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
1095 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1097 /* Allocate the context for mini-rdr */
1098 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
1099 if (Calldown
== NULL
)
1101 SrvCall
->Context
= NULL
;
1102 SrvCall
->Condition
= Condition_Bad
;
1103 RxReleasePrefixTableLock(PrefixTable
);
1104 *LockHoldingState
= LHS_LockNotHeld
;
1105 return STATUS_INSUFFICIENT_RESOURCES
;
1109 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
1111 SrvCall
->Context
= NULL
;
1112 SrvCall
->Condition
= Condition_InTransition
;
1114 RxReleasePrefixTableLock(PrefixTable
);
1115 *LockHoldingState
= LHS_LockNotHeld
;
1117 CallbackContext
= &Calldown
->CallbackContexts
[0];
1118 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
1119 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
1120 CallbackContext
->SrvCalldownStructure
= Calldown
;
1121 CallbackContext
->CallbackContextOrdinal
= 0;
1122 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
1124 RxReferenceSrvCall(SrvCall
);
1126 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1127 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1129 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
1133 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
1136 Calldown
->NumberToWait
= 1;
1137 Calldown
->NumberRemaining
= 1;
1138 Calldown
->RxContext
= RxContext
;
1139 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
1140 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
1141 Calldown
->BestFinisher
= NULL
;
1142 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
1143 InitializeListHead(&Calldown
->SrvCalldownList
);
1145 /* Call the mini-rdr */
1146 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
1147 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
1148 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
1149 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
1150 /* It has to return STATUS_PENDING! */
1151 ASSERT(Status
== STATUS_PENDING
);
1153 /* No async, start completion */
1154 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1156 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1158 /* Finish construction - we'll notify mini-rdr it's the winner */
1159 Status
= RxFinishSrvCallConstruction(Calldown
);
1160 if (!NT_SUCCESS(Status
))
1162 RxReleasePrefixTableLock(PrefixTable
);
1163 *LockHoldingState
= LHS_LockNotHeld
;
1167 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
1168 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1172 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
1180 RxConstructVirtualNetRoot(
1181 IN PRX_CONTEXT RxContext
,
1182 IN PUNICODE_STRING CanonicalName
,
1183 IN NET_ROOT_TYPE NetRootType
,
1184 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
1185 OUT PLOCK_HOLDING_STATE LockHoldingState
,
1186 OUT PRX_CONNECTION_ID RxConnectionId
)
1189 PV_NET_ROOT VNetRoot
;
1190 RX_BLOCK_CONDITION Condition
;
1191 UNICODE_STRING LocalNetRootName
, FilePathName
;
1195 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1198 Condition
= Condition_Bad
;
1199 /* Before creating the VNetRoot, try to find the appropriate connection */
1200 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
1201 &LocalNetRootName
, &FilePathName
,
1202 LockHoldingState
, RxConnectionId
);
1203 /* Found and active */
1204 if (Status
== STATUS_CONNECTION_ACTIVE
)
1206 /* We need a new VNetRoot */
1207 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
1208 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
1209 if (VNetRoot
!= NULL
)
1211 RxReferenceVNetRoot(VNetRoot
);
1214 /* Dereference previous VNetRoot */
1215 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
1216 /* Reset and start construct (new structures will replace old ones) */
1217 RxContext
->Create
.pSrvCall
= NULL
;
1218 RxContext
->Create
.pNetRoot
= NULL
;
1219 RxContext
->Create
.pVNetRoot
= NULL
;
1221 /* Construct new NetRoot */
1222 if (VNetRoot
!= NULL
)
1224 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
1225 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
1226 if (NT_SUCCESS(Status
))
1228 Condition
= Condition_Good
;
1233 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1238 /* If it failed creating the connection, leave */
1239 if (Status
!= STATUS_SUCCESS
)
1241 if (*LockHoldingState
!= LHS_LockNotHeld
)
1243 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1244 *LockHoldingState
= LHS_LockNotHeld
;
1247 *VirtualNetRootPointer
= VNetRoot
;
1248 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1252 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1254 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1255 Condition
= Condition_Good
;
1258 /* We have a non stable VNetRoot - transition it */
1259 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1261 RxTransitionVNetRoot(VNetRoot
, Condition
);
1264 /* If recreation failed */
1265 if (Status
!= STATUS_SUCCESS
)
1267 /* Dereference potential VNetRoot */
1268 if (VNetRoot
!= NULL
)
1270 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1271 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1276 if (*LockHoldingState
!= LHS_LockNotHeld
)
1278 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1279 *LockHoldingState
= LHS_LockNotHeld
;
1283 *VirtualNetRootPointer
= VNetRoot
;
1287 /* Return the allocated VNetRoot */
1288 *VirtualNetRootPointer
= VNetRoot
;
1297 IN PRX_CONTEXT RxContext
,
1298 IN PV_NET_ROOT VNetRoot
,
1299 IN PUNICODE_STRING Name
)
1305 NODE_TYPE_CODE NodeType
;
1306 PIO_STACK_LOCATION Stack
;
1307 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1311 /* We need a decent VNetRoot */
1312 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1314 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1315 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1316 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1318 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1319 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1321 Stack
= RxContext
->CurrentIrpSp
;
1323 /* Do we need to create a fake FCB? Like for renaming */
1324 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1325 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1326 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1328 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1329 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1331 /* Allocate the FCB */
1332 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1333 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1339 /* Initialize the FCB */
1340 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1341 Fcb
->RxDeviceObject
= RxDeviceObject
;
1342 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1343 Fcb
->VNetRoot
= VNetRoot
;
1344 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1346 InitializeListHead(&Fcb
->SrvOpenList
);
1347 Fcb
->SrvOpenListVersion
= 0;
1349 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1350 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1351 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1352 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1353 NetRoot
->InnerNamePrefix
.Length
);
1354 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1356 /* Copy back parameters from RxContext */
1357 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1359 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1362 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1364 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1366 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1369 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1371 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1374 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1375 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1377 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1378 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1380 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1381 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1383 /* Fake FCB doesn't go in prefix table */
1386 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1387 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1388 DPRINT("Fake FCB: %p\n", Fcb
);
1392 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1395 RxReferenceVNetRoot(VNetRoot
);
1396 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1398 Fcb
->ulFileSizeVersion
= 0;
1400 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1401 RxReferenceNetFcb(Fcb
);
1412 OUT PRX_CONTEXT RxContext
,
1413 IN PMRX_SRV_OPEN MrxSrvOpen
)
1424 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1425 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1426 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1427 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1430 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1431 /* Can we use pre-allocated FOBX? */
1432 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1434 Fobx
= Fcb
->InternalFobx
;
1435 /* Call allocate to initialize the FOBX */
1436 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1437 /* Mark it used now */
1438 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1439 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1441 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1443 Fobx
= SrvOpen
->InternalFobx
;
1444 /* Call allocate to initialize the FOBX */
1445 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1446 /* Mark it used now */
1447 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1448 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1452 /* Last case, we cannot, allocate a FOBX */
1453 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1457 /* Allocation failed! */
1464 Fobx
->Flags
= Flags
;
1466 /* Initialize throttling */
1467 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1468 if (NetRoot
!= NULL
)
1470 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1472 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1473 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1474 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1476 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1478 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1479 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1480 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1484 /* Propagate flags fron RxContext */
1485 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1487 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1490 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1492 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1496 Fobx
->FobxSerialNumber
= 0;
1497 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1498 Fobx
->NodeReferenceCount
= 1;
1499 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1501 RxReferenceSrvOpen(SrvOpen
);
1502 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1504 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1505 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1506 InitializeListHead(&Fobx
->ClosePendingList
);
1508 Fobx
->CloseTime
.QuadPart
= 0;
1509 Fobx
->fOpenCountDecremented
= FALSE
;
1511 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1513 return (PMRX_FOBX
)Fobx
;
1521 IN PSRV_CALL SrvCall
,
1522 IN PUNICODE_STRING Name
,
1523 IN ULONG NetRootFlags
,
1524 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1527 USHORT CaseInsensitiveLength
;
1528 PRX_PREFIX_TABLE PrefixTable
;
1530 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1534 /* We need a SRV_CALL */
1535 ASSERT(SrvCall
!= NULL
);
1537 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1538 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1540 /* Get name length */
1541 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1542 if (CaseInsensitiveLength
> MAXUSHORT
)
1547 /* Allocate the NetRoot */
1548 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1549 CaseInsensitiveLength
);
1550 if (NetRoot
== NULL
)
1555 /* Construct name */
1556 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1557 Name
->Buffer
, Name
->Length
);
1558 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1560 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1561 SrvCall
->PrefixEntry
.Prefix
.Length
);
1564 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1566 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1568 /* Inisert in prefix table */
1569 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1570 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1573 /* Prepare the FCB table */
1574 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1576 InitializeListHead(&NetRoot
->TransitionWaitList
);
1577 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1578 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1580 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1582 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1583 NetRoot
->Flags
|= NetRootFlags
;
1584 NetRoot
->DiskParameters
.ClusterSize
= 1;
1585 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1586 NetRoot
->SrvCall
= SrvCall
;
1588 RxReferenceSrvCall(SrvCall
);
1590 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1599 RxCreateNetRootCallBack(
1600 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1604 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1614 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1615 IN ULONG InitialContextFlags
)
1618 PRX_CONTEXT Context
;
1620 ASSERT(RxDeviceObject
!= NULL
);
1622 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1624 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1625 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1627 /* Allocate the context from our lookaside list */
1628 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1629 if (Context
== NULL
)
1634 /* And initialize it */
1635 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1636 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1637 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1639 /* Add it to our global list */
1640 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1641 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1642 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1644 DPRINT("Context: %p\n", Context
);
1653 IN PRX_CONTEXT RxContext
,
1654 IN PUNICODE_STRING Name
,
1655 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1656 IN PRX_CONNECTION_ID RxConnectionId
)
1663 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1665 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1667 /* Get the name length */
1668 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1669 if (InnerNamePrefix
!= NULL
)
1671 NameLength
+= InnerNamePrefix
->Length
;
1674 /* Allocate the object */
1675 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1676 if (SrvCall
== NULL
)
1682 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1683 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1684 RxInitializeBufferingManager(SrvCall
);
1685 InitializeListHead(&SrvCall
->TransitionWaitList
);
1686 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1687 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1688 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1689 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1690 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1691 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1692 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1693 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1695 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1704 RxCreateSrvCallCallBack(
1705 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1709 PRX_CONTEXT RxContext
;
1710 ULONG NumberRemaining
;
1711 BOOLEAN StartDispatcher
;
1712 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1714 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1716 /* Get our context structures */
1717 Calldown
= Context
->SrvCalldownStructure
;
1718 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1720 /* If it is a success, that's the winner */
1721 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1722 if (Context
->Status
== STATUS_SUCCESS
)
1724 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1725 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1727 NumberRemaining
= --Calldown
->NumberRemaining
;
1728 SrvCall
->Status
= Context
->Status
;
1729 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1731 /* Still some to ask, keep going */
1732 if (NumberRemaining
!= 0)
1737 /* If that's not async, signal we're done */
1738 RxContext
= Calldown
->RxContext
;
1739 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1741 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1744 /* If that's a mailslot, finish construction, no more to do */
1745 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1747 RxFinishSrvCallConstruction(Calldown
);
1751 /* Queue our finish call for delayed completion */
1752 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1753 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1754 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1755 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1756 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1758 /* If we have to start dispatcher, go ahead */
1759 if (StartDispatcher
)
1763 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1764 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1765 if (!NT_SUCCESS(Status
))
1767 /* It failed - run it manually.... */
1768 RxFinishSrvCallConstructionDispatcher(NULL
);
1778 IN PV_NET_ROOT VNetRoot
,
1787 ASSERT(NodeTypeIsFcb(Fcb
));
1788 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1790 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1794 SrvOpen
= Fcb
->InternalSrvOpen
;
1795 /* Check whethet we have to allocate a new SRV_OPEN */
1796 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1797 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1798 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1801 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1802 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1807 /* Otherwise, just use internal one and initialize it */
1808 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1809 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1810 Fcb
->InternalSrvOpen
);
1811 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1812 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1815 /* If SrvOpen was properly allocated, initialize it */
1816 if (SrvOpen
!= NULL
)
1818 SrvOpen
->Flags
= Flags
;
1819 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1820 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1821 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1822 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1823 SrvOpen
->NodeReferenceCount
= 1;
1825 RxReferenceVNetRoot(VNetRoot
);
1826 RxReferenceNetFcb(Fcb
);
1828 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1829 ++Fcb
->SrvOpenListVersion
;
1831 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1832 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1833 InitializeListHead(&SrvOpen
->FobxList
);
1834 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1839 if (_SEH2_AbnormalTermination())
1841 if (SrvOpen
!= NULL
)
1843 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1849 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1862 IN PRX_CONTEXT RxContext
,
1863 IN PNET_ROOT NetRoot
,
1864 IN PUNICODE_STRING CanonicalName
,
1865 IN PUNICODE_STRING LocalNetRootName
,
1866 IN PUNICODE_STRING FilePath
,
1867 IN PRX_CONNECTION_ID RxConnectionId
)
1870 PV_NET_ROOT VNetRoot
;
1871 USHORT CaseInsensitiveLength
;
1875 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
1876 LocalNetRootName
, FilePath
, RxConnectionId
);
1878 /* Lock must be held exclusively */
1879 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1881 /* Check for overflow */
1882 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
1887 /* Get name length and allocate VNetRoot */
1888 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1889 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
1890 CaseInsensitiveLength
);
1891 if (VNetRoot
== NULL
)
1896 /* Initialize its connection parameters */
1897 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
1898 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
1899 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1900 if (!NT_SUCCESS(Status
))
1902 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
1903 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1904 RxFreeObject(VNetRoot
);
1910 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
1912 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1913 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
1914 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1915 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1917 InitializeListHead(&VNetRoot
->TransitionWaitList
);
1918 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
1920 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
1924 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1926 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
1930 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1933 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
1935 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
1941 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
1944 /* Insert in prefix table */
1945 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
1946 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1949 RxReferenceNetRoot(NetRoot
);
1950 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
1953 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
1954 VNetRoot
->UpperFinalizationDone
= FALSE
;
1955 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
1956 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
1958 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
1959 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
1969 IN OUT PVOID Instance
,
1970 IN LOCK_HOLDING_STATE LockHoldingState
)
1973 NODE_TYPE_CODE NodeType
;
1974 PNODE_TYPE_AND_SIZE Node
;
1978 RxAcquireScavengerMutex();
1980 /* Check we have a node we can handle */
1981 NodeType
= NodeType(Instance
);
1982 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
1983 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
1984 (NodeType
== RDBSS_NTC_FOBX
));
1986 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
1987 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
1988 ASSERT(RefCount
>= 0);
1990 /* Trace refcount */
1993 case RDBSS_NTC_SRVCALL
:
1994 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
1997 case RDBSS_NTC_NETROOT
:
1998 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
2001 case RDBSS_NTC_V_NETROOT
:
2002 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
2005 case RDBSS_NTC_SRVOPEN
:
2006 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
2009 case RDBSS_NTC_FOBX
:
2010 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
2018 /* No need to free - still in use */
2021 RxReleaseScavengerMutex();
2025 /* We have to be locked exclusively */
2026 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
2028 if ((NodeType
== RDBSS_NTC_FOBX
&& RefCount
== 0) ||
2029 (NodeType
>= RDBSS_NTC_SRVCALL
&& NodeType
<= RDBSS_NTC_V_NETROOT
))
2031 RxpMarkInstanceForScavengedFinalization(Instance
);
2034 RxReleaseScavengerMutex();
2039 if (BooleanFlagOn(NodeType
, RX_SCAVENGER_MASK
))
2041 RxpUndoScavengerFinalizationMarking(Instance
);
2045 RxReleaseScavengerMutex();
2047 /* Now, deallocate the memory */
2050 case RDBSS_NTC_SRVCALL
:
2054 SrvCall
= (PSRV_CALL
)Instance
;
2056 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
2057 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
2058 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
2062 case RDBSS_NTC_NETROOT
:
2066 NetRoot
= (PNET_ROOT
)Instance
;
2068 ASSERT(NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2069 ASSERT(RxIsPrefixTableLockAcquired(NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2070 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2074 case RDBSS_NTC_V_NETROOT
:
2076 PV_NET_ROOT VNetRoot
;
2078 VNetRoot
= (PV_NET_ROOT
)Instance
;
2080 ASSERT(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2081 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2082 RxFinalizeVNetRoot(VNetRoot
, TRUE
, TRUE
);
2086 case RDBSS_NTC_SRVOPEN
:
2090 SrvOpen
= (PSRV_OPEN
)Instance
;
2092 ASSERT(RxIsFcbAcquired(SrvOpen
->Fcb
));
2093 if (SrvOpen
->OpenCount
== 0)
2095 RxFinalizeSrvOpen(SrvOpen
, FALSE
, FALSE
);
2100 case RDBSS_NTC_FOBX
:
2104 Fobx
= (PFOBX
)Instance
;
2106 ASSERT(RxIsFcbAcquired(Fobx
->SrvOpen
->Fcb
));
2107 RxFinalizeNetFobx(Fobx
, TRUE
, FALSE
);
2118 RxDereferenceAndDeleteRxContext_Real(
2119 IN PRX_CONTEXT RxContext
)
2124 PRX_CONTEXT StopContext
= NULL
;
2126 /* Make sure we really have a context */
2127 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
2128 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
2129 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
2130 /* If refcount is 0, start releasing stuff that needs spinlock held */
2133 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2135 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
2137 /* If that's stop context from DO, remove it */
2138 RxDeviceObject
= RxContext
->RxDeviceObject
;
2139 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
2141 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
2145 /* Remove it from the list */
2146 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
2147 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
2148 RemoveEntryList(&RxContext
->ContextListEntry
);
2150 /* If that was the last active context, save the stop context */
2151 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
2153 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
2155 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
2160 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
2162 /* Now, deal with what can be done without spinlock held */
2165 /* Refcount shouldn't have changed */
2166 ASSERT(RxContext
->ReferenceCount
== 0);
2167 /* Reset everything that can be */
2168 RxPrepareContextForReuse(RxContext
);
2170 #ifdef RDBSS_TRACKER
2171 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
2173 /* If that was the last active, set the event */
2174 if (StopContext
!= NULL
)
2176 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
2177 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
2180 /* Is ShadowCrit still owned? Shouldn't happen! */
2181 if (RxContext
->ShadowCritOwner
!= 0)
2183 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
2187 /* If it was allocated, free it */
2190 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
2197 RxDispatchChangeBufferingStateRequests(
2208 RxDispatchToWorkerThread(
2209 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
2210 IN WORK_QUEUE_TYPE WorkQueueType
,
2211 IN PRX_WORKERTHREAD_ROUTINE Routine
,
2215 PRX_WORK_DISPATCH_ITEM DispatchItem
;
2217 /* Allocate a bit of context */
2218 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
2219 if (DispatchItem
== NULL
)
2221 return STATUS_INSUFFICIENT_RESOURCES
;
2224 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2225 DispatchItem
->DispatchRoutine
= Routine
;
2226 DispatchItem
->DispatchRoutineParameter
= pContext
;
2227 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
2228 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
2231 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, &DispatchItem
->WorkQueueItem
);
2232 if (!NT_SUCCESS(Status
))
2234 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
2235 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
2238 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
2247 RxExclusivePrefixTableLockToShared(
2248 PRX_PREFIX_TABLE Table
)
2252 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
2259 RxExtractServerName(
2260 IN PUNICODE_STRING FilePathName
,
2261 OUT PUNICODE_STRING SrvCallName
,
2262 OUT PUNICODE_STRING RestOfName
)
2268 ASSERT(SrvCallName
!= NULL
);
2270 /* SrvCall name will start from the begin up to the first separator */
2271 SrvCallName
->Buffer
= FilePathName
->Buffer
;
2272 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2274 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2280 /* Compute length */
2281 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
2282 SrvCallName
->MaximumLength
= Length
;
2283 SrvCallName
->Length
= Length
;
2285 /* Return the rest if asked */
2286 if (RestOfName
!= NULL
)
2288 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
2289 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2290 RestOfName
->MaximumLength
= Length
;
2291 RestOfName
->Length
= Length
;
2299 RxFcbTableInsertFcb(
2300 IN OUT PRX_FCB_TABLE FcbTable
,
2305 /* We deal with the table, make sure it's locked */
2306 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2308 /* Compute the hash */
2309 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2311 RxReferenceNetFcb(Fcb
);
2313 /* If no length, it will be our null entry */
2314 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2316 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2318 /* Otherwise, insert in the appropriate bucket */
2321 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2322 &Fcb
->FcbTableEntry
.HashLinks
);
2325 /* Propagate the change by incrementing the version number */
2326 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2328 return STATUS_SUCCESS
;
2335 RxFcbTableLookupFcb(
2336 IN PRX_FCB_TABLE FcbTable
,
2337 IN PUNICODE_STRING Path
)
2340 PRX_FCB_TABLE_ENTRY TableEntry
;
2344 /* No path - easy, that's null entry */
2347 TableEntry
= FcbTable
->TableEntryForNull
;
2352 PLIST_ENTRY HashBucket
, ListEntry
;
2354 /* Otherwise, compute the hash value and find the associated bucket */
2355 Hash
= RxTableComputePathHashValue(Path
);
2356 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2357 /* If the bucket is empty, it means there's no entry yet */
2358 if (IsListEmpty(HashBucket
))
2364 /* Otherwise, browse all the entry */
2365 for (ListEntry
= HashBucket
->Flink
;
2366 ListEntry
!= HashBucket
;
2367 ListEntry
= ListEntry
->Flink
)
2369 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2370 InterlockedIncrement(&FcbTable
->Compares
);
2372 /* If entry hash and string are equal, thatt's the one! */
2373 if (TableEntry
->HashValue
== Hash
&&
2374 TableEntry
->Path
.Length
== Path
->Length
&&
2375 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2381 /* We reached the end? Not found */
2382 if (ListEntry
== HashBucket
)
2389 InterlockedIncrement(&FcbTable
->Lookups
);
2391 /* If table entry isn't null, return the FCB */
2392 if (TableEntry
!= NULL
)
2394 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2395 RxReferenceNetFcb(Fcb
);
2400 InterlockedIncrement(&FcbTable
->FailedLookups
);
2410 RxFcbTableRemoveFcb(
2411 IN OUT PRX_FCB_TABLE FcbTable
,
2416 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2418 /* If no path, then remove entry for null */
2419 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2421 FcbTable
->TableEntryForNull
= NULL
;
2423 /* Otherwise, remove from the bucket */
2426 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2429 /* Reset its list entry */
2430 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2432 /* Propagate the change by incrementing the version number */
2433 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2435 return STATUS_SUCCESS
;
2443 RxFinalizeConnection(
2444 IN OUT PNET_ROOT NetRoot
,
2445 IN OUT PV_NET_ROOT VNetRoot OPTIONAL
,
2446 IN LOGICAL ForceFilesClosed
)
2449 PRX_PREFIX_TABLE PrefixTable
;
2450 ULONG UncleanAny
, UncleanDir
;
2451 LONG FilesOpen
, AdditionalRef
;
2452 BOOLEAN PrefixLocked
, FcbTableLocked
, ForceClose
;
2456 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
2458 /* Get a BOOLEAN out of LOGICAL
2459 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2461 ForceClose
= (ForceFilesClosed
== TRUE
? TRUE
: FALSE
);
2463 /* First, delete any notification change */
2464 Status
= RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot
, ForceClose
);
2465 /* If it failed, continue if forced */
2466 if (Status
!= STATUS_SUCCESS
&& !ForceFilesClosed
)
2470 /* Reset status, in case notification deletion failed */
2471 Status
= STATUS_SUCCESS
;
2473 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2475 PrefixLocked
= FALSE
;
2476 FcbTableLocked
= FALSE
;
2483 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2484 PrefixLocked
= TRUE
;
2486 RxReferenceNetRoot(NetRoot
);
2488 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2489 FcbTableLocked
= TRUE
;
2491 /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2492 if (!VNetRoot
->ConnectionFinalizationDone
)
2495 PRX_FCB_TABLE FcbTable
;
2497 DPRINT("Finalizing connection %p: %wZ\n", NetRoot
, &NetRoot
->PrefixEntry
.Prefix
);
2499 /* We'll browse all its associated FCB to check whether they're open/orphaned */
2500 FcbTable
= &NetRoot
->FcbTable
;
2501 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2503 PLIST_ENTRY BucketList
, Entry
;
2505 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
2506 Entry
= BucketList
->Flink
;
2507 while (Entry
!= BucketList
)
2511 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
2512 Entry
= Entry
->Flink
;
2514 /* FCB for this connection, go ahead */
2515 if (Fcb
->VNetRoot
== VNetRoot
)
2517 /* It's still open, and no force? Fail and keep track */
2518 if (Fcb
->UncleanCount
> 0 && !ForceClose
)
2520 Status
= STATUS_CONNECTION_IN_USE
;
2521 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2532 /* Else, force purge */
2533 ASSERT(NodeTypeIsFcb(Fcb
));
2535 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
2536 ASSERT(Status
== STATUS_SUCCESS
);
2538 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2540 RxScavengeRelatedFobxs(Fcb
);
2543 /* We don't need to release FCB lock, FCB finalize will take care of it */
2549 /* No files left, our V_NET_ROOT is finalized */
2550 if (VNetRoot
->NumberOfFobxs
== 0)
2552 VNetRoot
->ConnectionFinalizationDone
= TRUE
;
2556 /* Keep Number of open files and track of the extra reference */
2557 FilesOpen
= VNetRoot
->NumberOfFobxs
;
2558 AdditionalRef
= VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
;
2559 /* If force close, caller doesn't want to keep connection alive
2560 * and wants it totally close, so drop the V_NET_ROOT too
2564 RxFinalizeVNetRoot(VNetRoot
, FALSE
, TRUE
);
2569 /* Release what was acquired */
2572 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2575 /* If close is forced, only fix status if there are open files */
2578 if (Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0)
2580 Status
= STATUS_FILES_OPEN
;
2583 /* Else, fix status and fail closing if there are open files */
2586 if ((Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0) || FilesOpen
> 0)
2588 Status
= STATUS_FILES_OPEN
;
2592 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny
, UncleanDir
, FilesOpen
);
2594 /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2595 * only if it was still referenced!
2597 if ((ForceFilesClosed
== 0xFF || Status
== STATUS_SUCCESS
) && AdditionalRef
!= 0)
2599 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2600 RxDereferenceVNetRoot(VNetRoot
, LHS_ExclusiveLockHeld
);
2605 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2606 RxReleasePrefixTableLock(PrefixTable
);
2619 IN OUT PRX_FCB_TABLE FcbTable
)
2625 /* Just delete the lock */
2626 ExDeleteResourceLite(&FcbTable
->TableLock
);
2628 /* And make sure (checked) that the table is really empty... */
2629 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2631 ASSERT(IsListEmpty(&FcbTable
->HashBuckets
[Bucket
]));
2641 IN BOOLEAN RecursiveFinalize
,
2642 IN BOOLEAN ForceFinalize
,
2643 IN LONG ReferenceCount
)
2647 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2648 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2650 /* Make sure we have an exclusively acquired FCB */
2651 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2652 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2654 /* We shouldn't force finalization... */
2655 ASSERT(!ForceFinalize
);
2657 /* If recurisve, finalize all the associated SRV_OPEN */
2658 if (RecursiveFinalize
)
2660 PLIST_ENTRY ListEntry
;
2662 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2663 ListEntry
!= &ThisFcb
->SrvOpenList
;
2664 ListEntry
= ListEntry
->Flink
)
2668 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2669 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2672 /* If FCB is still in use, that's over */
2675 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2677 ASSERT(ReferenceCount
> 0);
2683 ASSERT(ReferenceCount
>= 1);
2685 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2686 if (ReferenceCount
!= 1 && !ForceFinalize
)
2691 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2693 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb
->OpenCount
, ForceFinalize
);
2695 /* If finalization was not already initiated, go ahead */
2696 if (!ThisFcb
->UpperFinalizationDone
)
2698 /* Free any FCB_LOCK */
2699 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2701 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2703 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2707 Entry
= ThisFcb
->BufferedLocks
.List
;
2708 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2714 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2715 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2719 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2721 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2723 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2725 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2729 ThisFcb
->UpperFinalizationDone
= TRUE
;
2732 ASSERT(ReferenceCount
>= 1);
2734 /* Even if forced, don't allow broken free */
2735 if (ReferenceCount
!= 1)
2740 /* Now, release everything */
2741 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2743 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2746 if (ThisFcb
->MRxDispatch
!= NULL
)
2748 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2751 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2752 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2753 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2755 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2756 RxDereferenceVNetRoot(ThisFcb
->VNetRoot
, LHS_LockNotHeld
);
2758 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2759 ASSERT(!ThisFcb
->fMiniInited
);
2761 /* And free the object */
2762 RxFreeFcbObject(ThisFcb
);
2772 _Out_ PFOBX ThisFobx
,
2773 _In_ BOOLEAN RecursiveFinalize
,
2774 _In_ BOOLEAN ForceFinalize
)
2781 ASSERT(NodeType(ThisFobx
) == RDBSS_NTC_FOBX
);
2783 /* Only finalize if forced or if there's no ref left */
2784 if (ThisFobx
->NodeReferenceCount
!= 0 &&
2790 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx
, ThisFobx
->NodeReferenceCount
, ForceFinalize
);
2792 SrvOpen
= ThisFobx
->SrvOpen
;
2794 /* If it wasn't finalized yet, do it */
2795 if (!ThisFobx
->UpperFinalizationDone
)
2797 ASSERT(NodeType(SrvOpen
->Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
2798 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
2800 /* Remove it from the SRV_OPEN */
2801 RemoveEntryList(&ThisFobx
->FobxQLinks
);
2803 /* If we were used to browse a directory, free the query buffer */
2804 if (BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_FREE_UNICODE
))
2806 RxFreePoolWithTag(ThisFobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
2809 /* Notify the mini-rdr */
2810 if (Fcb
->MRxDispatch
!= NULL
&& Fcb
->MRxDispatch
->MRxDeallocateForFobx
!= NULL
)
2812 Fcb
->MRxDispatch
->MRxDeallocateForFobx((PMRX_FOBX
)ThisFobx
);
2815 /* If the SRV_OPEN wasn't closed yet, do it */
2816 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
2820 Status
= RxCloseAssociatedSrvOpen(ThisFobx
, FALSE
);
2821 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen
, ThisFobx
, Status
);
2824 /* Finalization done */
2825 ThisFobx
->UpperFinalizationDone
= TRUE
;
2828 /* If we're still referenced, don't go any further! */
2829 if (ThisFobx
->NodeReferenceCount
!= 0)
2834 /* At that point, everything should be closed */
2835 ASSERT(IsListEmpty(&ThisFobx
->ClosePendingList
));
2837 /* Was the FOBX allocated with another object?
2838 * If so, mark the buffer free in said object
2840 if (ThisFobx
== Fcb
->InternalFobx
)
2842 ClearFlag(Fcb
->FcbState
, FCB_STATE_FOBX_USED
);
2844 else if (ThisFobx
== SrvOpen
->InternalFobx
)
2846 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
);
2849 ThisFobx
->pSrvOpen
= NULL
;
2852 InterlockedDecrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
2854 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
2856 /* If it wasn't allocated with another object, free the FOBX */
2857 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_ENCLOSED_ALLOCATED
))
2859 RxFreeFcbObject(ThisFobx
);
2870 OUT PNET_ROOT ThisNetRoot
,
2871 IN BOOLEAN RecursiveFinalize
,
2872 IN BOOLEAN ForceFinalize
)
2875 PRX_FCB_TABLE FcbTable
;
2876 PRX_PREFIX_TABLE PrefixTable
;
2880 ASSERT(NodeType(ThisNetRoot
) == RDBSS_NTC_NETROOT
);
2882 PrefixTable
= ThisNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2883 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
2885 /* If sme finalization is already ongoing, leave */
2886 if (BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
))
2891 /* Mark we're finalizing */
2892 SetFlag(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
);
2894 FcbTable
= &ThisNetRoot
->FcbTable
;
2895 /* Did caller asked us to finalize any associated FCB? */
2896 if (RecursiveFinalize
)
2900 /* Browse all the FCBs in our FCB table */
2901 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
2902 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2904 PLIST_ENTRY HashBucket
, ListEntry
;
2906 HashBucket
= &FcbTable
->HashBuckets
[Bucket
];
2907 ListEntry
= HashBucket
->Flink
;
2908 while (ListEntry
!= HashBucket
)
2912 Fcb
= CONTAINING_RECORD(ListEntry
, FCB
, FcbTableEntry
.HashLinks
);
2913 ASSERT(NodeTypeIsFcb(Fcb
));
2915 ListEntry
= ListEntry
->Flink
;
2917 /* If the FCB isn't orphaned, then, it's time to purge it */
2918 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
2922 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
2923 ASSERT(Status
== STATUS_SUCCESS
);
2928 RxReleaseFcbTableLock(FcbTable
);
2931 /* Only finalize if forced or if there's a single ref left */
2932 if (ThisNetRoot
->NodeReferenceCount
!= 1 && !ForceFinalize
)
2937 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot
, &ThisNetRoot
->PrefixEntry
.Prefix
);
2939 /* If we're still referenced, don't go any further! */
2940 if (ThisNetRoot
->NodeReferenceCount
!= 1)
2945 /* Finalize the FCB table (and make sure it's empty!) */
2946 RxFinalizeFcbTable(FcbTable
);
2948 /* If name wasn't remove already, do it now */
2949 if (!BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
2951 RxRemovePrefixTableEntry(PrefixTable
, &ThisNetRoot
->PrefixEntry
);
2954 /* Delete the object */
2955 SrvCall
= (PSRV_CALL
)ThisNetRoot
->pSrvCall
;
2956 RxFreeObject(ThisNetRoot
);
2958 /* And dereference the associated SRV_CALL */
2959 if (SrvCall
!= NULL
)
2961 RxDereferenceSrvCall(SrvCall
, LHS_ExclusiveLockHeld
);
2972 OUT PSRV_CALL ThisSrvCall
,
2973 IN BOOLEAN RecursiveFinalize
,
2974 IN BOOLEAN ForceFinalize
)
2976 PRX_PREFIX_TABLE PrefixTable
;
2980 ASSERT(NodeType(ThisSrvCall
) == RDBSS_NTC_SRVCALL
);
2982 PrefixTable
= ThisSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2983 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
2985 /* Only finalize if forced or if there's a single ref left */
2986 if (ThisSrvCall
->NodeReferenceCount
!= 1 &&
2992 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall
, &ThisSrvCall
->PrefixEntry
.Prefix
);
2994 /* If it wasn't finalized yet, do it */
2995 if (!ThisSrvCall
->UpperFinalizationDone
)
2999 /* Remove ourselves from prefix table */
3000 RxRemovePrefixTableEntry(PrefixTable
, &ThisSrvCall
->PrefixEntry
);
3002 /* Remember our third arg, in case we get queued for later execution */
3005 SetFlag(ThisSrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
3009 ThisSrvCall
->UpperFinalizationDone
= TRUE
;
3011 /* Would defered execution free the object? */
3012 WillFree
= (ThisSrvCall
->NodeReferenceCount
== 1);
3014 /* If we have a device object */
3015 if (ThisSrvCall
->RxDeviceObject
!= NULL
)
3019 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3020 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3022 /* Extra ref, as usual */
3023 InterlockedIncrement((volatile long *)&ThisSrvCall
->NodeReferenceCount
);
3025 RxDispatchToWorkerThread(ThisSrvCall
->RxDeviceObject
, DelayedWorkQueue
, RxpDestroySrvCall
, ThisSrvCall
);
3027 /* Return to the caller, in advance, whether we're freeing the object or not */
3031 /* If in the right thread already, call the mini-rdr */
3032 MINIRDR_CALL_THROUGH(Status
, ThisSrvCall
->RxDeviceObject
->Dispatch
,
3033 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)ThisSrvCall
, ForceFinalize
));
3038 /* If we're still referenced, don't go any further! */
3039 if (ThisSrvCall
->NodeReferenceCount
!= 1)
3045 if (ThisSrvCall
->pDomainName
!= NULL
)
3047 RxFreePool(ThisSrvCall
->pDomainName
);
3051 RxTearDownBufferingManager(ThisSrvCall
);
3052 RxFreeObject(ThisSrvCall
);
3062 OUT PSRV_OPEN ThisSrvOpen
,
3063 IN BOOLEAN RecursiveFinalize
,
3064 IN BOOLEAN ForceFinalize
)
3070 /* We have to have a SRV_OPEN */
3071 ASSERT(NodeType(ThisSrvOpen
) == RDBSS_NTC_SRVOPEN
);
3073 /* If that's a recursive finalization, finalize any related FOBX */
3074 if (RecursiveFinalize
)
3076 PLIST_ENTRY ListEntry
;
3078 ListEntry
= ThisSrvOpen
->FobxList
.Flink
;
3079 while (ListEntry
!= &ThisSrvOpen
->FobxList
)
3083 Fobx
= CONTAINING_RECORD(ListEntry
, FOBX
, FobxQLinks
);
3084 ListEntry
= ListEntry
->Flink
;
3085 RxFinalizeNetFobx(Fobx
, TRUE
, ForceFinalize
);
3089 /* If we have still references, don't finalize unless forced */
3090 if (ThisSrvOpen
->NodeReferenceCount
!= 0 &&
3096 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen
, ThisSrvOpen
->NodeReferenceCount
, ForceFinalize
);
3098 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3099 Fcb
= (PFCB
)ThisSrvOpen
->pFcb
;
3100 if ((!ThisSrvOpen
->UpperFinalizationDone
&& ThisSrvOpen
->Condition
!= Condition_Good
) ||
3101 BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
3103 PV_NET_ROOT VNetRoot
;
3105 /* Associated FCB can't be fake one */
3106 ASSERT(NodeType(Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
3107 ASSERT(RxIsFcbAcquiredExclusive (Fcb
));
3109 /* Purge any pending operation */
3110 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen
);
3112 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3113 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3117 MINIRDR_CALL_THROUGH(Status
, Fcb
->MRxDispatch
, MRxForceClosed
, ((PMRX_SRV_OPEN
)ThisSrvOpen
));
3121 /* Remove ourselves from the FCB */
3122 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3123 InitializeListHead(&ThisSrvOpen
->SrvOpenQLinks
);
3124 ++Fcb
->SrvOpenListVersion
;
3126 /* If we have a V_NET_ROOT, dereference it */
3127 VNetRoot
= (PV_NET_ROOT
)ThisSrvOpen
->pVNetRoot
;
3128 if (VNetRoot
!= NULL
)
3130 InterlockedDecrement((volatile long *)&VNetRoot
->pNetRoot
->NumberOfSrvOpens
);
3131 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3132 ThisSrvOpen
->pVNetRoot
= NULL
;
3135 /* Finalization done */
3136 ThisSrvOpen
->UpperFinalizationDone
= TRUE
;
3139 /* Don't free memory if still referenced */
3140 if (ThisSrvOpen
->NodeReferenceCount
!= 0)
3145 /* No key association left */
3146 ASSERT(IsListEmpty(&ThisSrvOpen
->SrvOpenKeyList
));
3148 /* If we're still in some FCB, remove us */
3149 if (!IsListEmpty(&ThisSrvOpen
->SrvOpenQLinks
))
3151 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3154 /* If enclosed allocation, mark the memory zone free and dereference FCB */
3155 if (BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
))
3157 ClearFlag(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
);
3158 RxDereferenceNetFcb(Fcb
);
3160 /* Otherwise, free the memory */
3163 RxFreeFcbObject(ThisSrvOpen
);
3174 OUT PV_NET_ROOT ThisVNetRoot
,
3175 IN BOOLEAN RecursiveFinalize
,
3176 IN BOOLEAN ForceFinalize
)
3179 PRX_PREFIX_TABLE PrefixTable
;
3183 ASSERT(NodeType(ThisVNetRoot
) == RDBSS_NTC_V_NETROOT
);
3185 PrefixTable
= ThisVNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3186 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3188 /* Only finalize if forced or if there's a single ref left */
3189 if (ThisVNetRoot
->NodeReferenceCount
!= 1 &&
3195 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot
, &ThisVNetRoot
->PrefixEntry
.Prefix
);
3197 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
3198 /* If it wasn't finalized yet, do it */
3199 if (!ThisVNetRoot
->UpperFinalizationDone
)
3201 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
3203 /* Reference the NetRoot so that it doesn't disappear */
3204 RxReferenceNetRoot(NetRoot
);
3205 RxOrphanSrvOpens(ThisVNetRoot
);
3206 /* Remove us from the available VNetRoot for NetRoot */
3207 RxRemoveVirtualNetRootFromNetRoot(NetRoot
, ThisVNetRoot
);
3208 /* Remove extra ref */
3209 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3211 /* Remove ourselves from prefix table */
3212 RxRemovePrefixTableEntry(PrefixTable
, &ThisVNetRoot
->PrefixEntry
);
3214 /* Finalization done */
3215 ThisVNetRoot
->UpperFinalizationDone
= TRUE
;
3218 /* If we're still referenced, don't go any further! */
3219 if (ThisVNetRoot
->NodeReferenceCount
!= 1)
3224 /* If there's an associated device, notify mini-rdr */
3225 if (NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
3229 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
3230 MRxFinalizeVNetRoot
, ((PMRX_V_NET_ROOT
)ThisVNetRoot
, FALSE
));
3234 /* Free parameters */
3235 RxUninitializeVNetRootParameters(ThisVNetRoot
->pUserName
, ThisVNetRoot
->pUserDomainName
,
3236 ThisVNetRoot
->pPassword
, &ThisVNetRoot
->Flags
);
3237 /* Dereference our NetRoot, we won't reference it anymore */
3238 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3240 /* And free the object! */
3241 RxFreePoolWithTag(ThisVNetRoot
, RX_V_NETROOT_POOLTAG
);
3247 RxFindOrConstructVirtualNetRoot(
3248 IN PRX_CONTEXT RxContext
,
3249 IN PUNICODE_STRING CanonicalName
,
3250 IN NET_ROOT_TYPE NetRootType
,
3251 IN PUNICODE_STRING RemainingName
)
3257 PV_NET_ROOT VNetRoot
;
3258 RX_CONNECTION_ID ConnectionID
;
3259 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3260 LOCK_HOLDING_STATE LockHoldingState
;
3264 RxDeviceObject
= RxContext
->RxDeviceObject
;
3265 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
3266 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
3268 /* Ask the mini-rdr for connection ID */
3269 ConnectionID
.SessionID
= 0;
3270 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
3272 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
3273 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
3275 /* mini-rdr is expected not to fail - unless it's not implemented */
3276 DPRINT1("Failed to initialize connection ID\n");
3281 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
3283 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
3284 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3285 LockHoldingState
= LHS_SharedLockHeld
;
3289 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3293 PV_NET_ROOT SavedVNetRoot
;
3295 /* Look in prefix table */
3296 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
3297 if (Container
!= NULL
)
3299 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3300 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
3302 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3303 RxDereferenceSrvCall(Container
, LockHoldingState
);
3307 VNetRoot
= Container
;
3308 NetRoot
= VNetRoot
->NetRoot
;
3310 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3311 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
3312 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3314 Status
= STATUS_BAD_NETWORK_PATH
;
3315 SavedVNetRoot
= NULL
;
3321 PUNICODE_STRING UserName
, UserDomain
, Password
;
3323 /* We can reuse if we use same credentials */
3324 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
3325 &SessionId
, &UserName
,
3326 &UserDomain
, &Password
,
3328 if (NT_SUCCESS(Status
))
3330 SavedVNetRoot
= VNetRoot
;
3331 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
3333 UserDomain
, Password
,
3335 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
3337 PLIST_ENTRY ListEntry
;
3339 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
3340 ListEntry
!= &NetRoot
->VirtualNetRoots
;
3341 ListEntry
= ListEntry
->Flink
)
3343 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
3344 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
3346 UserDomain
, Password
,
3348 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3354 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
3356 SavedVNetRoot
= NULL
;
3360 if (!NT_SUCCESS(Status
))
3362 SavedVNetRoot
= NULL
;
3365 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
3369 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3370 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
3372 if (SavedVNetRoot
== NULL
)
3374 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3377 /* Reference VNetRoot we'll keep, and dereference current */
3378 else if (SavedVNetRoot
!= VNetRoot
)
3380 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3381 if (SavedVNetRoot
!= NULL
)
3383 RxReferenceVNetRoot(SavedVNetRoot
);
3388 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3389 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3396 /* If we're locked exclusive, we won't loop again, it was the second pass */
3397 if (LockHoldingState
!= LHS_SharedLockHeld
)
3402 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3403 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
3405 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3406 LockHoldingState
= LHS_ExclusiveLockHeld
;
3410 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3411 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3412 LockHoldingState
= LHS_ExclusiveLockHeld
;
3415 /* We didn't fail, and didn't find any VNetRoot, construct one */
3418 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
3420 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
3421 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
3423 if (Status
== STATUS_SUCCESS
)
3425 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
3426 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3427 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
3429 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3430 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
3431 RemainingName
->MaximumLength
= RemainingName
->Length
;
3433 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
3435 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
3437 VNetRoot
->Flags
|= Flags
;
3441 /* Release the prefix table - caller expects it to be released */
3442 if (LockHoldingState
!= LHS_LockNotHeld
)
3444 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3447 /* If we failed creating, quit */
3448 if (Status
!= STATUS_SUCCESS
)
3450 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
3454 /* Otherwise, wait until the VNetRoot is stable */
3455 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
3456 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
3457 /* It's all good, update the RX_CONTEXT with all our structs */
3458 if (VNetRoot
->Condition
== Condition_Good
)
3462 NetRoot
= VNetRoot
->NetRoot
;
3463 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3464 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3465 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
3469 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3470 RxContext
->Create
.pVNetRoot
= NULL
;
3471 Status
= STATUS_BAD_NETWORK_PATH
;
3481 RxFindOrCreateConnections(
3482 _In_ PRX_CONTEXT RxContext
,
3483 _In_ PUNICODE_STRING CanonicalName
,
3484 _In_ NET_ROOT_TYPE NetRootType
,
3485 _Out_ PUNICODE_STRING LocalNetRootName
,
3486 _Out_ PUNICODE_STRING FilePathName
,
3487 _Inout_ PLOCK_HOLDING_STATE LockState
,
3488 _In_ PRX_CONNECTION_ID RxConnectionId
)
3493 PV_NET_ROOT VNetRoot
;
3494 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
3495 PRX_PREFIX_TABLE PrefixTable
;
3496 UNICODE_STRING RemainingName
, NetRootName
;
3500 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3501 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
3502 FilePathName
, LockState
, RxConnectionId
);
3504 *FilePathName
= *CanonicalName
;
3505 LocalNetRootName
->Length
= 0;
3506 LocalNetRootName
->MaximumLength
= 0;
3507 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
3509 /* UNC path, split it */
3510 if (FilePathName
->Buffer
[1] == ';')
3516 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
3518 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
3527 return STATUS_OBJECT_NAME_INVALID
;
3530 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
3531 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
3532 LocalNetRootName
->Length
= Length
;
3533 LocalNetRootName
->MaximumLength
= Length
;
3534 FilePathName
->Length
-= Length
;
3536 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
3537 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
3538 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
3542 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
3547 ASSERT(*LockState
!= LHS_LockNotHeld
);
3549 /* If previous lookup left something, dereference it */
3550 if (Container
!= NULL
)
3552 switch (NodeType(Container
))
3554 case RDBSS_NTC_SRVCALL
:
3555 RxDereferenceSrvCall(Container
, *LockState
);
3558 case RDBSS_NTC_NETROOT
:
3559 RxDereferenceNetRoot(Container
, *LockState
);
3562 case RDBSS_NTC_V_NETROOT
:
3563 RxDereferenceVNetRoot(Container
, *LockState
);
3567 /* Should never happen */
3573 /* Look for our NetRoot in prefix table */
3574 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
3575 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
3579 UNICODE_STRING SrvCallName
;
3585 /* Assume we didn't succeed */
3586 RxContext
->Create
.pVNetRoot
= NULL
;
3587 RxContext
->Create
.pNetRoot
= NULL
;
3588 RxContext
->Create
.pSrvCall
= NULL
;
3589 RxContext
->Create
.Type
= NetRootType
;
3591 /* If we found something */
3592 if (Container
!= NULL
)
3595 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
3597 VNetRoot
= Container
;
3598 /* Use its NetRoot */
3599 NetRoot
= VNetRoot
->NetRoot
;
3601 /* If it's not stable, wait for it to be stable */
3602 if (NetRoot
->Condition
== Condition_InTransition
)
3604 RxReleasePrefixTableLock(PrefixTable
);
3605 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
3606 RxWaitForStableNetRoot(NetRoot
, RxContext
);
3607 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3608 *LockState
= LHS_ExclusiveLockHeld
;
3610 /* Now that's it's ok, retry lookup to find what we want */
3611 if (NetRoot
->Condition
== Condition_Good
)
3617 /* Is the associated netroot good? */
3618 if (NetRoot
->Condition
== Condition_Good
)
3620 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
3622 /* If it is, and SrvCall as well, then, we have our active connection */
3623 if (SrvCall
->Condition
== Condition_Good
&&
3624 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
3626 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3627 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3628 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3630 Status
= STATUS_CONNECTION_ACTIVE
;
3635 /* If VNetRoot was well constructed, it means the connection is active */
3636 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
3638 Status
= STATUS_CONNECTION_ACTIVE
;
3642 Status
= VNetRoot
->ConstructionStatus
;
3645 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3648 /* Can only be a SrvCall */
3651 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3652 SrvCall
= Container
;
3654 /* Wait for the SRV_CALL to be stable */
3655 if (SrvCall
->Condition
== Condition_InTransition
)
3657 RxReleasePrefixTableLock(PrefixTable
);
3658 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
3659 RxWaitForStableSrvCall(SrvCall
, RxContext
);
3660 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3661 *LockState
= LHS_ExclusiveLockHeld
;
3663 /* It went good, loop again to find what we look for */
3664 if (SrvCall
->Condition
== Condition_Good
)
3670 /* If it's not good... */
3671 if (SrvCall
->Condition
!= Condition_Good
)
3673 /* But SRV_CALL was well constructed, assume a connection was active */
3674 if (SrvCall
->Status
== STATUS_SUCCESS
)
3676 Status
= STATUS_CONNECTION_ACTIVE
;
3680 Status
= SrvCall
->Status
;
3683 RxDereferenceSrvCall(SrvCall
, *LockState
);
3689 /* If we found a SRV_CALL not matching our DO, quit */
3690 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
3691 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3693 RxDereferenceSrvCall(SrvCall
, *LockState
);
3694 Status
= STATUS_BAD_NETWORK_NAME
;
3698 /* Now, we want exclusive lock */
3699 if (*LockState
== LHS_SharedLockHeld
)
3701 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
3703 RxReleasePrefixTableLock(PrefixTable
);
3704 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3705 *LockState
= LHS_ExclusiveLockHeld
;
3709 RxReleasePrefixTableLock(PrefixTable
);
3710 *LockState
= LHS_ExclusiveLockHeld
;
3713 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3715 /* If we reach that point, we found something, no need to create something */
3716 if (Container
!= NULL
)
3721 /* Get the name for the SRV_CALL */
3722 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
3723 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
3724 /* And create the SRV_CALL */
3725 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
3726 if (SrvCall
== NULL
)
3728 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3732 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3733 RxReferenceSrvCall(SrvCall
);
3734 RxContext
->Create
.pVNetRoot
= NULL
;
3735 RxContext
->Create
.pNetRoot
= NULL
;
3736 RxContext
->Create
.pSrvCall
= NULL
;
3737 RxContext
->Create
.Type
= NetRootType
;
3738 Container
= SrvCall
;
3740 /* Construct SRV_CALL, ie, use mini-rdr */
3741 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
3742 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
3743 if (Status
!= STATUS_SUCCESS
)
3745 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
3746 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3747 RxDereferenceSrvCall(SrvCall
, *LockState
);
3748 RxReleasePrefixTableLock(PrefixTable
);
3752 /* Loop again to make use of SRV_CALL stable condition wait */
3755 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3756 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
3757 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
3758 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
3760 /* Call mini-rdr to get NetRoot name */
3761 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
3762 /* And create the NetRoot with that name */
3763 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
3764 if (NetRoot
== NULL
)
3766 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3769 NetRoot
->Type
= NetRootType
;
3771 RxDereferenceSrvCall(SrvCall
, *LockState
);
3773 /* Finally, create the associated VNetRoot */
3774 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
3775 if (VNetRoot
== NULL
)
3777 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
3778 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3781 RxReferenceVNetRoot(VNetRoot
);
3783 /* We're get closer! */
3784 NetRoot
->Condition
= Condition_InTransition
;
3785 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3786 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3787 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3789 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3790 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
3791 if (!NT_SUCCESS(Status
))
3793 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
3794 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
3795 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3797 RxContext
->Create
.pNetRoot
= NULL
;
3798 RxContext
->Create
.pVNetRoot
= NULL
;
3802 PIO_STACK_LOCATION Stack
;
3804 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3806 Stack
= RxContext
->CurrentIrpSp
;
3807 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
3809 RxExclusivePrefixTableLockToShared(PrefixTable
);
3810 *LockState
= LHS_SharedLockHeld
;
3816 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
3818 if (*LockState
!= LHS_LockNotHeld
)
3820 RxReleasePrefixTableLock(PrefixTable
);
3821 *LockState
= LHS_LockNotHeld
;
3827 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
3836 RxFinishFcbInitialization(
3837 IN OUT PMRX_FCB Fcb
,
3838 IN RX_FILE_TYPE FileType
,
3839 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
3841 RX_FILE_TYPE OldType
;
3845 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
3847 OldType
= NodeType(Fcb
);
3848 NodeType(Fcb
) = FileType
;
3849 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
3850 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
3852 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3854 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
3855 else if (InitPacket
!= NULL
)
3857 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
3858 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
3859 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
3860 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
3861 InitPacket
->pValidDataLength
->QuadPart
);
3864 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3865 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3867 /* If our FCB newly points to a file, initiliaze everything related */
3868 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
)
3871 if (OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
3873 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
3874 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, RxLockOperationCompletion
,
3877 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
3878 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
3880 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
3883 /* If not a file, validate type */
3886 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
3895 RxFinishSrvCallConstruction(
3896 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
3900 PRX_CONTEXT Context
;
3901 RX_BLOCK_CONDITION Condition
;
3902 PRX_PREFIX_TABLE PrefixTable
;
3904 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
3906 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
3907 Context
= Calldown
->RxContext
;
3908 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
3910 /* We have a winner, notify him */
3911 if (Calldown
->BestFinisher
!= NULL
)
3913 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
3915 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
3917 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
3918 MRxSrvCallWinnerNotify
,
3919 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
3920 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
3921 if (Status
!= STATUS_SUCCESS
)
3923 Condition
= Condition_Bad
;
3927 Condition
= Condition_Good
;
3930 /* Otherwise, just fail our SRV_CALL */
3933 Status
= Calldown
->CallbackContexts
[0].Status
;
3934 Condition
= Condition_Bad
;
3937 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3938 RxTransitionSrvCall(SrvCall
, Condition
);
3939 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
3941 /* If async, finish it here, otherwise, caller has already finished the stuff */
3942 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
3944 DPRINT("Finishing async call\n");
3946 RxReleasePrefixTableLock(PrefixTable
);
3948 /* Make sure we weren't cancelled in-between */
3949 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
3951 Status
= STATUS_CANCELLED
;
3954 /* In case that was a create, context can be reused */
3955 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
3957 RxpPrepareCreateContextForReuse(Context
);
3960 /* If that's a failure, reset everything and return failure */
3961 if (Status
!= STATUS_SUCCESS
)
3963 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
3964 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3966 if (Context
->Info
.Buffer
!= NULL
)
3968 RxFreePool(Context
->Info
.Buffer
);
3969 Context
->Info
.Buffer
= NULL
;
3972 Context
->CurrentIrp
->IoStatus
.Information
= 0;
3973 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
3974 RxCompleteRequest(Context
, Status
);
3976 /* Otherwise, call resume routine and done! */
3979 Status
= Context
->ResumeRoutine(Context
);
3980 if (Status
!= STATUS_PENDING
)
3982 RxCompleteRequest(Context
, Status
);
3985 DPRINT("Not completing, pending\n");
3989 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
3998 RxFinishSrvCallConstructionDispatcher(
4002 BOOLEAN Direct
, KeepLoop
;
4004 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
4006 /* In case of failure of starting dispatcher, context is not set
4007 * We keep track of it to fail associated SRV_CALL
4009 Direct
= (Context
== NULL
);
4011 /* Separated thread, loop forever */
4014 PLIST_ENTRY ListEntry
;
4015 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
4017 /* If there are no SRV_CALL to finalize left, just finish thread */
4018 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
4019 if (IsListEmpty(&RxSrvCalldownList
))
4022 RxSrvCallConstructionDispatcherActive
= FALSE
;
4024 /* Otherwise, get the SRV_CALL to finish construction */
4027 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
4030 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
4038 /* If direct is set, reset the finisher to avoid electing a winner
4039 * and fail SRV_CALL (see upper comment)
4041 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
4044 Calldown
->BestFinisher
= NULL
;
4046 /* Finish SRV_CALL construction */
4047 RxFinishSrvCallConstruction(Calldown
);
4055 RxFlushFcbInSystemCache(
4057 IN BOOLEAN SynchronizeWithLazyWriter
)
4059 IO_STATUS_BLOCK IoStatus
;
4064 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &IoStatus
);
4065 /* If we're asked to sync with LW, do it in case of success */
4066 if (SynchronizeWithLazyWriter
&& NT_SUCCESS(IoStatus
.Status
))
4068 RxAcquirePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4069 RxReleasePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4072 DPRINT("Flushing for FCB %p returns %lx\n", Fcb
, IoStatus
.Status
);
4073 return IoStatus
.Status
;
4085 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4086 if (NodeType(Object
) == RDBSS_NTC_FOBX
|| NodeType(Object
) == RDBSS_NTC_SRVOPEN
)
4088 RxFreePoolWithTag(Object
, RX_FCB_POOLTAG
);
4090 /* If that's a FCB... */
4091 else if (NodeTypeIsFcb(Object
))
4094 PRDBSS_DEVICE_OBJECT DeviceObject
;
4097 DeviceObject
= Fcb
->RxDeviceObject
;
4099 /* Delete per stream contexts */
4100 FsRtlTeardownPerStreamContexts(&Fcb
->Header
);
4102 SetFlag(Fcb
->Header
.Flags
, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH
);
4104 /* If there was a non-paged FCB allocated, free it */
4105 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
4107 RxFreePoolWithTag(Fcb
->NonPaged
, RX_NONPAGEDFCB_POOLTAG
);
4113 /* Update statistics */
4114 InterlockedDecrement(&RxNumberOfActiveFcbs
);
4115 InterlockedDecrement((volatile long *)&DeviceObject
->NumberOfActiveFcbs
);
4128 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4129 if (NodeType(pObject
) == RDBSS_NTC_SRVCALL
)
4132 PRDBSS_DEVICE_OBJECT DeviceObject
;
4134 SrvCall
= (PSRV_CALL
)pObject
;
4135 DeviceObject
= SrvCall
->RxDeviceObject
;
4136 if (DeviceObject
!= NULL
)
4138 if (!BooleanFlagOn(DeviceObject
->Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
4140 ASSERT(SrvCall
->Context
== NULL
);
4143 ASSERT(SrvCall
->Context2
== NULL
);
4145 SrvCall
->RxDeviceObject
= NULL
;
4148 else if (NodeType(pObject
) == RDBSS_NTC_NETROOT
)
4152 NetRoot
= (PNET_ROOT
)pObject
;
4153 NetRoot
->pSrvCall
= NULL
;
4154 NetRoot
->NodeTypeCode
= NodeType(pObject
) | 0xF000;
4157 /* And just free the object */
4158 RxFreePool(pObject
);
4165 RxGatherRequestsForSrvOpen(
4166 IN OUT PSRV_CALL SrvCall
,
4167 IN PSRV_OPEN SrvOpen
,
4168 IN OUT PLIST_ENTRY RequestsListHead
)
4171 LIST_ENTRY Discarded
, *Entry
;
4172 PCHANGE_BUFFERING_STATE_REQUEST Request
;
4174 /* Dispatch any pending operation first */
4175 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &Discarded
);
4177 /* Then, get any entry related to our key and SRV_OPEN */
4178 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
4179 Entry
= SrvCall
->BufferingManager
.HandlerList
.Flink
;
4180 while (Entry
!= &SrvCall
->BufferingManager
.HandlerList
)
4182 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4183 Entry
= Entry
->Flink
;
4184 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4186 RemoveEntryList(&Request
->ListEntry
);
4187 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4190 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
4192 /* Perform the same search in the last change list */
4193 Entry
= SrvCall
->BufferingManager
.LastChanceHandlerList
.Flink
;
4194 while (Entry
!= &SrvCall
->BufferingManager
.LastChanceHandlerList
)
4196 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4197 Entry
= Entry
->Flink
;
4198 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4200 RemoveEntryList(&Request
->ListEntry
);
4201 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4205 /* Discard the discarded requests */
4206 RxpDiscardChangeBufferingStateRequests(&Discarded
);
4212 PRDBSS_DEVICE_OBJECT
4213 RxGetDeviceObjectOfInstance(
4216 NODE_TYPE_CODE NodeType
;
4217 PRDBSS_DEVICE_OBJECT DeviceObject
;
4221 /* We only handle a few object types */
4222 NodeType
= NodeType(Instance
);
4223 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
4224 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) || (NodeType
== RDBSS_NTC_FOBX
));
4226 /* Get the device object depending on the object */
4229 case RDBSS_NTC_FOBX
:
4233 Fobx
= (PFOBX
)Instance
;
4234 DeviceObject
= Fobx
->RxDeviceObject
;
4238 case RDBSS_NTC_SRVCALL
:
4242 SrvCall
= (PSRV_CALL
)Instance
;
4243 DeviceObject
= SrvCall
->RxDeviceObject
;
4247 case RDBSS_NTC_NETROOT
:
4251 NetRoot
= (PNET_ROOT
)Instance
;
4252 DeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
4256 case RDBSS_NTC_V_NETROOT
:
4258 PV_NET_ROOT VNetRoot
;
4260 VNetRoot
= (PV_NET_ROOT
)Instance
;
4261 DeviceObject
= VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
;
4265 case RDBSS_NTC_SRVOPEN
:
4269 SrvOpen
= (PSRV_OPEN
)Instance
;
4270 DeviceObject
= ((PFCB
)SrvOpen
->pFcb
)->RxDeviceObject
;
4275 DeviceObject
= NULL
;
4280 return DeviceObject
;
4287 RxGetFileSizeWithLock(
4289 OUT PLONGLONG FileSize
)
4293 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
4304 return RxData
.OurProcess
;
4311 RxInitializeBufferingManager(
4314 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
4315 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
4316 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
4317 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
4318 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
4319 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
4320 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
4321 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
4322 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
4323 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
4325 return STATUS_SUCCESS
;
4333 RxInitializeContext(
4335 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
4336 IN ULONG InitialContextFlags
,
4337 IN OUT PRX_CONTEXT RxContext
)
4339 PIO_STACK_LOCATION Stack
;
4341 /* Initialize our various fields */
4342 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
4343 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
4344 RxContext
->ReferenceCount
= 1;
4345 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
4346 RxContext
->RxDeviceObject
= RxDeviceObject
;
4347 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
4348 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
4349 InitializeListHead(&RxContext
->BlockedOperations
);
4350 RxContext
->MRxCancelRoutine
= NULL
;
4351 RxContext
->ResumeRoutine
= NULL
;
4352 RxContext
->Flags
|= InitialContextFlags
;
4353 RxContext
->CurrentIrp
= Irp
;
4354 RxContext
->LastExecutionThread
= PsGetCurrentThread();
4355 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
4357 /* If've got no IRP, mark RX_CONTEXT */
4360 RxContext
->CurrentIrpSp
= NULL
;
4361 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
4362 RxContext
->MinorFunction
= 0;
4366 /* Otherwise, first determine whether we are performing async operation */
4367 Stack
= IoGetCurrentIrpStackLocation(Irp
);
4368 if (Stack
->FileObject
!= NULL
)
4372 Fcb
= Stack
->FileObject
->FsContext
;
4373 if (!IoIsOperationSynchronous(Irp
) ||
4374 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
4375 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
4376 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
4378 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4382 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
4384 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4386 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4388 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4391 /* Set proper flags if TopLevl IRP/Device */
4392 if (!RxIsThisTheTopLevelIrp(Irp
))
4394 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
4396 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
4398 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
4401 /* Copy stack information */
4402 RxContext
->MajorFunction
= Stack
->MajorFunction
;
4403 RxContext
->MinorFunction
= Stack
->MinorFunction
;
4404 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
4405 RxContext
->CurrentIrpSp
= Stack
;
4407 /* If we have a FO associated, learn for more */
4408 if (Stack
->FileObject
!= NULL
)
4413 /* Get the FCB and CCB (FOBX) */
4414 Fcb
= Stack
->FileObject
->FsContext
;
4415 Fobx
= Stack
->FileObject
->FsContext2
;
4416 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
4417 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
4419 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
4422 /* We have a FOBX, this not a DFS opening, keep track of it */
4423 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
4425 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
4426 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
4427 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4429 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
4434 RxContext
->pFobx
= NULL
;
4437 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4438 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
4441 PV_NET_ROOT VNetRoot
= NULL
;
4443 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4445 VNetRoot
= Fcb
->VNetRoot
;
4447 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
4449 VNetRoot
= (PV_NET_ROOT
)Fobx
;
4452 if (VNetRoot
!= NULL
)
4454 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
4458 /* Remember if that's a write through file */
4459 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
4460 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
4462 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
4467 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
4469 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4470 RxContext
, RxContext
->MinorFunction
, Irp
,
4471 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
4472 RxContext
->SerialNumber
);
4481 RxInitializeDispatcher(
4485 HANDLE ThreadHandle
;
4489 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4490 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4492 /* Set appropriate timeouts: 10s & 60s */
4493 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4494 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4495 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4496 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
4498 RxDispatcher
.NumberOfProcessors
= 1;
4499 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
4500 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
4502 /* Initialize our dispatchers */
4503 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
4504 if (!NT_SUCCESS(Status
))
4509 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
4510 if (!NT_SUCCESS(Status
))
4515 /* And start them */
4516 RxDispatcher
.State
= RxDispatcherActive
;
4517 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
4518 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
4519 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
4520 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
4521 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
4522 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
4523 if (NT_SUCCESS(Status
))
4525 ZwClose(ThreadHandle
);
4535 RxInitializeFcbTable(
4536 IN OUT PRX_FCB_TABLE FcbTable
,
4537 IN BOOLEAN CaseInsensitiveMatch
)
4543 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
4544 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
4546 ExInitializeResourceLite(&FcbTable
->TableLock
);
4547 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4548 FcbTable
->Version
= 0;
4549 FcbTable
->TableEntryForNull
= NULL
;
4551 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
4552 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
4554 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
4557 FcbTable
->Lookups
= 0;
4558 FcbTable
->FailedLookups
= 0;
4559 FcbTable
->Compares
= 0;
4567 RxInitializeLowIoContext(
4568 OUT PLOWIO_CONTEXT LowIoContext
,
4571 PRX_CONTEXT RxContext
;
4572 PIO_STACK_LOCATION Stack
;
4576 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
4577 ASSERT(LowIoContext
== &RxContext
->LowIoContext
);
4579 Stack
= RxContext
->CurrentIrpSp
;
4581 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
4582 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
4583 RxContext
->LowIoContext
.Operation
= Operation
;
4588 case LOWIO_OP_WRITE
:
4589 /* In case of RW, set a canary, to make sure these fields are properly set
4590 * they will be asserted when lowio request will be submit to mini-rdr
4593 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
4594 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
4595 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
4597 /* Keep track of paging IOs */
4598 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
4600 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
4604 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
4609 case LOWIO_OP_FSCTL
:
4610 case LOWIO_OP_IOCTL
:
4611 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4612 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
4613 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
4614 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
4615 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
4616 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
4617 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
4620 /* Nothing to do for these */
4621 case LOWIO_OP_SHAREDLOCK
:
4622 case LOWIO_OP_EXCLUSIVELOCK
:
4623 case LOWIO_OP_UNLOCK
:
4624 case LOWIO_OP_UNLOCK_MULTIPLE
:
4625 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4626 case LOWIO_OP_CLEAROUT
:
4630 /* Should never happen */
4640 RxInitializeLowIoPerFcbInfo(
4641 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
4645 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
4646 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
4653 RxInitializeMRxDispatcher(
4654 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
4658 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4659 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4661 return STATUS_SUCCESS
;
4668 RxInitializePrefixTable(
4669 IN OUT PRX_PREFIX_TABLE ThisTable
,
4670 IN ULONG TableSize OPTIONAL
,
4671 IN BOOLEAN CaseInsensitiveMatch
)
4677 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
4680 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
4681 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
4682 InitializeListHead(&ThisTable
->MemberQueue
);
4683 ThisTable
->Version
= 0;
4684 ThisTable
->TableEntryForNull
= NULL
;
4685 ThisTable
->IsNetNameTable
= FALSE
;
4686 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4687 ThisTable
->TableSize
= TableSize
;
4693 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
4695 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
4704 RxInitializePurgeSyncronizationContext(
4705 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
4709 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
4710 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
4714 RxInitializeSrvCallParameters(
4715 IN PRX_CONTEXT RxContext
,
4716 IN OUT PSRV_CALL SrvCall
)
4720 SrvCall
->pPrincipalName
= NULL
;
4722 /* We only have stuff to initialize for file opening from DFS */
4723 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
4725 return STATUS_SUCCESS
;
4728 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
4731 return STATUS_NOT_IMPLEMENTED
;
4739 RxInitializeRxTimer(
4744 RxTimerInterval
.QuadPart
= -550000;
4745 KeInitializeSpinLock(&RxTimerLock
);
4746 InitializeListHead(&RxTimerQueueHead
);
4747 InitializeListHead(&RxRecurrentWorkItemsList
);
4748 KeInitializeDpc(&RxTimerDpc
, RxTimerDispatch
, NULL
);
4749 KeInitializeTimer(&RxTimer
);
4750 RxTimerTickCount
= 0;
4752 return STATUS_SUCCESS
;
4756 RxInitializeVNetRootParameters(
4757 PRX_CONTEXT RxContext
,
4759 OUT PULONG SessionId
,
4760 OUT PUNICODE_STRING
*UserNamePtr
,
4761 OUT PUNICODE_STRING
*UserDomainNamePtr
,
4762 OUT PUNICODE_STRING
*PasswordPtr
,
4766 PACCESS_TOKEN Token
;
4770 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
4771 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
4773 *UserNamePtr
= NULL
;
4774 *UserDomainNamePtr
= NULL
;
4775 *PasswordPtr
= NULL
;
4776 /* By default, that's not CSC instance */
4777 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4779 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
4780 if (SeTokenIsRestricted(Token
))
4782 return STATUS_ACCESS_DENIED
;
4786 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
4787 if (!NT_SUCCESS(Status
))
4793 Status
= SeQuerySessionIdToken(Token
, SessionId
);
4794 if (!NT_SUCCESS(Status
))
4799 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
4802 Status
= STATUS_NOT_IMPLEMENTED
;
4806 /* Deal with connection credentials */
4807 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
4810 Status
= STATUS_NOT_IMPLEMENTED
;
4814 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
4817 Status
= STATUS_NOT_IMPLEMENTED
;
4822 if (NT_SUCCESS(Status
))
4824 /* If that's a CSC instance, mark it as such */
4825 if (RxIsThisACscAgentOpen(RxContext
))
4827 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4839 RxInitializeWorkQueue(
4840 PRX_WORK_QUEUE WorkQueue
,
4841 WORK_QUEUE_TYPE WorkQueueType
,
4842 ULONG MaximumNumberOfWorkerThreads
,
4843 ULONG MinimumNumberOfWorkerThreads
)
4847 WorkQueue
->Type
= WorkQueueType
;
4848 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
4849 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
4851 WorkQueue
->State
= RxWorkQueueActive
;
4852 WorkQueue
->SpinUpRequestPending
= FALSE
;
4853 WorkQueue
->pRundownContext
= NULL
;
4854 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
4855 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
4856 WorkQueue
->CumulativeQueueLength
= 0;
4857 WorkQueue
->NumberOfSpinUpRequests
= 0;
4858 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
4859 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
4860 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
4861 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
4862 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
4863 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
4864 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
4865 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
4866 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
4867 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
4868 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
4869 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
4870 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
4871 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
4872 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
4873 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
4875 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
4876 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
4883 RxInitializeWorkQueueDispatcher(
4884 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
4887 ULONG MaximumNumberOfWorkerThreads
;
4891 /* Number of threads will depend on system capacity */
4892 if (MmQuerySystemSize() != MmLargeSystem
)
4894 MaximumNumberOfWorkerThreads
= 5;
4898 MaximumNumberOfWorkerThreads
= 10;
4901 /* Initialize the work queues */
4902 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
4903 MaximumNumberOfWorkerThreads
, 1);
4904 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
4905 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
4907 /* And start the worker threads */
4908 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
4909 RxBootstrapWorkerThreadDispatcher
,
4910 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
4911 if (!NT_SUCCESS(Status
))
4916 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
4917 RxBootstrapWorkerThreadDispatcher
,
4918 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
4919 if (!NT_SUCCESS(Status
))
4924 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
4925 RxBootstrapWorkerThreadDispatcher
,
4926 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
4934 RxInitiateSrvOpenKeyAssociation(
4935 IN OUT PSRV_OPEN SrvOpen
)
4937 PRX_BUFFERING_MANAGER BufferingManager
;
4941 SrvOpen
->Key
= NULL
;
4943 /* Just keep track of the opening request */
4944 BufferingManager
= &((PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
;
4945 InterlockedIncrement(&BufferingManager
->NumberOfOutstandingOpens
);
4947 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
4954 RxInsertWorkQueueItem(
4955 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
4956 WORK_QUEUE_TYPE WorkQueueType
,
4957 PRX_WORK_QUEUE_ITEM WorkQueueItem
)
4961 BOOLEAN SpinUpThreads
;
4962 PRX_WORK_QUEUE WorkQueue
;
4964 /* No dispatcher, nothing to insert */
4965 if (RxDispatcher
.State
!= RxDispatcherActive
)
4967 return STATUS_UNSUCCESSFUL
;
4970 /* Get the work queue */
4971 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
4973 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
4974 /* Only insert if the work queue is in decent state */
4975 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
4977 Status
= STATUS_UNSUCCESSFUL
;
4981 SpinUpThreads
= FALSE
;
4982 WorkQueueItem
->pDeviceObject
= pMRxDeviceObject
;
4983 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
4984 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
4985 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
4987 /* If required (and possible!), spin up a new worker thread */
4988 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
4989 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
4990 !WorkQueue
->SpinUpRequestPending
)
4992 WorkQueue
->SpinUpRequestPending
= TRUE
;
4993 SpinUpThreads
= TRUE
;
4996 Status
= STATUS_SUCCESS
;
4998 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5000 /* If we failed, return and still not insert item */
5001 if (!NT_SUCCESS(Status
))
5006 /* All fine, insert the item */
5007 KeInsertQueue(&WorkQueue
->Queue
, &WorkQueueItem
->List
);
5009 /* And start a new worker thread if needed */
5012 RxSpinUpWorkerThreads(WorkQueue
);
5019 RxIsThisACscAgentOpen(
5020 IN PRX_CONTEXT RxContext
)
5026 /* Client Side Caching is DFS stuff - we don't support it */
5027 if (RxContext
->Create
.EaLength
!= 0)
5032 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
5033 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
5043 IN PRX_CONTEXT RxContext
,
5044 IN LOCK_OPERATION Operation
,
5045 IN ULONG BufferLength
)
5054 Irp
= RxContext
->CurrentIrp
;
5055 /* If we already have a MDL, make sure it's locked */
5056 if (Irp
->MdlAddress
!= NULL
)
5058 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
5062 /* That likely means the driver asks for buffered IOs - we don't support it! */
5063 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
5065 /* If we have a real length */
5066 if (BufferLength
> 0)
5068 /* Allocate a MDL and lock it */
5069 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
5072 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
5073 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
5076 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
5080 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5084 Status
= _SEH2_GetExceptionCode();
5086 /* Free the possible MDL we have allocated */
5088 Irp
->MdlAddress
= NULL
;
5090 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
5093 if (!FsRtlIsNtstatusExpected(Status
))
5095 Status
= STATUS_INVALID_USER_BUFFER
;
5098 RxContext
->IoStatusBlock
.Status
= Status
;
5099 ExRaiseStatus(Status
);
5108 RxLowIoCompletionTail(
5109 IN PRX_CONTEXT RxContext
)
5116 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
5118 /* Only continue if we're at APC_LEVEL or lower */
5119 if (RxShouldPostCompletion() &&
5120 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
5122 return STATUS_MORE_PROCESSING_REQUIRED
;
5125 /* Call the completion routine */
5126 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
5127 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
5128 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
5133 /* If it was a RW operation, for a paging file ... */
5134 Operation
= RxContext
->LowIoContext
.Operation
;
5135 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
5137 /* Remove ourselves from the list and resume operations */
5138 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5140 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5141 RemoveEntryList(&RxContext
->RxContextSerializationQLinks
);
5142 RxContext
->RxContextSerializationQLinks
.Flink
= NULL
;
5143 RxContext
->RxContextSerializationQLinks
.Blink
= NULL
;
5144 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5145 RxResumeBlockedOperations_ALL(RxContext
);
5150 /* Sanity check: we had known operation */
5151 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
5154 /* If not sync operation, complete now. Otherwise, caller has already completed */
5155 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
5157 RxCompleteRequest(RxContext
, Status
);
5160 DPRINT("Status: %x\n", Status
);
5169 RxLowIoPopulateFsctlInfo(
5170 IN PRX_CONTEXT RxContext
)
5175 PIO_STACK_LOCATION Stack
;
5179 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
5181 Irp
= RxContext
->CurrentIrp
;
5182 Stack
= RxContext
->CurrentIrpSp
;
5184 /* Copy stack parameters */
5185 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
5186 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
5187 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
5188 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
5189 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
5191 /* Same buffer in case of buffered */
5192 if (Method
== METHOD_BUFFERED
)
5194 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5195 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5197 return STATUS_SUCCESS
;
5200 /* Two buffers for neither */
5201 if (Method
== METHOD_NEITHER
)
5203 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
5204 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
5206 return STATUS_SUCCESS
;
5209 /* Only IN/OUT remain */
5210 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
5212 /* Use system buffer for input */
5213 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5214 /* And MDL for output */
5215 Mdl
= Irp
->MdlAddress
;
5218 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
5219 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
5221 return STATUS_INSUFFICIENT_RESOURCES
;
5226 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
5229 return STATUS_SUCCESS
;
5235 IN PRX_CONTEXT RxContext
,
5236 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
5240 BOOLEAN Synchronous
;
5241 PLOWIO_CONTEXT LowIoContext
;
5243 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
5247 LowIoContext
= &RxContext
->LowIoContext
;
5248 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
5250 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
5252 Status
= STATUS_SUCCESS
;
5253 Operation
= LowIoContext
->Operation
;
5257 case LOWIO_OP_WRITE
:
5258 /* Check that the parameters were properly set by caller
5259 * See comment in RxInitializeLowIoContext()
5261 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
5262 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
5264 /* Lock the buffer */
5265 RxLockUserBuffer(RxContext
,
5266 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
5267 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
5268 if (RxNewMapUserBuffer(RxContext
) == NULL
)
5270 return STATUS_INSUFFICIENT_RESOURCES
;
5272 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
5274 /* If that's a paging IO, initialize serial operation */
5275 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5279 Fcb
= (PFCB
)RxContext
->pFcb
;
5281 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5282 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
5283 if (Operation
== LOWIO_OP_READ
)
5285 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5289 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5292 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5297 case LOWIO_OP_FSCTL
:
5298 case LOWIO_OP_IOCTL
:
5299 /* Set FSCTL/IOCTL parameters */
5300 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
5301 /* Check whether we're consistent: a length means a buffer */
5302 if (NT_SUCCESS(Status
))
5304 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
5305 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
5306 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
5307 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
5309 Status
= STATUS_INVALID_PARAMETER
;
5315 case LOWIO_OP_SHAREDLOCK
:
5316 case LOWIO_OP_EXCLUSIVELOCK
:
5317 case LOWIO_OP_UNLOCK
:
5318 case LOWIO_OP_UNLOCK_MULTIPLE
:
5319 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
5320 case LOWIO_OP_CLEAROUT
:
5325 Status
= STATUS_INVALID_PARAMETER
;
5329 /* No need to perform extra init in case of posting */
5330 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
5332 /* Preflight checks were OK, time to submit */
5333 if (NT_SUCCESS(Status
))
5335 PMINIRDR_DISPATCH Dispatch
;
5339 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
5340 /* If not synchronous, we're likely to return before the operation is finished */
5341 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5343 IoMarkIrpPending(RxContext
->CurrentIrp
);
5347 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
5348 if (Dispatch
!= NULL
)
5350 /* We'll try to execute until the mini-rdr doesn't return pending */
5353 RxContext
->IoStatusBlock
.Information
= 0;
5355 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
5356 if (Status
== STATUS_PENDING
)
5358 /* Unless it's not synchronous, caller will be happy with pending op */
5364 RxWaitSync(RxContext
);
5365 Status
= RxContext
->IoStatusBlock
.Status
;
5371 /* We had marked the IRP pending, whereas the operation finished, drop that */
5372 if (Status
!= STATUS_RETRY
)
5374 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5376 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
5379 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
5383 } while (Status
== STATUS_PENDING
);
5387 Status
= STATUS_INVALID_PARAMETER
;
5391 /* Call completion and return */
5392 RxContext
->IoStatusBlock
.Status
= Status
;
5393 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
5394 return RxLowIoCompletionTail(RxContext
);
5402 IN PRX_CONTEXT RxContext
)
5408 Irp
= RxContext
->CurrentIrp
;
5409 /* We should have a MDL (buffered IOs are not supported!) */
5410 if (Irp
->MdlAddress
!= NULL
)
5413 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5416 /* Just return system buffer */
5417 return Irp
->AssociatedIrp
.SystemBuffer
;
5424 RxMarkFobxOnCleanup(
5429 PFOBX ScavengerFobx
;
5430 LARGE_INTEGER TickCount
;
5431 PRDBSS_SCAVENGER Scavenger
;
5435 /* No FOBX, nothing to mark */
5441 /* Query time for close */
5442 KeQueryTickCount(&TickCount
);
5444 Fcb
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
5445 ASSERT(NodeTypeIsFcb(Fcb
));
5447 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5448 RxAcquireScavengerMutex();
5450 ScavengerFobx
= NULL
;
5451 /* If that's not a file, or even not a disk resource, just mark as dormant */
5452 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
|| Fcb
->VNetRoot
->pNetRoot
->DeviceType
!= FILE_DEVICE_DISK
)
5454 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5455 InitializeListHead(&pFobx
->ClosePendingList
);
5456 ++Scavenger
->NumberOfDormantFiles
;
5460 ASSERT(Scavenger
->NumberOfDormantFiles
>= 0);
5461 /* If we're about to reach the maximum dormant of FOBX */
5462 if (Scavenger
->NumberOfDormantFiles
>= Scavenger
->MaximumNumberOfDormantFiles
)
5464 /* This should never be wrong... */
5465 if (!IsListEmpty(&Scavenger
->ClosePendingFobxsList
))
5467 /* Then, take the first from the list (oldest) and save it for later purge */
5468 ScavengerFobx
= CONTAINING_RECORD(Scavenger
->ClosePendingFobxsList
.Flink
, FOBX
, ClosePendingList
);
5469 if (ScavengerFobx
->pSrvOpen
!= NULL
&& ScavengerFobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
5472 ScavengerFobx
= NULL
;
5476 RxReferenceNetFobx(ScavengerFobx
);
5481 /* Mark ourselves as dormant */
5482 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5483 pFobx
->CloseTime
.QuadPart
= TickCount
.QuadPart
;
5485 /* And insert us in the list of dormant files */
5486 InsertTailList(&Scavenger
->ClosePendingFobxsList
, &pFobx
->ClosePendingList
);
5487 /* If scavenger was inactive, start it */
5488 if (Scavenger
->NumberOfDormantFiles
++ == 0 && Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
5490 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
5491 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
, RxScavengerTimerRoutine
,
5492 Fcb
->RxDeviceObject
, Scavenger
->TimeLimit
);
5496 RxReleaseScavengerMutex();
5498 /* If we had reached max */
5499 if (ScavengerFobx
!= NULL
)
5503 /* Purge the oldest FOBX */
5504 Status
= RxPurgeFobxFromCache(ScavengerFobx
);
5505 if (Status
!= STATUS_SUCCESS
)
5520 PRDBSS_SCAVENGER Scavenger
;
5524 /* No FOBX, nothing to mark */
5530 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5531 ASSERT(NodeTypeIsFcb(Fcb
));
5533 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5535 RxAcquireScavengerMutex();
5536 /* Only mark it if it was already marked as dormant */
5537 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
))
5539 /* If FCB wasn't already decrement, do it now */
5540 if (!Fobx
->fOpenCountDecremented
)
5542 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5543 ASSERT(NodeTypeIsFcb(Fcb
));
5544 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
5546 Fobx
->fOpenCountDecremented
= TRUE
;
5549 /* We're no longer dormant */
5550 InterlockedDecrement(&Scavenger
->NumberOfDormantFiles
);
5551 ClearFlag(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5554 /* If we were inserted in the scavenger, drop ourselves out */
5555 if (!IsListEmpty(&Fobx
->ClosePendingList
))
5557 RemoveEntryList(&Fobx
->ClosePendingList
);
5558 InitializeListHead(&Fobx
->ClosePendingList
);
5561 RxReleaseScavengerMutex();
5569 PRX_CONTEXT RxContext
)
5575 Irp
= RxContext
->CurrentIrp
;
5576 if (Irp
->MdlAddress
!= NULL
)
5578 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5581 return Irp
->UserBuffer
;
5611 IN PV_NET_ROOT ThisVNetRoot
)
5616 PRX_FCB_TABLE FcbTable
;
5617 PRX_PREFIX_TABLE PrefixTable
;
5621 /* Mailslot won't have any SRV_OPEN (to orphan) */
5622 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
5623 if (NetRoot
->Type
== NET_ROOT_MAILSLOT
)
5628 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
5629 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
5631 FcbTable
= &NetRoot
->FcbTable
;
5632 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
5636 /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
5637 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
5639 PLIST_ENTRY BucketList
, Entry
;
5641 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
5642 Entry
= BucketList
->Flink
;
5643 while (Entry
!= BucketList
)
5645 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
5646 Entry
= Entry
->Flink
;
5648 ASSERT(NodeTypeIsFcb(Fcb
));
5649 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5653 /* Of course, don't forget about NULL-entry */
5654 if (FcbTable
->TableEntryForNull
!= NULL
)
5656 Fcb
= CONTAINING_RECORD(FcbTable
->TableEntryForNull
, FCB
, FcbTableEntry
.HashLinks
);
5657 ASSERT(NodeTypeIsFcb(Fcb
));
5658 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5663 RxReleaseFcbTableLock(FcbTable
);
5669 RxOrphanSrvOpensForThisFcb(
5671 IN PV_NET_ROOT ThisVNetRoot
,
5672 IN BOOLEAN OrphanAll
)
5681 RxpAcquirePrefixTableLockShared(
5682 PRX_PREFIX_TABLE pTable
,
5684 BOOLEAN ProcessBufferingStateChangeRequests
)
5688 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5689 pTable
->TableLock
.ActiveEntries
);
5691 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
5698 RxpAcquirePrefixTableLockExclusive(
5699 PRX_PREFIX_TABLE pTable
,
5701 BOOLEAN ProcessBufferingStateChangeRequests
)
5705 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5706 pTable
->TableLock
.ActiveEntries
);
5708 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
5715 RxpDereferenceAndFinalizeNetFcb(
5717 IN PRX_CONTEXT RxContext
,
5718 IN BOOLEAN RecursiveFinalize
,
5719 IN BOOLEAN ForceFinalize
)
5724 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
5728 ASSERT(!ForceFinalize
);
5729 ASSERT(NodeTypeIsFcb(ThisFcb
));
5730 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
5732 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5733 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
5734 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
5740 Status
= STATUS_SUCCESS
;
5741 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
5742 ResourceAcquired
= FALSE
;
5743 NetRootReferenced
= FALSE
;
5744 /* If FCB isn't orphaned, it still have context attached */
5745 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
5747 /* Don't let NetRoot go away before we're done */
5748 RxReferenceNetRoot(NetRoot
);
5749 NetRootReferenced
= TRUE
;
5751 /* Try to acquire the table lock exclusively */
5752 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
5754 RxReferenceNetFcb(ThisFcb
);
5756 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
5758 if (RxContext
!= NULL
&& RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT
&&
5759 RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
5761 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
5764 RxReleaseFcb(RxContext
, ThisFcb
);
5766 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5768 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
5771 References
= RxDereferenceNetFcb(ThisFcb
);
5773 ResourceAcquired
= TRUE
;
5777 /* If locking was OK (or not needed!), attempt finalization */
5778 if (Status
== STATUS_SUCCESS
)
5780 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
5783 /* Release table lock if acquired */
5784 if (ResourceAcquired
)
5786 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5789 /* We don't need the NetRoot anylonger */
5790 if (NetRootReferenced
)
5792 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
5802 RxpDereferenceNetFcb(
5809 ASSERT(NodeTypeIsFcb(Fcb
));
5811 NewCount
= InterlockedDecrement((volatile long *)&Fcb
->NodeReferenceCount
);
5812 ASSERT(NewCount
>= 0);
5814 PRINT_REF_COUNT(NETFCB
, NewCount
);
5829 BOOLEAN ForceFinalize
;
5830 PRX_PREFIX_TABLE PrefixTable
;
5832 SrvCall
= (PSRV_CALL
)Context
;
5833 /* At this step, RxFinalizeSrvCall already cleaned some fields */
5834 ASSERT(SrvCall
->UpperFinalizationDone
);
5836 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
5837 /* Were we called with ForceFinalize? */
5838 ForceFinalize
= BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
5840 /* Notify mini-rdr */
5841 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
,
5842 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)SrvCall
,
5846 /* Dereference our extra reference (set before queueing) */
5847 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
5848 InterlockedDecrement((volatile long *)&SrvCall
->NodeReferenceCount
);
5849 /* And finalize for real, with the right context */
5850 RxFinalizeSrvCall(SrvCall
, FALSE
, ForceFinalize
);
5851 RxReleasePrefixTableLock(PrefixTable
);
5858 RxpDiscardChangeBufferingStateRequests(
5859 _Inout_ PLIST_ENTRY DiscardedRequests
)
5865 /* No requests to discard */
5866 if (IsListEmpty(DiscardedRequests
))
5871 /* Free all the discarded requests */
5872 Entry
= DiscardedRequests
->Flink
;
5873 while (Entry
!= DiscardedRequests
)
5875 PCHANGE_BUFFERING_STATE_REQUEST Request
;
5877 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
5878 Entry
= Entry
->Flink
;
5880 DPRINT("Req %p for %p (%p) discarded\n", Request
, Request
->SrvOpenKey
, Request
->SrvOpen
);
5882 RxPrepareRequestForReuse(Request
);
5883 RxFreePool(Request
);
5891 RxpDispatchChangeBufferingStateRequests(
5894 PLIST_ENTRY DiscardedRequests
)
5898 BOOLEAN StartDispatcher
;
5899 LIST_ENTRY AcceptedReqs
;
5900 LIST_ENTRY DispatcherList
;
5901 PRX_BUFFERING_MANAGER BufferingManager
;
5903 /* Initialize our lists */
5904 InitializeListHead(&AcceptedReqs
);
5905 InitializeListHead(DiscardedRequests
);
5907 /* Transfer the requests to dispatch locally */
5908 BufferingManager
= &SrvCall
->BufferingManager
;
5909 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
5910 RxTransferList(&DispatcherList
, &BufferingManager
->DispatcherList
);
5911 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
5913 /* If there were requests */
5914 if (!IsListEmpty(&DispatcherList
))
5918 /* For each of the entries... */
5919 Entry
= DispatcherList
.Flink
;
5920 while (Entry
!= &DispatcherList
)
5922 PCHANGE_BUFFERING_STATE_REQUEST Request
;
5924 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
5925 Entry
= Entry
->Flink
;
5927 /* If we have been provided a SRV_OPEN, see whether it matches */
5928 if (SrvOpen
!= NULL
)
5930 /* Match, the request is accepted */
5931 if (Request
->SrvOpenKey
== SrvOpen
->Key
)
5933 Request
->SrvOpen
= SrvOpen
;
5934 RxReferenceSrvOpen(SrvOpen
);
5936 RemoveEntryList(&Request
->ListEntry
);
5937 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
5939 /* Move to the next entry */
5944 Status
= STATUS_PENDING
;
5949 /* No SRV_OPEN provided, try to find one */
5950 Status
= RxpLookupSrvOpenForRequestLite(SrvCall
, Request
);
5953 /* We found a matching SRV_OPEN, accept the request */
5954 if (Status
== STATUS_SUCCESS
)
5956 RemoveEntryList(&Request
->ListEntry
);
5957 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
5959 /* Another run might help handling it, don't discard it */
5960 else if (Status
== STATUS_PENDING
)
5964 /* Otherwise, discard the request */
5967 ASSERT(Status
== STATUS_NOT_FOUND
);
5969 RemoveEntryList(&Request
->ListEntry
);
5970 InsertTailList(DiscardedRequests
, &Request
->ListEntry
);
5975 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
5976 /* Nothing to dispatch, no need to start dispatcher */
5977 if (IsListEmpty(&DispatcherList
))
5979 StartDispatcher
= FALSE
;
5983 /* Transfer back the list of the not treated entries to the buffering manager */
5984 RxTransferList(&BufferingManager
->DispatcherList
, &DispatcherList
);
5985 StartDispatcher
= (BufferingManager
->DispatcherActive
== FALSE
);
5986 /* If the dispatcher isn't active, start it */
5987 if (StartDispatcher
)
5989 BufferingManager
->DispatcherActive
= TRUE
;
5993 /* If there were accepted requests, move them to the buffering manager */
5994 if (!IsListEmpty(&AcceptedReqs
))
5996 RxTransferList(&BufferingManager
->HandlerList
, &AcceptedReqs
);
5998 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6000 /* If we're to start the dispatcher, do it */
6001 if (StartDispatcher
)
6003 RxReferenceSrvCall(SrvCall
);
6004 DPRINT("Starting dispatcher\n");
6005 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
6006 &BufferingManager
->DispatcherWorkItem
,
6007 RxDispatchChangeBufferingStateRequests
, SrvCall
);
6015 RxpLookupSrvOpenForRequestLite(
6016 IN PSRV_CALL SrvCall
,
6017 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request
)
6025 Status
= STATUS_SUCCESS
;
6026 /* Browse all our associated SRV_OPENs to find the one! */
6027 for (Entry
= SrvCall
->BufferingManager
.SrvOpenLists
[0].Flink
;
6028 Entry
!= &SrvCall
->BufferingManager
.SrvOpenLists
[0];
6029 Entry
= Entry
->Flink
)
6031 /* Same key, not orphaned, this is ours */
6032 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenKeyList
);
6033 if (SrvOpen
->Key
== Request
->SrvOpenKey
)
6035 if (!BooleanFlagOn(SrvOpen
->pFcb
->FcbState
, FCB_STATE_ORPHANED
))
6037 RxReferenceSrvOpen(SrvOpen
);
6043 /* We didn't manage to find a SRV_OPEN */
6044 if (Entry
== &SrvCall
->BufferingManager
.SrvOpenLists
[0])
6048 /* The coming open might help, mark as pending for later retry */
6049 if (SrvCall
->BufferingManager
.NumberOfOutstandingOpens
!= 0)
6051 Status
= STATUS_PENDING
;
6053 /* Else, it's a complete failure */
6056 Status
= STATUS_NOT_FOUND
;
6060 /* Return the (not) found SRV_OPEN */
6061 Request
->SrvOpen
= SrvOpen
;
6070 RxpMarkInstanceForScavengedFinalization(
6073 NODE_TYPE_CODE NodeType
;
6074 PNODE_TYPE_AND_SIZE Node
;
6075 PRDBSS_SCAVENGER Scavenger
;
6076 PRDBSS_DEVICE_OBJECT DeviceObject
;
6077 PLIST_ENTRY ScavengerHead
, InstEntry
;
6081 /* If still referenced, don't mark it (broken caller) */
6082 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6083 if (Node
->NodeReferenceCount
> 1)
6088 DeviceObject
= RxGetDeviceObjectOfInstance(Instance
);
6089 Scavenger
= DeviceObject
->pRdbssScavenger
;
6092 NodeType
= NodeType(Instance
);
6093 SetFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6094 DPRINT("Node %p has now the scavenger mark!\n", Instance
);
6096 /* Increase the count in the scavenger, and queue it */
6097 ScavengerHead
= NULL
;
6100 case RDBSS_NTC_FOBX
:
6101 ++Scavenger
->FobxsToBeFinalized
;
6102 ScavengerHead
= &Scavenger
->FobxFinalizationList
;
6103 InstEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6106 case RDBSS_NTC_SRVCALL
:
6107 ++Scavenger
->SrvCallsToBeFinalized
;
6108 ScavengerHead
= &Scavenger
->SrvCallFinalizationList
;
6109 InstEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6112 case RDBSS_NTC_NETROOT
:
6113 ++Scavenger
->NetRootsToBeFinalized
;
6114 ScavengerHead
= &Scavenger
->NetRootFinalizationList
;
6115 InstEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6118 case RDBSS_NTC_V_NETROOT
:
6119 ++Scavenger
->VNetRootsToBeFinalized
;
6120 ScavengerHead
= &Scavenger
->VNetRootFinalizationList
;
6121 InstEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6124 case RDBSS_NTC_SRVOPEN
:
6125 ++Scavenger
->SrvOpensToBeFinalized
;
6126 ScavengerHead
= &Scavenger
->SrvOpenFinalizationList
;
6127 InstEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6131 /* Extra ref for scavenger */
6132 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
6134 /* If matching type */
6135 if (ScavengerHead
!= NULL
)
6137 /* Insert in the scavenger list */
6138 InsertTailList(ScavengerHead
, InstEntry
);
6140 /* And if it wasn't started, start it */
6141 if (Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
6143 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
6144 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
6145 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
6155 RxPostOneShotTimerRequest(
6156 IN PRDBSS_DEVICE_OBJECT pDeviceObject
,
6157 IN PRX_WORK_ITEM pWorkItem
,
6158 IN PRX_WORKERTHREAD_ROUTINE Routine
,
6160 IN LARGE_INTEGER TimeInterval
)
6164 ASSERT(pWorkItem
!= NULL
);
6166 /* Prepare the work item */
6167 ExInitializeWorkItem(&pWorkItem
->WorkQueueItem
, Routine
, pContext
);
6168 pWorkItem
->WorkQueueItem
.pDeviceObject
= pDeviceObject
;
6170 /* Last tick can be computed with the number of times it was caller (timertickcount)
6171 * and the interval between calls
6173 KeAcquireSpinLock(&RxTimerLock
, &OldIrql
);
6174 pWorkItem
->LastTick
= (TimeInterval
.QuadPart
/ 550000) + RxTimerTickCount
+ 1;
6175 /* Insert in work queue */
6176 InsertTailList(&RxTimerQueueHead
, &pWorkItem
->WorkQueueItem
.List
);
6177 KeReleaseSpinLock(&RxTimerLock
, OldIrql
);
6179 /* If there are queued events, queue an execution */
6180 if (IsListEmpty(&RxTimerQueueHead
))
6182 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
6185 return STATUS_SUCCESS
;
6193 RxPostToWorkerThread(
6194 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
6195 _In_ WORK_QUEUE_TYPE WorkQueueType
,
6196 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem
,
6197 _In_ PRX_WORKERTHREAD_ROUTINE Routine
,
6198 _In_ PVOID pContext
)
6200 /* Initialize work queue item */
6201 pWorkQueueItem
->List
.Flink
= NULL
;
6202 pWorkQueueItem
->WorkerRoutine
= Routine
;
6203 pWorkQueueItem
->Parameter
= pContext
;
6205 /* And insert it in the work queue */
6206 return RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, pWorkQueueItem
);
6210 RxpProcessChangeBufferingStateRequests(
6212 BOOLEAN UpdateHandlerState
)
6221 RxPrefixTableInsertName(
6222 IN OUT PRX_PREFIX_TABLE ThisTable
,
6223 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
6225 IN PULONG ContainerRefCount
,
6226 IN USHORT CaseInsensitiveLength
,
6227 IN PRX_CONNECTION_ID ConnectionId
6232 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
6234 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
6235 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
6237 /* Copy parameters and compute hash */
6238 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
6239 ThisEntry
->ContainingRecord
= Container
;
6240 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
6241 InterlockedIncrement((volatile long *)ContainerRefCount
);
6242 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
6243 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
6245 /* If no path length: this is entry for null path */
6246 if (ThisEntry
->Prefix
.Length
== 0)
6248 ThisTable
->TableEntryForNull
= ThisEntry
;
6250 /* Otherwise, insert in the appropriate bucket */
6253 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
6256 /* If we had a connection ID, keep track of it */
6257 if (ConnectionId
!= NULL
)
6259 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
6263 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
6264 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
6267 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
6268 /* Reflect the changes */
6269 ++ThisTable
->Version
;
6271 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
6280 RxPrefixTableLookupName(
6281 IN PRX_PREFIX_TABLE ThisTable
,
6282 IN PUNICODE_STRING CanonicalName
,
6283 OUT PUNICODE_STRING RemainingName
,
6284 IN PRX_CONNECTION_ID ConnectionId
)
6290 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
6291 ASSERT(CanonicalName
->Length
> 0);
6293 /* Call the internal helper */
6294 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
6295 if (Container
== NULL
)
6300 /* Reference our container before returning it */
6301 if (RdbssReferenceTracingValue
!= 0)
6303 NODE_TYPE_CODE Type
;
6305 Type
= NodeType(Container
);
6308 case RDBSS_NTC_SRVCALL
:
6309 RxReferenceSrvCall(Container
);
6312 case RDBSS_NTC_NETROOT
:
6313 RxReferenceNetRoot(Container
);
6316 case RDBSS_NTC_V_NETROOT
:
6317 RxReferenceVNetRoot(Container
);
6327 RxReference(Container
);
6344 ASSERT(NodeTypeIsFcb(Fcb
));
6346 NewCount
= InterlockedIncrement((volatile long *)&Fcb
->NodeReferenceCount
);
6348 PRINT_REF_COUNT(NETFCB
, Fcb
->NodeReferenceCount
);
6357 RxpReleasePrefixTableLock(
6358 PRX_PREFIX_TABLE pTable
,
6359 BOOLEAN ProcessBufferingStateChangeRequests
)
6363 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
6364 pTable
->TableLock
.ActiveEntries
);
6366 ExReleaseResourceLite(&pTable
->TableLock
);
6374 RxPrepareContextForReuse(
6375 IN OUT PRX_CONTEXT RxContext
)
6379 /* When we reach that point, make sure mandatory parts are null-ed */
6380 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
6382 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
6383 RxContext
->Create
.RdrFlags
= 0;
6385 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
6387 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
6388 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
6391 RxContext
->ReferenceCount
= 0;
6398 RxPrepareRequestForReuse(
6399 PCHANGE_BUFFERING_STATE_REQUEST Request
)
6405 SrvOpen
= Request
->SrvOpen
;
6407 /* If the request was already prepared for service */
6408 if (BooleanFlagOn(Request
->Flags
, RX_REQUEST_PREPARED_FOR_HANDLING
))
6410 /* We have to dereference the associated SRV_OPEN depending on the lock */
6411 if (RxIsFcbAcquiredExclusive(SrvOpen
->pFcb
))
6413 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
6417 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6420 /* Otherwise, just dereference */
6421 else if (SrvOpen
!= NULL
)
6423 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6426 Request
->SrvOpen
= NULL
;
6434 RxProcessChangeBufferingStateRequests(
6437 /* Call internal routine */
6438 RxUndoScavengerFinalizationMarking(SrvCall
);
6439 RxpProcessChangeBufferingStateRequests(SrvCall
, TRUE
);
6446 RxProcessChangeBufferingStateRequestsForSrvOpen(
6449 LONG NumberOfBufferingChangeRequests
, LockedOldBufferingToken
, OldBufferingToken
;
6451 /* Get the current number of change requests */
6452 NumberOfBufferingChangeRequests
= ((PSRV_CALL
)SrvOpen
->pVNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
.CumulativeNumberOfBufferingChangeRequests
;
6453 /* Get our old token */
6454 OldBufferingToken
= SrvOpen
->BufferingToken
;
6455 LockedOldBufferingToken
= InterlockedCompareExchange(&SrvOpen
->BufferingToken
,
6456 NumberOfBufferingChangeRequests
,
6457 NumberOfBufferingChangeRequests
);
6458 /* If buffering state changed in between, process changes */
6459 if (OldBufferingToken
!= LockedOldBufferingToken
)
6464 /* Acquire the FCB and start processing */
6465 Fcb
= (PFCB
)SrvOpen
->pFcb
;
6466 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
6467 if (Status
== STATUS_SUCCESS
)
6469 RxProcessFcbChangeBufferingStateRequest(Fcb
);
6470 RxReleaseFcb(NULL
, Fcb
);
6476 RxProcessFcbChangeBufferingStateRequest(
6483 RxpTrackDereference(
6484 _In_ ULONG TraceType
,
6485 _In_ PCSTR FileName
,
6487 _In_ PVOID Instance
)
6491 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6502 _In_ ULONG TraceType
,
6503 _In_ PCSTR FileName
,
6505 _In_ PVOID Instance
)
6507 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6519 RxpUndoScavengerFinalizationMarking(
6522 PLIST_ENTRY ListEntry
;
6523 PNODE_TYPE_AND_SIZE Node
;
6524 PRDBSS_SCAVENGER Scavenger
;
6528 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6529 /* There's no marking - nothing to do */
6530 if (!BooleanFlagOn(NodeType(Node
), RX_SCAVENGER_MASK
))
6535 /* First of all, remove the mark */
6536 ClearFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6537 DPRINT("Node %p no longer has the scavenger mark\n");
6539 /* And now, remove from the scavenger */
6540 Scavenger
= RxGetDeviceObjectOfInstance(Instance
)->pRdbssScavenger
;
6541 switch (NodeType(Node
))
6543 case RDBSS_NTC_FOBX
:
6544 --Scavenger
->FobxsToBeFinalized
;
6545 ListEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6548 case RDBSS_NTC_SRVCALL
:
6549 --Scavenger
->SrvCallsToBeFinalized
;
6550 ListEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6553 case RDBSS_NTC_NETROOT
:
6554 --Scavenger
->NetRootsToBeFinalized
;
6555 ListEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6558 case RDBSS_NTC_V_NETROOT
:
6559 --Scavenger
->VNetRootsToBeFinalized
;
6560 ListEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6563 case RDBSS_NTC_SRVOPEN
:
6564 --Scavenger
->SrvOpensToBeFinalized
;
6565 ListEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6569 /* Also, remove the extra ref from the scavenger */
6570 RemoveEntryList(ListEntry
);
6571 InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
6578 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6582 LIST_ENTRY Discarded
;
6586 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
6588 /* Initialize our discarded list */
6589 InitializeListHead(&Discarded
);
6591 SrvCall
= (PSRV_CALL
)SrvOpen
->Fcb
->VNetRoot
->pNetRoot
->pSrvCall
;
6592 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
6594 /* Set the flag, and get the requests */
6595 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
6596 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED
);
6597 RxGatherRequestsForSrvOpen(SrvCall
, SrvOpen
, &Discarded
);
6599 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
6601 /* If there were discarded requests */
6602 if (!IsListEmpty(&Discarded
))
6604 /* And a pending buffering state change */
6605 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
6607 /* Clear the flag, and set the associated event - job done */
6608 RxAcquireSerializationMutex();
6609 ClearFlag(SrvOpen
->Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
6610 if (SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
6612 KeSetEvent(SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
, IO_NETWORK_INCREMENT
, FALSE
);
6614 RxReleaseSerializationMutex();
6617 /* Drop the discarded requests */
6618 RxpDiscardChangeBufferingStateRequests(&Discarded
);
6631 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6633 /* Reference our FCB so that it doesn't disappear */
6634 RxReferenceNetFcb(Fcb
);
6635 /* Purge Cc if required */
6636 if (Fcb
->OpenCount
!= 0)
6638 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
6641 /* If it wasn't freed, release the lock */
6642 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6644 RxReleaseFcb(NULL
, Fcb
);
6652 RxPurgeFcbInSystemCache(
6654 IN PLARGE_INTEGER FileOffset OPTIONAL
,
6656 IN BOOLEAN UninitializeCacheMaps
,
6657 IN BOOLEAN FlushFile
)
6664 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6666 /* Try to flush first, if asked */
6669 /* If flushing failed, just make some noise */
6670 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
6671 if (!NT_SUCCESS(Status
))
6673 PVOID CallersAddress
, CallersCaller
;
6675 RtlGetCallersAddress(&CallersAddress
, &CallersCaller
);
6676 DPRINT1("Flush failed with status %lx for FCB %p\n", Status
, Fcb
);
6677 DPRINT1("Caller was %p %p\n", CallersAddress
, CallersCaller
);
6681 /* Deal with Cc for purge */
6682 Purged
= CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, FileOffset
,
6683 Length
, UninitializeCacheMaps
);
6684 /* If purge failed, force section closing */
6687 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
6689 RxReleaseFcb(NULL
, Fcb
);
6690 Purged
= MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
6691 RxAcquireExclusiveFcb(NULL
, Fcb
);
6694 /* Return appropriate status */
6695 Status
= (Purged
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
6696 DPRINT("Purge for FCB %p returns %lx\n", Fcb
, Status
);
6705 RxPurgeFobxFromCache(
6706 PFOBX FobxToBePurged
)
6713 FcbToBePurged
= (PFCB
)FobxToBePurged
->pSrvOpen
->pFcb
;
6714 ASSERT(FcbToBePurged
!= NULL
);
6716 /* If we cannot have our FCB exclusively, give up */
6717 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
6718 if (Status
!= STATUS_SUCCESS
)
6720 RxDereferenceNetFobx(FobxToBePurged
, LHS_LockNotHeld
);
6724 /* Don't let the FCB disappear */
6725 RxReferenceNetFcb(FcbToBePurged
);
6727 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
6728 if (BooleanFlagOn(FobxToBePurged
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
) || FobxToBePurged
->pSrvOpen
->UncleanFobxCount
!= 0)
6730 DPRINT("FCB purge skipped\n");
6734 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
6737 RxDereferenceNetFobx(FobxToBePurged
, LHS_ExclusiveLockHeld
);
6738 /* Drop our extra reference */
6739 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged
, NULL
, FALSE
, FALSE
))
6741 RxReleaseFcb(NULL
, FcbToBePurged
);
6751 RxpWorkerThreadDispatcher(
6752 IN PRX_WORK_QUEUE WorkQueue
,
6753 IN PLARGE_INTEGER WaitInterval
)
6757 PETHREAD CurrentThread
;
6758 BOOLEAN KillThread
, Dereference
;
6759 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
6760 PWORKER_THREAD_ROUTINE WorkerRoutine
;
6762 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6764 /* Reference ourselves */
6765 CurrentThread
= PsGetCurrentThread();
6766 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
6767 ASSERT(NT_SUCCESS(Status
));
6769 /* Infinite loop for worker */
6771 Dereference
= FALSE
;
6775 PLIST_ENTRY ListEntry
;
6777 /* Remove an entry from the work queue */
6778 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
6779 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
6781 PRDBSS_DEVICE_OBJECT DeviceObject
;
6783 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
6785 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
6786 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
6787 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6789 /* Get the parameters, and null-them in the struct */
6790 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
6791 Parameter
= WorkQueueItem
->Parameter
;
6792 DeviceObject
= WorkQueueItem
->pDeviceObject
;
6794 WorkQueueItem
->List
.Flink
= NULL
;
6795 WorkQueueItem
->WorkerRoutine
= NULL
;
6796 WorkQueueItem
->Parameter
= NULL
;
6797 WorkQueueItem
->pDeviceObject
= NULL
;
6799 /* Call the routine */
6800 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
6801 WorkerRoutine(Parameter
);
6803 /* Are we going down now? */
6804 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
6806 PKEVENT TearDownEvent
;
6808 TearDownEvent
= InterlockedExchangePointer((void * volatile*)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
6809 if (TearDownEvent
!= NULL
)
6811 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
6815 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6818 /* Shall we shutdown... */
6819 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
6820 switch (WorkQueue
->State
)
6822 /* Our queue is active, kill it if we have no more items to dispatch
6823 * and more threads than the required minimum
6825 case RxWorkQueueActive
:
6826 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
6828 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
6829 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
6833 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
6838 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6843 /* The queue is inactive: kill it we have more threads than the required minimum */
6844 case RxWorkQueueInactive
:
6845 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
6846 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
6850 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
6855 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6859 /* Rundown in progress..., kill it for sure! */
6860 case RxWorkQueueRundownInProgress
:
6862 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
6864 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
6866 RundownContext
= WorkQueue
->pRundownContext
;
6867 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
6869 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
6871 Dereference
= FALSE
;
6873 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
6875 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
6878 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6885 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
6886 } while (!KillThread
);
6888 DPRINT("Killed worker thread\n");
6890 /* Do we have to dereference ourselves? */
6893 ObDereferenceObject(CurrentThread
);
6896 /* Dump last executed routine */
6897 if (DumpDispatchRoutine
)
6899 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
6902 PsTerminateSystemThread(STATUS_SUCCESS
);
6907 IN OUT PVOID Instance
)
6909 NODE_TYPE_CODE NodeType
;
6910 PNODE_TYPE_AND_SIZE Node
;
6914 RxAcquireScavengerMutex();
6916 /* We can only reference a few structs */
6917 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
6918 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
6919 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
6920 (NodeType
== RDBSS_NTC_FOBX
));
6922 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6923 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
6925 /* Trace refcount if asked */
6928 case RDBSS_NTC_SRVCALL
:
6929 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
6932 case RDBSS_NTC_NETROOT
:
6933 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
6936 case RDBSS_NTC_V_NETROOT
:
6937 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
6940 case RDBSS_NTC_SRVOPEN
:
6941 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
6944 case RDBSS_NTC_FOBX
:
6945 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
6953 RxpUndoScavengerFinalizationMarking(Instance
);
6954 RxReleaseScavengerMutex();
6968 ASSERT(NodeTypeIsFcb(ThisFcb
));
6970 /* Just remove the entry from the FCB_TABLE */
6971 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
6972 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
6973 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
6975 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
6976 DPRINT("FCB (%p) %wZ removed\n", ThisFcb
, &ThisFcb
->FcbTableEntry
.Path
);
6977 /* Mark, so that we don't try to do it twice */
6978 SetFlag(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
);
6985 RxRemovePrefixTableEntry(
6986 IN OUT PRX_PREFIX_TABLE ThisTable
,
6987 IN OUT PRX_PREFIX_ENTRY Entry
)
6991 ASSERT(NodeType(Entry
) == RDBSS_NTC_PREFIX_ENTRY
);
6992 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
6994 /* Check whether we're asked to remove null entry */
6995 if (Entry
->Prefix
.Length
== 0)
6997 ThisTable
->TableEntryForNull
= NULL
;
7001 RemoveEntryList(&Entry
->HashLinks
);
7004 Entry
->ContainingRecord
= NULL
;
7006 /* Also remove it from global list */
7007 RemoveEntryList(&Entry
->MemberQLinks
);
7009 ++ThisTable
->Version
;
7016 RxRemoveVirtualNetRootFromNetRoot(
7018 PV_NET_ROOT VNetRoot
)
7020 PRX_PREFIX_TABLE PrefixTable
;
7024 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
7025 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
7027 /* Remove the VNetRoot from the list in the NetRoot */
7028 --NetRoot
->NumberOfVirtualNetRoots
;
7029 RemoveEntryList(&VNetRoot
->NetRootListEntry
);
7031 /* Fix the NetRoot if we were the default VNetRoot */
7032 if (NetRoot
->DefaultVNetRoot
== VNetRoot
)
7034 /* Put the first one available */
7035 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7037 NetRoot
->DefaultVNetRoot
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
7039 /* Otherwise, none */
7042 NetRoot
->DefaultVNetRoot
= NULL
;
7046 /* If there are still other VNetRoot available, we're done */
7047 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7052 /* Otherwise, initiate NetRoot finalization */
7053 if (!BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
7055 RxRemovePrefixTableEntry(PrefixTable
, &NetRoot
->PrefixEntry
);
7056 SetFlag(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
);
7059 /* Notify mini-rdr */
7060 if (NetRoot
->pSrvCall
!= NULL
&& NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
7064 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
7065 MRxFinalizeNetRoot
, ((PMRX_NET_ROOT
)NetRoot
, FALSE
));
7071 RxResumeBlockedOperations_ALL(
7072 IN OUT PRX_CONTEXT RxContext
)
7074 LIST_ENTRY BlockedOps
;
7078 /* Get the blocked operations */
7079 RxTransferListWithMutex(&BlockedOps
, &RxContext
->BlockedOperations
, RxContext
->BlockedOpsMutex
);
7081 if (!IsListEmpty(&BlockedOps
))
7089 RxResumeBlockedOperations_Serially(
7090 IN OUT PRX_CONTEXT RxContext
,
7091 IN OUT PLIST_ENTRY BlockingIoQ
)
7095 RxAcquireSerializationMutex();
7097 /* This can only happen on pipes */
7098 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7100 RxReleaseSerializationMutex();
7106 RxReleaseSerializationMutex();
7113 RxScavengeRelatedFobxs(
7117 LIST_ENTRY LocalList
;
7118 PLIST_ENTRY NextEntry
;
7119 PRDBSS_SCAVENGER Scavenger
;
7123 /* First of all, check whether there are FOBX to scavenge */
7124 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
7125 RxAcquireScavengerMutex();
7126 if (Scavenger
->FobxsToBeFinalized
<= 0)
7128 RxReleaseScavengerMutex();
7132 /* Initialize our local list which will hold all the FOBX to scavenge so
7133 * that we don't acquire the scavenger mutex too long
7135 InitializeListHead(&LocalList
);
7137 /* Technically, that condition should all be true... */
7138 if (!IsListEmpty(&Scavenger
->FobxFinalizationList
))
7140 PLIST_ENTRY NextEntry
, LastEntry
;
7142 /* Browse all the FCBs to find the matching ones */
7143 NextEntry
= Scavenger
->FobxFinalizationList
.Flink
;
7144 LastEntry
= &Scavenger
->FobxFinalizationList
;
7145 while (NextEntry
!= LastEntry
)
7147 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7148 NextEntry
= NextEntry
->Flink
;
7149 /* Matching our FCB? Let's finalize it */
7150 if (Fobx
->pSrvOpen
!= NULL
&& Fobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
7152 RxpUndoScavengerFinalizationMarking(Fobx
);
7153 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7154 InsertTailList(&LocalList
, &Fobx
->ScavengerFinalizationList
);
7159 RxReleaseScavengerMutex();
7161 /* Nothing to scavenge? Quit */
7162 if (IsListEmpty(&LocalList
))
7167 /* Now, finalize all the extracted FOBX */
7168 while (!IsListEmpty(&LocalList
))
7170 NextEntry
= RemoveHeadList(&LocalList
);
7171 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7172 RxFinalizeNetFobx(Fobx
, TRUE
, TRUE
);
7179 RxScavengerFinalizeEntries(
7180 PRDBSS_DEVICE_OBJECT DeviceObject
)
7190 RxScavengerTimerRoutine(
7194 PRDBSS_DEVICE_OBJECT DeviceObject
;
7195 PRDBSS_SCAVENGER Scavenger
;
7199 DeviceObject
= Context
;
7200 Scavenger
= DeviceObject
->pRdbssScavenger
;
7203 RxAcquireScavengerMutex();
7204 /* If the scavenger was dormant, wake it up! */
7205 if (Scavenger
->State
== RDBSS_SCAVENGER_DORMANT
)
7208 Scavenger
->State
= RDBSS_SCAVENGER_ACTIVE
;
7209 KeResetEvent(&Scavenger
->ScavengeEvent
);
7211 /* Scavenger the entries */
7212 RxReleaseScavengerMutex();
7213 RxScavengerFinalizeEntries(DeviceObject
);
7214 RxAcquireScavengerMutex();
7216 /* If we're still active (race) */
7217 if (Scavenger
->State
== RDBSS_SCAVENGER_ACTIVE
)
7219 /* If there are new entries to scavenge, stay dormant and requeue a run */
7220 if (Scavenger
->NumberOfDormantFiles
+ Scavenger
->SrvCallsToBeFinalized
+
7221 Scavenger
->NetRootsToBeFinalized
+ Scavenger
->VNetRootsToBeFinalized
+
7222 Scavenger
->FcbsToBeFinalized
+ Scavenger
->SrvOpensToBeFinalized
+
7223 Scavenger
->FobxsToBeFinalized
!= 0)
7226 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
7228 /* Otherwise, we're inactive again */
7231 Scavenger
->State
= RDBSS_SCAVENGER_INACTIVE
;
7235 RxReleaseScavengerMutex();
7237 /* Requeue an execution */
7240 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
7241 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
7246 RxReleaseScavengerMutex();
7249 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
7253 RxScavengeVNetRoots(
7254 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7265 RxSpinUpRequestsDispatcher(
7269 PRX_DISPATCHER RxDispatcher
;
7271 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7272 if (!NT_SUCCESS(Status
))
7274 PsTerminateSystemThread(STATUS_SUCCESS
);
7277 RxDispatcher
= Dispatcher
;
7282 PLIST_ENTRY ListEntry
;
7284 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
7285 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
7286 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
7288 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
7289 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
7291 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
7295 ListEntry
= &RxDispatcher
->SpinUpRequests
;
7297 KeResetEvent(&RxDispatcher
->SpinUpRequestsEvent
);
7298 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
7300 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
7302 PWORK_QUEUE_ITEM WorkItem
;
7303 PRX_WORK_QUEUE WorkQueue
;
7305 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
7306 WorkQueue
= WorkItem
->Parameter
;
7308 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
7310 DPRINT("Workqueue: calling %p(%p)\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
7311 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
7313 } while (RxDispatcher
->State
== RxDispatcherActive
);
7315 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
7316 PsTerminateSystemThread(STATUS_SUCCESS
);
7323 RxSpinUpWorkerThread(
7324 PRX_WORK_QUEUE WorkQueue
,
7325 PRX_WORKERTHREAD_ROUTINE Routine
,
7330 HANDLE ThreadHandle
;
7334 /* If work queue is inactive, that cannot work */
7335 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7336 if (WorkQueue
->State
!= RxWorkQueueActive
)
7338 Status
= STATUS_UNSUCCESSFUL
;
7339 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
7343 ++WorkQueue
->NumberOfActiveWorkerThreads
;
7344 Status
= STATUS_SUCCESS
;
7346 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
7348 /* Quit on failure */
7349 if (!NT_SUCCESS(Status
))
7354 /* Spin up the worker thread */
7355 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
7356 if (NT_SUCCESS(Status
))
7358 ZwClose(ThreadHandle
);
7361 /* Read well: we reached that point because it failed! */
7362 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
7364 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7365 --WorkQueue
->NumberOfActiveWorkerThreads
;
7366 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
7368 /* Rundown, no more active threads, set the event! */
7369 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
7370 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
7372 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
7375 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
7377 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
7383 RxSpinUpWorkerThreads(
7384 PRX_WORK_QUEUE WorkQueue
)
7390 RxSynchronizeWithScavenger(
7391 IN PRX_CONTEXT RxContext
)
7400 RxTableComputeHashValue(
7401 IN PUNICODE_STRING Name
)
7409 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
7412 Loops
[1] = MaxChar
- 1;
7413 Loops
[2] = MaxChar
- 2;
7414 Loops
[3] = MaxChar
- 3;
7415 Loops
[4] = MaxChar
- 4;
7416 Loops
[5] = MaxChar
/ 4;
7417 Loops
[6] = 2 * MaxChar
/ 4;
7418 Loops
[7] = 3 * MaxChar
/ 4;
7421 for (i
= 0; i
< 8; ++i
)
7426 if (Idx
>= 0 && Idx
< MaxChar
)
7428 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
7439 RxTableComputePathHashValue(
7440 IN PUNICODE_STRING Name
)
7448 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
7451 Loops
[1] = MaxChar
- 1;
7452 Loops
[2] = MaxChar
- 2;
7453 Loops
[3] = MaxChar
- 3;
7454 Loops
[4] = MaxChar
- 4;
7455 Loops
[5] = MaxChar
/ 4;
7456 Loops
[6] = 2 * MaxChar
/ 4;
7457 Loops
[7] = 3 * MaxChar
/ 4;
7460 for (i
= 0; i
< 8; ++i
)
7465 if (Idx
>= 0 && Idx
< MaxChar
)
7467 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
7479 IN PRX_PREFIX_TABLE ThisTable
,
7480 IN PUNICODE_STRING Name
,
7481 OUT PUNICODE_STRING RemainingName
,
7482 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
7486 PRX_PREFIX_ENTRY Entry
;
7487 RX_CONNECTION_ID NullId
;
7488 UNICODE_STRING LookupString
;
7492 /* If caller didn't provide a connection ID, setup one */
7493 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
7495 NullId
.Luid
.LowPart
= 0;
7496 NullId
.Luid
.HighPart
= 0;
7497 RxConnectionId
= &NullId
;
7501 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
7505 LookupString
.Buffer
= Name
->Buffer
;
7506 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
7507 /* We'll perform the lookup, path component after another */
7508 for (i
= 1; i
< MaxChar
; ++i
)
7511 PRX_PREFIX_ENTRY CurEntry
;
7513 /* Don't cut in the middle of a path element */
7514 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
7519 /* Perform lookup in the table */
7520 LookupString
.Length
= i
* sizeof(WCHAR
);
7521 Hash
= RxTableComputeHashValue(&LookupString
);
7522 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
7524 ++ThisTable
->Lookups
;
7526 /* Entry not found, move to the next component */
7527 if (CurEntry
== NULL
)
7530 ++ThisTable
->FailedLookups
;
7536 ASSERT(Entry
->ContainingRecord
!= NULL
);
7537 Container
= Entry
->ContainingRecord
;
7539 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
7540 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
7544 NetRoot
= (PNET_ROOT
)Entry
->ContainingRecord
;
7545 /* If there's a default one, perfect, that's a match */
7546 if (NetRoot
->DefaultVNetRoot
!= NULL
)
7548 Container
= NetRoot
->DefaultVNetRoot
;
7550 /* If none (that shouldn't happen!), try to find one */
7553 /* Use the first one in the list */
7554 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7556 Container
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
7558 /* Really, really, shouldn't happen */
7569 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
7575 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
7579 /* Entry was found */
7584 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
7586 /* Setup remaining name */
7587 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
7588 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
7589 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
7593 /* Otherwise, that's the whole name */
7594 RemainingName
= Name
;
7604 RxTableLookupName_ExactLengthMatch(
7605 IN PRX_PREFIX_TABLE ThisTable
,
7606 IN PUNICODE_STRING Name
,
7608 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
7610 PLIST_ENTRY ListEntry
, HashBucket
;
7614 ASSERT(RxConnectionId
!= NULL
);
7616 /* Select the right bucket */
7617 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
7618 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
7619 /* If bucket is empty, no match */
7620 if (IsListEmpty(HashBucket
))
7625 /* Browse all the entries in the bucket */
7626 for (ListEntry
= HashBucket
->Flink
;
7627 ListEntry
!= HashBucket
;
7628 ListEntry
= ListEntry
->Flink
)
7631 PRX_PREFIX_ENTRY Entry
;
7632 BOOLEAN CaseInsensitive
;
7633 PUNICODE_STRING CmpName
, CmpPrefix
;
7634 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
7636 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
7637 ++ThisTable
->Considers
;
7638 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
7640 Container
= Entry
->ContainingRecord
;
7641 ASSERT(Container
!= NULL
);
7643 /* Not the same hash, not the same length, move on */
7644 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
7649 ++ThisTable
->Compares
;
7650 /* If we have to perform a case insensitive compare on a portion... */
7651 if (Entry
->CaseInsensitiveLength
!= 0)
7653 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
7655 /* Perform the case insensitive check on the asked length */
7656 InsensitiveName
.Buffer
= Name
->Buffer
;
7657 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
7658 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
7659 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
7660 /* No match, move to the next entry */
7661 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
7666 /* Was the case insensitive covering the whole name? */
7667 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
7669 /* If connection ID also matches, that a complete match! */
7670 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
7676 /* Otherwise, we have to continue with the sensitive match.... */
7677 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
7678 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
7679 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
7680 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
7682 CmpName
= &InsensitiveName
;
7683 CmpPrefix
= &InsensitivePrefix
;
7684 CaseInsensitive
= FALSE
;
7689 CmpPrefix
= &Entry
->Prefix
;
7690 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
7693 /* Perform the compare, if there's a match, also check for connection ID */
7694 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
7696 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
7710 RxTearDownBufferingManager(
7716 return STATUS_SUCCESS
;
7725 _In_
struct _KDPC
*Dpc
,
7726 _In_opt_ PVOID DeferredContext
,
7727 _In_opt_ PVOID SystemArgument1
,
7728 _In_opt_ PVOID SystemArgument2
)
7731 LIST_ENTRY LocalList
;
7732 PLIST_ENTRY ListEntry
;
7733 PRX_WORK_ITEM WorkItem
;
7735 InitializeListHead(&LocalList
);
7737 KeAcquireSpinLockAtDpcLevel(&RxTimerLock
);
7740 /* Find any entry matching */
7741 if (!IsListEmpty(&RxTimerQueueHead
))
7743 ListEntry
= RxTimerQueueHead
.Flink
;
7746 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
7747 if (WorkItem
->LastTick
== RxTimerTickCount
)
7749 ListEntry
= ListEntry
->Flink
;
7751 RemoveEntryList(&WorkItem
->WorkQueueItem
.List
);
7752 InsertTailList(&LocalList
, &WorkItem
->WorkQueueItem
.List
);
7756 ListEntry
= ListEntry
->Flink
;
7758 } while (ListEntry
!= &RxTimerQueueHead
);
7760 /* Do we have to requeue a later execution? */
7761 Set
= !IsListEmpty(&RxTimerQueueHead
);
7763 KeReleaseSpinLockFromDpcLevel(&RxTimerLock
);
7765 /* Requeue if list wasn't empty */
7768 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
7771 /* If we had matching entries */
7772 if (!IsListEmpty(&LocalList
))
7774 /* Post them, one after another */
7775 ListEntry
= LocalList
.Flink
;
7778 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
7779 ListEntry
= ListEntry
->Flink
;
7781 WorkItem
->WorkQueueItem
.List
.Flink
= NULL
;
7782 WorkItem
->WorkQueueItem
.List
.Blink
= NULL
;
7783 RxPostToWorkerThread(WorkItem
->WorkQueueItem
.pDeviceObject
, CriticalWorkQueue
,
7784 &WorkItem
->WorkQueueItem
, WorkItem
->WorkQueueItem
.WorkerRoutine
,
7785 WorkItem
->WorkQueueItem
.Parameter
);
7787 while (ListEntry
!= &LocalList
);
7795 RxTrackerUpdateHistory(
7796 _Inout_opt_ PRX_CONTEXT RxContext
,
7797 _Inout_ PMRX_FCB MrxFcb
,
7798 _In_ ULONG Operation
,
7799 _In_ ULONG LineNumber
,
7800 _In_ PCSTR FileName
,
7801 _In_ ULONG SerialNumber
)
7804 RX_FCBTRACKER_CASES Case
;
7806 /* Check for null or special context */
7807 if (RxContext
== NULL
)
7809 Case
= RX_FCBTRACKER_CASE_NULLCONTEXT
;
7811 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
)
7813 Case
= RX_FCBTRACKER_CASE_CBS_CONTEXT
;
7815 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
7817 Case
= RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT
;
7821 ASSERT(NodeType(RxContext
) == RDBSS_NTC_RX_CONTEXT
);
7822 Case
= RX_FCBTRACKER_CASE_NORMAL
;
7825 /* If caller provided a FCB, update its history */
7829 ASSERT(NodeTypeIsFcb(Fcb
));
7831 /* Only one acquire operation, so many release operations... */
7832 if (Operation
== TRACKER_ACQUIRE_FCB
)
7834 ++Fcb
->FcbAcquires
[Case
];
7838 ++Fcb
->FcbReleases
[Case
];
7842 /* If we have a normal context, update its history about this function calls */
7843 if (Case
== RX_FCBTRACKER_CASE_NORMAL
)
7845 ULONG TrackerHistoryPointer
;
7847 /* Only one acquire operation, so many release operations... */
7848 if (Operation
== TRACKER_ACQUIRE_FCB
)
7850 InterlockedIncrement(&RxContext
->AcquireReleaseFcbTrackerX
);
7854 InterlockedDecrement(&RxContext
->AcquireReleaseFcbTrackerX
);
7857 /* We only keep track of the 32 first calls */
7858 TrackerHistoryPointer
= InterlockedExchangeAdd((volatile long *)&RxContext
->TrackerHistoryPointer
, 1);
7859 if (TrackerHistoryPointer
< RDBSS_TRACKER_HISTORY_SIZE
)
7861 RxContext
->TrackerHistory
[TrackerHistoryPointer
].AcquireRelease
= Operation
;
7862 RxContext
->TrackerHistory
[TrackerHistoryPointer
].LineNumber
= LineNumber
;
7863 RxContext
->TrackerHistory
[TrackerHistoryPointer
].FileName
= (PSZ
)FileName
;
7864 RxContext
->TrackerHistory
[TrackerHistoryPointer
].SavedTrackerValue
= RxContext
->AcquireReleaseFcbTrackerX
;
7865 RxContext
->TrackerHistory
[TrackerHistoryPointer
].Flags
= RxContext
->Flags
;
7868 /* If it's negative, then we released once more than we acquired it?! */
7869 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
>= 0);
7874 RxTrackPagingIoResource(
7875 _Inout_ PVOID Instance
,
7887 RxUndoScavengerFinalizationMarking(
7890 /* Just call internal routine with mutex held */
7891 RxAcquireScavengerMutex();
7892 RxpUndoScavengerFinalizationMarking(Instance
);
7893 RxReleaseScavengerMutex();
7900 RxUninitializeVNetRootParameters(
7901 IN PUNICODE_STRING UserName
,
7902 IN PUNICODE_STRING UserDomainName
,
7903 IN PUNICODE_STRING Password
,
7908 /* Only free what could have been allocated */
7909 if (UserName
!= NULL
)
7911 RxFreePool(UserName
);
7914 if (UserDomainName
!= NULL
)
7916 RxFreePool(UserDomainName
);
7919 if (Password
!= NULL
)
7921 RxFreePool(Password
);
7924 /* And remove the possibly set CSC agent flag */
7927 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
7936 IN RX_BLOCK_CONDITION NewConditionValue
,
7937 OUT PRX_BLOCK_CONDITION Condition
,
7938 IN OUT PLIST_ENTRY TransitionWaitList
)
7940 PRX_CONTEXT Context
;
7941 LIST_ENTRY SerializationQueue
;
7945 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
7947 /* Set the new condition */
7948 RxAcquireSerializationMutex();
7949 ASSERT(NewConditionValue
!= Condition_InTransition
);
7950 *Condition
= NewConditionValue
;
7951 /* And get the serialization queue for treatment */
7952 RxTransferList(&SerializationQueue
, TransitionWaitList
);
7953 RxReleaseSerializationMutex();
7955 /* Handle the serialization queue */
7956 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
7957 while (Context
!= NULL
)
7959 /* If the caller asked for post, post the request */
7960 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
7962 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
7963 RxFsdPostRequest(Context
);
7965 /* Otherwise, wake up sleeping waiters */
7968 RxSignalSynchronousWaiter(Context
);
7971 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
7979 RxVerifyOperationIsLegal(
7980 IN PRX_CONTEXT RxContext
)
7985 PFILE_OBJECT FileObject
;
7986 PIO_STACK_LOCATION Stack
;
7990 Irp
= RxContext
->CurrentIrp
;
7991 Stack
= RxContext
->CurrentIrpSp
;
7992 FileObject
= Stack
->FileObject
;
7994 /* We'll only check stuff on opened files, this requires an IRP and a FO */
7995 if (Irp
== NULL
|| FileObject
== NULL
)
8000 /* Set no exception for breakpoint - remember whether is was already set */
8001 FlagSet
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8002 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8004 /* If we have a CCB, perform a few checks on opened file */
8005 Fobx
= RxContext
->pFobx
;
8008 PMRX_SRV_OPEN SrvOpen
;
8010 SrvOpen
= Fobx
->pSrvOpen
;
8011 if (SrvOpen
!= NULL
)
8013 UCHAR MajorFunction
;
8015 MajorFunction
= RxContext
->MajorFunction
;
8016 /* Only allow closing/cleanup operations on renamed files */
8017 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8018 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
8020 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_RENAMED
;
8021 ExRaiseStatus(STATUS_FILE_RENAMED
);
8024 /* Only allow closing/cleanup operations on deleted files */
8025 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8026 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
))
8028 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_DELETED
;
8029 ExRaiseStatus(STATUS_FILE_DELETED
);
8034 /* If that's an open operation */
8035 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
8037 PFILE_OBJECT RelatedFileObject
;
8039 /* We won't allow an open operation relative to a file to be deleted */
8040 RelatedFileObject
= FileObject
->RelatedFileObject
;
8041 if (RelatedFileObject
!= NULL
)
8045 Fcb
= RelatedFileObject
->FsContext
;
8046 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
8048 RxContext
->IoStatusBlock
.Status
= STATUS_DELETE_PENDING
;
8049 ExRaiseStatus(STATUS_DELETE_PENDING
);
8054 /* If cleanup was completed */
8055 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
8057 if (!BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
))
8059 UCHAR MajorFunction
;
8061 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
8062 MajorFunction
= Stack
->MajorFunction
;
8063 if (MajorFunction
!= IRP_MJ_CLOSE
&& MajorFunction
!= IRP_MJ_QUERY_INFORMATION
&&
8064 MajorFunction
!= IRP_MJ_SET_INFORMATION
)
8066 if ((MajorFunction
!= IRP_MJ_READ
&& MajorFunction
!= IRP_MJ_WRITE
) ||
8067 !BooleanFlagOn(Stack
->MinorFunction
, IRP_MN_COMPLETE
))
8069 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_CLOSED
;
8070 ExRaiseStatus(STATUS_FILE_CLOSED
);
8076 /* If flag was already set, don't clear it */
8079 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8087 RxWaitForStableCondition(
8088 IN PRX_BLOCK_CONDITION Condition
,
8089 IN OUT PLIST_ENTRY TransitionWaitList
,
8090 IN OUT PRX_CONTEXT RxContext
,
8091 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
8094 NTSTATUS LocalStatus
;
8098 /* Make sure to always get status */
8099 if (AsyncStatus
== NULL
)
8101 AsyncStatus
= &LocalStatus
;
8104 /* By default, it's a success */
8105 *AsyncStatus
= STATUS_SUCCESS
;
8108 /* If it's not stable, we've to wait */
8109 if (!StableCondition(*Condition
))
8111 /* Lock the mutex */
8112 RxAcquireSerializationMutex();
8113 /* Still not stable? */
8114 if (!StableCondition(*Condition
))
8116 /* Insert us in the wait list for processing on stable condition */
8117 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
8119 /* If we're asked to post on stable, don't wait, and just return pending */
8120 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8122 *AsyncStatus
= STATUS_PENDING
;
8129 RxReleaseSerializationMutex();
8131 /* We don't post on stable, so, just wait... */
8134 RxWaitSync(RxContext
);
8144 RxWorkItemDispatcher(
8147 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
8149 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
8151 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
8153 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
8161 _RxAllocatePoolWithTag(
8162 _In_ POOL_TYPE PoolType
,
8163 _In_ SIZE_T NumberOfBytes
,
8166 return ExAllocatePoolWithTagPriority(PoolType
, NumberOfBytes
, Tag
, LowPoolPriority
);
8177 ExFreePoolWithTag(Buffer
, 0);
8189 ExFreePoolWithTag(Buffer
, Tag
);
8195 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
8197 #ifdef RDBSS_TRACKER
8199 _In_ ULONG LineNumber
,
8200 _In_ PCSTR FileName
,
8201 _In_ ULONG SerialNumber
8206 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
8210 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
8212 SpecialContext
= FALSE
;
8213 ContextIsPresent
= FALSE
;
8214 /* Check for special context */
8215 if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
|| RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
8217 SpecialContext
= TRUE
;
8220 /* We don't handle buffering state change yet... */
8221 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
8222 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
8227 /* Nor special contexts */
8233 /* If we don't have a context, assume we can wait! */
8234 if (RxContext
== NULL
)
8240 /* That said: we have a real context! */
8241 ContextIsPresent
= TRUE
;
8243 /* If we've been cancelled in between, give up */
8244 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
8245 if (!NT_SUCCESS(Status
))
8251 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8256 /* Assume we cannot lock */
8257 Status
= STATUS_LOCK_NOT_GRANTED
;
8259 /* Lock according to what the caller asked */
8262 case FCB_MODE_EXCLUSIVE
:
8263 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
8266 case FCB_MODE_SHARED
:
8267 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
8270 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
8271 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
8275 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
8276 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
8283 Status
= STATUS_SUCCESS
;
8284 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
8286 /* Handle paging write - not implemented */
8287 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
8293 /* And break, that cool! */
8299 /* If it failed, return immediately */
8300 if (!NT_SUCCESS(Status
))
8306 /* If we don't have to check for valid operation, job done, nothing more to do */
8307 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
8309 if (NT_SUCCESS(Status
))
8311 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
8317 /* Verify operation */
8320 RxVerifyOperationIsLegal(RxContext
);
8324 /* If it failed, release lock and fail */
8325 if (_SEH2_AbnormalTermination())
8327 ExReleaseResourceLite(Fcb
->Header
.Resource
);
8328 Status
= STATUS_LOCK_NOT_GRANTED
;
8333 if (NT_SUCCESS(Status
))
8335 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
8338 DPRINT("Status: %x\n", Status
);
8346 __RxItsTheSameContext(
8347 _In_ PRX_CONTEXT RxContext
,
8348 _In_ ULONG CapturedRxContextSerialNumber
,
8352 /* Check we have a context with the same serial number */
8353 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
8354 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
8357 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
8363 _Inout_opt_ PRX_CONTEXT RxContext
,
8364 _Inout_ PMRX_FCB MrxFcb
8365 #ifdef RDBSS_TRACKER
8367 _In_ ULONG LineNumber
,
8368 _In_ PCSTR FileName
,
8369 _In_ ULONG SerialNumber
8373 BOOLEAN IsExclusive
, BufferingPending
;
8375 RxAcquireSerializationMutex();
8377 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
8378 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
8380 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
8381 * then just release the FCB
8383 if (!BufferingPending
|| !IsExclusive
)
8385 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
8386 LineNumber
, FileName
, SerialNumber
);
8387 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
8390 RxReleaseSerializationMutex();
8392 /* And finally leave */
8393 if (!BufferingPending
|| !IsExclusive
)
8398 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
8400 /* Otherwise, handle buffering state and release */
8401 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
8403 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
8404 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
8408 __RxReleaseFcbForThread(
8409 _Inout_opt_ PRX_CONTEXT RxContext
,
8410 _Inout_ PMRX_FCB MrxFcb
,
8411 _In_ ERESOURCE_THREAD ResourceThreadId
8412 #ifdef RDBSS_TRACKER
8414 _In_ ULONG LineNumber
,
8415 _In_ PCSTR FileName
,
8416 _In_ ULONG SerialNumber
8420 BOOLEAN IsExclusive
, BufferingPending
;
8422 RxAcquireSerializationMutex();
8424 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
8425 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
8427 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
8428 * then just release the FCB
8430 if (!BufferingPending
|| !IsExclusive
)
8432 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
8433 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
8434 LineNumber
, FileName
, SerialNumber
);
8435 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
8438 RxReleaseSerializationMutex();
8440 /* And finally leave */
8441 if (!BufferingPending
|| !IsExclusive
)
8446 /* Otherwise, handle buffering state and release */
8447 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
8448 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
8449 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);