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
;
125 ULONG RdbssReferenceTracingValue
= (RDBSS_REF_TRACK_SRVCALL
| RDBSS_REF_TRACK_NETROOT
|
126 RDBSS_REF_TRACK_VNETROOT
| RDBSS_REF_TRACK_NETFOBX
|
127 RDBSS_REF_TRACK_NETFCB
| RDBSS_REF_TRACK_SRVOPEN
|
128 RX_PRINT_REF_TRACKING
);
130 ULONG RdbssReferenceTracingValue
= 0;
132 LARGE_INTEGER RxWorkQueueWaitInterval
[RxMaximumWorkQueue
];
133 LARGE_INTEGER RxSpinUpDispatcherWaitInterval
;
134 RX_DISPATCHER RxDispatcher
;
135 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues
;
136 FAST_MUTEX RxLowIoPagingIoSyncMutex
;
137 BOOLEAN RxContinueFromAssert
= TRUE
;
138 ULONG RxExplodePoolTags
= 1;
139 LARGE_INTEGER RxTimerInterval
;
140 RX_SPIN_LOCK RxTimerLock
;
141 LIST_ENTRY RxTimerQueueHead
;
142 LIST_ENTRY RxRecurrentWorkItemsList
;
145 ULONG RxTimerTickCount
;
147 BOOLEAN DumpDispatchRoutine
= TRUE
;
149 BOOLEAN DumpDispatchRoutine
= FALSE
;
157 #define ASSERT(exp) \
160 RxAssert(#exp, __FILE__, __LINE__, NULL); \
165 #undef RxAllocatePool
166 #undef RxAllocatePoolWithTag
169 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
170 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
171 #define RxFreePool _RxFreePool
172 #define RxFreePoolWithTag _RxFreePoolWithTag
175 /* FUNCTIONS ****************************************************************/
182 RxAcquireExclusiveFcbResourceInMRx(
183 _Inout_ PMRX_FCB Fcb
)
185 return RxAcquireExclusiveFcb(NULL
, (PFCB
)Fcb
);
193 RxAcquireFcbForLazyWrite(
203 /* The received context is a FCB */
204 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
205 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
206 ASSERT(Fcb
->Specific
.Fcb
.LazyWriteThread
== NULL
);
208 /* Acquire the paging resource (shared) */
209 Ret
= ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, Wait
);
212 /* Update tracker information */
213 Fcb
->PagingIoResourceFile
= __FILE__
;
214 Fcb
->PagingIoResourceLine
= __LINE__
;
215 /* Lazy writer thread is the current one */
216 Fcb
->Specific
.Fcb
.LazyWriteThread
= PsGetCurrentThread();
218 /* There is no top level IRP */
219 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
220 /* Now, there will be! */
221 Ret
= RxTryToBecomeTheTopLevelIrp(NULL
, (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
,
222 Fcb
->RxDeviceObject
, TRUE
);
223 /* In case of failure, release the lock and reset everything */
226 Fcb
->PagingIoResourceFile
= NULL
;
227 Fcb
->PagingIoResourceLine
= 0;
228 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
229 Fcb
->Specific
.Fcb
.LazyWriteThread
= NULL
;
241 RxAcquireFcbForReadAhead(
251 /* The received context is a FCB */
252 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
253 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
255 Ret
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, Wait
);
258 /* There is no top level IRP */
259 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
260 /* Now, there will be! */
261 Ret
= RxTryToBecomeTheTopLevelIrp(NULL
, (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
,
262 Fcb
->RxDeviceObject
, TRUE
);
263 /* In case of failure, release the lock and reset everything */
266 ExReleaseResourceLite(Fcb
->Header
.Resource
);
275 RxAcquireFileForNtCreateSection(
276 PFILE_OBJECT FileObject
)
284 PFILE_OBJECT FileObject
,
285 PDEVICE_OBJECT DeviceObject
)
288 return STATUS_NOT_IMPLEMENTED
;
295 RxAddVirtualNetRootToNetRoot(
297 PV_NET_ROOT VNetRoot
)
301 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
303 /* Insert in the VNetRoot list - make sure lock is held */
304 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
306 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
307 ++NetRoot
->NumberOfVirtualNetRoots
;
308 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
316 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
317 NODE_TYPE_CODE NodeType
,
320 PVOID AlreadyAllocatedObject
)
325 PVOID Buffer
, PAPNBuffer
;
326 PNON_PAGED_FCB NonPagedFcb
;
327 PMINIRDR_DISPATCH Dispatch
;
328 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
332 Dispatch
= RxDeviceObject
->Dispatch
;
345 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
346 if (NodeType
== RDBSS_NTC_FOBX
)
348 FobxSize
= sizeof(FOBX
);
349 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
351 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
354 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
355 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
357 SrvOpenSize
= sizeof(SRV_OPEN
);
358 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
360 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
363 FobxSize
= sizeof(FOBX
);
364 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
366 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
369 /* Otherwise, we're asked to allocate a FCB */
372 /* So, allocate the FCB and its extension if asked */
373 FcbSize
= sizeof(FCB
);
374 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
376 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
379 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
380 * Otherwise, it will be allocated later on, specifically
382 if (PoolType
== NonPagedPool
)
384 NonPagedSize
= sizeof(NON_PAGED_FCB
);
387 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
388 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
390 SrvOpenSize
= sizeof(SRV_OPEN
);
391 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
393 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
396 FobxSize
= sizeof(FOBX
);
397 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
399 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
404 /* If we already have a buffer, go ahead */
405 if (AlreadyAllocatedObject
!= NULL
)
407 Buffer
= AlreadyAllocatedObject
;
409 /* Otherwise, allocate it */
412 Buffer
= RxAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
419 /* Now, get the pointers - FOBX is easy */
420 if (NodeType
== RDBSS_NTC_FOBX
)
424 /* SRV_OPEN first, FOBX next */
425 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
428 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
430 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
436 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
438 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
440 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
441 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
444 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
445 if (PoolType
!= NonPagedPool
)
447 NonPagedFcb
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
448 if (NonPagedFcb
== NULL
)
450 RxFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
454 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
456 /* Otherwise, just point at the right place in what has been allocated previously */
459 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
460 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
464 /* If we have allocated a SRV_OPEN, initialize it */
467 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
469 if (NodeType
== RDBSS_NTC_SRVOPEN
)
471 SrvOpen
->InternalFobx
= Fobx
;
475 SrvOpen
->InternalFobx
= NULL
;
476 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
479 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
481 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
484 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
487 /* If we have allocated a FOBX, initialize it */
490 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
492 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
494 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
498 /* If we have allocated a FCB, initialize it */
501 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
503 Fcb
->NonPaged
= NonPagedFcb
;
504 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
506 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
507 NonPagedFcb
->FcbBackPointer
= Fcb
;
510 Fcb
->InternalSrvOpen
= SrvOpen
;
511 Fcb
->InternalFobx
= Fobx
;
513 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
514 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
515 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
517 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
519 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
522 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
524 InterlockedIncrement(&RxNumberOfActiveFcbs
);
525 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
527 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
528 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
531 DPRINT("Allocated %p\n", Buffer
);
541 NODE_TYPE_CODE NodeType
,
542 PMINIRDR_DISPATCH MRxDispatch
,
545 ULONG Tag
, ObjectSize
;
546 PVOID Object
, *Extension
;
547 PRX_PREFIX_ENTRY PrefixEntry
;
548 USHORT StructSize
, ExtensionSize
;
552 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
556 case RDBSS_NTC_SRVCALL
:
557 Tag
= RX_SRVCALL_POOLTAG
;
558 StructSize
= sizeof(SRV_CALL
);
559 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
561 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
565 case RDBSS_NTC_NETROOT
:
566 Tag
= RX_NETROOT_POOLTAG
;
567 StructSize
= sizeof(NET_ROOT
);
568 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
570 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
574 case RDBSS_NTC_V_NETROOT
:
575 Tag
= RX_V_NETROOT_POOLTAG
;
576 StructSize
= sizeof(V_NET_ROOT
);
577 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
579 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
588 /* Now, allocate the object */
589 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
590 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
596 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
598 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
601 case RDBSS_NTC_SRVCALL
:
602 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
603 Extension
= &((PSRV_CALL
)Object
)->Context
;
604 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
607 case RDBSS_NTC_NETROOT
:
608 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
609 Extension
= &((PNET_ROOT
)Object
)->Context
;
610 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
613 case RDBSS_NTC_V_NETROOT
:
614 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
615 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
623 /* Set the prefix table unicode string */
624 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
625 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
626 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
627 PrefixEntry
->Prefix
.Length
= NameLength
;
628 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
629 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
631 /* Return the extension if we are asked to manage it */
632 if (ExtensionSize
!= 0)
634 *Extension
= Add2Ptr(Object
, StructSize
);
653 /* If we're not asked to continue, just stop the system */
654 if (!RxContinueFromAssert
)
656 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
659 /* Otherwise, capture context to offer the user to dump it */
660 RtlCaptureContext(&Context
);
662 /* Loop until the user hits 'i' */
665 /* If no file provided, use empty name */
671 /* If no message provided, use empty one */
677 /* Display the message */
678 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
679 /* And ask the user */
680 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
681 /* If he asks for ignore, quit
682 * In case of invalid input, ask again
684 if (Response
[0] != 'B' && Response
[0] != 'b')
686 if (Response
[0] == 'I' || Response
[0] == 'i')
694 /* Break: offer the user to dump the context and break */
695 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
698 /* Continue looping, so that after dump, execution can continue (with ignore) */
707 RxBootstrapWorkerThreadDispatcher(
710 PRX_WORK_QUEUE RxWorkQueue
;
714 RxWorkQueue
= WorkQueue
;
715 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
723 RxChangeBufferingState(
726 BOOLEAN ComputeNewState
)
729 NTSTATUS Status
, MiniStatus
;
730 ULONG NewBufferingState
, OldBufferingState
;
734 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen
, Context
, ComputeNewState
);
736 Fcb
= (PFCB
)SrvOpen
->pFcb
;
737 ASSERT(NodeTypeIsFcb(Fcb
));
738 /* First of all, mark that buffering state is changing */
739 SetFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
742 Status
= STATUS_SUCCESS
;
745 /* If we're asked to compute a new state, ask the mini-rdr for it */
748 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxComputeNewBufferingState
,
749 ((PMRX_SRV_OPEN
)SrvOpen
, Context
, &NewBufferingState
));
750 if (MiniStatus
!= STATUS_SUCCESS
)
752 NewBufferingState
= 0;
757 /* If not, use SRV_OPEN state */
758 NewBufferingState
= SrvOpen
->BufferingFlags
;
761 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
762 if ((Fcb
->ShareAccess
.SharedRead
+ Fcb
->ShareAccess
.SharedWrite
+ Fcb
->ShareAccess
.SharedDelete
) == 0 && !ComputeNewState
)
764 SetFlag(NewBufferingState
, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES
);
767 /* If there's a lock operation to complete, clear that flag */
768 if (Fcb
->OutstandingLockOperationsCount
!= 0)
770 ClearFlag(NewBufferingState
, FCB_STATE_LOCK_BUFFERING_ENABLED
);
773 /* Get the old state */
774 OldBufferingState
= Fcb
->FcbState
& FCB_STATE_BUFFERING_STATE_MASK
;
775 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState
, NewBufferingState
, SrvOpen
->BufferingFlags
);
777 /* If we're dropping write cache, then flush the FCB */
778 if (BooleanFlagOn(OldBufferingState
, FCB_STATE_WRITECACHING_ENABLED
) &&
779 !BooleanFlagOn(NewBufferingState
, FCB_STATE_WRITECACHING_ENABLED
))
781 DPRINT("Flushing\n");
783 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
786 /* If we're dropping read cache, then purge */
787 if (Fcb
->UncleanCount
== 0 ||
788 (BooleanFlagOn(OldBufferingState
, FCB_STATE_READCACHING_ENABLED
) &&
789 !BooleanFlagOn(NewBufferingState
, FCB_STATE_READCACHING_ENABLED
)) ||
790 BooleanFlagOn(NewBufferingState
, FCB_STATE_DELETE_ON_CLOSE
))
794 if (!NT_SUCCESS(Status
))
796 DPRINT("Previous flush failed with status: %lx\n", Status
);
799 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, TRUE
);
802 /* If there's already a change pending in SRV_OPEN */
803 if (ComputeNewState
&& BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
805 /* If there's a FOBX at least */
806 if (!IsListEmpty(&SrvOpen
->FobxList
))
808 PRX_CONTEXT RxContext
;
810 /* Create a fake context to pass to the mini-rdr */
811 RxContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
812 if (RxContext
!= NULL
)
816 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
818 /* Give the first FOBX */
819 Fobx
= CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
);
820 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
821 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
823 /* If there was a delayed close, perform it */
824 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
826 DPRINT("Oplock break close for %p\n", SrvOpen
);
828 RxCloseAssociatedSrvOpen(Fobx
, RxContext
);
830 /* Otherwise, inform the mini-rdr about completion */
833 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxCompleteBufferingStateChangeRequest
,
834 (RxContext
, (PMRX_SRV_OPEN
)SrvOpen
, Context
));
838 RxDereferenceAndDeleteRxContext(RxContext
);
843 /* Set the new state */
844 Fcb
->FcbState
^= (NewBufferingState
^ Fcb
->FcbState
) & FCB_STATE_BUFFERING_STATE_MASK
;
848 /* Job done, clear the flag */
849 ClearFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
851 if (!BooleanFlagOn(NewBufferingState
, FCB_STATE_FILETIMECACHEING_ENABLED
))
853 ClearFlag(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
);
862 RxCheckVNetRootCredentials(
863 PRX_CONTEXT RxContext
,
864 PV_NET_ROOT VNetRoot
,
866 PUNICODE_STRING UserName
,
867 PUNICODE_STRING UserDomain
,
868 PUNICODE_STRING Password
,
873 /* If that's a UNC name, there's nothing to process */
874 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
875 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
878 return STATUS_MORE_PROCESSING_REQUIRED
;
881 /* Compare the logon ID in the VNetRoot with the one provided */
882 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
884 return STATUS_MORE_PROCESSING_REQUIRED
;
887 /* No credential provided? That's OK */
888 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
890 return STATUS_SUCCESS
;
895 return STATUS_NOT_IMPLEMENTED
;
907 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
909 ASSERT(Context
!= NULL
);
910 ASSERT(Context
->CurrentIrp
!= NULL
);
911 Irp
= Context
->CurrentIrp
;
913 /* Debug what the caller asks for */
914 if (Context
->LoudCompletionString
!= NULL
)
916 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
917 /* Does the user asks to stop on failed completion */
918 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
920 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
924 /* Complete for real */
925 Context
->CurrentIrp
= NULL
;
926 RxCompleteRequest_Real(Context
, Irp
, Status
);
928 DPRINT("Status: %lx\n", Status
);
936 RxCompleteRequest_Real(
937 IN PRX_CONTEXT RxContext
,
943 PIO_STACK_LOCATION Stack
;
945 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
947 /* Nothing to complete, just free context */
950 DPRINT("NULL IRP for %p\n", RxContext
);
951 if (RxContext
!= NULL
)
953 RxDereferenceAndDeleteRxContext_Real(RxContext
);
959 /* Remove cancel routine */
960 IoAcquireCancelSpinLock(&OldIrql
);
961 IoSetCancelRoutine(Irp
, NULL
);
962 IoReleaseCancelSpinLock(OldIrql
);
964 /* Select the boost, given the success/paging operation */
965 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
967 Boost
= IO_DISK_INCREMENT
;
971 Irp
->IoStatus
.Information
= 0;
972 Boost
= IO_NO_INCREMENT
;
974 Irp
->IoStatus
.Status
= Status
;
976 if (RxContext
!= NULL
)
978 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
979 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
981 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
982 RxContext
->MinorFunction
, RxContext
, Irp
,
983 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
987 /* If that's an opening, there might be a canonical name allocated,
988 * if completion isn't pending, release it
990 Stack
= IoGetCurrentIrpStackLocation(Irp
);
991 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
994 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
996 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
999 RxpPrepareCreateContextForReuse(RxContext
);
1000 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
1003 /* If it's a write, validate the correct behavior of the operation */
1004 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
1006 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
1008 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
1012 /* If it's pending, make sure IRP is marked as such */
1013 if (RxContext
!= NULL
)
1015 if (RxContext
->PendingReturned
)
1017 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
1022 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
1023 IoCompleteRequest(Irp
, Boost
);
1025 /* If there's a context, dereference it */
1026 if (RxContext
!= NULL
)
1028 RxDereferenceAndDeleteRxContext_Real(RxContext
);
1036 RxCompleteSrvOpenKeyAssociation(
1037 IN OUT PSRV_OPEN SrvOpen
)
1041 SrvCall
= (PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
;
1042 /* Only handle requests if opening was a success */
1043 if (SrvOpen
->Condition
== Condition_Good
)
1046 BOOLEAN ProcessChange
;
1047 LIST_ENTRY DiscardedRequests
;
1049 /* Initialize our discarded requests list */
1050 InitializeListHead(&DiscardedRequests
);
1052 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
1054 /* Transfer our requests in the SRV_CALL */
1055 RxTransferList(&SrvCall
->BufferingManager
.SrvOpenLists
[0], &SrvOpen
->SrvOpenKeyList
);
1057 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
1058 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
1060 /* Dispatch requests and get the discarded ones */
1061 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &DiscardedRequests
);
1063 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
1065 /* Is there still anything to process? */
1066 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
1067 if (IsListEmpty(&SrvCall
->BufferingManager
.HandlerList
))
1069 ProcessChange
= FALSE
;
1073 ProcessChange
= (SrvCall
->BufferingManager
.HandlerInactive
== FALSE
);
1076 SrvCall
->BufferingManager
.HandlerInactive
= TRUE
;
1079 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
1081 /* Yes? Go ahead! */
1084 RxReferenceSrvCall(SrvCall
);
1085 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
1086 &SrvCall
->BufferingManager
.HandlerWorkItem
,
1087 RxProcessChangeBufferingStateRequests
, SrvCall
);
1090 /* And discard left requests */
1091 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests
);
1095 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
1104 IN PRX_CONTEXT RxContext
,
1105 IN PSRV_CALL SrvCall
,
1106 IN PNET_ROOT NetRoot
,
1107 IN PV_NET_ROOT VirtualNetRoot
,
1108 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1111 PRX_PREFIX_TABLE PrefixTable
;
1112 PMRX_CREATENETROOT_CONTEXT Context
;
1113 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
1117 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
1118 VirtualNetRoot
, LockHoldingState
);
1120 /* Validate the lock is exclusively held */
1121 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
1122 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1124 /* Allocate the context */
1125 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
1126 if (Context
== NULL
)
1128 return STATUS_INSUFFICIENT_RESOURCES
;
1131 /* We can release lock now */
1132 RxReleasePrefixTableLock(PrefixTable
);
1133 *LockHoldingState
= LHS_LockNotHeld
;
1135 RootCondition
= Condition_Bad
;
1136 VRootCondition
= Condition_Bad
;
1138 /* Initialize the context */
1139 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
1140 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
1141 Context
->RxContext
= RxContext
;
1142 Context
->pVNetRoot
= VirtualNetRoot
;
1143 Context
->Callback
= RxCreateNetRootCallBack
;
1145 /* And call the mini-rdr */
1146 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
1147 if (Status
== STATUS_PENDING
)
1149 /* Wait for the mini-rdr to be done */
1150 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1151 /* Update the structures condition according to mini-rdr return */
1152 if (NT_SUCCESS(Context
->NetRootStatus
))
1154 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
1156 RootCondition
= Condition_Good
;
1157 VRootCondition
= Condition_Good
;
1158 Status
= STATUS_SUCCESS
;
1162 RootCondition
= Condition_Good
;
1163 Status
= Context
->VirtualNetRootStatus
;
1168 Status
= Context
->VirtualNetRootStatus
;
1169 if (NT_SUCCESS(Status
))
1171 Status
= Context
->NetRootStatus
;
1177 /* It has to return STATUS_PENDING! */
1181 /* Acquire lock again - for caller lock status will remain unchanged */
1182 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
1183 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
1184 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1186 /* Do the transition to the condition got from mini-rdr */
1187 RxTransitionNetRoot(NetRoot
, RootCondition
);
1188 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
1190 /* Context is not longer needed */
1191 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
1193 DPRINT("Status: %x\n", Status
);
1203 IN PRX_CONTEXT RxContext
,
1204 IN PSRV_CALL SrvCall
,
1205 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1208 PRX_PREFIX_TABLE PrefixTable
;
1209 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1210 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1211 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
1215 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
1217 /* Validate the lock is exclusively held */
1218 RxDeviceObject
= RxContext
->RxDeviceObject
;
1219 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
1220 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1222 /* Allocate the context for mini-rdr */
1223 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
1224 if (Calldown
== NULL
)
1226 SrvCall
->Context
= NULL
;
1227 SrvCall
->Condition
= Condition_Bad
;
1228 RxReleasePrefixTableLock(PrefixTable
);
1229 *LockHoldingState
= LHS_LockNotHeld
;
1230 return STATUS_INSUFFICIENT_RESOURCES
;
1234 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
1236 SrvCall
->Context
= NULL
;
1237 SrvCall
->Condition
= Condition_InTransition
;
1239 RxReleasePrefixTableLock(PrefixTable
);
1240 *LockHoldingState
= LHS_LockNotHeld
;
1242 CallbackContext
= &Calldown
->CallbackContexts
[0];
1243 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
1244 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
1245 CallbackContext
->SrvCalldownStructure
= Calldown
;
1246 CallbackContext
->CallbackContextOrdinal
= 0;
1247 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
1249 RxReferenceSrvCall(SrvCall
);
1251 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1252 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1254 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
1258 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
1261 Calldown
->NumberToWait
= 1;
1262 Calldown
->NumberRemaining
= 1;
1263 Calldown
->RxContext
= RxContext
;
1264 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
1265 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
1266 Calldown
->BestFinisher
= NULL
;
1267 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
1268 InitializeListHead(&Calldown
->SrvCalldownList
);
1270 /* Call the mini-rdr */
1271 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
1272 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
1273 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
1274 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
1275 /* It has to return STATUS_PENDING! */
1276 ASSERT(Status
== STATUS_PENDING
);
1278 /* No async, start completion */
1279 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1281 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1283 /* Finish construction - we'll notify mini-rdr it's the winner */
1284 Status
= RxFinishSrvCallConstruction(Calldown
);
1285 if (!NT_SUCCESS(Status
))
1287 RxReleasePrefixTableLock(PrefixTable
);
1288 *LockHoldingState
= LHS_LockNotHeld
;
1292 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
1293 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1297 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
1305 RxConstructVirtualNetRoot(
1306 IN PRX_CONTEXT RxContext
,
1307 IN PUNICODE_STRING CanonicalName
,
1308 IN NET_ROOT_TYPE NetRootType
,
1309 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
1310 OUT PLOCK_HOLDING_STATE LockHoldingState
,
1311 OUT PRX_CONNECTION_ID RxConnectionId
)
1314 PV_NET_ROOT VNetRoot
;
1315 RX_BLOCK_CONDITION Condition
;
1316 UNICODE_STRING LocalNetRootName
, FilePathName
;
1320 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1323 Condition
= Condition_Bad
;
1324 /* Before creating the VNetRoot, try to find the appropriate connection */
1325 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
1326 &LocalNetRootName
, &FilePathName
,
1327 LockHoldingState
, RxConnectionId
);
1328 /* Found and active */
1329 if (Status
== STATUS_CONNECTION_ACTIVE
)
1331 /* We need a new VNetRoot */
1332 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
1333 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
1334 if (VNetRoot
!= NULL
)
1336 RxReferenceVNetRoot(VNetRoot
);
1339 /* Dereference previous VNetRoot */
1340 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
1341 /* Reset and start construct (new structures will replace old ones) */
1342 RxContext
->Create
.pSrvCall
= NULL
;
1343 RxContext
->Create
.pNetRoot
= NULL
;
1344 RxContext
->Create
.pVNetRoot
= NULL
;
1346 /* Construct new NetRoot */
1347 if (VNetRoot
!= NULL
)
1349 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
1350 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
1351 if (NT_SUCCESS(Status
))
1353 Condition
= Condition_Good
;
1358 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1363 /* If it failed creating the connection, leave */
1364 if (Status
!= STATUS_SUCCESS
)
1366 if (*LockHoldingState
!= LHS_LockNotHeld
)
1368 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1369 *LockHoldingState
= LHS_LockNotHeld
;
1372 *VirtualNetRootPointer
= VNetRoot
;
1373 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1377 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1379 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1380 Condition
= Condition_Good
;
1383 /* We have a non stable VNetRoot - transition it */
1384 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1386 RxTransitionVNetRoot(VNetRoot
, Condition
);
1389 /* If recreation failed */
1390 if (Status
!= STATUS_SUCCESS
)
1392 /* Dereference potential VNetRoot */
1393 if (VNetRoot
!= NULL
)
1395 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1396 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1401 if (*LockHoldingState
!= LHS_LockNotHeld
)
1403 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1404 *LockHoldingState
= LHS_LockNotHeld
;
1408 *VirtualNetRootPointer
= VNetRoot
;
1412 /* Return the allocated VNetRoot */
1413 *VirtualNetRootPointer
= VNetRoot
;
1422 IN PRX_CONTEXT RxContext
,
1423 IN PV_NET_ROOT VNetRoot
,
1424 IN PUNICODE_STRING Name
)
1430 NODE_TYPE_CODE NodeType
;
1431 PIO_STACK_LOCATION Stack
;
1432 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1436 /* We need a decent VNetRoot */
1437 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1439 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1440 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1441 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1443 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1444 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1446 Stack
= RxContext
->CurrentIrpSp
;
1448 /* Do we need to create a fake FCB? Like for renaming */
1449 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1450 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1451 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1453 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1454 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1456 /* Allocate the FCB */
1457 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1458 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1464 /* Initialize the FCB */
1465 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1466 Fcb
->RxDeviceObject
= RxDeviceObject
;
1467 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1468 Fcb
->VNetRoot
= VNetRoot
;
1469 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1471 InitializeListHead(&Fcb
->SrvOpenList
);
1472 Fcb
->SrvOpenListVersion
= 0;
1474 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1475 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1476 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1477 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1478 NetRoot
->InnerNamePrefix
.Length
);
1479 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1481 /* Copy back parameters from RxContext */
1482 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1484 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1487 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1489 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1491 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1494 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1496 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1499 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1500 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1502 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1503 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1505 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1506 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1508 /* Fake FCB doesn't go in prefix table */
1511 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1512 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1513 DPRINT("Fake FCB: %p\n", Fcb
);
1517 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1520 RxReferenceVNetRoot(VNetRoot
);
1521 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1523 Fcb
->ulFileSizeVersion
= 0;
1525 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1526 RxReferenceNetFcb(Fcb
);
1537 OUT PRX_CONTEXT RxContext
,
1538 IN PMRX_SRV_OPEN MrxSrvOpen
)
1549 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1550 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1551 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1552 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1555 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1556 /* Can we use pre-allocated FOBX? */
1557 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1559 Fobx
= Fcb
->InternalFobx
;
1560 /* Call allocate to initialize the FOBX */
1561 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1562 /* Mark it used now */
1563 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1564 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1566 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1568 Fobx
= SrvOpen
->InternalFobx
;
1569 /* Call allocate to initialize the FOBX */
1570 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1571 /* Mark it used now */
1572 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1573 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1577 /* Last case, we cannot, allocate a FOBX */
1578 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1582 /* Allocation failed! */
1589 Fobx
->Flags
= Flags
;
1591 /* Initialize throttling */
1592 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1593 if (NetRoot
!= NULL
)
1595 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1597 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1598 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1599 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1601 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1603 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1604 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1605 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1609 /* Propagate flags fron RxContext */
1610 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1612 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1615 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1617 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1621 Fobx
->FobxSerialNumber
= 0;
1622 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1623 Fobx
->NodeReferenceCount
= 1;
1624 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1626 RxReferenceSrvOpen(SrvOpen
);
1627 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1629 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1630 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1631 InitializeListHead(&Fobx
->ClosePendingList
);
1633 Fobx
->CloseTime
.QuadPart
= 0;
1634 Fobx
->fOpenCountDecremented
= FALSE
;
1636 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1638 return (PMRX_FOBX
)Fobx
;
1646 IN PSRV_CALL SrvCall
,
1647 IN PUNICODE_STRING Name
,
1648 IN ULONG NetRootFlags
,
1649 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1652 USHORT CaseInsensitiveLength
;
1653 PRX_PREFIX_TABLE PrefixTable
;
1655 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1659 /* We need a SRV_CALL */
1660 ASSERT(SrvCall
!= NULL
);
1662 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1663 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1665 /* Get name length */
1666 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1667 if (CaseInsensitiveLength
> MAXUSHORT
)
1672 /* Allocate the NetRoot */
1673 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1674 CaseInsensitiveLength
);
1675 if (NetRoot
== NULL
)
1680 /* Construct name */
1681 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1682 Name
->Buffer
, Name
->Length
);
1683 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1685 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1686 SrvCall
->PrefixEntry
.Prefix
.Length
);
1689 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1691 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1693 /* Inisert in prefix table */
1694 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1695 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1698 /* Prepare the FCB table */
1699 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1701 InitializeListHead(&NetRoot
->TransitionWaitList
);
1702 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1703 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1705 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1707 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1708 NetRoot
->Flags
|= NetRootFlags
;
1709 NetRoot
->DiskParameters
.ClusterSize
= 1;
1710 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1711 NetRoot
->SrvCall
= SrvCall
;
1713 RxReferenceSrvCall(SrvCall
);
1715 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1724 RxCreateNetRootCallBack(
1725 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1729 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1739 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1740 IN ULONG InitialContextFlags
)
1743 PRX_CONTEXT Context
;
1745 ASSERT(RxDeviceObject
!= NULL
);
1747 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1750 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1752 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1754 /* Allocate the context from our lookaside list */
1755 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1756 if (Context
== NULL
)
1762 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1764 /* It was allocated on NP pool, keep track of it! */
1765 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
1766 /* And initialize it */
1767 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1768 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1770 /* Add it to our global list */
1771 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1772 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1773 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1775 DPRINT("Context: %p\n", Context
);
1784 IN PRX_CONTEXT RxContext
,
1785 IN PUNICODE_STRING Name
,
1786 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1787 IN PRX_CONNECTION_ID RxConnectionId
)
1794 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1796 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1798 /* Get the name length */
1799 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1800 if (InnerNamePrefix
!= NULL
)
1802 NameLength
+= InnerNamePrefix
->Length
;
1805 /* Allocate the object */
1806 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1807 if (SrvCall
== NULL
)
1813 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1814 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1815 RxInitializeBufferingManager(SrvCall
);
1816 InitializeListHead(&SrvCall
->TransitionWaitList
);
1817 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1818 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1819 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1820 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1821 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1822 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1823 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1824 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1826 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1835 RxCreateSrvCallCallBack(
1836 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1840 PRX_CONTEXT RxContext
;
1841 ULONG NumberRemaining
;
1842 BOOLEAN StartDispatcher
;
1843 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1845 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1847 /* Get our context structures */
1848 Calldown
= Context
->SrvCalldownStructure
;
1849 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1851 /* If it is a success, that's the winner */
1852 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1853 if (Context
->Status
== STATUS_SUCCESS
)
1855 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1856 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1858 NumberRemaining
= --Calldown
->NumberRemaining
;
1859 SrvCall
->Status
= Context
->Status
;
1860 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1862 /* Still some to ask, keep going */
1863 if (NumberRemaining
!= 0)
1868 /* If that's not async, signal we're done */
1869 RxContext
= Calldown
->RxContext
;
1870 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1872 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1875 /* If that's a mailslot, finish construction, no more to do */
1876 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1878 RxFinishSrvCallConstruction(Calldown
);
1882 /* Queue our finish call for delayed completion */
1883 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1884 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1885 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1886 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1887 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1889 /* If we have to start dispatcher, go ahead */
1890 if (StartDispatcher
)
1894 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1895 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1896 if (!NT_SUCCESS(Status
))
1898 /* It failed - run it manually.... */
1899 RxFinishSrvCallConstructionDispatcher(NULL
);
1909 IN PV_NET_ROOT VNetRoot
,
1918 ASSERT(NodeTypeIsFcb(Fcb
));
1919 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1921 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1925 SrvOpen
= Fcb
->InternalSrvOpen
;
1926 /* Check whethet we have to allocate a new SRV_OPEN */
1927 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1928 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1929 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1932 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1933 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1938 /* Otherwise, just use internal one and initialize it */
1939 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1940 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1941 Fcb
->InternalSrvOpen
);
1942 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1943 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1946 /* If SrvOpen was properly allocated, initialize it */
1947 if (SrvOpen
!= NULL
)
1949 SrvOpen
->Flags
= Flags
;
1950 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1951 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1952 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1953 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1954 SrvOpen
->NodeReferenceCount
= 1;
1956 RxReferenceVNetRoot(VNetRoot
);
1957 RxReferenceNetFcb(Fcb
);
1959 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1960 ++Fcb
->SrvOpenListVersion
;
1962 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1963 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1964 InitializeListHead(&SrvOpen
->FobxList
);
1965 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1970 if (_SEH2_AbnormalTermination())
1972 if (SrvOpen
!= NULL
)
1974 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1980 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1993 IN PRX_CONTEXT RxContext
,
1994 IN PNET_ROOT NetRoot
,
1995 IN PUNICODE_STRING CanonicalName
,
1996 IN PUNICODE_STRING LocalNetRootName
,
1997 IN PUNICODE_STRING FilePath
,
1998 IN PRX_CONNECTION_ID RxConnectionId
)
2001 PV_NET_ROOT VNetRoot
;
2002 USHORT CaseInsensitiveLength
;
2006 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
2007 LocalNetRootName
, FilePath
, RxConnectionId
);
2009 /* Lock must be held exclusively */
2010 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
2012 /* Check for overflow */
2013 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
2018 /* Get name length and allocate VNetRoot */
2019 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
2020 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
2021 CaseInsensitiveLength
);
2022 if (VNetRoot
== NULL
)
2027 /* Initialize its connection parameters */
2028 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
2029 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
2030 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
2031 if (!NT_SUCCESS(Status
))
2033 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
2034 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
2035 RxFreeObject(VNetRoot
);
2041 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2043 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
2044 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
2045 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
2046 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
2048 InitializeListHead(&VNetRoot
->TransitionWaitList
);
2049 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
2051 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
2055 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
2057 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
2061 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
2064 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
2066 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
2072 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
2075 /* Insert in prefix table */
2076 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
2077 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
2080 RxReferenceNetRoot(NetRoot
);
2081 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
2084 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
2085 VNetRoot
->UpperFinalizationDone
= FALSE
;
2086 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
2087 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2089 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
2090 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
2100 IN OUT PVOID Instance
,
2101 IN LOCK_HOLDING_STATE LockHoldingState
)
2104 NODE_TYPE_CODE NodeType
;
2105 PNODE_TYPE_AND_SIZE Node
;
2109 RxAcquireScavengerMutex();
2111 /* Check we have a node we can handle */
2112 NodeType
= NodeType(Instance
);
2113 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
2114 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
2115 (NodeType
== RDBSS_NTC_FOBX
));
2117 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
2118 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
2119 ASSERT(RefCount
>= 0);
2121 /* Trace refcount */
2124 case RDBSS_NTC_SRVCALL
:
2125 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
2128 case RDBSS_NTC_NETROOT
:
2129 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
2132 case RDBSS_NTC_V_NETROOT
:
2133 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
2136 case RDBSS_NTC_SRVOPEN
:
2137 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
2140 case RDBSS_NTC_FOBX
:
2141 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
2149 /* No need to free - still in use */
2152 RxReleaseScavengerMutex();
2156 /* We have to be locked exclusively */
2157 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
2159 if ((NodeType
== RDBSS_NTC_FOBX
&& RefCount
== 0) ||
2160 (NodeType
>= RDBSS_NTC_SRVCALL
&& NodeType
<= RDBSS_NTC_V_NETROOT
))
2162 RxpMarkInstanceForScavengedFinalization(Instance
);
2165 RxReleaseScavengerMutex();
2170 if (BooleanFlagOn(NodeType
, RX_SCAVENGER_MASK
))
2172 RxpUndoScavengerFinalizationMarking(Instance
);
2176 RxReleaseScavengerMutex();
2178 /* Now, deallocate the memory */
2181 case RDBSS_NTC_SRVCALL
:
2185 SrvCall
= (PSRV_CALL
)Instance
;
2187 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
2188 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
2189 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
2193 case RDBSS_NTC_NETROOT
:
2197 NetRoot
= (PNET_ROOT
)Instance
;
2199 ASSERT(NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2200 ASSERT(RxIsPrefixTableLockAcquired(NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2201 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2205 case RDBSS_NTC_V_NETROOT
:
2207 PV_NET_ROOT VNetRoot
;
2209 VNetRoot
= (PV_NET_ROOT
)Instance
;
2211 ASSERT(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2212 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2213 RxFinalizeVNetRoot(VNetRoot
, TRUE
, TRUE
);
2217 case RDBSS_NTC_SRVOPEN
:
2221 SrvOpen
= (PSRV_OPEN
)Instance
;
2223 ASSERT(RxIsFcbAcquired(SrvOpen
->Fcb
));
2224 if (SrvOpen
->OpenCount
== 0)
2226 RxFinalizeSrvOpen(SrvOpen
, FALSE
, FALSE
);
2231 case RDBSS_NTC_FOBX
:
2235 Fobx
= (PFOBX
)Instance
;
2237 ASSERT(RxIsFcbAcquired(Fobx
->SrvOpen
->Fcb
));
2238 RxFinalizeNetFobx(Fobx
, TRUE
, FALSE
);
2249 RxDereferenceAndDeleteRxContext_Real(
2250 IN PRX_CONTEXT RxContext
)
2255 PRX_CONTEXT StopContext
= NULL
;
2257 /* Make sure we really have a context */
2258 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
2259 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
2260 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
2261 /* If refcount is 0, start releasing stuff that needs spinlock held */
2264 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2266 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
2268 /* If that's stop context from DO, remove it */
2269 RxDeviceObject
= RxContext
->RxDeviceObject
;
2270 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
2272 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
2276 /* Remove it from the list */
2277 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
2278 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
2279 RemoveEntryList(&RxContext
->ContextListEntry
);
2281 /* If that was the last active context, save the stop context */
2282 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
2284 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
2286 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
2291 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
2293 /* Now, deal with what can be done without spinlock held */
2296 /* Refcount shouldn't have changed */
2297 ASSERT(RxContext
->ReferenceCount
== 0);
2298 /* Reset everything that can be */
2299 RxPrepareContextForReuse(RxContext
);
2301 #ifdef RDBSS_TRACKER
2302 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
2304 /* If that was the last active, set the event */
2305 if (StopContext
!= NULL
)
2307 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
2308 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
2312 /* Is ShadowCrit still owned? Shouldn't happen! */
2313 if (RxContext
->ShadowCritOwner
!= 0)
2315 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
2320 /* If it was allocated, free it */
2323 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
2330 RxDispatchChangeBufferingStateRequests(
2341 RxDispatchToWorkerThread(
2342 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
2343 IN WORK_QUEUE_TYPE WorkQueueType
,
2344 IN PRX_WORKERTHREAD_ROUTINE Routine
,
2348 PRX_WORK_DISPATCH_ITEM DispatchItem
;
2350 /* Allocate a bit of context */
2351 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
2352 if (DispatchItem
== NULL
)
2354 return STATUS_INSUFFICIENT_RESOURCES
;
2357 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2358 DispatchItem
->DispatchRoutine
= Routine
;
2359 DispatchItem
->DispatchRoutineParameter
= pContext
;
2360 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
2361 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
2364 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, &DispatchItem
->WorkQueueItem
);
2365 if (!NT_SUCCESS(Status
))
2367 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
2368 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
2371 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
2380 RxExclusivePrefixTableLockToShared(
2381 PRX_PREFIX_TABLE Table
)
2385 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
2392 RxExtractServerName(
2393 IN PUNICODE_STRING FilePathName
,
2394 OUT PUNICODE_STRING SrvCallName
,
2395 OUT PUNICODE_STRING RestOfName
)
2401 ASSERT(SrvCallName
!= NULL
);
2403 /* SrvCall name will start from the begin up to the first separator */
2404 SrvCallName
->Buffer
= FilePathName
->Buffer
;
2405 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2407 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2413 /* Compute length */
2414 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
2415 SrvCallName
->MaximumLength
= Length
;
2416 SrvCallName
->Length
= Length
;
2418 /* Return the rest if asked */
2419 if (RestOfName
!= NULL
)
2421 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
2422 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2423 RestOfName
->MaximumLength
= Length
;
2424 RestOfName
->Length
= Length
;
2432 RxFcbTableInsertFcb(
2433 IN OUT PRX_FCB_TABLE FcbTable
,
2438 /* We deal with the table, make sure it's locked */
2439 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2441 /* Compute the hash */
2442 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2444 RxReferenceNetFcb(Fcb
);
2446 /* If no length, it will be our null entry */
2447 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2449 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2451 /* Otherwise, insert in the appropriate bucket */
2454 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2455 &Fcb
->FcbTableEntry
.HashLinks
);
2458 /* Propagate the change by incrementing the version number */
2459 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2461 return STATUS_SUCCESS
;
2468 RxFcbTableLookupFcb(
2469 IN PRX_FCB_TABLE FcbTable
,
2470 IN PUNICODE_STRING Path
)
2473 PRX_FCB_TABLE_ENTRY TableEntry
;
2477 /* No path - easy, that's null entry */
2480 TableEntry
= FcbTable
->TableEntryForNull
;
2485 PLIST_ENTRY HashBucket
, ListEntry
;
2487 /* Otherwise, compute the hash value and find the associated bucket */
2488 Hash
= RxTableComputePathHashValue(Path
);
2489 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2490 /* If the bucket is empty, it means there's no entry yet */
2491 if (IsListEmpty(HashBucket
))
2497 /* Otherwise, browse all the entry */
2498 for (ListEntry
= HashBucket
->Flink
;
2499 ListEntry
!= HashBucket
;
2500 ListEntry
= ListEntry
->Flink
)
2502 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2503 InterlockedIncrement(&FcbTable
->Compares
);
2505 /* If entry hash and string are equal, thatt's the one! */
2506 if (TableEntry
->HashValue
== Hash
&&
2507 TableEntry
->Path
.Length
== Path
->Length
&&
2508 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2514 /* We reached the end? Not found */
2515 if (ListEntry
== HashBucket
)
2522 InterlockedIncrement(&FcbTable
->Lookups
);
2524 /* If table entry isn't null, return the FCB */
2525 if (TableEntry
!= NULL
)
2527 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2528 RxReferenceNetFcb(Fcb
);
2533 InterlockedIncrement(&FcbTable
->FailedLookups
);
2543 RxFcbTableRemoveFcb(
2544 IN OUT PRX_FCB_TABLE FcbTable
,
2549 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2551 /* If no path, then remove entry for null */
2552 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2554 FcbTable
->TableEntryForNull
= NULL
;
2556 /* Otherwise, remove from the bucket */
2559 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2562 /* Reset its list entry */
2563 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2565 /* Propagate the change by incrementing the version number */
2566 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2568 return STATUS_SUCCESS
;
2576 RxFinalizeConnection(
2577 IN OUT PNET_ROOT NetRoot
,
2578 IN OUT PV_NET_ROOT VNetRoot OPTIONAL
,
2579 IN LOGICAL ForceFilesClosed
)
2582 PRX_PREFIX_TABLE PrefixTable
;
2583 ULONG UncleanAny
, UncleanDir
;
2584 LONG FilesOpen
, AdditionalRef
;
2585 BOOLEAN PrefixLocked
, FcbTableLocked
, ForceClose
;
2589 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
2591 /* Get a BOOLEAN out of LOGICAL
2592 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2594 ForceClose
= (ForceFilesClosed
== TRUE
? TRUE
: FALSE
);
2596 /* First, delete any notification change */
2597 Status
= RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot
, ForceClose
);
2598 /* If it failed, continue if forced */
2599 if (Status
!= STATUS_SUCCESS
&& !ForceFilesClosed
)
2603 /* Reset status, in case notification deletion failed */
2604 Status
= STATUS_SUCCESS
;
2606 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2608 PrefixLocked
= FALSE
;
2609 FcbTableLocked
= FALSE
;
2616 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2617 PrefixLocked
= TRUE
;
2619 RxReferenceNetRoot(NetRoot
);
2621 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2622 FcbTableLocked
= TRUE
;
2624 /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2625 if (!VNetRoot
->ConnectionFinalizationDone
)
2628 PRX_FCB_TABLE FcbTable
;
2630 DPRINT("Finalizing connection %p: %wZ\n", NetRoot
, &NetRoot
->PrefixEntry
.Prefix
);
2632 /* We'll browse all its associated FCB to check whether they're open/orphaned */
2633 FcbTable
= &NetRoot
->FcbTable
;
2634 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2636 PLIST_ENTRY BucketList
, Entry
;
2638 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
2639 Entry
= BucketList
->Flink
;
2640 while (Entry
!= BucketList
)
2644 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
2645 Entry
= Entry
->Flink
;
2647 /* FCB for this connection, go ahead */
2648 if (Fcb
->VNetRoot
== VNetRoot
)
2650 /* It's still open, and no force? Fail and keep track */
2651 if (Fcb
->UncleanCount
> 0 && !ForceClose
)
2653 Status
= STATUS_CONNECTION_IN_USE
;
2654 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2665 /* Else, force purge */
2666 ASSERT(NodeTypeIsFcb(Fcb
));
2668 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
2669 ASSERT(Status
== STATUS_SUCCESS
);
2671 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2673 RxScavengeRelatedFobxs(Fcb
);
2676 /* We don't need to release FCB lock, FCB finalize will take care of it */
2682 /* No files left, our V_NET_ROOT is finalized */
2683 if (VNetRoot
->NumberOfFobxs
== 0)
2685 VNetRoot
->ConnectionFinalizationDone
= TRUE
;
2689 /* Keep Number of open files and track of the extra reference */
2690 FilesOpen
= VNetRoot
->NumberOfFobxs
;
2691 AdditionalRef
= VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
;
2692 /* If force close, caller doesn't want to keep connection alive
2693 * and wants it totally close, so drop the V_NET_ROOT too
2697 RxFinalizeVNetRoot(VNetRoot
, FALSE
, TRUE
);
2702 /* Release what was acquired */
2705 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2708 /* If close is forced, only fix status if there are open files */
2711 if (Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0)
2713 Status
= STATUS_FILES_OPEN
;
2716 /* Else, fix status and fail closing if there are open files */
2719 if ((Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0) || FilesOpen
> 0)
2721 Status
= STATUS_FILES_OPEN
;
2725 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny
, UncleanDir
, FilesOpen
);
2727 /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2728 * only if it was still referenced!
2730 if ((ForceFilesClosed
== 0xFF || Status
== STATUS_SUCCESS
) && AdditionalRef
!= 0)
2732 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2733 RxDereferenceVNetRoot(VNetRoot
, LHS_ExclusiveLockHeld
);
2738 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2739 RxReleasePrefixTableLock(PrefixTable
);
2752 IN OUT PRX_FCB_TABLE FcbTable
)
2758 /* Just delete the lock */
2759 ExDeleteResourceLite(&FcbTable
->TableLock
);
2761 /* And make sure (checked) that the table is really empty... */
2762 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2764 ASSERT(IsListEmpty(&FcbTable
->HashBuckets
[Bucket
]));
2774 IN BOOLEAN RecursiveFinalize
,
2775 IN BOOLEAN ForceFinalize
,
2776 IN LONG ReferenceCount
)
2780 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2781 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2783 /* Make sure we have an exclusively acquired FCB */
2784 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2785 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2787 /* We shouldn't force finalization... */
2788 ASSERT(!ForceFinalize
);
2790 /* If recurisve, finalize all the associated SRV_OPEN */
2791 if (RecursiveFinalize
)
2793 PLIST_ENTRY ListEntry
;
2795 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2796 ListEntry
!= &ThisFcb
->SrvOpenList
;
2797 ListEntry
= ListEntry
->Flink
)
2801 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2802 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2805 /* If FCB is still in use, that's over */
2808 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2810 ASSERT(ReferenceCount
> 0);
2816 ASSERT(ReferenceCount
>= 1);
2818 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2819 if (ReferenceCount
!= 1 && !ForceFinalize
)
2824 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2826 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb
->OpenCount
, ForceFinalize
);
2828 /* If finalization was not already initiated, go ahead */
2829 if (!ThisFcb
->UpperFinalizationDone
)
2831 /* Free any FCB_LOCK */
2832 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2834 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2836 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2840 Entry
= ThisFcb
->BufferedLocks
.List
;
2841 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2847 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2848 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2852 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2854 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2856 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2858 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2862 ThisFcb
->UpperFinalizationDone
= TRUE
;
2865 ASSERT(ReferenceCount
>= 1);
2867 /* Even if forced, don't allow broken free */
2868 if (ReferenceCount
!= 1)
2873 /* Now, release everything */
2874 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2876 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2879 if (ThisFcb
->MRxDispatch
!= NULL
)
2881 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2884 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2885 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2886 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2888 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2889 RxDereferenceVNetRoot(ThisFcb
->VNetRoot
, LHS_LockNotHeld
);
2891 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2892 ASSERT(!ThisFcb
->fMiniInited
);
2894 /* And free the object */
2895 RxFreeFcbObject(ThisFcb
);
2905 _Out_ PFOBX ThisFobx
,
2906 _In_ BOOLEAN RecursiveFinalize
,
2907 _In_ BOOLEAN ForceFinalize
)
2914 ASSERT(NodeType(ThisFobx
) == RDBSS_NTC_FOBX
);
2916 /* Only finalize if forced or if there's no ref left */
2917 if (ThisFobx
->NodeReferenceCount
!= 0 &&
2923 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx
, ThisFobx
->NodeReferenceCount
, ForceFinalize
);
2925 SrvOpen
= ThisFobx
->SrvOpen
;
2927 /* If it wasn't finalized yet, do it */
2928 if (!ThisFobx
->UpperFinalizationDone
)
2930 ASSERT(NodeType(SrvOpen
->Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
2931 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
2933 /* Remove it from the SRV_OPEN */
2934 RemoveEntryList(&ThisFobx
->FobxQLinks
);
2936 /* If we were used to browse a directory, free the query buffer */
2937 if (BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_FREE_UNICODE
))
2939 RxFreePoolWithTag(ThisFobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
2942 /* Notify the mini-rdr */
2943 if (Fcb
->MRxDispatch
!= NULL
&& Fcb
->MRxDispatch
->MRxDeallocateForFobx
!= NULL
)
2945 Fcb
->MRxDispatch
->MRxDeallocateForFobx((PMRX_FOBX
)ThisFobx
);
2948 /* If the SRV_OPEN wasn't closed yet, do it */
2949 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
2953 Status
= RxCloseAssociatedSrvOpen(ThisFobx
, FALSE
);
2954 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen
, ThisFobx
, Status
);
2957 /* Finalization done */
2958 ThisFobx
->UpperFinalizationDone
= TRUE
;
2961 /* If we're still referenced, don't go any further! */
2962 if (ThisFobx
->NodeReferenceCount
!= 0)
2967 /* At that point, everything should be closed */
2968 ASSERT(IsListEmpty(&ThisFobx
->ClosePendingList
));
2970 /* Was the FOBX allocated with another object?
2971 * If so, mark the buffer free in said object
2973 if (ThisFobx
== Fcb
->InternalFobx
)
2975 ClearFlag(Fcb
->FcbState
, FCB_STATE_FOBX_USED
);
2977 else if (ThisFobx
== SrvOpen
->InternalFobx
)
2979 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
);
2982 ThisFobx
->pSrvOpen
= NULL
;
2985 InterlockedDecrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
2987 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
2989 /* If it wasn't allocated with another object, free the FOBX */
2990 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_ENCLOSED_ALLOCATED
))
2992 RxFreeFcbObject(ThisFobx
);
3003 OUT PNET_ROOT ThisNetRoot
,
3004 IN BOOLEAN RecursiveFinalize
,
3005 IN BOOLEAN ForceFinalize
)
3008 PRX_FCB_TABLE FcbTable
;
3009 PRX_PREFIX_TABLE PrefixTable
;
3013 ASSERT(NodeType(ThisNetRoot
) == RDBSS_NTC_NETROOT
);
3015 PrefixTable
= ThisNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3016 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3018 /* If sme finalization is already ongoing, leave */
3019 if (BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
))
3024 /* Mark we're finalizing */
3025 SetFlag(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
);
3027 FcbTable
= &ThisNetRoot
->FcbTable
;
3028 /* Did caller asked us to finalize any associated FCB? */
3029 if (RecursiveFinalize
)
3033 /* Browse all the FCBs in our FCB table */
3034 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
3035 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
3037 PLIST_ENTRY HashBucket
, ListEntry
;
3039 HashBucket
= &FcbTable
->HashBuckets
[Bucket
];
3040 ListEntry
= HashBucket
->Flink
;
3041 while (ListEntry
!= HashBucket
)
3045 Fcb
= CONTAINING_RECORD(ListEntry
, FCB
, FcbTableEntry
.HashLinks
);
3046 ASSERT(NodeTypeIsFcb(Fcb
));
3048 ListEntry
= ListEntry
->Flink
;
3050 /* If the FCB isn't orphaned, then, it's time to purge it */
3051 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3055 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
3056 ASSERT(Status
== STATUS_SUCCESS
);
3061 RxReleaseFcbTableLock(FcbTable
);
3064 /* Only finalize if forced or if there's a single ref left */
3065 if (ThisNetRoot
->NodeReferenceCount
!= 1 && !ForceFinalize
)
3070 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot
, &ThisNetRoot
->PrefixEntry
.Prefix
);
3072 /* If we're still referenced, don't go any further! */
3073 if (ThisNetRoot
->NodeReferenceCount
!= 1)
3078 /* Finalize the FCB table (and make sure it's empty!) */
3079 RxFinalizeFcbTable(FcbTable
);
3081 /* If name wasn't remove already, do it now */
3082 if (!BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
3084 RxRemovePrefixTableEntry(PrefixTable
, &ThisNetRoot
->PrefixEntry
);
3087 /* Delete the object */
3088 SrvCall
= (PSRV_CALL
)ThisNetRoot
->pSrvCall
;
3089 RxFreeObject(ThisNetRoot
);
3091 /* And dereference the associated SRV_CALL */
3092 if (SrvCall
!= NULL
)
3094 RxDereferenceSrvCall(SrvCall
, LHS_ExclusiveLockHeld
);
3105 OUT PSRV_CALL ThisSrvCall
,
3106 IN BOOLEAN RecursiveFinalize
,
3107 IN BOOLEAN ForceFinalize
)
3109 PRX_PREFIX_TABLE PrefixTable
;
3113 ASSERT(NodeType(ThisSrvCall
) == RDBSS_NTC_SRVCALL
);
3115 PrefixTable
= ThisSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3116 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3118 /* Only finalize if forced or if there's a single ref left */
3119 if (ThisSrvCall
->NodeReferenceCount
!= 1 &&
3125 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall
, &ThisSrvCall
->PrefixEntry
.Prefix
);
3127 /* If it wasn't finalized yet, do it */
3128 if (!ThisSrvCall
->UpperFinalizationDone
)
3132 /* Remove ourselves from prefix table */
3133 RxRemovePrefixTableEntry(PrefixTable
, &ThisSrvCall
->PrefixEntry
);
3135 /* Remember our third arg, in case we get queued for later execution */
3138 SetFlag(ThisSrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
3142 ThisSrvCall
->UpperFinalizationDone
= TRUE
;
3144 /* Would defered execution free the object? */
3145 WillFree
= (ThisSrvCall
->NodeReferenceCount
== 1);
3147 /* If we have a device object */
3148 if (ThisSrvCall
->RxDeviceObject
!= NULL
)
3152 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3153 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3155 /* Extra ref, as usual */
3156 InterlockedIncrement((volatile long *)&ThisSrvCall
->NodeReferenceCount
);
3158 RxDispatchToWorkerThread(ThisSrvCall
->RxDeviceObject
, DelayedWorkQueue
, RxpDestroySrvCall
, ThisSrvCall
);
3160 /* Return to the caller, in advance, whether we're freeing the object or not */
3164 /* If in the right thread already, call the mini-rdr */
3165 MINIRDR_CALL_THROUGH(Status
, ThisSrvCall
->RxDeviceObject
->Dispatch
,
3166 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)ThisSrvCall
, ForceFinalize
));
3171 /* If we're still referenced, don't go any further! */
3172 if (ThisSrvCall
->NodeReferenceCount
!= 1)
3178 if (ThisSrvCall
->pDomainName
!= NULL
)
3180 RxFreePool(ThisSrvCall
->pDomainName
);
3184 RxTearDownBufferingManager(ThisSrvCall
);
3185 RxFreeObject(ThisSrvCall
);
3195 OUT PSRV_OPEN ThisSrvOpen
,
3196 IN BOOLEAN RecursiveFinalize
,
3197 IN BOOLEAN ForceFinalize
)
3203 /* We have to have a SRV_OPEN */
3204 ASSERT(NodeType(ThisSrvOpen
) == RDBSS_NTC_SRVOPEN
);
3206 /* If that's a recursive finalization, finalize any related FOBX */
3207 if (RecursiveFinalize
)
3209 PLIST_ENTRY ListEntry
;
3211 ListEntry
= ThisSrvOpen
->FobxList
.Flink
;
3212 while (ListEntry
!= &ThisSrvOpen
->FobxList
)
3216 Fobx
= CONTAINING_RECORD(ListEntry
, FOBX
, FobxQLinks
);
3217 ListEntry
= ListEntry
->Flink
;
3218 RxFinalizeNetFobx(Fobx
, TRUE
, ForceFinalize
);
3222 /* If we have still references, don't finalize unless forced */
3223 if (ThisSrvOpen
->NodeReferenceCount
!= 0 &&
3229 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen
, ThisSrvOpen
->NodeReferenceCount
, ForceFinalize
);
3231 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3232 Fcb
= (PFCB
)ThisSrvOpen
->pFcb
;
3233 if ((!ThisSrvOpen
->UpperFinalizationDone
&& ThisSrvOpen
->Condition
!= Condition_Good
) ||
3234 BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
3236 PV_NET_ROOT VNetRoot
;
3238 /* Associated FCB can't be fake one */
3239 ASSERT(NodeType(Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
3240 ASSERT(RxIsFcbAcquiredExclusive (Fcb
));
3242 /* Purge any pending operation */
3243 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen
);
3245 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3246 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3250 MINIRDR_CALL_THROUGH(Status
, Fcb
->MRxDispatch
, MRxForceClosed
, ((PMRX_SRV_OPEN
)ThisSrvOpen
));
3254 /* Remove ourselves from the FCB */
3255 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3256 InitializeListHead(&ThisSrvOpen
->SrvOpenQLinks
);
3257 ++Fcb
->SrvOpenListVersion
;
3259 /* If we have a V_NET_ROOT, dereference it */
3260 VNetRoot
= (PV_NET_ROOT
)ThisSrvOpen
->pVNetRoot
;
3261 if (VNetRoot
!= NULL
)
3263 InterlockedDecrement((volatile long *)&VNetRoot
->pNetRoot
->NumberOfSrvOpens
);
3264 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3265 ThisSrvOpen
->pVNetRoot
= NULL
;
3268 /* Finalization done */
3269 ThisSrvOpen
->UpperFinalizationDone
= TRUE
;
3272 /* Don't free memory if still referenced */
3273 if (ThisSrvOpen
->NodeReferenceCount
!= 0)
3278 /* No key association left */
3279 ASSERT(IsListEmpty(&ThisSrvOpen
->SrvOpenKeyList
));
3281 /* If we're still in some FCB, remove us */
3282 if (!IsListEmpty(&ThisSrvOpen
->SrvOpenQLinks
))
3284 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3287 /* If enclosed allocation, mark the memory zone free */
3288 if (BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
))
3290 ClearFlag(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
);
3292 /* Otherwise, free the memory */
3295 RxFreeFcbObject(ThisSrvOpen
);
3298 RxDereferenceNetFcb(Fcb
);
3308 OUT PV_NET_ROOT ThisVNetRoot
,
3309 IN BOOLEAN RecursiveFinalize
,
3310 IN BOOLEAN ForceFinalize
)
3313 PRX_PREFIX_TABLE PrefixTable
;
3317 ASSERT(NodeType(ThisVNetRoot
) == RDBSS_NTC_V_NETROOT
);
3319 PrefixTable
= ThisVNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3320 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3322 /* Only finalize if forced or if there's a single ref left */
3323 if (ThisVNetRoot
->NodeReferenceCount
!= 1 &&
3329 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot
, &ThisVNetRoot
->PrefixEntry
.Prefix
);
3331 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
3332 /* If it wasn't finalized yet, do it */
3333 if (!ThisVNetRoot
->UpperFinalizationDone
)
3335 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
3337 /* Reference the NetRoot so that it doesn't disappear */
3338 RxReferenceNetRoot(NetRoot
);
3339 RxOrphanSrvOpens(ThisVNetRoot
);
3340 /* Remove us from the available VNetRoot for NetRoot */
3341 RxRemoveVirtualNetRootFromNetRoot(NetRoot
, ThisVNetRoot
);
3342 /* Remove extra ref */
3343 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3345 /* Remove ourselves from prefix table */
3346 RxRemovePrefixTableEntry(PrefixTable
, &ThisVNetRoot
->PrefixEntry
);
3348 /* Finalization done */
3349 ThisVNetRoot
->UpperFinalizationDone
= TRUE
;
3352 /* If we're still referenced, don't go any further! */
3353 if (ThisVNetRoot
->NodeReferenceCount
!= 1)
3358 /* If there's an associated device, notify mini-rdr */
3359 if (NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
3363 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
3364 MRxFinalizeVNetRoot
, ((PMRX_V_NET_ROOT
)ThisVNetRoot
, FALSE
));
3368 /* Free parameters */
3369 RxUninitializeVNetRootParameters(ThisVNetRoot
->pUserName
, ThisVNetRoot
->pUserDomainName
,
3370 ThisVNetRoot
->pPassword
, &ThisVNetRoot
->Flags
);
3371 /* Dereference our NetRoot, we won't reference it anymore */
3372 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3374 /* And free the object! */
3375 RxFreePoolWithTag(ThisVNetRoot
, RX_V_NETROOT_POOLTAG
);
3381 RxFindOrConstructVirtualNetRoot(
3382 IN PRX_CONTEXT RxContext
,
3383 IN PUNICODE_STRING CanonicalName
,
3384 IN NET_ROOT_TYPE NetRootType
,
3385 IN PUNICODE_STRING RemainingName
)
3391 PV_NET_ROOT VNetRoot
;
3392 RX_CONNECTION_ID ConnectionID
;
3393 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3394 LOCK_HOLDING_STATE LockHoldingState
;
3398 RxDeviceObject
= RxContext
->RxDeviceObject
;
3399 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
3400 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
3402 /* Ask the mini-rdr for connection ID */
3403 ConnectionID
.SessionID
= 0;
3404 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
3406 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
3407 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
3409 /* mini-rdr is expected not to fail - unless it's not implemented */
3410 DPRINT1("Failed to initialize connection ID\n");
3415 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
3417 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
3418 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3419 LockHoldingState
= LHS_SharedLockHeld
;
3423 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3427 PV_NET_ROOT SavedVNetRoot
;
3429 /* Look in prefix table */
3430 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
3431 if (Container
!= NULL
)
3433 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3434 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
3436 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3437 RxDereferenceSrvCall(Container
, LockHoldingState
);
3441 VNetRoot
= Container
;
3442 NetRoot
= VNetRoot
->NetRoot
;
3444 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3445 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
3446 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3448 Status
= STATUS_BAD_NETWORK_PATH
;
3449 SavedVNetRoot
= NULL
;
3455 PUNICODE_STRING UserName
, UserDomain
, Password
;
3457 /* We can reuse if we use same credentials */
3458 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
3459 &SessionId
, &UserName
,
3460 &UserDomain
, &Password
,
3462 if (NT_SUCCESS(Status
))
3464 SavedVNetRoot
= VNetRoot
;
3465 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
3467 UserDomain
, Password
,
3469 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
3471 PLIST_ENTRY ListEntry
;
3473 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
3474 ListEntry
!= &NetRoot
->VirtualNetRoots
;
3475 ListEntry
= ListEntry
->Flink
)
3477 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
3478 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
3480 UserDomain
, Password
,
3482 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3488 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
3490 SavedVNetRoot
= NULL
;
3494 if (!NT_SUCCESS(Status
))
3496 SavedVNetRoot
= NULL
;
3499 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
3503 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3504 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
3506 if (SavedVNetRoot
== NULL
)
3508 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3511 /* Reference VNetRoot we'll keep, and dereference current */
3512 else if (SavedVNetRoot
!= VNetRoot
)
3514 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3515 if (SavedVNetRoot
!= NULL
)
3517 RxReferenceVNetRoot(SavedVNetRoot
);
3522 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3523 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3530 /* If we're locked exclusive, we won't loop again, it was the second pass */
3531 if (LockHoldingState
!= LHS_SharedLockHeld
)
3536 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3537 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
3539 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3540 LockHoldingState
= LHS_ExclusiveLockHeld
;
3544 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3545 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3546 LockHoldingState
= LHS_ExclusiveLockHeld
;
3549 /* We didn't fail, and didn't find any VNetRoot, construct one */
3552 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
3554 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
3555 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
3557 if (Status
== STATUS_SUCCESS
)
3559 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
3560 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3561 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
3563 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3564 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
3565 RemainingName
->MaximumLength
= RemainingName
->Length
;
3567 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
3569 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
3571 VNetRoot
->Flags
|= Flags
;
3575 /* Release the prefix table - caller expects it to be released */
3576 if (LockHoldingState
!= LHS_LockNotHeld
)
3578 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3581 /* If we failed creating, quit */
3582 if (Status
!= STATUS_SUCCESS
)
3584 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
3588 /* Otherwise, wait until the VNetRoot is stable */
3589 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
3590 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
3591 /* It's all good, update the RX_CONTEXT with all our structs */
3592 if (VNetRoot
->Condition
== Condition_Good
)
3596 NetRoot
= VNetRoot
->NetRoot
;
3597 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3598 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3599 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
3603 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3604 RxContext
->Create
.pVNetRoot
= NULL
;
3605 Status
= STATUS_BAD_NETWORK_PATH
;
3615 RxFindOrCreateConnections(
3616 _In_ PRX_CONTEXT RxContext
,
3617 _In_ PUNICODE_STRING CanonicalName
,
3618 _In_ NET_ROOT_TYPE NetRootType
,
3619 _Out_ PUNICODE_STRING LocalNetRootName
,
3620 _Out_ PUNICODE_STRING FilePathName
,
3621 _Inout_ PLOCK_HOLDING_STATE LockState
,
3622 _In_ PRX_CONNECTION_ID RxConnectionId
)
3627 PV_NET_ROOT VNetRoot
;
3628 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
3629 PRX_PREFIX_TABLE PrefixTable
;
3630 UNICODE_STRING RemainingName
, NetRootName
;
3634 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3635 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
3636 FilePathName
, LockState
, RxConnectionId
);
3638 *FilePathName
= *CanonicalName
;
3639 LocalNetRootName
->Length
= 0;
3640 LocalNetRootName
->MaximumLength
= 0;
3641 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
3643 /* UNC path, split it */
3644 if (FilePathName
->Buffer
[1] == ';')
3650 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
3652 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
3661 return STATUS_OBJECT_NAME_INVALID
;
3664 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
3665 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
3666 LocalNetRootName
->Length
= Length
;
3667 LocalNetRootName
->MaximumLength
= Length
;
3668 FilePathName
->Length
-= Length
;
3670 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
3671 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
3672 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
3676 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
3681 ASSERT(*LockState
!= LHS_LockNotHeld
);
3683 /* If previous lookup left something, dereference it */
3684 if (Container
!= NULL
)
3686 switch (NodeType(Container
))
3688 case RDBSS_NTC_SRVCALL
:
3689 RxDereferenceSrvCall(Container
, *LockState
);
3692 case RDBSS_NTC_NETROOT
:
3693 RxDereferenceNetRoot(Container
, *LockState
);
3696 case RDBSS_NTC_V_NETROOT
:
3697 RxDereferenceVNetRoot(Container
, *LockState
);
3701 /* Should never happen */
3707 /* Look for our NetRoot in prefix table */
3708 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
3709 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
3713 UNICODE_STRING SrvCallName
;
3719 /* Assume we didn't succeed */
3720 RxContext
->Create
.pVNetRoot
= NULL
;
3721 RxContext
->Create
.pNetRoot
= NULL
;
3722 RxContext
->Create
.pSrvCall
= NULL
;
3723 RxContext
->Create
.Type
= NetRootType
;
3725 /* If we found something */
3726 if (Container
!= NULL
)
3729 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
3731 VNetRoot
= Container
;
3732 /* Use its NetRoot */
3733 NetRoot
= VNetRoot
->NetRoot
;
3735 /* If it's not stable, wait for it to be stable */
3736 if (NetRoot
->Condition
== Condition_InTransition
)
3738 RxReleasePrefixTableLock(PrefixTable
);
3739 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
3740 RxWaitForStableNetRoot(NetRoot
, RxContext
);
3741 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3742 *LockState
= LHS_ExclusiveLockHeld
;
3744 /* Now that's it's ok, retry lookup to find what we want */
3745 if (NetRoot
->Condition
== Condition_Good
)
3751 /* Is the associated netroot good? */
3752 if (NetRoot
->Condition
== Condition_Good
)
3754 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
3756 /* If it is, and SrvCall as well, then, we have our active connection */
3757 if (SrvCall
->Condition
== Condition_Good
&&
3758 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
3760 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3761 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3762 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3764 Status
= STATUS_CONNECTION_ACTIVE
;
3769 /* If VNetRoot was well constructed, it means the connection is active */
3770 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
3772 Status
= STATUS_CONNECTION_ACTIVE
;
3776 Status
= VNetRoot
->ConstructionStatus
;
3779 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3782 /* Can only be a SrvCall */
3785 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3786 SrvCall
= Container
;
3788 /* Wait for the SRV_CALL to be stable */
3789 if (SrvCall
->Condition
== Condition_InTransition
)
3791 RxReleasePrefixTableLock(PrefixTable
);
3792 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
3793 RxWaitForStableSrvCall(SrvCall
, RxContext
);
3794 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3795 *LockState
= LHS_ExclusiveLockHeld
;
3797 /* It went good, loop again to find what we look for */
3798 if (SrvCall
->Condition
== Condition_Good
)
3804 /* If it's not good... */
3805 if (SrvCall
->Condition
!= Condition_Good
)
3807 /* But SRV_CALL was well constructed, assume a connection was active */
3808 if (SrvCall
->Status
== STATUS_SUCCESS
)
3810 Status
= STATUS_CONNECTION_ACTIVE
;
3814 Status
= SrvCall
->Status
;
3817 RxDereferenceSrvCall(SrvCall
, *LockState
);
3823 /* If we found a SRV_CALL not matching our DO, quit */
3824 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
3825 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3827 RxDereferenceSrvCall(SrvCall
, *LockState
);
3828 Status
= STATUS_BAD_NETWORK_NAME
;
3832 /* Now, we want exclusive lock */
3833 if (*LockState
== LHS_SharedLockHeld
)
3835 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
3837 RxReleasePrefixTableLock(PrefixTable
);
3838 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3839 *LockState
= LHS_ExclusiveLockHeld
;
3843 RxReleasePrefixTableLock(PrefixTable
);
3844 *LockState
= LHS_ExclusiveLockHeld
;
3847 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3849 /* If we reach that point, we found something, no need to create something */
3850 if (Container
!= NULL
)
3855 /* Get the name for the SRV_CALL */
3856 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
3857 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
3858 /* And create the SRV_CALL */
3859 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
3860 if (SrvCall
== NULL
)
3862 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3866 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3867 RxReferenceSrvCall(SrvCall
);
3868 RxContext
->Create
.pVNetRoot
= NULL
;
3869 RxContext
->Create
.pNetRoot
= NULL
;
3870 RxContext
->Create
.pSrvCall
= NULL
;
3871 RxContext
->Create
.Type
= NetRootType
;
3872 Container
= SrvCall
;
3874 /* Construct SRV_CALL, ie, use mini-rdr */
3875 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
3876 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
3877 if (Status
!= STATUS_SUCCESS
)
3879 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
3880 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3881 RxDereferenceSrvCall(SrvCall
, *LockState
);
3882 RxReleasePrefixTableLock(PrefixTable
);
3886 /* Loop again to make use of SRV_CALL stable condition wait */
3889 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3890 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
3891 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
3892 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
3894 /* Call mini-rdr to get NetRoot name */
3895 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
3896 /* And create the NetRoot with that name */
3897 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
3898 if (NetRoot
== NULL
)
3900 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3903 NetRoot
->Type
= NetRootType
;
3905 RxDereferenceSrvCall(SrvCall
, *LockState
);
3907 /* Finally, create the associated VNetRoot */
3908 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
3909 if (VNetRoot
== NULL
)
3911 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
3912 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3915 RxReferenceVNetRoot(VNetRoot
);
3917 /* We're get closer! */
3918 NetRoot
->Condition
= Condition_InTransition
;
3919 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3920 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3921 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3923 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3924 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
3925 if (!NT_SUCCESS(Status
))
3927 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
3928 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
3929 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3931 RxContext
->Create
.pNetRoot
= NULL
;
3932 RxContext
->Create
.pVNetRoot
= NULL
;
3936 PIO_STACK_LOCATION Stack
;
3938 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3940 Stack
= RxContext
->CurrentIrpSp
;
3941 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
3943 RxExclusivePrefixTableLockToShared(PrefixTable
);
3944 *LockState
= LHS_SharedLockHeld
;
3950 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
3952 if (*LockState
!= LHS_LockNotHeld
)
3954 RxReleasePrefixTableLock(PrefixTable
);
3955 *LockState
= LHS_LockNotHeld
;
3961 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
3970 RxFinishFcbInitialization(
3971 IN OUT PMRX_FCB Fcb
,
3972 IN RX_FILE_TYPE FileType
,
3973 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
3975 RX_FILE_TYPE OldType
;
3979 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
3981 OldType
= NodeType(Fcb
);
3982 NodeType(Fcb
) = FileType
;
3983 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
3984 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
3986 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3988 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
3989 else if (InitPacket
!= NULL
)
3991 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
3992 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
3993 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
3994 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
3995 InitPacket
->pValidDataLength
->QuadPart
);
3998 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3999 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
4001 /* If our FCB newly points to a file, initiliaze everything related */
4002 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
)
4005 if (OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
4007 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
4008 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, RxLockOperationCompletion
,
4011 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
4012 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
4014 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
4017 /* If not a file, validate type */
4020 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
4029 RxFinishSrvCallConstruction(
4030 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
4034 PRX_CONTEXT Context
;
4035 RX_BLOCK_CONDITION Condition
;
4036 PRX_PREFIX_TABLE PrefixTable
;
4038 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
4040 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
4041 Context
= Calldown
->RxContext
;
4042 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
4044 /* We have a winner, notify him */
4045 if (Calldown
->BestFinisher
!= NULL
)
4047 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
4049 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
4051 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
4052 MRxSrvCallWinnerNotify
,
4053 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
4054 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
4055 if (Status
!= STATUS_SUCCESS
)
4057 Condition
= Condition_Bad
;
4061 Condition
= Condition_Good
;
4064 /* Otherwise, just fail our SRV_CALL */
4067 Status
= Calldown
->CallbackContexts
[0].Status
;
4068 Condition
= Condition_Bad
;
4071 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
4072 RxTransitionSrvCall(SrvCall
, Condition
);
4073 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
4075 /* If async, finish it here, otherwise, caller has already finished the stuff */
4076 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
4078 DPRINT("Finishing async call\n");
4080 RxReleasePrefixTableLock(PrefixTable
);
4082 /* Make sure we weren't cancelled in-between */
4083 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
4085 Status
= STATUS_CANCELLED
;
4088 /* In case that was a create, context can be reused */
4089 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
4091 RxpPrepareCreateContextForReuse(Context
);
4094 /* If that's a failure, reset everything and return failure */
4095 if (Status
!= STATUS_SUCCESS
)
4097 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
4098 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4100 if (Context
->Info
.Buffer
!= NULL
)
4102 RxFreePool(Context
->Info
.Buffer
);
4103 Context
->Info
.Buffer
= NULL
;
4106 Context
->CurrentIrp
->IoStatus
.Information
= 0;
4107 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
4108 RxCompleteRequest(Context
, Status
);
4110 /* Otherwise, call resume routine and done! */
4113 Status
= Context
->ResumeRoutine(Context
);
4114 if (Status
!= STATUS_PENDING
)
4116 RxCompleteRequest(Context
, Status
);
4119 DPRINT("Not completing, pending\n");
4123 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
4132 RxFinishSrvCallConstructionDispatcher(
4136 BOOLEAN Direct
, KeepLoop
;
4138 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
4140 /* In case of failure of starting dispatcher, context is not set
4141 * We keep track of it to fail associated SRV_CALL
4143 Direct
= (Context
== NULL
);
4145 /* Separated thread, loop forever */
4148 PLIST_ENTRY ListEntry
;
4149 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
4151 /* If there are no SRV_CALL to finalize left, just finish thread */
4152 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
4153 if (IsListEmpty(&RxSrvCalldownList
))
4156 RxSrvCallConstructionDispatcherActive
= FALSE
;
4158 /* Otherwise, get the SRV_CALL to finish construction */
4161 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
4164 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
4172 /* If direct is set, reset the finisher to avoid electing a winner
4173 * and fail SRV_CALL (see upper comment)
4175 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
4178 Calldown
->BestFinisher
= NULL
;
4180 /* Finish SRV_CALL construction */
4181 RxFinishSrvCallConstruction(Calldown
);
4189 RxFlushFcbInSystemCache(
4191 IN BOOLEAN SynchronizeWithLazyWriter
)
4193 IO_STATUS_BLOCK IoStatus
;
4198 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &IoStatus
);
4199 /* If we're asked to sync with LW, do it in case of success */
4200 if (SynchronizeWithLazyWriter
&& NT_SUCCESS(IoStatus
.Status
))
4202 RxAcquirePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4203 RxReleasePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4206 DPRINT("Flushing for FCB %p returns %lx\n", Fcb
, IoStatus
.Status
);
4207 return IoStatus
.Status
;
4219 DPRINT("Freeing %p\n", Object
);
4221 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4222 if (NodeType(Object
) == RDBSS_NTC_FOBX
|| NodeType(Object
) == RDBSS_NTC_SRVOPEN
)
4224 RxFreePoolWithTag(Object
, RX_FCB_POOLTAG
);
4226 /* If that's a FCB... */
4227 else if (NodeTypeIsFcb(Object
))
4230 PRDBSS_DEVICE_OBJECT DeviceObject
;
4233 DeviceObject
= Fcb
->RxDeviceObject
;
4235 /* Delete per stream contexts */
4236 FsRtlTeardownPerStreamContexts(&Fcb
->Header
);
4238 SetFlag(Fcb
->Header
.Flags
, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH
);
4240 /* If there was a non-paged FCB allocated, free it */
4241 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
4243 RxFreePoolWithTag(Fcb
->NonPaged
, RX_NONPAGEDFCB_POOLTAG
);
4249 /* Update statistics */
4250 InterlockedDecrement(&RxNumberOfActiveFcbs
);
4251 InterlockedDecrement((volatile long *)&DeviceObject
->NumberOfActiveFcbs
);
4264 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4265 if (NodeType(pObject
) == RDBSS_NTC_SRVCALL
)
4268 PRDBSS_DEVICE_OBJECT DeviceObject
;
4270 SrvCall
= (PSRV_CALL
)pObject
;
4271 DeviceObject
= SrvCall
->RxDeviceObject
;
4272 if (DeviceObject
!= NULL
)
4274 if (!BooleanFlagOn(DeviceObject
->Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
4276 ASSERT(SrvCall
->Context
== NULL
);
4279 ASSERT(SrvCall
->Context2
== NULL
);
4281 SrvCall
->RxDeviceObject
= NULL
;
4284 else if (NodeType(pObject
) == RDBSS_NTC_NETROOT
)
4288 NetRoot
= (PNET_ROOT
)pObject
;
4289 NetRoot
->pSrvCall
= NULL
;
4290 NetRoot
->NodeTypeCode
= NodeType(pObject
) | 0xF000;
4293 /* And just free the object */
4294 RxFreePool(pObject
);
4301 RxGatherRequestsForSrvOpen(
4302 IN OUT PSRV_CALL SrvCall
,
4303 IN PSRV_OPEN SrvOpen
,
4304 IN OUT PLIST_ENTRY RequestsListHead
)
4307 LIST_ENTRY Discarded
, *Entry
;
4308 PCHANGE_BUFFERING_STATE_REQUEST Request
;
4310 /* Dispatch any pending operation first */
4311 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &Discarded
);
4313 /* Then, get any entry related to our key and SRV_OPEN */
4314 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
4315 Entry
= SrvCall
->BufferingManager
.HandlerList
.Flink
;
4316 while (Entry
!= &SrvCall
->BufferingManager
.HandlerList
)
4318 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4319 Entry
= Entry
->Flink
;
4320 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4322 RemoveEntryList(&Request
->ListEntry
);
4323 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4326 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
4328 /* Perform the same search in the last change list */
4329 Entry
= SrvCall
->BufferingManager
.LastChanceHandlerList
.Flink
;
4330 while (Entry
!= &SrvCall
->BufferingManager
.LastChanceHandlerList
)
4332 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4333 Entry
= Entry
->Flink
;
4334 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4336 RemoveEntryList(&Request
->ListEntry
);
4337 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4341 /* Discard the discarded requests */
4342 RxpDiscardChangeBufferingStateRequests(&Discarded
);
4348 PRDBSS_DEVICE_OBJECT
4349 RxGetDeviceObjectOfInstance(
4352 NODE_TYPE_CODE NodeType
;
4353 PRDBSS_DEVICE_OBJECT DeviceObject
;
4357 /* We only handle a few object types */
4358 NodeType
= NodeType(Instance
);
4359 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
4360 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) || (NodeType
== RDBSS_NTC_FOBX
));
4362 /* Get the device object depending on the object */
4365 case RDBSS_NTC_FOBX
:
4369 Fobx
= (PFOBX
)Instance
;
4370 DeviceObject
= Fobx
->RxDeviceObject
;
4374 case RDBSS_NTC_SRVCALL
:
4378 SrvCall
= (PSRV_CALL
)Instance
;
4379 DeviceObject
= SrvCall
->RxDeviceObject
;
4383 case RDBSS_NTC_NETROOT
:
4387 NetRoot
= (PNET_ROOT
)Instance
;
4388 DeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
4392 case RDBSS_NTC_V_NETROOT
:
4394 PV_NET_ROOT VNetRoot
;
4396 VNetRoot
= (PV_NET_ROOT
)Instance
;
4397 DeviceObject
= VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
;
4401 case RDBSS_NTC_SRVOPEN
:
4405 SrvOpen
= (PSRV_OPEN
)Instance
;
4406 DeviceObject
= ((PFCB
)SrvOpen
->pFcb
)->RxDeviceObject
;
4411 DeviceObject
= NULL
;
4416 return DeviceObject
;
4423 RxGetFileSizeWithLock(
4425 OUT PLONGLONG FileSize
)
4429 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
4440 return RxData
.OurProcess
;
4447 RxInitializeBufferingManager(
4450 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
4451 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
4452 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
4453 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
4454 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
4455 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
4456 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
4457 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
4458 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
4459 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
4461 return STATUS_SUCCESS
;
4469 RxInitializeContext(
4471 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
4472 IN ULONG InitialContextFlags
,
4473 IN OUT PRX_CONTEXT RxContext
)
4475 PIO_STACK_LOCATION Stack
;
4477 /* Initialize our various fields */
4478 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
4479 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
4480 RxContext
->ReferenceCount
= 1;
4481 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
4482 RxContext
->RxDeviceObject
= RxDeviceObject
;
4483 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
4484 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
4485 InitializeListHead(&RxContext
->BlockedOperations
);
4486 RxContext
->MRxCancelRoutine
= NULL
;
4487 RxContext
->ResumeRoutine
= NULL
;
4488 RxContext
->Flags
|= InitialContextFlags
;
4489 RxContext
->CurrentIrp
= Irp
;
4490 RxContext
->LastExecutionThread
= PsGetCurrentThread();
4491 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
4493 /* If've got no IRP, mark RX_CONTEXT */
4496 RxContext
->CurrentIrpSp
= NULL
;
4497 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
4498 RxContext
->MinorFunction
= 0;
4502 /* Otherwise, first determine whether we are performing async operation */
4503 Stack
= IoGetCurrentIrpStackLocation(Irp
);
4504 if (Stack
->FileObject
!= NULL
)
4508 Fcb
= Stack
->FileObject
->FsContext
;
4509 if (!IoIsOperationSynchronous(Irp
) ||
4510 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
4511 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
4512 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
4514 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4518 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
4520 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4522 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4524 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4527 /* Set proper flags if TopLevl IRP/Device */
4528 if (!RxIsThisTheTopLevelIrp(Irp
))
4530 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
4532 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
4534 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
4537 /* Copy stack information */
4538 RxContext
->MajorFunction
= Stack
->MajorFunction
;
4539 RxContext
->MinorFunction
= Stack
->MinorFunction
;
4540 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
4541 RxContext
->CurrentIrpSp
= Stack
;
4543 /* If we have a FO associated, learn for more */
4544 if (Stack
->FileObject
!= NULL
)
4549 /* Get the FCB and CCB (FOBX) */
4550 Fcb
= Stack
->FileObject
->FsContext
;
4551 Fobx
= Stack
->FileObject
->FsContext2
;
4552 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
4553 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
4555 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
4558 /* We have a FOBX, this not a DFS opening, keep track of it */
4559 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
4561 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
4562 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
4563 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4565 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
4570 RxContext
->pFobx
= NULL
;
4573 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4574 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
4577 PV_NET_ROOT VNetRoot
= NULL
;
4579 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4581 VNetRoot
= Fcb
->VNetRoot
;
4583 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
4585 VNetRoot
= (PV_NET_ROOT
)Fobx
;
4588 if (VNetRoot
!= NULL
)
4590 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
4594 /* Remember if that's a write through file */
4595 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
4596 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
4598 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
4603 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
4605 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4606 RxContext
, RxContext
->MinorFunction
, Irp
,
4607 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
4608 RxContext
->SerialNumber
);
4617 RxInitializeDebugSupport(
4628 RxInitializeDispatcher(
4632 HANDLE ThreadHandle
;
4636 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4637 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4639 /* Set appropriate timeouts: 10s & 60s */
4640 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4641 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4642 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4643 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
4645 RxDispatcher
.NumberOfProcessors
= 1;
4646 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
4647 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
4649 /* Initialize our dispatchers */
4650 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
4651 if (!NT_SUCCESS(Status
))
4656 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
4657 if (!NT_SUCCESS(Status
))
4662 /* And start them */
4663 RxDispatcher
.State
= RxDispatcherActive
;
4664 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
4665 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
4666 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
4667 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
4668 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
4669 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
4670 if (NT_SUCCESS(Status
))
4672 ZwClose(ThreadHandle
);
4682 RxInitializeFcbTable(
4683 IN OUT PRX_FCB_TABLE FcbTable
,
4684 IN BOOLEAN CaseInsensitiveMatch
)
4690 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
4691 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
4693 ExInitializeResourceLite(&FcbTable
->TableLock
);
4694 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4695 FcbTable
->Version
= 0;
4696 FcbTable
->TableEntryForNull
= NULL
;
4698 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
4699 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
4701 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
4704 FcbTable
->Lookups
= 0;
4705 FcbTable
->FailedLookups
= 0;
4706 FcbTable
->Compares
= 0;
4714 RxInitializeLowIoContext(
4715 OUT PLOWIO_CONTEXT LowIoContext
,
4718 PRX_CONTEXT RxContext
;
4719 PIO_STACK_LOCATION Stack
;
4723 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
4724 ASSERT(LowIoContext
== &RxContext
->LowIoContext
);
4726 Stack
= RxContext
->CurrentIrpSp
;
4728 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
4729 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
4730 RxContext
->LowIoContext
.Operation
= Operation
;
4735 case LOWIO_OP_WRITE
:
4736 /* In case of RW, set a canary, to make sure these fields are properly set
4737 * they will be asserted when lowio request will be submit to mini-rdr
4740 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
4741 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
4742 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
4744 /* Keep track of paging IOs */
4745 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
4747 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
4751 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
4756 case LOWIO_OP_FSCTL
:
4757 case LOWIO_OP_IOCTL
:
4758 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4759 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
4760 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
4761 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
4762 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
4763 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
4764 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
4767 /* Nothing to do for these */
4768 case LOWIO_OP_SHAREDLOCK
:
4769 case LOWIO_OP_EXCLUSIVELOCK
:
4770 case LOWIO_OP_UNLOCK
:
4771 case LOWIO_OP_UNLOCK_MULTIPLE
:
4772 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4773 case LOWIO_OP_CLEAROUT
:
4777 /* Should never happen */
4787 RxInitializeLowIoPerFcbInfo(
4788 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
4792 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
4793 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
4800 RxInitializeMRxDispatcher(
4801 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
4805 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4806 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4808 return STATUS_SUCCESS
;
4815 RxInitializePrefixTable(
4816 IN OUT PRX_PREFIX_TABLE ThisTable
,
4817 IN ULONG TableSize OPTIONAL
,
4818 IN BOOLEAN CaseInsensitiveMatch
)
4824 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
4827 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
4828 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
4829 InitializeListHead(&ThisTable
->MemberQueue
);
4830 ThisTable
->Version
= 0;
4831 ThisTable
->TableEntryForNull
= NULL
;
4832 ThisTable
->IsNetNameTable
= FALSE
;
4833 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4834 ThisTable
->TableSize
= TableSize
;
4840 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
4842 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
4851 RxInitializePurgeSyncronizationContext(
4852 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
4856 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
4857 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
4861 RxInitializeSrvCallParameters(
4862 IN PRX_CONTEXT RxContext
,
4863 IN OUT PSRV_CALL SrvCall
)
4867 SrvCall
->pPrincipalName
= NULL
;
4869 /* We only have stuff to initialize for file opening from DFS */
4870 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
4872 return STATUS_SUCCESS
;
4875 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
4878 return STATUS_NOT_IMPLEMENTED
;
4886 RxInitializeRxTimer(
4891 RxTimerInterval
.QuadPart
= -550000;
4892 KeInitializeSpinLock(&RxTimerLock
);
4893 InitializeListHead(&RxTimerQueueHead
);
4894 InitializeListHead(&RxRecurrentWorkItemsList
);
4895 KeInitializeDpc(&RxTimerDpc
, RxTimerDispatch
, NULL
);
4896 KeInitializeTimer(&RxTimer
);
4897 RxTimerTickCount
= 0;
4899 return STATUS_SUCCESS
;
4903 RxInitializeVNetRootParameters(
4904 PRX_CONTEXT RxContext
,
4906 OUT PULONG SessionId
,
4907 OUT PUNICODE_STRING
*UserNamePtr
,
4908 OUT PUNICODE_STRING
*UserDomainNamePtr
,
4909 OUT PUNICODE_STRING
*PasswordPtr
,
4913 PACCESS_TOKEN Token
;
4917 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
4918 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
4920 *UserNamePtr
= NULL
;
4921 *UserDomainNamePtr
= NULL
;
4922 *PasswordPtr
= NULL
;
4923 /* By default, that's not CSC instance */
4924 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4926 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
4927 if (SeTokenIsRestricted(Token
))
4929 return STATUS_ACCESS_DENIED
;
4933 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
4934 if (!NT_SUCCESS(Status
))
4940 Status
= SeQuerySessionIdToken(Token
, SessionId
);
4941 if (!NT_SUCCESS(Status
))
4946 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
4949 Status
= STATUS_NOT_IMPLEMENTED
;
4953 /* Deal with connection credentials */
4954 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
4957 Status
= STATUS_NOT_IMPLEMENTED
;
4961 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
4964 Status
= STATUS_NOT_IMPLEMENTED
;
4969 if (NT_SUCCESS(Status
))
4971 /* If that's a CSC instance, mark it as such */
4972 if (RxIsThisACscAgentOpen(RxContext
))
4974 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4986 RxInitializeWorkQueue(
4987 PRX_WORK_QUEUE WorkQueue
,
4988 WORK_QUEUE_TYPE WorkQueueType
,
4989 ULONG MaximumNumberOfWorkerThreads
,
4990 ULONG MinimumNumberOfWorkerThreads
)
4994 WorkQueue
->Type
= WorkQueueType
;
4995 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
4996 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
4998 WorkQueue
->State
= RxWorkQueueActive
;
4999 WorkQueue
->SpinUpRequestPending
= FALSE
;
5000 WorkQueue
->pRundownContext
= NULL
;
5001 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
5002 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
5003 WorkQueue
->CumulativeQueueLength
= 0;
5004 WorkQueue
->NumberOfSpinUpRequests
= 0;
5005 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
5006 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
5007 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
5008 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
5009 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
5010 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
5011 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
5012 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
5013 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
5014 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
5015 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
5016 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
5017 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
5018 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
5019 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
5020 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
5022 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
5023 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
5030 RxInitializeWorkQueueDispatcher(
5031 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
5034 ULONG MaximumNumberOfWorkerThreads
;
5038 /* Number of threads will depend on system capacity */
5039 if (MmQuerySystemSize() != MmLargeSystem
)
5041 MaximumNumberOfWorkerThreads
= 5;
5045 MaximumNumberOfWorkerThreads
= 10;
5048 /* Initialize the work queues */
5049 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
5050 MaximumNumberOfWorkerThreads
, 1);
5051 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
5052 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
5054 /* And start the worker threads */
5055 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
5056 RxBootstrapWorkerThreadDispatcher
,
5057 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
5058 if (!NT_SUCCESS(Status
))
5063 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
5064 RxBootstrapWorkerThreadDispatcher
,
5065 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
5066 if (!NT_SUCCESS(Status
))
5071 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
5072 RxBootstrapWorkerThreadDispatcher
,
5073 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
5081 RxInitiateSrvOpenKeyAssociation(
5082 IN OUT PSRV_OPEN SrvOpen
)
5084 PRX_BUFFERING_MANAGER BufferingManager
;
5088 SrvOpen
->Key
= NULL
;
5090 /* Just keep track of the opening request */
5091 BufferingManager
= &((PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
;
5092 InterlockedIncrement(&BufferingManager
->NumberOfOutstandingOpens
);
5094 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
5101 RxInsertWorkQueueItem(
5102 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
5103 WORK_QUEUE_TYPE WorkQueueType
,
5104 PRX_WORK_QUEUE_ITEM WorkQueueItem
)
5108 BOOLEAN SpinUpThreads
;
5109 PRX_WORK_QUEUE WorkQueue
;
5111 /* No dispatcher, nothing to insert */
5112 if (RxDispatcher
.State
!= RxDispatcherActive
)
5114 return STATUS_UNSUCCESSFUL
;
5117 /* Get the work queue */
5118 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
5120 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
5121 /* Only insert if the work queue is in decent state */
5122 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
5124 Status
= STATUS_UNSUCCESSFUL
;
5128 SpinUpThreads
= FALSE
;
5129 WorkQueueItem
->pDeviceObject
= pMRxDeviceObject
;
5130 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
5131 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
5132 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
5134 /* If required (and possible!), spin up a new worker thread */
5135 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
5136 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
5137 !WorkQueue
->SpinUpRequestPending
)
5139 WorkQueue
->SpinUpRequestPending
= TRUE
;
5140 SpinUpThreads
= TRUE
;
5143 Status
= STATUS_SUCCESS
;
5145 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5147 /* If we failed, return and still not insert item */
5148 if (!NT_SUCCESS(Status
))
5153 /* All fine, insert the item */
5154 KeInsertQueue(&WorkQueue
->Queue
, &WorkQueueItem
->List
);
5156 /* And start a new worker thread if needed */
5159 RxSpinUpWorkerThreads(WorkQueue
);
5166 RxIsThisACscAgentOpen(
5167 IN PRX_CONTEXT RxContext
)
5173 /* Client Side Caching is DFS stuff - we don't support it */
5174 if (RxContext
->Create
.EaLength
!= 0)
5179 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
5180 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
5190 IN PRX_CONTEXT RxContext
,
5191 IN LOCK_OPERATION Operation
,
5192 IN ULONG BufferLength
)
5201 Irp
= RxContext
->CurrentIrp
;
5202 /* If we already have a MDL, make sure it's locked */
5203 if (Irp
->MdlAddress
!= NULL
)
5205 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
5209 /* That likely means the driver asks for buffered IOs - we don't support it! */
5210 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
5212 /* If we have a real length */
5213 if (BufferLength
> 0)
5215 /* Allocate a MDL and lock it */
5216 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
5219 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
5220 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
5223 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
5227 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5231 Status
= _SEH2_GetExceptionCode();
5233 /* Free the possible MDL we have allocated */
5235 Irp
->MdlAddress
= NULL
;
5237 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
5240 if (!FsRtlIsNtstatusExpected(Status
))
5242 Status
= STATUS_INVALID_USER_BUFFER
;
5245 RxContext
->IoStatusBlock
.Status
= Status
;
5246 ExRaiseStatus(Status
);
5255 RxLowIoCompletionTail(
5256 IN PRX_CONTEXT RxContext
)
5263 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
5265 /* Only continue if we're at APC_LEVEL or lower */
5266 if (RxShouldPostCompletion() &&
5267 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
5269 return STATUS_MORE_PROCESSING_REQUIRED
;
5272 /* Call the completion routine */
5273 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
5274 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
5275 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
5280 /* If it was a RW operation, for a paging file ... */
5281 Operation
= RxContext
->LowIoContext
.Operation
;
5282 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
5284 /* Remove ourselves from the list and resume operations */
5285 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5287 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5288 RemoveEntryList(&RxContext
->RxContextSerializationQLinks
);
5289 RxContext
->RxContextSerializationQLinks
.Flink
= NULL
;
5290 RxContext
->RxContextSerializationQLinks
.Blink
= NULL
;
5291 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5292 RxResumeBlockedOperations_ALL(RxContext
);
5297 /* Sanity check: we had known operation */
5298 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
5301 /* If not sync operation, complete now. Otherwise, caller has already completed */
5302 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
5304 RxCompleteRequest(RxContext
, Status
);
5307 DPRINT("Status: %x\n", Status
);
5316 RxLowIoPopulateFsctlInfo(
5317 IN PRX_CONTEXT RxContext
)
5322 PIO_STACK_LOCATION Stack
;
5326 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
5328 Irp
= RxContext
->CurrentIrp
;
5329 Stack
= RxContext
->CurrentIrpSp
;
5331 /* Copy stack parameters */
5332 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
5333 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
5334 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
5335 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
5336 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
5338 /* Same buffer in case of buffered */
5339 if (Method
== METHOD_BUFFERED
)
5341 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5342 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5344 return STATUS_SUCCESS
;
5347 /* Two buffers for neither */
5348 if (Method
== METHOD_NEITHER
)
5350 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
5351 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
5353 return STATUS_SUCCESS
;
5356 /* Only IN/OUT remain */
5357 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
5359 /* Use system buffer for input */
5360 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5361 /* And MDL for output */
5362 Mdl
= Irp
->MdlAddress
;
5365 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
5366 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
5368 return STATUS_INSUFFICIENT_RESOURCES
;
5373 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
5376 return STATUS_SUCCESS
;
5382 IN PRX_CONTEXT RxContext
,
5383 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
5387 BOOLEAN Synchronous
;
5388 PLOWIO_CONTEXT LowIoContext
;
5390 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
5394 LowIoContext
= &RxContext
->LowIoContext
;
5395 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
5397 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
5399 Status
= STATUS_SUCCESS
;
5400 Operation
= LowIoContext
->Operation
;
5404 case LOWIO_OP_WRITE
:
5405 /* Check that the parameters were properly set by caller
5406 * See comment in RxInitializeLowIoContext()
5408 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
5409 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
5411 /* Lock the buffer */
5412 RxLockUserBuffer(RxContext
,
5413 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
5414 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
5415 if (RxNewMapUserBuffer(RxContext
) == NULL
)
5417 return STATUS_INSUFFICIENT_RESOURCES
;
5419 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
5421 /* If that's a paging IO, initialize serial operation */
5422 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5426 Fcb
= (PFCB
)RxContext
->pFcb
;
5428 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5429 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
5430 if (Operation
== LOWIO_OP_READ
)
5432 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5436 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5439 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5444 case LOWIO_OP_FSCTL
:
5445 case LOWIO_OP_IOCTL
:
5446 /* Set FSCTL/IOCTL parameters */
5447 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
5448 /* Check whether we're consistent: a length means a buffer */
5449 if (NT_SUCCESS(Status
))
5451 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
5452 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
5453 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
5454 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
5456 Status
= STATUS_INVALID_PARAMETER
;
5462 case LOWIO_OP_SHAREDLOCK
:
5463 case LOWIO_OP_EXCLUSIVELOCK
:
5464 case LOWIO_OP_UNLOCK
:
5465 case LOWIO_OP_UNLOCK_MULTIPLE
:
5466 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
5467 case LOWIO_OP_CLEAROUT
:
5472 Status
= STATUS_INVALID_PARAMETER
;
5476 /* No need to perform extra init in case of posting */
5477 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
5479 /* Preflight checks were OK, time to submit */
5480 if (NT_SUCCESS(Status
))
5482 PMINIRDR_DISPATCH Dispatch
;
5486 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
5487 /* If not synchronous, we're likely to return before the operation is finished */
5488 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5490 IoMarkIrpPending(RxContext
->CurrentIrp
);
5494 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
5495 if (Dispatch
!= NULL
)
5497 /* We'll try to execute until the mini-rdr doesn't return pending */
5500 RxContext
->IoStatusBlock
.Information
= 0;
5502 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
5503 if (Status
== STATUS_PENDING
)
5505 /* Unless it's not synchronous, caller will be happy with pending op */
5511 RxWaitSync(RxContext
);
5512 Status
= RxContext
->IoStatusBlock
.Status
;
5518 /* We had marked the IRP pending, whereas the operation finished, drop that */
5519 if (Status
!= STATUS_RETRY
)
5521 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5523 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
5526 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
5530 } while (Status
== STATUS_PENDING
);
5534 Status
= STATUS_INVALID_PARAMETER
;
5538 /* Call completion and return */
5539 RxContext
->IoStatusBlock
.Status
= Status
;
5540 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
5541 return RxLowIoCompletionTail(RxContext
);
5549 IN PRX_CONTEXT RxContext
)
5555 Irp
= RxContext
->CurrentIrp
;
5556 /* We should have a MDL (buffered IOs are not supported!) */
5557 if (Irp
->MdlAddress
!= NULL
)
5560 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5563 /* Just return system buffer */
5564 return Irp
->AssociatedIrp
.SystemBuffer
;
5571 RxMarkFobxOnCleanup(
5576 PFOBX ScavengerFobx
;
5577 LARGE_INTEGER TickCount
;
5578 PRDBSS_SCAVENGER Scavenger
;
5582 /* No FOBX, nothing to mark */
5588 /* Query time for close */
5589 KeQueryTickCount(&TickCount
);
5591 Fcb
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
5592 ASSERT(NodeTypeIsFcb(Fcb
));
5594 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5595 RxAcquireScavengerMutex();
5597 ScavengerFobx
= NULL
;
5598 /* If that's not a file, or even not a disk resource, just mark as dormant */
5599 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
|| Fcb
->VNetRoot
->pNetRoot
->DeviceType
!= FILE_DEVICE_DISK
)
5601 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5602 InitializeListHead(&pFobx
->ClosePendingList
);
5603 ++Scavenger
->NumberOfDormantFiles
;
5607 ASSERT(Scavenger
->NumberOfDormantFiles
>= 0);
5608 /* If we're about to reach the maximum dormant of FOBX */
5609 if (Scavenger
->NumberOfDormantFiles
>= Scavenger
->MaximumNumberOfDormantFiles
)
5611 /* This should never be wrong... */
5612 if (!IsListEmpty(&Scavenger
->ClosePendingFobxsList
))
5614 /* Then, take the first from the list (oldest) and save it for later purge */
5615 ScavengerFobx
= CONTAINING_RECORD(Scavenger
->ClosePendingFobxsList
.Flink
, FOBX
, ClosePendingList
);
5616 if (ScavengerFobx
->pSrvOpen
!= NULL
&& ScavengerFobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
5619 ScavengerFobx
= NULL
;
5623 RxReferenceNetFobx(ScavengerFobx
);
5628 /* Mark ourselves as dormant */
5629 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5630 pFobx
->CloseTime
.QuadPart
= TickCount
.QuadPart
;
5632 /* And insert us in the list of dormant files */
5633 InsertTailList(&Scavenger
->ClosePendingFobxsList
, &pFobx
->ClosePendingList
);
5634 /* If scavenger was inactive, start it */
5635 if (Scavenger
->NumberOfDormantFiles
++ == 0 && Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
5637 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
5638 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
, RxScavengerTimerRoutine
,
5639 Fcb
->RxDeviceObject
, Scavenger
->TimeLimit
);
5643 RxReleaseScavengerMutex();
5645 /* If we had reached max */
5646 if (ScavengerFobx
!= NULL
)
5650 /* Purge the oldest FOBX */
5651 Status
= RxPurgeFobxFromCache(ScavengerFobx
);
5652 if (Status
!= STATUS_SUCCESS
)
5667 PRDBSS_SCAVENGER Scavenger
;
5671 /* No FOBX, nothing to mark */
5677 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5678 ASSERT(NodeTypeIsFcb(Fcb
));
5680 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5682 RxAcquireScavengerMutex();
5683 /* Only mark it if it was already marked as dormant */
5684 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
))
5686 /* If FCB wasn't already decrement, do it now */
5687 if (!Fobx
->fOpenCountDecremented
)
5689 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5690 ASSERT(NodeTypeIsFcb(Fcb
));
5691 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
5693 Fobx
->fOpenCountDecremented
= TRUE
;
5696 /* We're no longer dormant */
5697 InterlockedDecrement(&Scavenger
->NumberOfDormantFiles
);
5698 ClearFlag(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5701 /* If we were inserted in the scavenger, drop ourselves out */
5702 if (!IsListEmpty(&Fobx
->ClosePendingList
))
5704 RemoveEntryList(&Fobx
->ClosePendingList
);
5705 InitializeListHead(&Fobx
->ClosePendingList
);
5708 RxReleaseScavengerMutex();
5716 PRX_CONTEXT RxContext
)
5722 Irp
= RxContext
->CurrentIrp
;
5723 if (Irp
->MdlAddress
!= NULL
)
5725 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5728 return Irp
->UserBuffer
;
5758 IN PV_NET_ROOT ThisVNetRoot
)
5763 PRX_FCB_TABLE FcbTable
;
5764 PRX_PREFIX_TABLE PrefixTable
;
5768 /* Mailslot won't have any SRV_OPEN (to orphan) */
5769 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
5770 if (NetRoot
->Type
== NET_ROOT_MAILSLOT
)
5775 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
5776 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
5778 FcbTable
= &NetRoot
->FcbTable
;
5779 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
5783 /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
5784 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
5786 PLIST_ENTRY BucketList
, Entry
;
5788 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
5789 Entry
= BucketList
->Flink
;
5790 while (Entry
!= BucketList
)
5792 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
5793 Entry
= Entry
->Flink
;
5795 ASSERT(NodeTypeIsFcb(Fcb
));
5796 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5800 /* Of course, don't forget about NULL-entry */
5801 if (FcbTable
->TableEntryForNull
!= NULL
)
5803 Fcb
= CONTAINING_RECORD(FcbTable
->TableEntryForNull
, FCB
, FcbTableEntry
.HashLinks
);
5804 ASSERT(NodeTypeIsFcb(Fcb
));
5805 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5810 RxReleaseFcbTableLock(FcbTable
);
5816 RxOrphanSrvOpensForThisFcb(
5818 IN PV_NET_ROOT ThisVNetRoot
,
5819 IN BOOLEAN OrphanAll
)
5828 RxpAcquirePrefixTableLockShared(
5829 PRX_PREFIX_TABLE pTable
,
5831 BOOLEAN ProcessBufferingStateChangeRequests
)
5835 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5836 pTable
->TableLock
.ActiveEntries
);
5838 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
5845 RxpAcquirePrefixTableLockExclusive(
5846 PRX_PREFIX_TABLE pTable
,
5848 BOOLEAN ProcessBufferingStateChangeRequests
)
5852 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5853 pTable
->TableLock
.ActiveEntries
);
5855 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
5862 RxpDereferenceAndFinalizeNetFcb(
5864 IN PRX_CONTEXT RxContext
,
5865 IN BOOLEAN RecursiveFinalize
,
5866 IN BOOLEAN ForceFinalize
)
5871 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
5875 ASSERT(!ForceFinalize
);
5876 ASSERT(NodeTypeIsFcb(ThisFcb
));
5877 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
5879 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5880 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
5881 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
5887 Status
= STATUS_SUCCESS
;
5888 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
5889 ResourceAcquired
= FALSE
;
5890 NetRootReferenced
= FALSE
;
5891 /* If FCB isn't orphaned, it still have context attached */
5892 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
5894 /* Don't let NetRoot go away before we're done */
5895 RxReferenceNetRoot(NetRoot
);
5896 NetRootReferenced
= TRUE
;
5898 /* Try to acquire the table lock exclusively */
5899 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
5901 RxReferenceNetFcb(ThisFcb
);
5903 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
5905 if (RxContext
!= NULL
&& RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT
&&
5906 RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
5908 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
5911 RxReleaseFcb(RxContext
, ThisFcb
);
5913 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5915 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
5918 References
= RxDereferenceNetFcb(ThisFcb
);
5920 ResourceAcquired
= TRUE
;
5924 /* If locking was OK (or not needed!), attempt finalization */
5925 if (Status
== STATUS_SUCCESS
)
5927 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
5930 /* Release table lock if acquired */
5931 if (ResourceAcquired
)
5933 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5936 /* We don't need the NetRoot anylonger */
5937 if (NetRootReferenced
)
5939 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
5949 RxpDereferenceNetFcb(
5956 ASSERT(NodeTypeIsFcb(Fcb
));
5958 NewCount
= InterlockedDecrement((volatile long *)&Fcb
->NodeReferenceCount
);
5959 ASSERT(NewCount
>= 0);
5961 PRINT_REF_COUNT(NETFCB
, NewCount
);
5976 BOOLEAN ForceFinalize
;
5977 PRX_PREFIX_TABLE PrefixTable
;
5979 SrvCall
= (PSRV_CALL
)Context
;
5980 /* At this step, RxFinalizeSrvCall already cleaned some fields */
5981 ASSERT(SrvCall
->UpperFinalizationDone
);
5983 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
5984 /* Were we called with ForceFinalize? */
5985 ForceFinalize
= BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
5987 /* Notify mini-rdr */
5988 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
,
5989 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)SrvCall
,
5993 /* Dereference our extra reference (set before queueing) */
5994 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
5995 InterlockedDecrement((volatile long *)&SrvCall
->NodeReferenceCount
);
5996 /* And finalize for real, with the right context */
5997 RxFinalizeSrvCall(SrvCall
, FALSE
, ForceFinalize
);
5998 RxReleasePrefixTableLock(PrefixTable
);
6005 RxpDiscardChangeBufferingStateRequests(
6006 _Inout_ PLIST_ENTRY DiscardedRequests
)
6012 /* No requests to discard */
6013 if (IsListEmpty(DiscardedRequests
))
6018 /* Free all the discarded requests */
6019 Entry
= DiscardedRequests
->Flink
;
6020 while (Entry
!= DiscardedRequests
)
6022 PCHANGE_BUFFERING_STATE_REQUEST Request
;
6024 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
6025 Entry
= Entry
->Flink
;
6027 DPRINT("Req %p for %p (%p) discarded\n", Request
, Request
->SrvOpenKey
, Request
->SrvOpen
);
6029 RxPrepareRequestForReuse(Request
);
6030 RxFreePool(Request
);
6038 RxpDispatchChangeBufferingStateRequests(
6041 PLIST_ENTRY DiscardedRequests
)
6045 BOOLEAN StartDispatcher
;
6046 LIST_ENTRY AcceptedReqs
;
6047 LIST_ENTRY DispatcherList
;
6048 PRX_BUFFERING_MANAGER BufferingManager
;
6050 /* Initialize our lists */
6051 InitializeListHead(&AcceptedReqs
);
6052 InitializeListHead(DiscardedRequests
);
6054 /* Transfer the requests to dispatch locally */
6055 BufferingManager
= &SrvCall
->BufferingManager
;
6056 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
6057 RxTransferList(&DispatcherList
, &BufferingManager
->DispatcherList
);
6058 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6060 /* If there were requests */
6061 if (!IsListEmpty(&DispatcherList
))
6065 /* For each of the entries... */
6066 Entry
= DispatcherList
.Flink
;
6067 while (Entry
!= &DispatcherList
)
6069 PCHANGE_BUFFERING_STATE_REQUEST Request
;
6071 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
6072 Entry
= Entry
->Flink
;
6074 /* If we have been provided a SRV_OPEN, see whether it matches */
6075 if (SrvOpen
!= NULL
)
6077 /* Match, the request is accepted */
6078 if (Request
->SrvOpenKey
== SrvOpen
->Key
)
6080 Request
->SrvOpen
= SrvOpen
;
6081 RxReferenceSrvOpen(SrvOpen
);
6083 RemoveEntryList(&Request
->ListEntry
);
6084 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
6086 /* Move to the next entry */
6091 Status
= STATUS_PENDING
;
6096 /* No SRV_OPEN provided, try to find one */
6097 Status
= RxpLookupSrvOpenForRequestLite(SrvCall
, Request
);
6100 /* We found a matching SRV_OPEN, accept the request */
6101 if (Status
== STATUS_SUCCESS
)
6103 RemoveEntryList(&Request
->ListEntry
);
6104 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
6106 /* Another run might help handling it, don't discard it */
6107 else if (Status
== STATUS_PENDING
)
6111 /* Otherwise, discard the request */
6114 ASSERT(Status
== STATUS_NOT_FOUND
);
6116 RemoveEntryList(&Request
->ListEntry
);
6117 InsertTailList(DiscardedRequests
, &Request
->ListEntry
);
6122 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
6123 /* Nothing to dispatch, no need to start dispatcher */
6124 if (IsListEmpty(&DispatcherList
))
6126 StartDispatcher
= FALSE
;
6130 /* Transfer back the list of the not treated entries to the buffering manager */
6131 RxTransferList(&BufferingManager
->DispatcherList
, &DispatcherList
);
6132 StartDispatcher
= (BufferingManager
->DispatcherActive
== FALSE
);
6133 /* If the dispatcher isn't active, start it */
6134 if (StartDispatcher
)
6136 BufferingManager
->DispatcherActive
= TRUE
;
6140 /* If there were accepted requests, move them to the buffering manager */
6141 if (!IsListEmpty(&AcceptedReqs
))
6143 RxTransferList(&BufferingManager
->HandlerList
, &AcceptedReqs
);
6145 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6147 /* If we're to start the dispatcher, do it */
6148 if (StartDispatcher
)
6150 RxReferenceSrvCall(SrvCall
);
6151 DPRINT("Starting dispatcher\n");
6152 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
6153 &BufferingManager
->DispatcherWorkItem
,
6154 RxDispatchChangeBufferingStateRequests
, SrvCall
);
6162 RxpLookupSrvOpenForRequestLite(
6163 IN PSRV_CALL SrvCall
,
6164 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request
)
6172 Status
= STATUS_SUCCESS
;
6173 /* Browse all our associated SRV_OPENs to find the one! */
6174 for (Entry
= SrvCall
->BufferingManager
.SrvOpenLists
[0].Flink
;
6175 Entry
!= &SrvCall
->BufferingManager
.SrvOpenLists
[0];
6176 Entry
= Entry
->Flink
)
6178 /* Same key, not orphaned, this is ours */
6179 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenKeyList
);
6180 if (SrvOpen
->Key
== Request
->SrvOpenKey
)
6182 if (!BooleanFlagOn(SrvOpen
->pFcb
->FcbState
, FCB_STATE_ORPHANED
))
6184 RxReferenceSrvOpen(SrvOpen
);
6190 /* We didn't manage to find a SRV_OPEN */
6191 if (Entry
== &SrvCall
->BufferingManager
.SrvOpenLists
[0])
6195 /* The coming open might help, mark as pending for later retry */
6196 if (SrvCall
->BufferingManager
.NumberOfOutstandingOpens
!= 0)
6198 Status
= STATUS_PENDING
;
6200 /* Else, it's a complete failure */
6203 Status
= STATUS_NOT_FOUND
;
6207 /* Return the (not) found SRV_OPEN */
6208 Request
->SrvOpen
= SrvOpen
;
6217 RxpMarkInstanceForScavengedFinalization(
6220 NODE_TYPE_CODE NodeType
;
6221 PNODE_TYPE_AND_SIZE Node
;
6222 PRDBSS_SCAVENGER Scavenger
;
6223 PRDBSS_DEVICE_OBJECT DeviceObject
;
6224 PLIST_ENTRY ScavengerHead
, InstEntry
;
6228 /* If still referenced, don't mark it (broken caller) */
6229 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6230 if (Node
->NodeReferenceCount
> 1)
6235 DeviceObject
= RxGetDeviceObjectOfInstance(Instance
);
6236 Scavenger
= DeviceObject
->pRdbssScavenger
;
6239 NodeType
= NodeType(Instance
);
6240 SetFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6241 DPRINT("Node %p has now the scavenger mark!\n", Instance
);
6243 /* Increase the count in the scavenger, and queue it */
6244 ScavengerHead
= NULL
;
6247 case RDBSS_NTC_FOBX
:
6248 ++Scavenger
->FobxsToBeFinalized
;
6249 ScavengerHead
= &Scavenger
->FobxFinalizationList
;
6250 InstEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6253 case RDBSS_NTC_SRVCALL
:
6254 ++Scavenger
->SrvCallsToBeFinalized
;
6255 ScavengerHead
= &Scavenger
->SrvCallFinalizationList
;
6256 InstEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6259 case RDBSS_NTC_NETROOT
:
6260 ++Scavenger
->NetRootsToBeFinalized
;
6261 ScavengerHead
= &Scavenger
->NetRootFinalizationList
;
6262 InstEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6265 case RDBSS_NTC_V_NETROOT
:
6266 ++Scavenger
->VNetRootsToBeFinalized
;
6267 ScavengerHead
= &Scavenger
->VNetRootFinalizationList
;
6268 InstEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6271 case RDBSS_NTC_SRVOPEN
:
6272 ++Scavenger
->SrvOpensToBeFinalized
;
6273 ScavengerHead
= &Scavenger
->SrvOpenFinalizationList
;
6274 InstEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6278 /* Extra ref for scavenger */
6279 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
6281 /* If matching type */
6282 if (ScavengerHead
!= NULL
)
6284 /* Insert in the scavenger list */
6285 InsertTailList(ScavengerHead
, InstEntry
);
6287 /* And if it wasn't started, start it */
6288 if (Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
6290 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
6291 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
6292 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
6302 RxPostOneShotTimerRequest(
6303 IN PRDBSS_DEVICE_OBJECT pDeviceObject
,
6304 IN PRX_WORK_ITEM pWorkItem
,
6305 IN PRX_WORKERTHREAD_ROUTINE Routine
,
6307 IN LARGE_INTEGER TimeInterval
)
6311 ASSERT(pWorkItem
!= NULL
);
6313 /* Prepare the work item */
6314 ExInitializeWorkItem(&pWorkItem
->WorkQueueItem
, Routine
, pContext
);
6315 pWorkItem
->WorkQueueItem
.pDeviceObject
= pDeviceObject
;
6317 /* Last tick can be computed with the number of times it was caller (timertickcount)
6318 * and the interval between calls
6320 KeAcquireSpinLock(&RxTimerLock
, &OldIrql
);
6321 pWorkItem
->LastTick
= (TimeInterval
.QuadPart
/ 550000) + RxTimerTickCount
+ 1;
6322 /* Insert in work queue */
6323 InsertTailList(&RxTimerQueueHead
, &pWorkItem
->WorkQueueItem
.List
);
6324 KeReleaseSpinLock(&RxTimerLock
, OldIrql
);
6326 /* If there are queued events, queue an execution */
6327 if (IsListEmpty(&RxTimerQueueHead
))
6329 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
6332 return STATUS_SUCCESS
;
6340 RxPostToWorkerThread(
6341 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
6342 _In_ WORK_QUEUE_TYPE WorkQueueType
,
6343 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem
,
6344 _In_ PRX_WORKERTHREAD_ROUTINE Routine
,
6345 _In_ PVOID pContext
)
6347 /* Initialize work queue item */
6348 pWorkQueueItem
->List
.Flink
= NULL
;
6349 pWorkQueueItem
->WorkerRoutine
= Routine
;
6350 pWorkQueueItem
->Parameter
= pContext
;
6352 /* And insert it in the work queue */
6353 return RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, pWorkQueueItem
);
6357 RxpProcessChangeBufferingStateRequests(
6359 BOOLEAN UpdateHandlerState
)
6368 RxPrefixTableInsertName(
6369 IN OUT PRX_PREFIX_TABLE ThisTable
,
6370 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
6372 IN PULONG ContainerRefCount
,
6373 IN USHORT CaseInsensitiveLength
,
6374 IN PRX_CONNECTION_ID ConnectionId
6379 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
6381 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
6382 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
6384 /* Copy parameters and compute hash */
6385 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
6386 ThisEntry
->ContainingRecord
= Container
;
6387 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
6388 InterlockedIncrement((volatile long *)ContainerRefCount
);
6389 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
6390 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
6392 /* If no path length: this is entry for null path */
6393 if (ThisEntry
->Prefix
.Length
== 0)
6395 ThisTable
->TableEntryForNull
= ThisEntry
;
6397 /* Otherwise, insert in the appropriate bucket */
6400 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
6403 /* If we had a connection ID, keep track of it */
6404 if (ConnectionId
!= NULL
)
6406 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
6410 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
6411 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
6414 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
6415 /* Reflect the changes */
6416 ++ThisTable
->Version
;
6418 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
6427 RxPrefixTableLookupName(
6428 IN PRX_PREFIX_TABLE ThisTable
,
6429 IN PUNICODE_STRING CanonicalName
,
6430 OUT PUNICODE_STRING RemainingName
,
6431 IN PRX_CONNECTION_ID ConnectionId
)
6437 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
6438 ASSERT(CanonicalName
->Length
> 0);
6440 /* Call the internal helper */
6441 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
6442 if (Container
== NULL
)
6447 /* Reference our container before returning it */
6448 if (RdbssReferenceTracingValue
!= 0)
6450 NODE_TYPE_CODE Type
;
6452 Type
= (NodeType(Container
) & ~RX_SCAVENGER_MASK
);
6455 case RDBSS_NTC_SRVCALL
:
6456 RxReferenceSrvCall(Container
);
6459 case RDBSS_NTC_NETROOT
:
6460 RxReferenceNetRoot(Container
);
6463 case RDBSS_NTC_V_NETROOT
:
6464 RxReferenceVNetRoot(Container
);
6468 DPRINT1("Invalid node type: %x\n", Type
);
6470 RxReference(Container
);
6476 RxReference(Container
);
6493 ASSERT(NodeTypeIsFcb(Fcb
));
6495 NewCount
= InterlockedIncrement((volatile long *)&Fcb
->NodeReferenceCount
);
6497 PRINT_REF_COUNT(NETFCB
, Fcb
->NodeReferenceCount
);
6506 RxpReleasePrefixTableLock(
6507 PRX_PREFIX_TABLE pTable
,
6508 BOOLEAN ProcessBufferingStateChangeRequests
)
6512 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
6513 pTable
->TableLock
.ActiveEntries
);
6515 ExReleaseResourceLite(&pTable
->TableLock
);
6523 RxPrepareContextForReuse(
6524 IN OUT PRX_CONTEXT RxContext
)
6528 /* When we reach that point, make sure mandatory parts are null-ed */
6529 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
6531 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
6532 RxContext
->Create
.RdrFlags
= 0;
6534 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
6536 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
6537 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
6540 RxContext
->ReferenceCount
= 0;
6547 RxPrepareRequestForReuse(
6548 PCHANGE_BUFFERING_STATE_REQUEST Request
)
6554 SrvOpen
= Request
->SrvOpen
;
6556 /* If the request was already prepared for service */
6557 if (BooleanFlagOn(Request
->Flags
, RX_REQUEST_PREPARED_FOR_HANDLING
))
6559 /* We have to dereference the associated SRV_OPEN depending on the lock */
6560 if (RxIsFcbAcquiredExclusive(SrvOpen
->pFcb
))
6562 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
6566 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6569 /* Otherwise, just dereference */
6570 else if (SrvOpen
!= NULL
)
6572 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6575 Request
->SrvOpen
= NULL
;
6583 RxProcessChangeBufferingStateRequests(
6586 /* Call internal routine */
6587 RxUndoScavengerFinalizationMarking(SrvCall
);
6588 RxpProcessChangeBufferingStateRequests(SrvCall
, TRUE
);
6595 RxProcessChangeBufferingStateRequestsForSrvOpen(
6598 LONG NumberOfBufferingChangeRequests
, LockedOldBufferingToken
, OldBufferingToken
;
6600 /* Get the current number of change requests */
6601 NumberOfBufferingChangeRequests
= ((PSRV_CALL
)SrvOpen
->pVNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
.CumulativeNumberOfBufferingChangeRequests
;
6602 /* Get our old token */
6603 OldBufferingToken
= SrvOpen
->BufferingToken
;
6604 LockedOldBufferingToken
= InterlockedCompareExchange(&SrvOpen
->BufferingToken
,
6605 NumberOfBufferingChangeRequests
,
6606 NumberOfBufferingChangeRequests
);
6607 /* If buffering state changed in between, process changes */
6608 if (OldBufferingToken
!= LockedOldBufferingToken
)
6613 /* Acquire the FCB and start processing */
6614 Fcb
= (PFCB
)SrvOpen
->pFcb
;
6615 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
6616 if (Status
== STATUS_SUCCESS
)
6618 RxProcessFcbChangeBufferingStateRequest(Fcb
);
6619 RxReleaseFcb(NULL
, Fcb
);
6625 RxProcessFcbChangeBufferingStateRequest(
6636 PRDBSS_SCAVENGER Scavenger
,
6637 PLIST_ENTRY FobxToScavenge
)
6639 /* Explore the whole list of FOBX to scavenge */
6640 while (!IsListEmpty(FobxToScavenge
))
6646 Entry
= RemoveHeadList(FobxToScavenge
);
6647 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ScavengerFinalizationList
);
6648 Fcb
= (PFCB
)Fobx
->SrvOpen
->pFcb
;
6650 /* Try to acquire the lock exclusively to perform finalization */
6651 if (RxAcquireExclusiveFcb(NULL
, Fcb
) != STATUS_SUCCESS
)
6653 RxDereferenceNetRoot(Fobx
, LHS_LockNotHeld
);
6657 RxReferenceNetFcb(Fcb
);
6658 RxDereferenceNetRoot(Fobx
, LHS_ExclusiveLockHeld
);
6660 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6662 RxReleaseFcb(NULL
, Fcb
);
6669 RxpTrackDereference(
6670 _In_ ULONG TraceType
,
6671 _In_ PCSTR FileName
,
6673 _In_ PVOID Instance
)
6676 ULONG ReferenceCount
;
6680 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6687 case RDBSS_REF_TRACK_SRVCALL
:
6688 InstanceType
= "SrvCall";
6689 ReferenceCount
= ((PSRV_CALL
)Instance
)->NodeReferenceCount
;
6692 case RDBSS_REF_TRACK_NETROOT
:
6693 InstanceType
= "NetRoot";
6694 ReferenceCount
= ((PNET_ROOT
)Instance
)->NodeReferenceCount
;
6697 case RDBSS_REF_TRACK_VNETROOT
:
6698 InstanceType
= "VNetRoot";
6699 ReferenceCount
= ((PV_NET_ROOT
)Instance
)->NodeReferenceCount
;
6702 case RDBSS_REF_TRACK_NETFOBX
:
6703 InstanceType
= "NetFobx";
6704 ReferenceCount
= ((PFOBX
)Instance
)->NodeReferenceCount
;
6707 case RDBSS_REF_TRACK_NETFCB
:
6708 InstanceType
= "NetFcb";
6709 ReferenceCount
= ((PFCB
)Instance
)->NodeReferenceCount
;
6712 case RDBSS_REF_TRACK_SRVOPEN
:
6713 InstanceType
= "SrvOpen";
6714 ReferenceCount
= ((PSRV_OPEN
)Instance
)->NodeReferenceCount
;
6718 DPRINT1("Invalid node type!\n");
6722 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_LOG_REF_TRACKING
))
6727 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_PRINT_REF_TRACKING
))
6729 DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName
, Line
, Instance
, InstanceType
, ReferenceCount
);
6737 _In_ ULONG TraceType
,
6738 _In_ PCSTR FileName
,
6740 _In_ PVOID Instance
)
6743 ULONG ReferenceCount
;
6745 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6752 case RDBSS_REF_TRACK_SRVCALL
:
6753 InstanceType
= "SrvCall";
6754 ReferenceCount
= ((PSRV_CALL
)Instance
)->NodeReferenceCount
;
6757 case RDBSS_REF_TRACK_NETROOT
:
6758 InstanceType
= "NetRoot";
6759 ReferenceCount
= ((PNET_ROOT
)Instance
)->NodeReferenceCount
;
6762 case RDBSS_REF_TRACK_VNETROOT
:
6763 InstanceType
= "VNetRoot";
6764 ReferenceCount
= ((PV_NET_ROOT
)Instance
)->NodeReferenceCount
;
6767 case RDBSS_REF_TRACK_NETFOBX
:
6768 InstanceType
= "NetFobx";
6769 ReferenceCount
= ((PFOBX
)Instance
)->NodeReferenceCount
;
6772 case RDBSS_REF_TRACK_NETFCB
:
6773 InstanceType
= "NetFcb";
6774 ReferenceCount
= ((PFCB
)Instance
)->NodeReferenceCount
;
6777 case RDBSS_REF_TRACK_SRVOPEN
:
6778 InstanceType
= "SrvOpen";
6779 ReferenceCount
= ((PSRV_OPEN
)Instance
)->NodeReferenceCount
;
6783 DPRINT1("Invalid node type!\n");
6787 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_LOG_REF_TRACKING
))
6792 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_PRINT_REF_TRACKING
))
6794 DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName
, Line
, Instance
, InstanceType
, ReferenceCount
);
6802 RxpUndoScavengerFinalizationMarking(
6805 PLIST_ENTRY ListEntry
;
6806 PNODE_TYPE_AND_SIZE Node
;
6807 PRDBSS_SCAVENGER Scavenger
;
6811 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6812 /* There's no marking - nothing to do */
6813 if (!BooleanFlagOn(NodeType(Node
), RX_SCAVENGER_MASK
))
6818 /* First of all, remove the mark */
6819 ClearFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6820 DPRINT("Node %p no longer has the scavenger mark\n");
6822 /* And now, remove from the scavenger */
6823 Scavenger
= RxGetDeviceObjectOfInstance(Instance
)->pRdbssScavenger
;
6824 switch (NodeType(Node
))
6826 case RDBSS_NTC_FOBX
:
6827 --Scavenger
->FobxsToBeFinalized
;
6828 ListEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6831 case RDBSS_NTC_SRVCALL
:
6832 --Scavenger
->SrvCallsToBeFinalized
;
6833 ListEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6836 case RDBSS_NTC_NETROOT
:
6837 --Scavenger
->NetRootsToBeFinalized
;
6838 ListEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6841 case RDBSS_NTC_V_NETROOT
:
6842 --Scavenger
->VNetRootsToBeFinalized
;
6843 ListEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6846 case RDBSS_NTC_SRVOPEN
:
6847 --Scavenger
->SrvOpensToBeFinalized
;
6848 ListEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6855 /* Also, remove the extra ref from the scavenger */
6856 RemoveEntryList(ListEntry
);
6857 InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
6864 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6868 LIST_ENTRY Discarded
;
6872 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
6874 /* Initialize our discarded list */
6875 InitializeListHead(&Discarded
);
6877 SrvCall
= (PSRV_CALL
)SrvOpen
->Fcb
->VNetRoot
->pNetRoot
->pSrvCall
;
6878 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
6880 /* Set the flag, and get the requests */
6881 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
6882 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED
);
6883 RxGatherRequestsForSrvOpen(SrvCall
, SrvOpen
, &Discarded
);
6885 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
6887 /* If there were discarded requests */
6888 if (!IsListEmpty(&Discarded
))
6890 /* And a pending buffering state change */
6891 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
6893 /* Clear the flag, and set the associated event - job done */
6894 RxAcquireSerializationMutex();
6895 ClearFlag(SrvOpen
->Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
6896 if (SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
6898 KeSetEvent(SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
, IO_NETWORK_INCREMENT
, FALSE
);
6900 RxReleaseSerializationMutex();
6903 /* Drop the discarded requests */
6904 RxpDiscardChangeBufferingStateRequests(&Discarded
);
6917 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6919 /* Reference our FCB so that it doesn't disappear */
6920 RxReferenceNetFcb(Fcb
);
6921 /* Purge Cc if required */
6922 if (Fcb
->OpenCount
!= 0)
6924 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
6927 /* If it wasn't freed, release the lock */
6928 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6930 RxReleaseFcb(NULL
, Fcb
);
6938 RxPurgeFcbInSystemCache(
6940 IN PLARGE_INTEGER FileOffset OPTIONAL
,
6942 IN BOOLEAN UninitializeCacheMaps
,
6943 IN BOOLEAN FlushFile
)
6950 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6952 /* Try to flush first, if asked */
6955 /* If flushing failed, just make some noise */
6956 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
6957 if (!NT_SUCCESS(Status
))
6959 PVOID CallersAddress
, CallersCaller
;
6961 RtlGetCallersAddress(&CallersAddress
, &CallersCaller
);
6962 DPRINT1("Flush failed with status %lx for FCB %p\n", Status
, Fcb
);
6963 DPRINT1("Caller was %p %p\n", CallersAddress
, CallersCaller
);
6967 /* Deal with Cc for purge */
6968 Purged
= CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, FileOffset
,
6969 Length
, UninitializeCacheMaps
);
6970 /* If purge failed, force section closing */
6973 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
6975 RxReleaseFcb(NULL
, Fcb
);
6976 Purged
= MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
6977 RxAcquireExclusiveFcb(NULL
, Fcb
);
6980 /* Return appropriate status */
6981 Status
= (Purged
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
6982 DPRINT("Purge for FCB %p returns %lx\n", Fcb
, Status
);
6999 /* Get the associated FCB */
7000 FcbToBePurged
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
7001 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
7002 ASSERT(Status
== STATUS_SUCCESS
);
7005 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
7006 if (Status
!= STATUS_SUCCESS
)
7008 DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged
, pFobx
);
7013 if (!MmFlushImageSection(&FcbToBePurged
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
))
7015 DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged
, pFobx
);
7019 DPRINT("Purge OK for %p (%p)\n", FcbToBePurged
, pFobx
);
7027 RxPurgeFobxFromCache(
7028 PFOBX FobxToBePurged
)
7035 FcbToBePurged
= (PFCB
)FobxToBePurged
->pSrvOpen
->pFcb
;
7036 ASSERT(FcbToBePurged
!= NULL
);
7038 /* If we cannot have our FCB exclusively, give up */
7039 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
7040 if (Status
!= STATUS_SUCCESS
)
7042 RxDereferenceNetFobx(FobxToBePurged
, LHS_LockNotHeld
);
7046 /* Don't let the FCB disappear */
7047 RxReferenceNetFcb(FcbToBePurged
);
7049 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
7050 if (BooleanFlagOn(FobxToBePurged
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
) || FobxToBePurged
->pSrvOpen
->UncleanFobxCount
!= 0)
7052 DPRINT("FCB purge skipped\n");
7056 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
7059 RxDereferenceNetFobx(FobxToBePurged
, LHS_ExclusiveLockHeld
);
7060 /* Drop our extra reference */
7061 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged
, NULL
, FALSE
, FALSE
))
7063 RxReleaseFcb(NULL
, FcbToBePurged
);
7073 RxPurgeRelatedFobxs(
7075 PRX_CONTEXT RxContext
,
7076 BOOLEAN AttemptFinalization
,
7080 ULONG SuccessfullPurge
;
7081 PRDBSS_SCAVENGER Scavenger
;
7082 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7083 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx
;
7087 RxDeviceObject
= RxContext
->RxDeviceObject
;
7088 Scavenger
= RxDeviceObject
->pRdbssScavenger
;
7089 PurgeSyncCtx
= &NetRoot
->PurgeSyncronizationContext
;
7091 RxAcquireScavengerMutex();
7093 /* If there's already a purge in progress */
7094 if (PurgeSyncCtx
->PurgeInProgress
)
7096 /* Add our RX_CONTEXT to the current run */
7097 InsertTailList(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
,
7098 &RxContext
->RxContextSerializationQLinks
);
7100 /* And wait until it's done */
7101 RxReleaseScavengerMutex();
7102 RxWaitSync(RxContext
);
7103 RxAcquireScavengerMutex();
7106 /* Start the purge */
7107 PurgeSyncCtx
->PurgeInProgress
= TRUE
;
7109 /* While the purge is still handling our NET_ROOT, do nothing but wait */
7110 while (Scavenger
->CurrentNetRootForClosePendingProcessing
== NetRoot
)
7112 RxReleaseScavengerMutex();
7113 KeWaitForSingleObject(&Scavenger
->ClosePendingProcessingSyncEvent
, Executive
,
7114 KernelMode
, TRUE
, NULL
);
7115 RxAcquireScavengerMutex();
7118 /* Now, for all the entries */
7119 SuccessfullPurge
= 0;
7120 Entry
= Scavenger
->ClosePendingFobxsList
.Flink
;
7121 while (Entry
!= &Scavenger
->ClosePendingFobxsList
)
7127 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ClosePendingList
);
7128 DPRINT("Dealing with FOBX: %p\n", Fobx
);
7130 Entry
= Entry
->Flink
;
7132 /* If it's not matching our NET_ROOT, ignore */
7133 if (Fobx
->pSrvOpen
== NULL
||
7134 Fobx
->pSrvOpen
->pFcb
== NULL
||
7135 ((PFCB
)Fobx
->pSrvOpen
->pFcb
)->VNetRoot
== NULL
||
7136 (PNET_ROOT
)((PFCB
)Fobx
->pSrvOpen
->pFcb
)->VNetRoot
->pNetRoot
!= NetRoot
)
7141 /* Determine if it matches our FCB */
7142 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
7143 if (PurgingFcb
!= NULL
&& NodeType(PurgingFcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
7148 MINIRDR_CALL_THROUGH(Status
, RxDeviceObject
->Dispatch
, MRxAreFilesAliased
, (Fcb
, PurgingFcb
));
7149 if (Status
== STATUS_SUCCESS
)
7155 /* Matching, we'll purge it */
7156 RemoveEntryList(&Fobx
->ClosePendingList
);
7158 /* Reference it so that it doesn't disappear */
7159 RxReferenceNetFobx(Fobx
);
7161 RxReleaseScavengerMutex();
7164 Success
= RxPurgeFobx(Fobx
);
7170 /* If we don't have to finalize it (or if we cannot acquire lock exclusively
7171 * Just normally dereference
7173 if ((AttemptFinalization
== DONT_ATTEMPT_FINALIZE_ON_PURGE
) ||
7174 RxAcquireExclusiveFcb(NULL
, Fcb
) != STATUS_SUCCESS
)
7176 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
7178 /* Otherwise, finalize */
7181 RxReferenceNetFcb(Fcb
);
7182 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
7183 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
7185 RxReleaseFcb(NULL
, Fcb
);
7191 DPRINT1("Failed purging %p (%p)\n", Fcb
, Fobx
);
7194 RxAcquireScavengerMutex();
7197 /* If no contexts left, purge is not running */
7198 if (IsListEmpty(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
))
7200 PurgeSyncCtx
->PurgeInProgress
= FALSE
;
7202 /* Otherwise, notify a waiter it can start */
7205 PRX_CONTEXT Context
;
7207 Entry
= RemoveHeadList(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
);
7208 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, RxContextSerializationQLinks
);
7210 RxSignalSynchronousWaiter(Context
);
7213 RxReleaseScavengerMutex();
7215 return (SuccessfullPurge
> 0 ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
7222 RxpWorkerThreadDispatcher(
7223 IN PRX_WORK_QUEUE WorkQueue
,
7224 IN PLARGE_INTEGER WaitInterval
)
7228 PETHREAD CurrentThread
;
7229 BOOLEAN KillThread
, Dereference
;
7230 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
7231 PWORKER_THREAD_ROUTINE WorkerRoutine
;
7233 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7235 /* Reference ourselves */
7236 CurrentThread
= PsGetCurrentThread();
7237 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7238 ASSERT(NT_SUCCESS(Status
));
7240 /* Infinite loop for worker */
7242 Dereference
= FALSE
;
7246 PLIST_ENTRY ListEntry
;
7248 /* Remove an entry from the work queue */
7249 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
7250 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
7252 PRDBSS_DEVICE_OBJECT DeviceObject
;
7254 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
7256 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
7257 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
7258 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7260 /* Get the parameters, and null-them in the struct */
7261 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
7262 Parameter
= WorkQueueItem
->Parameter
;
7263 DeviceObject
= WorkQueueItem
->pDeviceObject
;
7265 WorkQueueItem
->List
.Flink
= NULL
;
7266 WorkQueueItem
->WorkerRoutine
= NULL
;
7267 WorkQueueItem
->Parameter
= NULL
;
7268 WorkQueueItem
->pDeviceObject
= NULL
;
7270 /* Call the routine */
7271 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
7272 WorkerRoutine(Parameter
);
7274 /* Are we going down now? */
7275 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
7277 PKEVENT TearDownEvent
;
7279 TearDownEvent
= InterlockedExchangePointer((void * volatile*)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
7280 if (TearDownEvent
!= NULL
)
7282 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
7286 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7289 /* Shall we shutdown... */
7290 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7291 switch (WorkQueue
->State
)
7293 /* Our queue is active, kill it if we have no more items to dispatch
7294 * and more threads than the required minimum
7296 case RxWorkQueueActive
:
7297 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
7299 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
7300 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
7304 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7309 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7314 /* The queue is inactive: kill it we have more threads than the required minimum */
7315 case RxWorkQueueInactive
:
7316 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
7317 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
7321 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7326 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7330 /* Rundown in progress..., kill it for sure! */
7331 case RxWorkQueueRundownInProgress
:
7333 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
7335 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
7337 RundownContext
= WorkQueue
->pRundownContext
;
7338 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
7340 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7342 Dereference
= FALSE
;
7344 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
7346 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
7349 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7356 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
7357 } while (!KillThread
);
7359 DPRINT("Killed worker thread\n");
7361 /* Do we have to dereference ourselves? */
7364 ObDereferenceObject(CurrentThread
);
7367 /* Dump last executed routine */
7368 if (DumpDispatchRoutine
)
7370 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
7373 PsTerminateSystemThread(STATUS_SUCCESS
);
7378 IN OUT PVOID Instance
)
7380 NODE_TYPE_CODE NodeType
;
7381 PNODE_TYPE_AND_SIZE Node
;
7385 RxAcquireScavengerMutex();
7387 /* We can only reference a few structs */
7388 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
7389 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
7390 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
7391 (NodeType
== RDBSS_NTC_FOBX
));
7393 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
7394 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
7396 /* Trace refcount if asked */
7399 case RDBSS_NTC_SRVCALL
:
7400 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
7403 case RDBSS_NTC_NETROOT
:
7404 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
7407 case RDBSS_NTC_V_NETROOT
:
7408 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
7411 case RDBSS_NTC_SRVOPEN
:
7412 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
7415 case RDBSS_NTC_FOBX
:
7416 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
7424 RxpUndoScavengerFinalizationMarking(Instance
);
7425 RxReleaseScavengerMutex();
7433 RxReinitializeContext(
7434 IN OUT PRX_CONTEXT RxContext
)
7437 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7438 ULONG InitialContextFlags
, SavedFlags
;
7442 /* Backup a few flags */
7443 Irp
= RxContext
->CurrentIrp
;
7444 RxDeviceObject
= RxContext
->RxDeviceObject
;
7445 SavedFlags
= RxContext
->Flags
& RX_CONTEXT_PRESERVED_FLAGS
;
7446 InitialContextFlags
= RxContext
->Flags
& RX_CONTEXT_INITIALIZATION_FLAGS
;
7448 /* Reset our context */
7449 RxPrepareContextForReuse(RxContext
);
7451 /* Zero everything */
7452 RtlZeroMemory(&RxContext
->MajorFunction
, sizeof(RX_CONTEXT
) - FIELD_OFFSET(RX_CONTEXT
, MajorFunction
));
7454 /* Restore saved flags */
7455 RxContext
->Flags
= SavedFlags
;
7456 /* And reinit the context */
7457 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, RxContext
);
7465 RxReleaseFcbFromLazyWrite(
7473 /* The received context is a FCB */
7474 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
7475 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
7477 /* Lazy writer is releasing lock, so forget about it */
7478 Fcb
->Specific
.Fcb
.LazyWriteThread
= NULL
;
7480 /* If we were top level IRP, unwind */
7481 if (RxGetTopIrpIfRdbssIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
)
7483 RxUnwindTopLevelIrp(NULL
);
7486 /* And finally, release the lock */
7487 Fcb
->PagingIoResourceFile
= NULL
;
7488 Fcb
->PagingIoResourceLine
= 0;
7489 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
7497 RxReleaseFcbFromReadAhead(
7505 /* The received context is a FCB */
7506 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
7507 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
7509 /* Top Level IRP is CC */
7510 ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
);
7511 RxUnwindTopLevelIrp(NULL
);
7513 ExReleaseResourceLite(Fcb
->Header
.Resource
);
7518 RxReleaseFileForNtCreateSection(
7519 PFILE_OBJECT FileObject
)
7526 RxReleaseForCcFlush(
7527 PFILE_OBJECT FileObject
,
7528 PDEVICE_OBJECT DeviceObject
)
7531 return STATUS_NOT_IMPLEMENTED
;
7545 ASSERT(NodeTypeIsFcb(ThisFcb
));
7547 /* Just remove the entry from the FCB_TABLE */
7548 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
7549 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
7550 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
7553 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
7556 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
7557 DPRINT("FCB (%p) %wZ removed\n", ThisFcb
, &ThisFcb
->FcbTableEntry
.Path
);
7558 /* Mark, so that we don't try to do it twice */
7559 SetFlag(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
);
7569 RxRemovePrefixTableEntry(
7570 IN OUT PRX_PREFIX_TABLE ThisTable
,
7571 IN OUT PRX_PREFIX_ENTRY Entry
)
7575 ASSERT(NodeType(Entry
) == RDBSS_NTC_PREFIX_ENTRY
);
7576 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
7578 /* Check whether we're asked to remove null entry */
7579 if (Entry
->Prefix
.Length
== 0)
7581 ThisTable
->TableEntryForNull
= NULL
;
7585 RemoveEntryList(&Entry
->HashLinks
);
7588 Entry
->ContainingRecord
= NULL
;
7590 /* Also remove it from global list */
7591 RemoveEntryList(&Entry
->MemberQLinks
);
7593 ++ThisTable
->Version
;
7600 RxRemoveVirtualNetRootFromNetRoot(
7602 PV_NET_ROOT VNetRoot
)
7604 PRX_PREFIX_TABLE PrefixTable
;
7608 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
7609 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
7611 /* Remove the VNetRoot from the list in the NetRoot */
7612 --NetRoot
->NumberOfVirtualNetRoots
;
7613 RemoveEntryList(&VNetRoot
->NetRootListEntry
);
7615 /* Fix the NetRoot if we were the default VNetRoot */
7616 if (NetRoot
->DefaultVNetRoot
== VNetRoot
)
7618 /* Put the first one available */
7619 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7621 NetRoot
->DefaultVNetRoot
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
7623 /* Otherwise, none */
7626 NetRoot
->DefaultVNetRoot
= NULL
;
7630 /* If there are still other VNetRoot available, we're done */
7631 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7636 /* Otherwise, initiate NetRoot finalization */
7637 if (!BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
7639 RxRemovePrefixTableEntry(PrefixTable
, &NetRoot
->PrefixEntry
);
7640 SetFlag(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
);
7643 /* Notify mini-rdr */
7644 if (NetRoot
->pSrvCall
!= NULL
&& NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
7648 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
7649 MRxFinalizeNetRoot
, ((PMRX_NET_ROOT
)NetRoot
, FALSE
));
7655 RxResumeBlockedOperations_ALL(
7656 IN OUT PRX_CONTEXT RxContext
)
7658 LIST_ENTRY BlockedOps
;
7662 /* Get the blocked operations */
7663 RxTransferListWithMutex(&BlockedOps
, &RxContext
->BlockedOperations
, RxContext
->BlockedOpsMutex
);
7665 if (!IsListEmpty(&BlockedOps
))
7673 RxResumeBlockedOperations_Serially(
7674 IN OUT PRX_CONTEXT RxContext
,
7675 IN OUT PLIST_ENTRY BlockingIoQ
)
7679 RxAcquireSerializationMutex();
7681 /* This can only happen on pipes */
7682 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7684 RxReleaseSerializationMutex();
7690 RxReleaseSerializationMutex();
7697 RxSetFileSizeWithLock(
7699 IN PLONGLONG FileSize
)
7703 /* Set attribute and increase version */
7704 Fcb
->Header
.FileSize
.QuadPart
= *FileSize
;
7705 ++Fcb
->ulFileSizeVersion
;
7712 RxScavengeFobxsForNetRoot(
7715 BOOLEAN SynchronizeWithScavenger
)
7717 PRDBSS_SCAVENGER Scavenger
;
7718 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7722 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
7723 Scavenger
= RxDeviceObject
->pRdbssScavenger
;
7725 /* Wait for the scavenger, if asked to */
7726 if (SynchronizeWithScavenger
)
7728 KeWaitForSingleObject(&Scavenger
->ScavengeEvent
, Executive
, KernelMode
, FALSE
, NULL
);
7731 RxAcquireScavengerMutex();
7733 /* If there's nothing left to do... */
7734 if (Scavenger
->FobxsToBeFinalized
<= 0)
7736 RxReleaseScavengerMutex();
7741 LIST_ENTRY FobxToScavenge
;
7743 InitializeListHead(&FobxToScavenge
);
7745 /* Browse all the FOBXs to finalize */
7746 Entry
= Scavenger
->FobxFinalizationList
.Flink
;
7747 while (Entry
!= &Scavenger
->FobxFinalizationList
)
7751 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ScavengerFinalizationList
);
7752 Entry
= Entry
->Flink
;
7754 if (Fobx
->SrvOpen
!= NULL
)
7758 Fcb
= (PFCB
)Fobx
->SrvOpen
->pFcb
;
7760 /* If it matches our NET_ROOT */
7761 if ((PNET_ROOT
)Fcb
->pNetRoot
== NetRoot
)
7765 /* Check whether it matches our FCB */
7766 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
7767 if (PurgingFcb
!= NULL
&& PurgingFcb
!= Fcb
)
7769 MINIRDR_CALL_THROUGH(Status
, RxDeviceObject
->Dispatch
, MRxAreFilesAliased
, (Fcb
, PurgingFcb
));
7772 /* If so, add it to the list of the FOBXs to scavenge */
7773 if (Status
!= STATUS_SUCCESS
)
7775 RxReferenceNetFobx(Fobx
);
7776 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7778 RemoveEntryList(&Fobx
->ScavengerFinalizationList
);
7779 InsertTailList(&FobxToScavenge
, &Fobx
->ScavengerFinalizationList
);
7785 RxReleaseScavengerMutex();
7787 /* Now, scavenge all the extracted FOBX */
7788 RxpScavengeFobxs(Scavenger
, &FobxToScavenge
);
7791 if (SynchronizeWithScavenger
)
7793 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
7801 RxScavengeRelatedFobxs(
7805 LIST_ENTRY LocalList
;
7806 PLIST_ENTRY NextEntry
;
7807 PRDBSS_SCAVENGER Scavenger
;
7811 /* First of all, check whether there are FOBX to scavenge */
7812 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
7813 RxAcquireScavengerMutex();
7814 if (Scavenger
->FobxsToBeFinalized
<= 0)
7816 RxReleaseScavengerMutex();
7820 /* Initialize our local list which will hold all the FOBX to scavenge so
7821 * that we don't acquire the scavenger mutex too long
7823 InitializeListHead(&LocalList
);
7825 /* Technically, that condition should all be true... */
7826 if (!IsListEmpty(&Scavenger
->FobxFinalizationList
))
7828 PLIST_ENTRY NextEntry
, LastEntry
;
7830 /* Browse all the FCBs to find the matching ones */
7831 NextEntry
= Scavenger
->FobxFinalizationList
.Flink
;
7832 LastEntry
= &Scavenger
->FobxFinalizationList
;
7833 while (NextEntry
!= LastEntry
)
7835 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7836 NextEntry
= NextEntry
->Flink
;
7837 /* Matching our FCB? Let's finalize it */
7838 if (Fobx
->pSrvOpen
!= NULL
&& Fobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
7840 RxpUndoScavengerFinalizationMarking(Fobx
);
7841 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7842 InsertTailList(&LocalList
, &Fobx
->ScavengerFinalizationList
);
7847 RxReleaseScavengerMutex();
7849 /* Nothing to scavenge? Quit */
7850 if (IsListEmpty(&LocalList
))
7855 /* Now, finalize all the extracted FOBX */
7856 while (!IsListEmpty(&LocalList
))
7858 NextEntry
= RemoveHeadList(&LocalList
);
7859 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7860 RxFinalizeNetFobx(Fobx
, TRUE
, TRUE
);
7867 RxScavengerFinalizeEntries(
7868 PRDBSS_DEVICE_OBJECT DeviceObject
)
7878 RxScavengerTimerRoutine(
7882 PRDBSS_DEVICE_OBJECT DeviceObject
;
7883 PRDBSS_SCAVENGER Scavenger
;
7887 DeviceObject
= Context
;
7888 Scavenger
= DeviceObject
->pRdbssScavenger
;
7891 RxAcquireScavengerMutex();
7892 /* If the scavenger was dormant, wake it up! */
7893 if (Scavenger
->State
== RDBSS_SCAVENGER_DORMANT
)
7896 Scavenger
->State
= RDBSS_SCAVENGER_ACTIVE
;
7897 KeResetEvent(&Scavenger
->ScavengeEvent
);
7899 /* Scavenger the entries */
7900 RxReleaseScavengerMutex();
7901 RxScavengerFinalizeEntries(DeviceObject
);
7902 RxAcquireScavengerMutex();
7904 /* If we're still active (race) */
7905 if (Scavenger
->State
== RDBSS_SCAVENGER_ACTIVE
)
7907 /* If there are new entries to scavenge, stay dormant and requeue a run */
7908 if (Scavenger
->NumberOfDormantFiles
+ Scavenger
->SrvCallsToBeFinalized
+
7909 Scavenger
->NetRootsToBeFinalized
+ Scavenger
->VNetRootsToBeFinalized
+
7910 Scavenger
->FcbsToBeFinalized
+ Scavenger
->SrvOpensToBeFinalized
+
7911 Scavenger
->FobxsToBeFinalized
!= 0)
7914 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
7916 /* Otherwise, we're inactive again */
7919 Scavenger
->State
= RDBSS_SCAVENGER_INACTIVE
;
7923 RxReleaseScavengerMutex();
7925 /* Requeue an execution */
7928 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
7929 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
7934 RxReleaseScavengerMutex();
7937 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
7941 RxScavengeVNetRoots(
7942 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7953 RxSpinUpRequestsDispatcher(
7957 PRX_DISPATCHER RxDispatcher
;
7959 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7960 if (!NT_SUCCESS(Status
))
7962 PsTerminateSystemThread(STATUS_SUCCESS
);
7965 RxDispatcher
= Dispatcher
;
7970 PLIST_ENTRY ListEntry
;
7972 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
7973 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
7974 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
7976 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
7977 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
7979 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
7983 ListEntry
= &RxDispatcher
->SpinUpRequests
;
7985 KeResetEvent(&RxDispatcher
->SpinUpRequestsEvent
);
7986 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
7988 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
7990 PWORK_QUEUE_ITEM WorkItem
;
7991 PRX_WORK_QUEUE WorkQueue
;
7993 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
7994 WorkQueue
= WorkItem
->Parameter
;
7996 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
7998 DPRINT("Workqueue: calling %p(%p)\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
7999 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
8001 } while (RxDispatcher
->State
== RxDispatcherActive
);
8003 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
8004 PsTerminateSystemThread(STATUS_SUCCESS
);
8011 RxSpinUpWorkerThread(
8012 PRX_WORK_QUEUE WorkQueue
,
8013 PRX_WORKERTHREAD_ROUTINE Routine
,
8018 HANDLE ThreadHandle
;
8022 /* If work queue is inactive, that cannot work */
8023 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
8024 if (WorkQueue
->State
!= RxWorkQueueActive
)
8026 Status
= STATUS_UNSUCCESSFUL
;
8027 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
8031 ++WorkQueue
->NumberOfActiveWorkerThreads
;
8032 Status
= STATUS_SUCCESS
;
8034 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
8036 /* Quit on failure */
8037 if (!NT_SUCCESS(Status
))
8042 /* Spin up the worker thread */
8043 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
8044 if (NT_SUCCESS(Status
))
8046 ZwClose(ThreadHandle
);
8049 /* Read well: we reached that point because it failed! */
8050 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
8052 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
8053 --WorkQueue
->NumberOfActiveWorkerThreads
;
8054 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
8056 /* Rundown, no more active threads, set the event! */
8057 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
8058 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
8060 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
8063 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
8065 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
8071 RxSpinUpWorkerThreads(
8072 PRX_WORK_QUEUE WorkQueue
)
8078 RxSynchronizeWithScavenger(
8079 IN PRX_CONTEXT RxContext
)
8088 RxTableComputeHashValue(
8089 IN PUNICODE_STRING Name
)
8097 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8100 Loops
[1] = MaxChar
- 1;
8101 Loops
[2] = MaxChar
- 2;
8102 Loops
[3] = MaxChar
- 3;
8103 Loops
[4] = MaxChar
- 4;
8104 Loops
[5] = MaxChar
/ 4;
8105 Loops
[6] = 2 * MaxChar
/ 4;
8106 Loops
[7] = 3 * MaxChar
/ 4;
8109 for (i
= 0; i
< 8; ++i
)
8114 if (Idx
>= 0 && Idx
< MaxChar
)
8116 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
8127 RxTableComputePathHashValue(
8128 IN PUNICODE_STRING Name
)
8136 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8139 Loops
[1] = MaxChar
- 1;
8140 Loops
[2] = MaxChar
- 2;
8141 Loops
[3] = MaxChar
- 3;
8142 Loops
[4] = MaxChar
- 4;
8143 Loops
[5] = MaxChar
/ 4;
8144 Loops
[6] = 2 * MaxChar
/ 4;
8145 Loops
[7] = 3 * MaxChar
/ 4;
8148 for (i
= 0; i
< 8; ++i
)
8153 if (Idx
>= 0 && Idx
< MaxChar
)
8155 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
8167 IN PRX_PREFIX_TABLE ThisTable
,
8168 IN PUNICODE_STRING Name
,
8169 OUT PUNICODE_STRING RemainingName
,
8170 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
8174 PRX_PREFIX_ENTRY Entry
;
8175 RX_CONNECTION_ID NullId
;
8176 UNICODE_STRING LookupString
;
8180 /* If caller didn't provide a connection ID, setup one */
8181 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
8183 NullId
.Luid
.LowPart
= 0;
8184 NullId
.Luid
.HighPart
= 0;
8185 RxConnectionId
= &NullId
;
8189 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
8193 LookupString
.Buffer
= Name
->Buffer
;
8194 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8195 /* We'll perform the lookup, path component after another */
8196 for (i
= 1; i
< MaxChar
; ++i
)
8199 PRX_PREFIX_ENTRY CurEntry
;
8201 /* Don't cut in the middle of a path element */
8202 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
8207 /* Perform lookup in the table */
8208 LookupString
.Length
= i
* sizeof(WCHAR
);
8209 Hash
= RxTableComputeHashValue(&LookupString
);
8210 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
8212 ++ThisTable
->Lookups
;
8214 /* Entry not found, move to the next component */
8215 if (CurEntry
== NULL
)
8218 ++ThisTable
->FailedLookups
;
8224 ASSERT(Entry
->ContainingRecord
!= NULL
);
8225 Container
= Entry
->ContainingRecord
;
8227 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
8228 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
8232 NetRoot
= (PNET_ROOT
)Entry
->ContainingRecord
;
8233 /* If there's a default one, perfect, that's a match */
8234 if (NetRoot
->DefaultVNetRoot
!= NULL
)
8236 Container
= NetRoot
->DefaultVNetRoot
;
8238 /* If none (that shouldn't happen!), try to find one */
8241 /* Use the first one in the list */
8242 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
8244 Container
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
8246 /* Really, really, shouldn't happen */
8257 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
8263 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
8267 /* Entry was found */
8272 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
8274 /* Setup remaining name */
8275 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
8276 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
8277 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
8281 /* Otherwise, that's the whole name */
8282 RemainingName
= Name
;
8292 RxTableLookupName_ExactLengthMatch(
8293 IN PRX_PREFIX_TABLE ThisTable
,
8294 IN PUNICODE_STRING Name
,
8296 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
8298 PLIST_ENTRY ListEntry
, HashBucket
;
8302 ASSERT(RxConnectionId
!= NULL
);
8304 /* Select the right bucket */
8305 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
8306 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
8307 /* If bucket is empty, no match */
8308 if (IsListEmpty(HashBucket
))
8313 /* Browse all the entries in the bucket */
8314 for (ListEntry
= HashBucket
->Flink
;
8315 ListEntry
!= HashBucket
;
8316 ListEntry
= ListEntry
->Flink
)
8319 PRX_PREFIX_ENTRY Entry
;
8320 BOOLEAN CaseInsensitive
;
8321 PUNICODE_STRING CmpName
, CmpPrefix
;
8322 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
8324 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
8326 ++ThisTable
->Considers
;
8328 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
8330 Container
= Entry
->ContainingRecord
;
8331 ASSERT(Container
!= NULL
);
8333 /* Not the same hash, not the same length, move on */
8334 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
8340 ++ThisTable
->Compares
;
8342 /* If we have to perform a case insensitive compare on a portion... */
8343 if (Entry
->CaseInsensitiveLength
!= 0)
8345 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
8347 /* Perform the case insensitive check on the asked length */
8348 InsensitiveName
.Buffer
= Name
->Buffer
;
8349 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
8350 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
8351 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
8352 /* No match, move to the next entry */
8353 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
8358 /* Was the case insensitive covering the whole name? */
8359 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
8361 /* If connection ID also matches, that a complete match! */
8362 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
8368 /* Otherwise, we have to continue with the sensitive match.... */
8369 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
8370 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
8371 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
8372 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
8374 CmpName
= &InsensitiveName
;
8375 CmpPrefix
= &InsensitivePrefix
;
8376 CaseInsensitive
= FALSE
;
8381 CmpPrefix
= &Entry
->Prefix
;
8382 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
8385 /* Perform the compare, if there's a match, also check for connection ID */
8386 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
8388 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
8402 RxTearDownBufferingManager(
8408 return STATUS_SUCCESS
;
8417 _In_
struct _KDPC
*Dpc
,
8418 _In_opt_ PVOID DeferredContext
,
8419 _In_opt_ PVOID SystemArgument1
,
8420 _In_opt_ PVOID SystemArgument2
)
8423 LIST_ENTRY LocalList
;
8424 PLIST_ENTRY ListEntry
;
8425 PRX_WORK_ITEM WorkItem
;
8427 InitializeListHead(&LocalList
);
8429 KeAcquireSpinLockAtDpcLevel(&RxTimerLock
);
8432 /* Find any entry matching */
8433 if (!IsListEmpty(&RxTimerQueueHead
))
8435 ListEntry
= RxTimerQueueHead
.Flink
;
8438 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
8439 if (WorkItem
->LastTick
== RxTimerTickCount
)
8441 ListEntry
= ListEntry
->Flink
;
8443 RemoveEntryList(&WorkItem
->WorkQueueItem
.List
);
8444 InsertTailList(&LocalList
, &WorkItem
->WorkQueueItem
.List
);
8448 ListEntry
= ListEntry
->Flink
;
8450 } while (ListEntry
!= &RxTimerQueueHead
);
8452 /* Do we have to requeue a later execution? */
8453 Set
= !IsListEmpty(&RxTimerQueueHead
);
8455 KeReleaseSpinLockFromDpcLevel(&RxTimerLock
);
8457 /* Requeue if list wasn't empty */
8460 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
8463 /* If we had matching entries */
8464 if (!IsListEmpty(&LocalList
))
8466 /* Post them, one after another */
8467 ListEntry
= LocalList
.Flink
;
8470 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
8471 ListEntry
= ListEntry
->Flink
;
8473 WorkItem
->WorkQueueItem
.List
.Flink
= NULL
;
8474 WorkItem
->WorkQueueItem
.List
.Blink
= NULL
;
8475 RxPostToWorkerThread(WorkItem
->WorkQueueItem
.pDeviceObject
, CriticalWorkQueue
,
8476 &WorkItem
->WorkQueueItem
, WorkItem
->WorkQueueItem
.WorkerRoutine
,
8477 WorkItem
->WorkQueueItem
.Parameter
);
8479 while (ListEntry
!= &LocalList
);
8483 #ifdef RDBSS_TRACKER
8488 RxTrackerUpdateHistory(
8489 _Inout_opt_ PRX_CONTEXT RxContext
,
8490 _Inout_ PMRX_FCB MrxFcb
,
8491 _In_ ULONG Operation
,
8492 _In_ ULONG LineNumber
,
8493 _In_ PCSTR FileName
,
8494 _In_ ULONG SerialNumber
)
8497 RX_FCBTRACKER_CASES Case
;
8499 /* Check for null or special context */
8500 if (RxContext
== NULL
)
8502 Case
= RX_FCBTRACKER_CASE_NULLCONTEXT
;
8504 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
)
8506 Case
= RX_FCBTRACKER_CASE_CBS_CONTEXT
;
8508 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
8510 Case
= RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT
;
8514 ASSERT(NodeType(RxContext
) == RDBSS_NTC_RX_CONTEXT
);
8515 Case
= RX_FCBTRACKER_CASE_NORMAL
;
8518 /* If caller provided a FCB, update its history */
8522 ASSERT(NodeTypeIsFcb(Fcb
));
8524 /* Only one acquire operation, so many release operations... */
8525 if (Operation
== TRACKER_ACQUIRE_FCB
)
8527 ++Fcb
->FcbAcquires
[Case
];
8531 ++Fcb
->FcbReleases
[Case
];
8535 /* If we have a normal context, update its history about this function calls */
8536 if (Case
== RX_FCBTRACKER_CASE_NORMAL
)
8538 ULONG TrackerHistoryPointer
;
8540 /* Only one acquire operation, so many release operations... */
8541 if (Operation
== TRACKER_ACQUIRE_FCB
)
8543 InterlockedIncrement(&RxContext
->AcquireReleaseFcbTrackerX
);
8547 InterlockedDecrement(&RxContext
->AcquireReleaseFcbTrackerX
);
8550 /* We only keep track of the 32 first calls */
8551 TrackerHistoryPointer
= InterlockedExchangeAdd((volatile long *)&RxContext
->TrackerHistoryPointer
, 1);
8552 if (TrackerHistoryPointer
< RDBSS_TRACKER_HISTORY_SIZE
)
8554 RxContext
->TrackerHistory
[TrackerHistoryPointer
].AcquireRelease
= Operation
;
8555 RxContext
->TrackerHistory
[TrackerHistoryPointer
].LineNumber
= LineNumber
;
8556 RxContext
->TrackerHistory
[TrackerHistoryPointer
].FileName
= (PSZ
)FileName
;
8557 RxContext
->TrackerHistory
[TrackerHistoryPointer
].SavedTrackerValue
= RxContext
->AcquireReleaseFcbTrackerX
;
8558 RxContext
->TrackerHistory
[TrackerHistoryPointer
].Flags
= RxContext
->Flags
;
8561 /* If it's negative, then we released once more than we acquired it?! */
8562 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
>= 0);
8568 RxTrackPagingIoResource(
8569 _Inout_ PVOID Instance
,
8581 RxUndoScavengerFinalizationMarking(
8584 /* Just call internal routine with mutex held */
8585 RxAcquireScavengerMutex();
8586 RxpUndoScavengerFinalizationMarking(Instance
);
8587 RxReleaseScavengerMutex();
8594 RxUninitializeVNetRootParameters(
8595 IN PUNICODE_STRING UserName
,
8596 IN PUNICODE_STRING UserDomainName
,
8597 IN PUNICODE_STRING Password
,
8602 /* Only free what could have been allocated */
8603 if (UserName
!= NULL
)
8605 RxFreePool(UserName
);
8608 if (UserDomainName
!= NULL
)
8610 RxFreePool(UserDomainName
);
8613 if (Password
!= NULL
)
8615 RxFreePool(Password
);
8618 /* And remove the possibly set CSC agent flag */
8621 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
8630 IN RX_BLOCK_CONDITION NewConditionValue
,
8631 OUT PRX_BLOCK_CONDITION Condition
,
8632 IN OUT PLIST_ENTRY TransitionWaitList
)
8634 PRX_CONTEXT Context
;
8635 LIST_ENTRY SerializationQueue
;
8639 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
8641 /* Set the new condition */
8642 RxAcquireSerializationMutex();
8643 ASSERT(NewConditionValue
!= Condition_InTransition
);
8644 *Condition
= NewConditionValue
;
8645 /* And get the serialization queue for treatment */
8646 RxTransferList(&SerializationQueue
, TransitionWaitList
);
8647 RxReleaseSerializationMutex();
8649 /* Handle the serialization queue */
8650 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
8651 while (Context
!= NULL
)
8653 /* If the caller asked for post, post the request */
8654 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8656 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
8657 RxFsdPostRequest(Context
);
8659 /* Otherwise, wake up sleeping waiters */
8662 RxSignalSynchronousWaiter(Context
);
8665 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
8673 RxVerifyOperationIsLegal(
8674 IN PRX_CONTEXT RxContext
)
8679 PFILE_OBJECT FileObject
;
8680 PIO_STACK_LOCATION Stack
;
8684 Irp
= RxContext
->CurrentIrp
;
8685 Stack
= RxContext
->CurrentIrpSp
;
8686 FileObject
= Stack
->FileObject
;
8688 /* We'll only check stuff on opened files, this requires an IRP and a FO */
8689 if (Irp
== NULL
|| FileObject
== NULL
)
8694 /* Set no exception for breakpoint - remember whether is was already set */
8695 FlagSet
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8696 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8698 /* If we have a CCB, perform a few checks on opened file */
8699 Fobx
= RxContext
->pFobx
;
8702 PMRX_SRV_OPEN SrvOpen
;
8704 SrvOpen
= Fobx
->pSrvOpen
;
8705 if (SrvOpen
!= NULL
)
8707 UCHAR MajorFunction
;
8709 MajorFunction
= RxContext
->MajorFunction
;
8710 /* Only allow closing/cleanup operations on renamed files */
8711 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8712 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
8714 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_RENAMED
;
8715 ExRaiseStatus(STATUS_FILE_RENAMED
);
8718 /* Only allow closing/cleanup operations on deleted files */
8719 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8720 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
))
8722 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_DELETED
;
8723 ExRaiseStatus(STATUS_FILE_DELETED
);
8728 /* If that's an open operation */
8729 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
8731 PFILE_OBJECT RelatedFileObject
;
8733 /* We won't allow an open operation relative to a file to be deleted */
8734 RelatedFileObject
= FileObject
->RelatedFileObject
;
8735 if (RelatedFileObject
!= NULL
)
8739 Fcb
= RelatedFileObject
->FsContext
;
8740 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
8742 RxContext
->IoStatusBlock
.Status
= STATUS_DELETE_PENDING
;
8743 ExRaiseStatus(STATUS_DELETE_PENDING
);
8748 /* If cleanup was completed */
8749 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
8751 if (!BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
))
8753 UCHAR MajorFunction
;
8755 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
8756 MajorFunction
= Stack
->MajorFunction
;
8757 if (MajorFunction
!= IRP_MJ_CLOSE
&& MajorFunction
!= IRP_MJ_QUERY_INFORMATION
&&
8758 MajorFunction
!= IRP_MJ_SET_INFORMATION
)
8760 if ((MajorFunction
!= IRP_MJ_READ
&& MajorFunction
!= IRP_MJ_WRITE
) ||
8761 !BooleanFlagOn(Stack
->MinorFunction
, IRP_MN_COMPLETE
))
8763 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_CLOSED
;
8764 ExRaiseStatus(STATUS_FILE_CLOSED
);
8770 /* If flag was already set, don't clear it */
8773 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8781 RxWaitForStableCondition(
8782 IN PRX_BLOCK_CONDITION Condition
,
8783 IN OUT PLIST_ENTRY TransitionWaitList
,
8784 IN OUT PRX_CONTEXT RxContext
,
8785 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
8788 NTSTATUS LocalStatus
;
8792 /* Make sure to always get status */
8793 if (AsyncStatus
== NULL
)
8795 AsyncStatus
= &LocalStatus
;
8798 /* By default, it's a success */
8799 *AsyncStatus
= STATUS_SUCCESS
;
8802 /* If it's not stable, we've to wait */
8803 if (!StableCondition(*Condition
))
8805 /* Lock the mutex */
8806 RxAcquireSerializationMutex();
8807 /* Still not stable? */
8808 if (!StableCondition(*Condition
))
8810 /* Insert us in the wait list for processing on stable condition */
8811 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
8813 /* If we're asked to post on stable, don't wait, and just return pending */
8814 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8816 *AsyncStatus
= STATUS_PENDING
;
8823 RxReleaseSerializationMutex();
8825 /* We don't post on stable, so, just wait... */
8828 RxWaitSync(RxContext
);
8838 RxWorkItemDispatcher(
8841 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
8843 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
8845 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
8847 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
8855 _RxAllocatePoolWithTag(
8856 _In_ POOL_TYPE PoolType
,
8857 _In_ SIZE_T NumberOfBytes
,
8860 return ExAllocatePoolWithTagPriority(PoolType
, NumberOfBytes
, Tag
, LowPoolPriority
);
8871 ExFreePoolWithTag(Buffer
, 0);
8883 ExFreePoolWithTag(Buffer
, Tag
);
8889 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
8891 #ifdef RDBSS_TRACKER
8893 _In_ ULONG LineNumber
,
8894 _In_ PCSTR FileName
,
8895 _In_ ULONG SerialNumber
8900 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
8904 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
8906 SpecialContext
= FALSE
;
8907 ContextIsPresent
= FALSE
;
8908 /* Check for special context */
8909 if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
|| RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
8911 SpecialContext
= TRUE
;
8914 /* We don't handle buffering state change yet... */
8915 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
8916 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
8921 /* Nor special contexts */
8927 /* If we don't have a context, assume we can wait! */
8928 if (RxContext
== NULL
)
8934 /* That said: we have a real context! */
8935 ContextIsPresent
= TRUE
;
8937 /* If we've been cancelled in between, give up */
8938 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
8939 if (!NT_SUCCESS(Status
))
8945 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8950 /* Assume we cannot lock */
8951 Status
= STATUS_LOCK_NOT_GRANTED
;
8953 /* Lock according to what the caller asked */
8956 case FCB_MODE_EXCLUSIVE
:
8957 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
8960 case FCB_MODE_SHARED
:
8961 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
8964 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
8965 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
8969 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
8970 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
8977 Status
= STATUS_SUCCESS
;
8978 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
8980 /* Handle paging write - not implemented */
8981 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
8987 /* And break, that cool! */
8993 /* If it failed, return immediately */
8994 if (!NT_SUCCESS(Status
))
9000 /* If we don't have to check for valid operation, job done, nothing more to do */
9001 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
9003 if (NT_SUCCESS(Status
))
9005 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
9011 /* Verify operation */
9014 RxVerifyOperationIsLegal(RxContext
);
9018 /* If it failed, release lock and fail */
9019 if (_SEH2_AbnormalTermination())
9021 ExReleaseResourceLite(Fcb
->Header
.Resource
);
9022 Status
= STATUS_LOCK_NOT_GRANTED
;
9027 if (NT_SUCCESS(Status
))
9029 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
9032 DPRINT("Status: %x\n", Status
);
9040 __RxItsTheSameContext(
9041 _In_ PRX_CONTEXT RxContext
,
9042 _In_ ULONG CapturedRxContextSerialNumber
,
9046 /* Check we have a context with the same serial number */
9047 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
9048 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
9051 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
9057 _Inout_opt_ PRX_CONTEXT RxContext
,
9058 _Inout_ PMRX_FCB MrxFcb
9059 #ifdef RDBSS_TRACKER
9061 _In_ ULONG LineNumber
,
9062 _In_ PCSTR FileName
,
9063 _In_ ULONG SerialNumber
9067 BOOLEAN IsExclusive
, BufferingPending
;
9069 RxAcquireSerializationMutex();
9071 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
9072 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
9074 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9075 * then just release the FCB
9077 if (!BufferingPending
|| !IsExclusive
)
9079 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
9080 LineNumber
, FileName
, SerialNumber
);
9081 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
9084 RxReleaseSerializationMutex();
9086 /* And finally leave */
9087 if (!BufferingPending
|| !IsExclusive
)
9092 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
9094 /* Otherwise, handle buffering state and release */
9095 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
9097 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
9098 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
9102 __RxReleaseFcbForThread(
9103 _Inout_opt_ PRX_CONTEXT RxContext
,
9104 _Inout_ PMRX_FCB MrxFcb
,
9105 _In_ ERESOURCE_THREAD ResourceThreadId
9106 #ifdef RDBSS_TRACKER
9108 _In_ ULONG LineNumber
,
9109 _In_ PCSTR FileName
,
9110 _In_ ULONG SerialNumber
9114 BOOLEAN IsExclusive
, BufferingPending
;
9116 RxAcquireSerializationMutex();
9118 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
9119 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
9121 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9122 * then just release the FCB
9124 if (!BufferingPending
|| !IsExclusive
)
9126 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
9127 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
9128 LineNumber
, FileName
, SerialNumber
);
9129 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
9132 RxReleaseSerializationMutex();
9134 /* And finally leave */
9135 if (!BufferingPending
|| !IsExclusive
)
9140 /* Otherwise, handle buffering state and release */
9141 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
9142 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
9143 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);