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 ****************************************************************/
179 RxAcquireExclusiveFcbResourceInMRx(
180 _Inout_ PMRX_FCB Fcb
)
183 return STATUS_NOT_IMPLEMENTED
;
191 RxAcquireFcbForLazyWrite(
201 /* The received context is a FCB */
202 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
203 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
204 ASSERT(Fcb
->Specific
.Fcb
.LazyWriteThread
== NULL
);
206 /* Acquire the paging resource (shared) */
207 Ret
= ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, Wait
);
210 /* Update tracker information */
211 Fcb
->PagingIoResourceFile
= __FILE__
;
212 Fcb
->PagingIoResourceLine
= __LINE__
;
213 /* Lazy writer thread is the current one */
214 Fcb
->Specific
.Fcb
.LazyWriteThread
= PsGetCurrentThread();
216 /* There is no top level IRP */
217 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
218 /* Now, there will be! */
219 Ret
= RxTryToBecomeTheTopLevelIrp(NULL
, (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
,
220 Fcb
->RxDeviceObject
, TRUE
);
221 /* In case of failure, release the lock and reset everything */
224 Fcb
->PagingIoResourceFile
= NULL
;
225 Fcb
->PagingIoResourceLine
= 0;
226 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
227 Fcb
->Specific
.Fcb
.LazyWriteThread
= NULL
;
239 RxAcquireFcbForReadAhead(
249 /* The received context is a FCB */
250 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
251 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
253 Ret
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, Wait
);
256 /* There is no top level IRP */
257 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
258 /* Now, there will be! */
259 Ret
= RxTryToBecomeTheTopLevelIrp(NULL
, (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
,
260 Fcb
->RxDeviceObject
, TRUE
);
261 /* In case of failure, release the lock and reset everything */
264 ExReleaseResourceLite(Fcb
->Header
.Resource
);
273 RxAcquireFileForNtCreateSection(
274 PFILE_OBJECT FileObject
)
282 PFILE_OBJECT FileObject
,
283 PDEVICE_OBJECT DeviceObject
)
286 return STATUS_NOT_IMPLEMENTED
;
293 RxAddVirtualNetRootToNetRoot(
295 PV_NET_ROOT VNetRoot
)
299 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
301 /* Insert in the VNetRoot list - make sure lock is held */
302 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
304 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
305 ++NetRoot
->NumberOfVirtualNetRoots
;
306 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
314 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
315 NODE_TYPE_CODE NodeType
,
318 PVOID AlreadyAllocatedObject
)
323 PVOID Buffer
, PAPNBuffer
;
324 PNON_PAGED_FCB NonPagedFcb
;
325 PMINIRDR_DISPATCH Dispatch
;
326 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
330 Dispatch
= RxDeviceObject
->Dispatch
;
343 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
344 if (NodeType
== RDBSS_NTC_FOBX
)
346 FobxSize
= sizeof(FOBX
);
347 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
349 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
352 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
353 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
355 SrvOpenSize
= sizeof(SRV_OPEN
);
356 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
358 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
361 FobxSize
= sizeof(FOBX
);
362 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
364 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
367 /* Otherwise, we're asked to allocate a FCB */
370 /* So, allocate the FCB and its extension if asked */
371 FcbSize
= sizeof(FCB
);
372 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
374 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
377 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
378 * Otherwise, it will be allocated later on, specifically
380 if (PoolType
== NonPagedPool
)
382 NonPagedSize
= sizeof(NON_PAGED_FCB
);
385 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
386 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
388 SrvOpenSize
= sizeof(SRV_OPEN
);
389 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
391 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
394 FobxSize
= sizeof(FOBX
);
395 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
397 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
402 /* If we already have a buffer, go ahead */
403 if (AlreadyAllocatedObject
!= NULL
)
405 Buffer
= AlreadyAllocatedObject
;
407 /* Otherwise, allocate it */
410 Buffer
= RxAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
417 /* Now, get the pointers - FOBX is easy */
418 if (NodeType
== RDBSS_NTC_FOBX
)
422 /* SRV_OPEN first, FOBX next */
423 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
426 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
428 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
434 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
436 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
438 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
439 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
442 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
443 if (PoolType
!= NonPagedPool
)
445 NonPagedFcb
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
446 if (NonPagedFcb
== NULL
)
448 RxFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
452 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
454 /* Otherwise, just point at the right place in what has been allocated previously */
457 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
458 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
462 /* If we have allocated a SRV_OPEN, initialize it */
465 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
467 if (NodeType
== RDBSS_NTC_SRVOPEN
)
469 SrvOpen
->InternalFobx
= Fobx
;
473 SrvOpen
->InternalFobx
= NULL
;
474 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
477 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
479 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
482 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
485 /* If we have allocated a FOBX, initialize it */
488 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
490 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
492 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
496 /* If we have allocated a FCB, initialize it */
499 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
501 Fcb
->NonPaged
= NonPagedFcb
;
502 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
503 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
504 NonPagedFcb
->FcbBackPointer
= Fcb
;
506 Fcb
->InternalSrvOpen
= SrvOpen
;
507 Fcb
->InternalFobx
= Fobx
;
509 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
510 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
511 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
513 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
515 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
518 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
520 InterlockedIncrement(&RxNumberOfActiveFcbs
);
521 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
523 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
524 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
527 DPRINT("Allocated %p\n", Buffer
);
537 NODE_TYPE_CODE NodeType
,
538 PMINIRDR_DISPATCH MRxDispatch
,
541 ULONG Tag
, ObjectSize
;
542 PVOID Object
, *Extension
;
543 PRX_PREFIX_ENTRY PrefixEntry
;
544 USHORT StructSize
, ExtensionSize
;
548 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
552 case RDBSS_NTC_SRVCALL
:
553 Tag
= RX_SRVCALL_POOLTAG
;
554 StructSize
= sizeof(SRV_CALL
);
555 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
557 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
561 case RDBSS_NTC_NETROOT
:
562 Tag
= RX_NETROOT_POOLTAG
;
563 StructSize
= sizeof(NET_ROOT
);
564 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
566 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
570 case RDBSS_NTC_V_NETROOT
:
571 Tag
= RX_V_NETROOT_POOLTAG
;
572 StructSize
= sizeof(V_NET_ROOT
);
573 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
575 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
584 /* Now, allocate the object */
585 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
586 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
592 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
594 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
597 case RDBSS_NTC_SRVCALL
:
598 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
599 Extension
= &((PSRV_CALL
)Object
)->Context
;
600 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
603 case RDBSS_NTC_NETROOT
:
604 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
605 Extension
= &((PNET_ROOT
)Object
)->Context
;
606 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
609 case RDBSS_NTC_V_NETROOT
:
610 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
611 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
619 /* Set the prefix table unicode string */
620 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
621 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
622 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
623 PrefixEntry
->Prefix
.Length
= NameLength
;
624 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
625 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
627 /* Return the extension if we are asked to manage it */
628 if (ExtensionSize
!= 0)
630 *Extension
= Add2Ptr(Object
, StructSize
);
649 /* If we're not asked to continue, just stop the system */
650 if (!RxContinueFromAssert
)
652 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
655 /* Otherwise, capture context to offer the user to dump it */
656 RtlCaptureContext(&Context
);
658 /* Loop until the user hits 'i' */
661 /* If no file provided, use empty name */
667 /* If no message provided, use empty one */
673 /* Display the message */
674 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
675 /* And ask the user */
676 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
677 /* If he asks for ignore, quit
678 * In case of invalid input, ask again
680 if (Response
[0] != 'B' && Response
[0] != 'b')
682 if (Response
[0] == 'I' || Response
[0] == 'i')
690 /* Break: offer the user to dump the context and break */
691 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
694 /* Continue looping, so that after dump, execution can continue (with ignore) */
703 RxBootstrapWorkerThreadDispatcher(
706 PRX_WORK_QUEUE RxWorkQueue
;
710 RxWorkQueue
= WorkQueue
;
711 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
719 RxChangeBufferingState(
722 BOOLEAN ComputeNewState
)
725 NTSTATUS Status
, MiniStatus
;
726 ULONG NewBufferingState
, OldBufferingState
;
730 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen
, Context
, ComputeNewState
);
732 Fcb
= (PFCB
)SrvOpen
->pFcb
;
733 ASSERT(NodeTypeIsFcb(Fcb
));
734 /* First of all, mark that buffering state is changing */
735 SetFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
738 Status
= STATUS_SUCCESS
;
741 /* If we're asked to compute a new state, ask the mini-rdr for it */
744 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxComputeNewBufferingState
,
745 ((PMRX_SRV_OPEN
)SrvOpen
, Context
, &NewBufferingState
));
746 if (MiniStatus
!= STATUS_SUCCESS
)
748 NewBufferingState
= 0;
753 /* If not, use SRV_OPEN state */
754 NewBufferingState
= SrvOpen
->BufferingFlags
;
757 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
758 if ((Fcb
->ShareAccess
.SharedRead
+ Fcb
->ShareAccess
.SharedWrite
+ Fcb
->ShareAccess
.SharedDelete
) == 0 && !ComputeNewState
)
760 SetFlag(NewBufferingState
, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES
);
763 /* If there's a lock operation to complete, clear that flag */
764 if (Fcb
->OutstandingLockOperationsCount
!= 0)
766 ClearFlag(NewBufferingState
, FCB_STATE_LOCK_BUFFERING_ENABLED
);
769 /* Get the old state */
770 OldBufferingState
= Fcb
->FcbState
& FCB_STATE_BUFFERING_STATE_MASK
;
771 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState
, NewBufferingState
, SrvOpen
->BufferingFlags
);
773 /* If we're dropping write cache, then flush the FCB */
774 if (BooleanFlagOn(OldBufferingState
, FCB_STATE_WRITECACHING_ENABLED
) &&
775 !BooleanFlagOn(NewBufferingState
, FCB_STATE_WRITECACHING_ENABLED
))
777 DPRINT("Flushing\n");
779 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
782 /* If we're dropping read cache, then purge */
783 if (Fcb
->UncleanCount
== 0 ||
784 (BooleanFlagOn(OldBufferingState
, FCB_STATE_READCACHING_ENABLED
) &&
785 !BooleanFlagOn(NewBufferingState
, FCB_STATE_READCACHING_ENABLED
)) ||
786 BooleanFlagOn(NewBufferingState
, FCB_STATE_DELETE_ON_CLOSE
))
790 if (!NT_SUCCESS(Status
))
792 DPRINT("Previous flush failed with status: %lx\n", Status
);
795 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, TRUE
);
798 /* If there's already a change pending in SRV_OPEN */
799 if (ComputeNewState
&& BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
801 /* If there's a FOBX at least */
802 if (!IsListEmpty(&SrvOpen
->FobxList
))
804 PRX_CONTEXT RxContext
;
806 /* Create a fake context to pass to the mini-rdr */
807 RxContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
808 if (RxContext
!= NULL
)
812 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
814 /* Give the first FOBX */
815 Fobx
= CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
);
816 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
817 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
819 /* If there was a delayed close, perform it */
820 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
822 DPRINT("Oplock break close for %p\n", SrvOpen
);
824 RxCloseAssociatedSrvOpen(Fobx
, RxContext
);
826 /* Otherwise, inform the mini-rdr about completion */
829 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxCompleteBufferingStateChangeRequest
,
830 (RxContext
, (PMRX_SRV_OPEN
)SrvOpen
, Context
));
834 RxDereferenceAndDeleteRxContext(RxContext
);
839 /* Set the new state */
840 Fcb
->FcbState
^= (NewBufferingState
^ Fcb
->FcbState
) & FCB_STATE_BUFFERING_STATE_MASK
;
844 /* Job done, clear the flag */
845 ClearFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
847 if (!BooleanFlagOn(NewBufferingState
, FCB_STATE_FILETIMECACHEING_ENABLED
))
849 ClearFlag(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
);
858 RxCheckVNetRootCredentials(
859 PRX_CONTEXT RxContext
,
860 PV_NET_ROOT VNetRoot
,
862 PUNICODE_STRING UserName
,
863 PUNICODE_STRING UserDomain
,
864 PUNICODE_STRING Password
,
869 /* If that's a UNC name, there's nothing to process */
870 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
871 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
874 return STATUS_MORE_PROCESSING_REQUIRED
;
877 /* Compare the logon ID in the VNetRoot with the one provided */
878 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
880 return STATUS_MORE_PROCESSING_REQUIRED
;
883 /* No credential provided? That's OK */
884 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
886 return STATUS_SUCCESS
;
891 return STATUS_NOT_IMPLEMENTED
;
903 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
905 ASSERT(Context
!= NULL
);
906 ASSERT(Context
->CurrentIrp
!= NULL
);
907 Irp
= Context
->CurrentIrp
;
909 /* Debug what the caller asks for */
910 if (Context
->LoudCompletionString
!= NULL
)
912 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
913 /* Does the user asks to stop on failed completion */
914 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
916 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
920 /* Complete for real */
921 Context
->CurrentIrp
= NULL
;
922 RxCompleteRequest_Real(Context
, Irp
, Status
);
924 DPRINT("Status: %lx\n", Status
);
932 RxCompleteRequest_Real(
933 IN PRX_CONTEXT RxContext
,
939 PIO_STACK_LOCATION Stack
;
941 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
943 /* Nothing to complete, just free context */
946 DPRINT("NULL IRP for %p\n", RxContext
);
947 if (RxContext
!= NULL
)
949 RxDereferenceAndDeleteRxContext_Real(RxContext
);
955 /* Remove cancel routine */
956 IoAcquireCancelSpinLock(&OldIrql
);
957 IoSetCancelRoutine(Irp
, NULL
);
958 IoReleaseCancelSpinLock(OldIrql
);
960 /* Select the boost, given the success/paging operation */
961 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
963 Boost
= IO_DISK_INCREMENT
;
967 Irp
->IoStatus
.Information
= 0;
968 Boost
= IO_NO_INCREMENT
;
970 Irp
->IoStatus
.Status
= Status
;
972 if (RxContext
!= NULL
)
974 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
975 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
977 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
978 RxContext
->MinorFunction
, RxContext
, Irp
,
979 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
983 /* If that's an opening, there might be a canonical name allocated,
984 * if completion isn't pending, release it
986 Stack
= IoGetCurrentIrpStackLocation(Irp
);
987 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
990 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
992 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
995 RxpPrepareCreateContextForReuse(RxContext
);
996 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
999 /* If it's a write, validate the correct behavior of the operation */
1000 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
1002 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
1004 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
1008 /* If it's pending, make sure IRP is marked as such */
1009 if (RxContext
!= NULL
)
1011 if (RxContext
->PendingReturned
)
1013 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
1018 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
1019 IoCompleteRequest(Irp
, Boost
);
1021 /* If there's a context, dereference it */
1022 if (RxContext
!= NULL
)
1024 RxDereferenceAndDeleteRxContext_Real(RxContext
);
1032 RxCompleteSrvOpenKeyAssociation(
1033 IN OUT PSRV_OPEN SrvOpen
)
1037 SrvCall
= (PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
;
1038 /* Only handle requests if opening was a success */
1039 if (SrvOpen
->Condition
== Condition_Good
)
1042 BOOLEAN ProcessChange
;
1043 LIST_ENTRY DiscardedRequests
;
1045 /* Initialize our discarded requests list */
1046 InitializeListHead(&DiscardedRequests
);
1048 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
1050 /* Transfer our requests in the SRV_CALL */
1051 RxTransferList(&SrvCall
->BufferingManager
.SrvOpenLists
[0], &SrvOpen
->SrvOpenKeyList
);
1053 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
1054 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
1056 /* Dispatch requests and get the discarded ones */
1057 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &DiscardedRequests
);
1059 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
1061 /* Is there still anything to process? */
1062 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
1063 if (IsListEmpty(&SrvCall
->BufferingManager
.HandlerList
))
1065 ProcessChange
= FALSE
;
1069 ProcessChange
= (SrvCall
->BufferingManager
.HandlerInactive
== FALSE
);
1072 SrvCall
->BufferingManager
.HandlerInactive
= TRUE
;
1075 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
1077 /* Yes? Go ahead! */
1080 RxReferenceSrvCall(SrvCall
);
1081 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
1082 &SrvCall
->BufferingManager
.HandlerWorkItem
,
1083 RxProcessChangeBufferingStateRequests
, SrvCall
);
1086 /* And discard left requests */
1087 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests
);
1091 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
1100 IN PRX_CONTEXT RxContext
,
1101 IN PSRV_CALL SrvCall
,
1102 IN PNET_ROOT NetRoot
,
1103 IN PV_NET_ROOT VirtualNetRoot
,
1104 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1107 PRX_PREFIX_TABLE PrefixTable
;
1108 PMRX_CREATENETROOT_CONTEXT Context
;
1109 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
1113 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
1114 VirtualNetRoot
, LockHoldingState
);
1116 /* Validate the lock is exclusively held */
1117 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
1118 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1120 /* Allocate the context */
1121 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
1122 if (Context
== NULL
)
1124 return STATUS_INSUFFICIENT_RESOURCES
;
1127 /* We can release lock now */
1128 RxReleasePrefixTableLock(PrefixTable
);
1129 *LockHoldingState
= LHS_LockNotHeld
;
1131 RootCondition
= Condition_Bad
;
1132 VRootCondition
= Condition_Bad
;
1134 /* Initialize the context */
1135 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
1136 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
1137 Context
->RxContext
= RxContext
;
1138 Context
->pVNetRoot
= VirtualNetRoot
;
1139 Context
->Callback
= RxCreateNetRootCallBack
;
1141 /* And call the mini-rdr */
1142 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
1143 if (Status
== STATUS_PENDING
)
1145 /* Wait for the mini-rdr to be done */
1146 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1147 /* Update the structures condition according to mini-rdr return */
1148 if (NT_SUCCESS(Context
->NetRootStatus
))
1150 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
1152 RootCondition
= Condition_Good
;
1153 VRootCondition
= Condition_Good
;
1154 Status
= STATUS_SUCCESS
;
1158 RootCondition
= Condition_Good
;
1159 Status
= Context
->VirtualNetRootStatus
;
1164 Status
= Context
->VirtualNetRootStatus
;
1165 if (NT_SUCCESS(Status
))
1167 Status
= Context
->NetRootStatus
;
1173 /* It has to return STATUS_PENDING! */
1177 /* Acquire lock again - for caller lock status will remain unchanged */
1178 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
1179 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
1180 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1182 /* Do the transition to the condition got from mini-rdr */
1183 RxTransitionNetRoot(NetRoot
, RootCondition
);
1184 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
1186 /* Context is not longer needed */
1187 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
1189 DPRINT("Status: %x\n", Status
);
1199 IN PRX_CONTEXT RxContext
,
1200 IN PSRV_CALL SrvCall
,
1201 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1204 PRX_PREFIX_TABLE PrefixTable
;
1205 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1206 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1207 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
1211 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
1213 /* Validate the lock is exclusively held */
1214 RxDeviceObject
= RxContext
->RxDeviceObject
;
1215 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
1216 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1218 /* Allocate the context for mini-rdr */
1219 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
1220 if (Calldown
== NULL
)
1222 SrvCall
->Context
= NULL
;
1223 SrvCall
->Condition
= Condition_Bad
;
1224 RxReleasePrefixTableLock(PrefixTable
);
1225 *LockHoldingState
= LHS_LockNotHeld
;
1226 return STATUS_INSUFFICIENT_RESOURCES
;
1230 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
1232 SrvCall
->Context
= NULL
;
1233 SrvCall
->Condition
= Condition_InTransition
;
1235 RxReleasePrefixTableLock(PrefixTable
);
1236 *LockHoldingState
= LHS_LockNotHeld
;
1238 CallbackContext
= &Calldown
->CallbackContexts
[0];
1239 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
1240 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
1241 CallbackContext
->SrvCalldownStructure
= Calldown
;
1242 CallbackContext
->CallbackContextOrdinal
= 0;
1243 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
1245 RxReferenceSrvCall(SrvCall
);
1247 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1248 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1250 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
1254 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
1257 Calldown
->NumberToWait
= 1;
1258 Calldown
->NumberRemaining
= 1;
1259 Calldown
->RxContext
= RxContext
;
1260 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
1261 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
1262 Calldown
->BestFinisher
= NULL
;
1263 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
1264 InitializeListHead(&Calldown
->SrvCalldownList
);
1266 /* Call the mini-rdr */
1267 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
1268 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
1269 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
1270 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
1271 /* It has to return STATUS_PENDING! */
1272 ASSERT(Status
== STATUS_PENDING
);
1274 /* No async, start completion */
1275 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1277 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1279 /* Finish construction - we'll notify mini-rdr it's the winner */
1280 Status
= RxFinishSrvCallConstruction(Calldown
);
1281 if (!NT_SUCCESS(Status
))
1283 RxReleasePrefixTableLock(PrefixTable
);
1284 *LockHoldingState
= LHS_LockNotHeld
;
1288 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
1289 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1293 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
1301 RxConstructVirtualNetRoot(
1302 IN PRX_CONTEXT RxContext
,
1303 IN PUNICODE_STRING CanonicalName
,
1304 IN NET_ROOT_TYPE NetRootType
,
1305 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
1306 OUT PLOCK_HOLDING_STATE LockHoldingState
,
1307 OUT PRX_CONNECTION_ID RxConnectionId
)
1310 PV_NET_ROOT VNetRoot
;
1311 RX_BLOCK_CONDITION Condition
;
1312 UNICODE_STRING LocalNetRootName
, FilePathName
;
1316 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1319 Condition
= Condition_Bad
;
1320 /* Before creating the VNetRoot, try to find the appropriate connection */
1321 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
1322 &LocalNetRootName
, &FilePathName
,
1323 LockHoldingState
, RxConnectionId
);
1324 /* Found and active */
1325 if (Status
== STATUS_CONNECTION_ACTIVE
)
1327 /* We need a new VNetRoot */
1328 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
1329 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
1330 if (VNetRoot
!= NULL
)
1332 RxReferenceVNetRoot(VNetRoot
);
1335 /* Dereference previous VNetRoot */
1336 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
1337 /* Reset and start construct (new structures will replace old ones) */
1338 RxContext
->Create
.pSrvCall
= NULL
;
1339 RxContext
->Create
.pNetRoot
= NULL
;
1340 RxContext
->Create
.pVNetRoot
= NULL
;
1342 /* Construct new NetRoot */
1343 if (VNetRoot
!= NULL
)
1345 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
1346 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
1347 if (NT_SUCCESS(Status
))
1349 Condition
= Condition_Good
;
1354 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1359 /* If it failed creating the connection, leave */
1360 if (Status
!= STATUS_SUCCESS
)
1362 if (*LockHoldingState
!= LHS_LockNotHeld
)
1364 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1365 *LockHoldingState
= LHS_LockNotHeld
;
1368 *VirtualNetRootPointer
= VNetRoot
;
1369 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1373 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1375 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1376 Condition
= Condition_Good
;
1379 /* We have a non stable VNetRoot - transition it */
1380 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1382 RxTransitionVNetRoot(VNetRoot
, Condition
);
1385 /* If recreation failed */
1386 if (Status
!= STATUS_SUCCESS
)
1388 /* Dereference potential VNetRoot */
1389 if (VNetRoot
!= NULL
)
1391 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1392 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1397 if (*LockHoldingState
!= LHS_LockNotHeld
)
1399 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1400 *LockHoldingState
= LHS_LockNotHeld
;
1404 *VirtualNetRootPointer
= VNetRoot
;
1408 /* Return the allocated VNetRoot */
1409 *VirtualNetRootPointer
= VNetRoot
;
1418 IN PRX_CONTEXT RxContext
,
1419 IN PV_NET_ROOT VNetRoot
,
1420 IN PUNICODE_STRING Name
)
1426 NODE_TYPE_CODE NodeType
;
1427 PIO_STACK_LOCATION Stack
;
1428 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1432 /* We need a decent VNetRoot */
1433 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1435 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1436 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1437 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1439 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1440 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1442 Stack
= RxContext
->CurrentIrpSp
;
1444 /* Do we need to create a fake FCB? Like for renaming */
1445 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1446 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1447 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1449 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1450 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1452 /* Allocate the FCB */
1453 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1454 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1460 /* Initialize the FCB */
1461 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1462 Fcb
->RxDeviceObject
= RxDeviceObject
;
1463 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1464 Fcb
->VNetRoot
= VNetRoot
;
1465 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1467 InitializeListHead(&Fcb
->SrvOpenList
);
1468 Fcb
->SrvOpenListVersion
= 0;
1470 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1471 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1472 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1473 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1474 NetRoot
->InnerNamePrefix
.Length
);
1475 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1477 /* Copy back parameters from RxContext */
1478 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1480 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1483 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1485 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1487 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1490 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1492 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1495 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1496 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1498 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1499 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1501 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1502 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1504 /* Fake FCB doesn't go in prefix table */
1507 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1508 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1509 DPRINT("Fake FCB: %p\n", Fcb
);
1513 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1516 RxReferenceVNetRoot(VNetRoot
);
1517 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1519 Fcb
->ulFileSizeVersion
= 0;
1521 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1522 RxReferenceNetFcb(Fcb
);
1533 OUT PRX_CONTEXT RxContext
,
1534 IN PMRX_SRV_OPEN MrxSrvOpen
)
1545 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1546 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1547 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1548 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1551 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1552 /* Can we use pre-allocated FOBX? */
1553 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1555 Fobx
= Fcb
->InternalFobx
;
1556 /* Call allocate to initialize the FOBX */
1557 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1558 /* Mark it used now */
1559 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1560 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1562 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1564 Fobx
= SrvOpen
->InternalFobx
;
1565 /* Call allocate to initialize the FOBX */
1566 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1567 /* Mark it used now */
1568 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1569 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1573 /* Last case, we cannot, allocate a FOBX */
1574 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1578 /* Allocation failed! */
1585 Fobx
->Flags
= Flags
;
1587 /* Initialize throttling */
1588 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1589 if (NetRoot
!= NULL
)
1591 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1593 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1594 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1595 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1597 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1599 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1600 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1601 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1605 /* Propagate flags fron RxContext */
1606 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1608 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1611 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1613 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1617 Fobx
->FobxSerialNumber
= 0;
1618 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1619 Fobx
->NodeReferenceCount
= 1;
1620 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1622 RxReferenceSrvOpen(SrvOpen
);
1623 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1625 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1626 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1627 InitializeListHead(&Fobx
->ClosePendingList
);
1629 Fobx
->CloseTime
.QuadPart
= 0;
1630 Fobx
->fOpenCountDecremented
= FALSE
;
1632 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1634 return (PMRX_FOBX
)Fobx
;
1642 IN PSRV_CALL SrvCall
,
1643 IN PUNICODE_STRING Name
,
1644 IN ULONG NetRootFlags
,
1645 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1648 USHORT CaseInsensitiveLength
;
1649 PRX_PREFIX_TABLE PrefixTable
;
1651 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1655 /* We need a SRV_CALL */
1656 ASSERT(SrvCall
!= NULL
);
1658 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1659 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1661 /* Get name length */
1662 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1663 if (CaseInsensitiveLength
> MAXUSHORT
)
1668 /* Allocate the NetRoot */
1669 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1670 CaseInsensitiveLength
);
1671 if (NetRoot
== NULL
)
1676 /* Construct name */
1677 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1678 Name
->Buffer
, Name
->Length
);
1679 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1681 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1682 SrvCall
->PrefixEntry
.Prefix
.Length
);
1685 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1687 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1689 /* Inisert in prefix table */
1690 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1691 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1694 /* Prepare the FCB table */
1695 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1697 InitializeListHead(&NetRoot
->TransitionWaitList
);
1698 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1699 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1701 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1703 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1704 NetRoot
->Flags
|= NetRootFlags
;
1705 NetRoot
->DiskParameters
.ClusterSize
= 1;
1706 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1707 NetRoot
->SrvCall
= SrvCall
;
1709 RxReferenceSrvCall(SrvCall
);
1711 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1720 RxCreateNetRootCallBack(
1721 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1725 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1735 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1736 IN ULONG InitialContextFlags
)
1739 PRX_CONTEXT Context
;
1741 ASSERT(RxDeviceObject
!= NULL
);
1743 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1745 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1746 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1748 /* Allocate the context from our lookaside list */
1749 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1750 if (Context
== NULL
)
1756 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1758 /* It was allocated on NP pool, keep track of it! */
1759 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
1760 /* And initialize it */
1761 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1762 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1764 /* Add it to our global list */
1765 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1766 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1767 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1769 DPRINT("Context: %p\n", Context
);
1778 IN PRX_CONTEXT RxContext
,
1779 IN PUNICODE_STRING Name
,
1780 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1781 IN PRX_CONNECTION_ID RxConnectionId
)
1788 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1790 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1792 /* Get the name length */
1793 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1794 if (InnerNamePrefix
!= NULL
)
1796 NameLength
+= InnerNamePrefix
->Length
;
1799 /* Allocate the object */
1800 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1801 if (SrvCall
== NULL
)
1807 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1808 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1809 RxInitializeBufferingManager(SrvCall
);
1810 InitializeListHead(&SrvCall
->TransitionWaitList
);
1811 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1812 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1813 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1814 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1815 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1816 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1817 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1818 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1820 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1829 RxCreateSrvCallCallBack(
1830 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1834 PRX_CONTEXT RxContext
;
1835 ULONG NumberRemaining
;
1836 BOOLEAN StartDispatcher
;
1837 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1839 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1841 /* Get our context structures */
1842 Calldown
= Context
->SrvCalldownStructure
;
1843 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1845 /* If it is a success, that's the winner */
1846 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1847 if (Context
->Status
== STATUS_SUCCESS
)
1849 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1850 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1852 NumberRemaining
= --Calldown
->NumberRemaining
;
1853 SrvCall
->Status
= Context
->Status
;
1854 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1856 /* Still some to ask, keep going */
1857 if (NumberRemaining
!= 0)
1862 /* If that's not async, signal we're done */
1863 RxContext
= Calldown
->RxContext
;
1864 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1866 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1869 /* If that's a mailslot, finish construction, no more to do */
1870 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1872 RxFinishSrvCallConstruction(Calldown
);
1876 /* Queue our finish call for delayed completion */
1877 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1878 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1879 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1880 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1881 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1883 /* If we have to start dispatcher, go ahead */
1884 if (StartDispatcher
)
1888 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1889 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1890 if (!NT_SUCCESS(Status
))
1892 /* It failed - run it manually.... */
1893 RxFinishSrvCallConstructionDispatcher(NULL
);
1903 IN PV_NET_ROOT VNetRoot
,
1912 ASSERT(NodeTypeIsFcb(Fcb
));
1913 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1915 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1919 SrvOpen
= Fcb
->InternalSrvOpen
;
1920 /* Check whethet we have to allocate a new SRV_OPEN */
1921 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1922 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1923 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1926 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1927 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1932 /* Otherwise, just use internal one and initialize it */
1933 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1934 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1935 Fcb
->InternalSrvOpen
);
1936 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1937 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1940 /* If SrvOpen was properly allocated, initialize it */
1941 if (SrvOpen
!= NULL
)
1943 SrvOpen
->Flags
= Flags
;
1944 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1945 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1946 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1947 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1948 SrvOpen
->NodeReferenceCount
= 1;
1950 RxReferenceVNetRoot(VNetRoot
);
1951 RxReferenceNetFcb(Fcb
);
1953 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1954 ++Fcb
->SrvOpenListVersion
;
1956 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1957 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1958 InitializeListHead(&SrvOpen
->FobxList
);
1959 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1964 if (_SEH2_AbnormalTermination())
1966 if (SrvOpen
!= NULL
)
1968 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1974 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1987 IN PRX_CONTEXT RxContext
,
1988 IN PNET_ROOT NetRoot
,
1989 IN PUNICODE_STRING CanonicalName
,
1990 IN PUNICODE_STRING LocalNetRootName
,
1991 IN PUNICODE_STRING FilePath
,
1992 IN PRX_CONNECTION_ID RxConnectionId
)
1995 PV_NET_ROOT VNetRoot
;
1996 USHORT CaseInsensitiveLength
;
2000 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
2001 LocalNetRootName
, FilePath
, RxConnectionId
);
2003 /* Lock must be held exclusively */
2004 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
2006 /* Check for overflow */
2007 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
2012 /* Get name length and allocate VNetRoot */
2013 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
2014 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
2015 CaseInsensitiveLength
);
2016 if (VNetRoot
== NULL
)
2021 /* Initialize its connection parameters */
2022 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
2023 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
2024 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
2025 if (!NT_SUCCESS(Status
))
2027 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
2028 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
2029 RxFreeObject(VNetRoot
);
2035 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2037 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
2038 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
2039 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
2040 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
2042 InitializeListHead(&VNetRoot
->TransitionWaitList
);
2043 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
2045 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
2049 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
2051 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
2055 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
2058 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
2060 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
2066 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
2069 /* Insert in prefix table */
2070 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
2071 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
2074 RxReferenceNetRoot(NetRoot
);
2075 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
2078 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
2079 VNetRoot
->UpperFinalizationDone
= FALSE
;
2080 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
2081 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2083 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
2084 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
2094 IN OUT PVOID Instance
,
2095 IN LOCK_HOLDING_STATE LockHoldingState
)
2098 NODE_TYPE_CODE NodeType
;
2099 PNODE_TYPE_AND_SIZE Node
;
2103 RxAcquireScavengerMutex();
2105 /* Check we have a node we can handle */
2106 NodeType
= NodeType(Instance
);
2107 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
2108 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
2109 (NodeType
== RDBSS_NTC_FOBX
));
2111 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
2112 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
2113 ASSERT(RefCount
>= 0);
2115 /* Trace refcount */
2118 case RDBSS_NTC_SRVCALL
:
2119 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
2122 case RDBSS_NTC_NETROOT
:
2123 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
2126 case RDBSS_NTC_V_NETROOT
:
2127 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
2130 case RDBSS_NTC_SRVOPEN
:
2131 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
2134 case RDBSS_NTC_FOBX
:
2135 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
2143 /* No need to free - still in use */
2146 RxReleaseScavengerMutex();
2150 /* We have to be locked exclusively */
2151 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
2153 if ((NodeType
== RDBSS_NTC_FOBX
&& RefCount
== 0) ||
2154 (NodeType
>= RDBSS_NTC_SRVCALL
&& NodeType
<= RDBSS_NTC_V_NETROOT
))
2156 RxpMarkInstanceForScavengedFinalization(Instance
);
2159 RxReleaseScavengerMutex();
2164 if (BooleanFlagOn(NodeType
, RX_SCAVENGER_MASK
))
2166 RxpUndoScavengerFinalizationMarking(Instance
);
2170 RxReleaseScavengerMutex();
2172 /* Now, deallocate the memory */
2175 case RDBSS_NTC_SRVCALL
:
2179 SrvCall
= (PSRV_CALL
)Instance
;
2181 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
2182 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
2183 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
2187 case RDBSS_NTC_NETROOT
:
2191 NetRoot
= (PNET_ROOT
)Instance
;
2193 ASSERT(NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2194 ASSERT(RxIsPrefixTableLockAcquired(NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2195 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2199 case RDBSS_NTC_V_NETROOT
:
2201 PV_NET_ROOT VNetRoot
;
2203 VNetRoot
= (PV_NET_ROOT
)Instance
;
2205 ASSERT(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2206 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2207 RxFinalizeVNetRoot(VNetRoot
, TRUE
, TRUE
);
2211 case RDBSS_NTC_SRVOPEN
:
2215 SrvOpen
= (PSRV_OPEN
)Instance
;
2217 ASSERT(RxIsFcbAcquired(SrvOpen
->Fcb
));
2218 if (SrvOpen
->OpenCount
== 0)
2220 RxFinalizeSrvOpen(SrvOpen
, FALSE
, FALSE
);
2225 case RDBSS_NTC_FOBX
:
2229 Fobx
= (PFOBX
)Instance
;
2231 ASSERT(RxIsFcbAcquired(Fobx
->SrvOpen
->Fcb
));
2232 RxFinalizeNetFobx(Fobx
, TRUE
, FALSE
);
2243 RxDereferenceAndDeleteRxContext_Real(
2244 IN PRX_CONTEXT RxContext
)
2249 PRX_CONTEXT StopContext
= NULL
;
2251 /* Make sure we really have a context */
2252 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
2253 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
2254 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
2255 /* If refcount is 0, start releasing stuff that needs spinlock held */
2258 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2260 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
2262 /* If that's stop context from DO, remove it */
2263 RxDeviceObject
= RxContext
->RxDeviceObject
;
2264 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
2266 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
2270 /* Remove it from the list */
2271 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
2272 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
2273 RemoveEntryList(&RxContext
->ContextListEntry
);
2275 /* If that was the last active context, save the stop context */
2276 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
2278 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
2280 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
2285 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
2287 /* Now, deal with what can be done without spinlock held */
2290 /* Refcount shouldn't have changed */
2291 ASSERT(RxContext
->ReferenceCount
== 0);
2292 /* Reset everything that can be */
2293 RxPrepareContextForReuse(RxContext
);
2295 #ifdef RDBSS_TRACKER
2296 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
2298 /* If that was the last active, set the event */
2299 if (StopContext
!= NULL
)
2301 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
2302 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
2305 /* Is ShadowCrit still owned? Shouldn't happen! */
2306 if (RxContext
->ShadowCritOwner
!= 0)
2308 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
2312 /* If it was allocated, free it */
2315 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
2322 RxDispatchChangeBufferingStateRequests(
2333 RxDispatchToWorkerThread(
2334 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
2335 IN WORK_QUEUE_TYPE WorkQueueType
,
2336 IN PRX_WORKERTHREAD_ROUTINE Routine
,
2340 PRX_WORK_DISPATCH_ITEM DispatchItem
;
2342 /* Allocate a bit of context */
2343 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
2344 if (DispatchItem
== NULL
)
2346 return STATUS_INSUFFICIENT_RESOURCES
;
2349 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2350 DispatchItem
->DispatchRoutine
= Routine
;
2351 DispatchItem
->DispatchRoutineParameter
= pContext
;
2352 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
2353 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
2356 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, &DispatchItem
->WorkQueueItem
);
2357 if (!NT_SUCCESS(Status
))
2359 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
2360 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
2363 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
2372 RxExclusivePrefixTableLockToShared(
2373 PRX_PREFIX_TABLE Table
)
2377 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
2384 RxExtractServerName(
2385 IN PUNICODE_STRING FilePathName
,
2386 OUT PUNICODE_STRING SrvCallName
,
2387 OUT PUNICODE_STRING RestOfName
)
2393 ASSERT(SrvCallName
!= NULL
);
2395 /* SrvCall name will start from the begin up to the first separator */
2396 SrvCallName
->Buffer
= FilePathName
->Buffer
;
2397 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2399 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2405 /* Compute length */
2406 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
2407 SrvCallName
->MaximumLength
= Length
;
2408 SrvCallName
->Length
= Length
;
2410 /* Return the rest if asked */
2411 if (RestOfName
!= NULL
)
2413 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
2414 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2415 RestOfName
->MaximumLength
= Length
;
2416 RestOfName
->Length
= Length
;
2424 RxFcbTableInsertFcb(
2425 IN OUT PRX_FCB_TABLE FcbTable
,
2430 /* We deal with the table, make sure it's locked */
2431 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2433 /* Compute the hash */
2434 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2436 RxReferenceNetFcb(Fcb
);
2438 /* If no length, it will be our null entry */
2439 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2441 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2443 /* Otherwise, insert in the appropriate bucket */
2446 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2447 &Fcb
->FcbTableEntry
.HashLinks
);
2450 /* Propagate the change by incrementing the version number */
2451 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2453 return STATUS_SUCCESS
;
2460 RxFcbTableLookupFcb(
2461 IN PRX_FCB_TABLE FcbTable
,
2462 IN PUNICODE_STRING Path
)
2465 PRX_FCB_TABLE_ENTRY TableEntry
;
2469 /* No path - easy, that's null entry */
2472 TableEntry
= FcbTable
->TableEntryForNull
;
2477 PLIST_ENTRY HashBucket
, ListEntry
;
2479 /* Otherwise, compute the hash value and find the associated bucket */
2480 Hash
= RxTableComputePathHashValue(Path
);
2481 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2482 /* If the bucket is empty, it means there's no entry yet */
2483 if (IsListEmpty(HashBucket
))
2489 /* Otherwise, browse all the entry */
2490 for (ListEntry
= HashBucket
->Flink
;
2491 ListEntry
!= HashBucket
;
2492 ListEntry
= ListEntry
->Flink
)
2494 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2495 InterlockedIncrement(&FcbTable
->Compares
);
2497 /* If entry hash and string are equal, thatt's the one! */
2498 if (TableEntry
->HashValue
== Hash
&&
2499 TableEntry
->Path
.Length
== Path
->Length
&&
2500 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2506 /* We reached the end? Not found */
2507 if (ListEntry
== HashBucket
)
2514 InterlockedIncrement(&FcbTable
->Lookups
);
2516 /* If table entry isn't null, return the FCB */
2517 if (TableEntry
!= NULL
)
2519 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2520 RxReferenceNetFcb(Fcb
);
2525 InterlockedIncrement(&FcbTable
->FailedLookups
);
2535 RxFcbTableRemoveFcb(
2536 IN OUT PRX_FCB_TABLE FcbTable
,
2541 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2543 /* If no path, then remove entry for null */
2544 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2546 FcbTable
->TableEntryForNull
= NULL
;
2548 /* Otherwise, remove from the bucket */
2551 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2554 /* Reset its list entry */
2555 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2557 /* Propagate the change by incrementing the version number */
2558 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2560 return STATUS_SUCCESS
;
2568 RxFinalizeConnection(
2569 IN OUT PNET_ROOT NetRoot
,
2570 IN OUT PV_NET_ROOT VNetRoot OPTIONAL
,
2571 IN LOGICAL ForceFilesClosed
)
2574 PRX_PREFIX_TABLE PrefixTable
;
2575 ULONG UncleanAny
, UncleanDir
;
2576 LONG FilesOpen
, AdditionalRef
;
2577 BOOLEAN PrefixLocked
, FcbTableLocked
, ForceClose
;
2581 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
2583 /* Get a BOOLEAN out of LOGICAL
2584 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2586 ForceClose
= (ForceFilesClosed
== TRUE
? TRUE
: FALSE
);
2588 /* First, delete any notification change */
2589 Status
= RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot
, ForceClose
);
2590 /* If it failed, continue if forced */
2591 if (Status
!= STATUS_SUCCESS
&& !ForceFilesClosed
)
2595 /* Reset status, in case notification deletion failed */
2596 Status
= STATUS_SUCCESS
;
2598 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2600 PrefixLocked
= FALSE
;
2601 FcbTableLocked
= FALSE
;
2608 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2609 PrefixLocked
= TRUE
;
2611 RxReferenceNetRoot(NetRoot
);
2613 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2614 FcbTableLocked
= TRUE
;
2616 /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2617 if (!VNetRoot
->ConnectionFinalizationDone
)
2620 PRX_FCB_TABLE FcbTable
;
2622 DPRINT("Finalizing connection %p: %wZ\n", NetRoot
, &NetRoot
->PrefixEntry
.Prefix
);
2624 /* We'll browse all its associated FCB to check whether they're open/orphaned */
2625 FcbTable
= &NetRoot
->FcbTable
;
2626 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2628 PLIST_ENTRY BucketList
, Entry
;
2630 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
2631 Entry
= BucketList
->Flink
;
2632 while (Entry
!= BucketList
)
2636 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
2637 Entry
= Entry
->Flink
;
2639 /* FCB for this connection, go ahead */
2640 if (Fcb
->VNetRoot
== VNetRoot
)
2642 /* It's still open, and no force? Fail and keep track */
2643 if (Fcb
->UncleanCount
> 0 && !ForceClose
)
2645 Status
= STATUS_CONNECTION_IN_USE
;
2646 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2657 /* Else, force purge */
2658 ASSERT(NodeTypeIsFcb(Fcb
));
2660 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
2661 ASSERT(Status
== STATUS_SUCCESS
);
2663 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2665 RxScavengeRelatedFobxs(Fcb
);
2668 /* We don't need to release FCB lock, FCB finalize will take care of it */
2674 /* No files left, our V_NET_ROOT is finalized */
2675 if (VNetRoot
->NumberOfFobxs
== 0)
2677 VNetRoot
->ConnectionFinalizationDone
= TRUE
;
2681 /* Keep Number of open files and track of the extra reference */
2682 FilesOpen
= VNetRoot
->NumberOfFobxs
;
2683 AdditionalRef
= VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
;
2684 /* If force close, caller doesn't want to keep connection alive
2685 * and wants it totally close, so drop the V_NET_ROOT too
2689 RxFinalizeVNetRoot(VNetRoot
, FALSE
, TRUE
);
2694 /* Release what was acquired */
2697 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2700 /* If close is forced, only fix status if there are open files */
2703 if (Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0)
2705 Status
= STATUS_FILES_OPEN
;
2708 /* Else, fix status and fail closing if there are open files */
2711 if ((Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0) || FilesOpen
> 0)
2713 Status
= STATUS_FILES_OPEN
;
2717 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny
, UncleanDir
, FilesOpen
);
2719 /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2720 * only if it was still referenced!
2722 if ((ForceFilesClosed
== 0xFF || Status
== STATUS_SUCCESS
) && AdditionalRef
!= 0)
2724 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2725 RxDereferenceVNetRoot(VNetRoot
, LHS_ExclusiveLockHeld
);
2730 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2731 RxReleasePrefixTableLock(PrefixTable
);
2744 IN OUT PRX_FCB_TABLE FcbTable
)
2750 /* Just delete the lock */
2751 ExDeleteResourceLite(&FcbTable
->TableLock
);
2753 /* And make sure (checked) that the table is really empty... */
2754 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2756 ASSERT(IsListEmpty(&FcbTable
->HashBuckets
[Bucket
]));
2766 IN BOOLEAN RecursiveFinalize
,
2767 IN BOOLEAN ForceFinalize
,
2768 IN LONG ReferenceCount
)
2772 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2773 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2775 /* Make sure we have an exclusively acquired FCB */
2776 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2777 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2779 /* We shouldn't force finalization... */
2780 ASSERT(!ForceFinalize
);
2782 /* If recurisve, finalize all the associated SRV_OPEN */
2783 if (RecursiveFinalize
)
2785 PLIST_ENTRY ListEntry
;
2787 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2788 ListEntry
!= &ThisFcb
->SrvOpenList
;
2789 ListEntry
= ListEntry
->Flink
)
2793 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2794 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2797 /* If FCB is still in use, that's over */
2800 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2802 ASSERT(ReferenceCount
> 0);
2808 ASSERT(ReferenceCount
>= 1);
2810 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2811 if (ReferenceCount
!= 1 && !ForceFinalize
)
2816 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2818 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb
->OpenCount
, ForceFinalize
);
2820 /* If finalization was not already initiated, go ahead */
2821 if (!ThisFcb
->UpperFinalizationDone
)
2823 /* Free any FCB_LOCK */
2824 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2826 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2828 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2832 Entry
= ThisFcb
->BufferedLocks
.List
;
2833 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2839 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2840 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2844 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2846 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2848 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2850 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2854 ThisFcb
->UpperFinalizationDone
= TRUE
;
2857 ASSERT(ReferenceCount
>= 1);
2859 /* Even if forced, don't allow broken free */
2860 if (ReferenceCount
!= 1)
2865 /* Now, release everything */
2866 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2868 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2871 if (ThisFcb
->MRxDispatch
!= NULL
)
2873 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2876 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2877 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2878 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2880 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2881 RxDereferenceVNetRoot(ThisFcb
->VNetRoot
, LHS_LockNotHeld
);
2883 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2884 ASSERT(!ThisFcb
->fMiniInited
);
2886 /* And free the object */
2887 RxFreeFcbObject(ThisFcb
);
2897 _Out_ PFOBX ThisFobx
,
2898 _In_ BOOLEAN RecursiveFinalize
,
2899 _In_ BOOLEAN ForceFinalize
)
2906 ASSERT(NodeType(ThisFobx
) == RDBSS_NTC_FOBX
);
2908 /* Only finalize if forced or if there's no ref left */
2909 if (ThisFobx
->NodeReferenceCount
!= 0 &&
2915 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx
, ThisFobx
->NodeReferenceCount
, ForceFinalize
);
2917 SrvOpen
= ThisFobx
->SrvOpen
;
2919 /* If it wasn't finalized yet, do it */
2920 if (!ThisFobx
->UpperFinalizationDone
)
2922 ASSERT(NodeType(SrvOpen
->Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
2923 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
2925 /* Remove it from the SRV_OPEN */
2926 RemoveEntryList(&ThisFobx
->FobxQLinks
);
2928 /* If we were used to browse a directory, free the query buffer */
2929 if (BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_FREE_UNICODE
))
2931 RxFreePoolWithTag(ThisFobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
2934 /* Notify the mini-rdr */
2935 if (Fcb
->MRxDispatch
!= NULL
&& Fcb
->MRxDispatch
->MRxDeallocateForFobx
!= NULL
)
2937 Fcb
->MRxDispatch
->MRxDeallocateForFobx((PMRX_FOBX
)ThisFobx
);
2940 /* If the SRV_OPEN wasn't closed yet, do it */
2941 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
2945 Status
= RxCloseAssociatedSrvOpen(ThisFobx
, FALSE
);
2946 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen
, ThisFobx
, Status
);
2949 /* Finalization done */
2950 ThisFobx
->UpperFinalizationDone
= TRUE
;
2953 /* If we're still referenced, don't go any further! */
2954 if (ThisFobx
->NodeReferenceCount
!= 0)
2959 /* At that point, everything should be closed */
2960 ASSERT(IsListEmpty(&ThisFobx
->ClosePendingList
));
2962 /* Was the FOBX allocated with another object?
2963 * If so, mark the buffer free in said object
2965 if (ThisFobx
== Fcb
->InternalFobx
)
2967 ClearFlag(Fcb
->FcbState
, FCB_STATE_FOBX_USED
);
2969 else if (ThisFobx
== SrvOpen
->InternalFobx
)
2971 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
);
2974 ThisFobx
->pSrvOpen
= NULL
;
2977 InterlockedDecrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
2979 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
2981 /* If it wasn't allocated with another object, free the FOBX */
2982 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_ENCLOSED_ALLOCATED
))
2984 RxFreeFcbObject(ThisFobx
);
2995 OUT PNET_ROOT ThisNetRoot
,
2996 IN BOOLEAN RecursiveFinalize
,
2997 IN BOOLEAN ForceFinalize
)
3000 PRX_FCB_TABLE FcbTable
;
3001 PRX_PREFIX_TABLE PrefixTable
;
3005 ASSERT(NodeType(ThisNetRoot
) == RDBSS_NTC_NETROOT
);
3007 PrefixTable
= ThisNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3008 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3010 /* If sme finalization is already ongoing, leave */
3011 if (BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
))
3016 /* Mark we're finalizing */
3017 SetFlag(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
);
3019 FcbTable
= &ThisNetRoot
->FcbTable
;
3020 /* Did caller asked us to finalize any associated FCB? */
3021 if (RecursiveFinalize
)
3025 /* Browse all the FCBs in our FCB table */
3026 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
3027 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
3029 PLIST_ENTRY HashBucket
, ListEntry
;
3031 HashBucket
= &FcbTable
->HashBuckets
[Bucket
];
3032 ListEntry
= HashBucket
->Flink
;
3033 while (ListEntry
!= HashBucket
)
3037 Fcb
= CONTAINING_RECORD(ListEntry
, FCB
, FcbTableEntry
.HashLinks
);
3038 ASSERT(NodeTypeIsFcb(Fcb
));
3040 ListEntry
= ListEntry
->Flink
;
3042 /* If the FCB isn't orphaned, then, it's time to purge it */
3043 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3047 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
3048 ASSERT(Status
== STATUS_SUCCESS
);
3053 RxReleaseFcbTableLock(FcbTable
);
3056 /* Only finalize if forced or if there's a single ref left */
3057 if (ThisNetRoot
->NodeReferenceCount
!= 1 && !ForceFinalize
)
3062 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot
, &ThisNetRoot
->PrefixEntry
.Prefix
);
3064 /* If we're still referenced, don't go any further! */
3065 if (ThisNetRoot
->NodeReferenceCount
!= 1)
3070 /* Finalize the FCB table (and make sure it's empty!) */
3071 RxFinalizeFcbTable(FcbTable
);
3073 /* If name wasn't remove already, do it now */
3074 if (!BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
3076 RxRemovePrefixTableEntry(PrefixTable
, &ThisNetRoot
->PrefixEntry
);
3079 /* Delete the object */
3080 SrvCall
= (PSRV_CALL
)ThisNetRoot
->pSrvCall
;
3081 RxFreeObject(ThisNetRoot
);
3083 /* And dereference the associated SRV_CALL */
3084 if (SrvCall
!= NULL
)
3086 RxDereferenceSrvCall(SrvCall
, LHS_ExclusiveLockHeld
);
3097 OUT PSRV_CALL ThisSrvCall
,
3098 IN BOOLEAN RecursiveFinalize
,
3099 IN BOOLEAN ForceFinalize
)
3101 PRX_PREFIX_TABLE PrefixTable
;
3105 ASSERT(NodeType(ThisSrvCall
) == RDBSS_NTC_SRVCALL
);
3107 PrefixTable
= ThisSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3108 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3110 /* Only finalize if forced or if there's a single ref left */
3111 if (ThisSrvCall
->NodeReferenceCount
!= 1 &&
3117 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall
, &ThisSrvCall
->PrefixEntry
.Prefix
);
3119 /* If it wasn't finalized yet, do it */
3120 if (!ThisSrvCall
->UpperFinalizationDone
)
3124 /* Remove ourselves from prefix table */
3125 RxRemovePrefixTableEntry(PrefixTable
, &ThisSrvCall
->PrefixEntry
);
3127 /* Remember our third arg, in case we get queued for later execution */
3130 SetFlag(ThisSrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
3134 ThisSrvCall
->UpperFinalizationDone
= TRUE
;
3136 /* Would defered execution free the object? */
3137 WillFree
= (ThisSrvCall
->NodeReferenceCount
== 1);
3139 /* If we have a device object */
3140 if (ThisSrvCall
->RxDeviceObject
!= NULL
)
3144 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3145 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3147 /* Extra ref, as usual */
3148 InterlockedIncrement((volatile long *)&ThisSrvCall
->NodeReferenceCount
);
3150 RxDispatchToWorkerThread(ThisSrvCall
->RxDeviceObject
, DelayedWorkQueue
, RxpDestroySrvCall
, ThisSrvCall
);
3152 /* Return to the caller, in advance, whether we're freeing the object or not */
3156 /* If in the right thread already, call the mini-rdr */
3157 MINIRDR_CALL_THROUGH(Status
, ThisSrvCall
->RxDeviceObject
->Dispatch
,
3158 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)ThisSrvCall
, ForceFinalize
));
3163 /* If we're still referenced, don't go any further! */
3164 if (ThisSrvCall
->NodeReferenceCount
!= 1)
3170 if (ThisSrvCall
->pDomainName
!= NULL
)
3172 RxFreePool(ThisSrvCall
->pDomainName
);
3176 RxTearDownBufferingManager(ThisSrvCall
);
3177 RxFreeObject(ThisSrvCall
);
3187 OUT PSRV_OPEN ThisSrvOpen
,
3188 IN BOOLEAN RecursiveFinalize
,
3189 IN BOOLEAN ForceFinalize
)
3195 /* We have to have a SRV_OPEN */
3196 ASSERT(NodeType(ThisSrvOpen
) == RDBSS_NTC_SRVOPEN
);
3198 /* If that's a recursive finalization, finalize any related FOBX */
3199 if (RecursiveFinalize
)
3201 PLIST_ENTRY ListEntry
;
3203 ListEntry
= ThisSrvOpen
->FobxList
.Flink
;
3204 while (ListEntry
!= &ThisSrvOpen
->FobxList
)
3208 Fobx
= CONTAINING_RECORD(ListEntry
, FOBX
, FobxQLinks
);
3209 ListEntry
= ListEntry
->Flink
;
3210 RxFinalizeNetFobx(Fobx
, TRUE
, ForceFinalize
);
3214 /* If we have still references, don't finalize unless forced */
3215 if (ThisSrvOpen
->NodeReferenceCount
!= 0 &&
3221 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen
, ThisSrvOpen
->NodeReferenceCount
, ForceFinalize
);
3223 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3224 Fcb
= (PFCB
)ThisSrvOpen
->pFcb
;
3225 if ((!ThisSrvOpen
->UpperFinalizationDone
&& ThisSrvOpen
->Condition
!= Condition_Good
) ||
3226 BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
3228 PV_NET_ROOT VNetRoot
;
3230 /* Associated FCB can't be fake one */
3231 ASSERT(NodeType(Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
3232 ASSERT(RxIsFcbAcquiredExclusive (Fcb
));
3234 /* Purge any pending operation */
3235 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen
);
3237 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3238 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3242 MINIRDR_CALL_THROUGH(Status
, Fcb
->MRxDispatch
, MRxForceClosed
, ((PMRX_SRV_OPEN
)ThisSrvOpen
));
3246 /* Remove ourselves from the FCB */
3247 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3248 InitializeListHead(&ThisSrvOpen
->SrvOpenQLinks
);
3249 ++Fcb
->SrvOpenListVersion
;
3251 /* If we have a V_NET_ROOT, dereference it */
3252 VNetRoot
= (PV_NET_ROOT
)ThisSrvOpen
->pVNetRoot
;
3253 if (VNetRoot
!= NULL
)
3255 InterlockedDecrement((volatile long *)&VNetRoot
->pNetRoot
->NumberOfSrvOpens
);
3256 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3257 ThisSrvOpen
->pVNetRoot
= NULL
;
3260 /* Finalization done */
3261 ThisSrvOpen
->UpperFinalizationDone
= TRUE
;
3264 /* Don't free memory if still referenced */
3265 if (ThisSrvOpen
->NodeReferenceCount
!= 0)
3270 /* No key association left */
3271 ASSERT(IsListEmpty(&ThisSrvOpen
->SrvOpenKeyList
));
3273 /* If we're still in some FCB, remove us */
3274 if (!IsListEmpty(&ThisSrvOpen
->SrvOpenQLinks
))
3276 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3279 /* If enclosed allocation, mark the memory zone free */
3280 if (BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
))
3282 ClearFlag(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
);
3284 /* Otherwise, free the memory */
3287 RxFreeFcbObject(ThisSrvOpen
);
3290 RxDereferenceNetFcb(Fcb
);
3300 OUT PV_NET_ROOT ThisVNetRoot
,
3301 IN BOOLEAN RecursiveFinalize
,
3302 IN BOOLEAN ForceFinalize
)
3305 PRX_PREFIX_TABLE PrefixTable
;
3309 ASSERT(NodeType(ThisVNetRoot
) == RDBSS_NTC_V_NETROOT
);
3311 PrefixTable
= ThisVNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3312 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3314 /* Only finalize if forced or if there's a single ref left */
3315 if (ThisVNetRoot
->NodeReferenceCount
!= 1 &&
3321 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot
, &ThisVNetRoot
->PrefixEntry
.Prefix
);
3323 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
3324 /* If it wasn't finalized yet, do it */
3325 if (!ThisVNetRoot
->UpperFinalizationDone
)
3327 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
3329 /* Reference the NetRoot so that it doesn't disappear */
3330 RxReferenceNetRoot(NetRoot
);
3331 RxOrphanSrvOpens(ThisVNetRoot
);
3332 /* Remove us from the available VNetRoot for NetRoot */
3333 RxRemoveVirtualNetRootFromNetRoot(NetRoot
, ThisVNetRoot
);
3334 /* Remove extra ref */
3335 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3337 /* Remove ourselves from prefix table */
3338 RxRemovePrefixTableEntry(PrefixTable
, &ThisVNetRoot
->PrefixEntry
);
3340 /* Finalization done */
3341 ThisVNetRoot
->UpperFinalizationDone
= TRUE
;
3344 /* If we're still referenced, don't go any further! */
3345 if (ThisVNetRoot
->NodeReferenceCount
!= 1)
3350 /* If there's an associated device, notify mini-rdr */
3351 if (NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
3355 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
3356 MRxFinalizeVNetRoot
, ((PMRX_V_NET_ROOT
)ThisVNetRoot
, FALSE
));
3360 /* Free parameters */
3361 RxUninitializeVNetRootParameters(ThisVNetRoot
->pUserName
, ThisVNetRoot
->pUserDomainName
,
3362 ThisVNetRoot
->pPassword
, &ThisVNetRoot
->Flags
);
3363 /* Dereference our NetRoot, we won't reference it anymore */
3364 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3366 /* And free the object! */
3367 RxFreePoolWithTag(ThisVNetRoot
, RX_V_NETROOT_POOLTAG
);
3373 RxFindOrConstructVirtualNetRoot(
3374 IN PRX_CONTEXT RxContext
,
3375 IN PUNICODE_STRING CanonicalName
,
3376 IN NET_ROOT_TYPE NetRootType
,
3377 IN PUNICODE_STRING RemainingName
)
3383 PV_NET_ROOT VNetRoot
;
3384 RX_CONNECTION_ID ConnectionID
;
3385 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3386 LOCK_HOLDING_STATE LockHoldingState
;
3390 RxDeviceObject
= RxContext
->RxDeviceObject
;
3391 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
3392 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
3394 /* Ask the mini-rdr for connection ID */
3395 ConnectionID
.SessionID
= 0;
3396 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
3398 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
3399 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
3401 /* mini-rdr is expected not to fail - unless it's not implemented */
3402 DPRINT1("Failed to initialize connection ID\n");
3407 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
3409 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
3410 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3411 LockHoldingState
= LHS_SharedLockHeld
;
3415 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3419 PV_NET_ROOT SavedVNetRoot
;
3421 /* Look in prefix table */
3422 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
3423 if (Container
!= NULL
)
3425 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3426 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
3428 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3429 RxDereferenceSrvCall(Container
, LockHoldingState
);
3433 VNetRoot
= Container
;
3434 NetRoot
= VNetRoot
->NetRoot
;
3436 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3437 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
3438 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3440 Status
= STATUS_BAD_NETWORK_PATH
;
3441 SavedVNetRoot
= NULL
;
3447 PUNICODE_STRING UserName
, UserDomain
, Password
;
3449 /* We can reuse if we use same credentials */
3450 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
3451 &SessionId
, &UserName
,
3452 &UserDomain
, &Password
,
3454 if (NT_SUCCESS(Status
))
3456 SavedVNetRoot
= VNetRoot
;
3457 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
3459 UserDomain
, Password
,
3461 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
3463 PLIST_ENTRY ListEntry
;
3465 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
3466 ListEntry
!= &NetRoot
->VirtualNetRoots
;
3467 ListEntry
= ListEntry
->Flink
)
3469 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
3470 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
3472 UserDomain
, Password
,
3474 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3480 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
3482 SavedVNetRoot
= NULL
;
3486 if (!NT_SUCCESS(Status
))
3488 SavedVNetRoot
= NULL
;
3491 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
3495 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3496 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
3498 if (SavedVNetRoot
== NULL
)
3500 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3503 /* Reference VNetRoot we'll keep, and dereference current */
3504 else if (SavedVNetRoot
!= VNetRoot
)
3506 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3507 if (SavedVNetRoot
!= NULL
)
3509 RxReferenceVNetRoot(SavedVNetRoot
);
3514 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3515 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3522 /* If we're locked exclusive, we won't loop again, it was the second pass */
3523 if (LockHoldingState
!= LHS_SharedLockHeld
)
3528 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3529 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
3531 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3532 LockHoldingState
= LHS_ExclusiveLockHeld
;
3536 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3537 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3538 LockHoldingState
= LHS_ExclusiveLockHeld
;
3541 /* We didn't fail, and didn't find any VNetRoot, construct one */
3544 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
3546 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
3547 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
3549 if (Status
== STATUS_SUCCESS
)
3551 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
3552 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3553 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
3555 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3556 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
3557 RemainingName
->MaximumLength
= RemainingName
->Length
;
3559 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
3561 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
3563 VNetRoot
->Flags
|= Flags
;
3567 /* Release the prefix table - caller expects it to be released */
3568 if (LockHoldingState
!= LHS_LockNotHeld
)
3570 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3573 /* If we failed creating, quit */
3574 if (Status
!= STATUS_SUCCESS
)
3576 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
3580 /* Otherwise, wait until the VNetRoot is stable */
3581 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
3582 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
3583 /* It's all good, update the RX_CONTEXT with all our structs */
3584 if (VNetRoot
->Condition
== Condition_Good
)
3588 NetRoot
= VNetRoot
->NetRoot
;
3589 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3590 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3591 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
3595 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3596 RxContext
->Create
.pVNetRoot
= NULL
;
3597 Status
= STATUS_BAD_NETWORK_PATH
;
3607 RxFindOrCreateConnections(
3608 _In_ PRX_CONTEXT RxContext
,
3609 _In_ PUNICODE_STRING CanonicalName
,
3610 _In_ NET_ROOT_TYPE NetRootType
,
3611 _Out_ PUNICODE_STRING LocalNetRootName
,
3612 _Out_ PUNICODE_STRING FilePathName
,
3613 _Inout_ PLOCK_HOLDING_STATE LockState
,
3614 _In_ PRX_CONNECTION_ID RxConnectionId
)
3619 PV_NET_ROOT VNetRoot
;
3620 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
3621 PRX_PREFIX_TABLE PrefixTable
;
3622 UNICODE_STRING RemainingName
, NetRootName
;
3626 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3627 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
3628 FilePathName
, LockState
, RxConnectionId
);
3630 *FilePathName
= *CanonicalName
;
3631 LocalNetRootName
->Length
= 0;
3632 LocalNetRootName
->MaximumLength
= 0;
3633 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
3635 /* UNC path, split it */
3636 if (FilePathName
->Buffer
[1] == ';')
3642 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
3644 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
3653 return STATUS_OBJECT_NAME_INVALID
;
3656 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
3657 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
3658 LocalNetRootName
->Length
= Length
;
3659 LocalNetRootName
->MaximumLength
= Length
;
3660 FilePathName
->Length
-= Length
;
3662 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
3663 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
3664 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
3668 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
3673 ASSERT(*LockState
!= LHS_LockNotHeld
);
3675 /* If previous lookup left something, dereference it */
3676 if (Container
!= NULL
)
3678 switch (NodeType(Container
))
3680 case RDBSS_NTC_SRVCALL
:
3681 RxDereferenceSrvCall(Container
, *LockState
);
3684 case RDBSS_NTC_NETROOT
:
3685 RxDereferenceNetRoot(Container
, *LockState
);
3688 case RDBSS_NTC_V_NETROOT
:
3689 RxDereferenceVNetRoot(Container
, *LockState
);
3693 /* Should never happen */
3699 /* Look for our NetRoot in prefix table */
3700 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
3701 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
3705 UNICODE_STRING SrvCallName
;
3711 /* Assume we didn't succeed */
3712 RxContext
->Create
.pVNetRoot
= NULL
;
3713 RxContext
->Create
.pNetRoot
= NULL
;
3714 RxContext
->Create
.pSrvCall
= NULL
;
3715 RxContext
->Create
.Type
= NetRootType
;
3717 /* If we found something */
3718 if (Container
!= NULL
)
3721 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
3723 VNetRoot
= Container
;
3724 /* Use its NetRoot */
3725 NetRoot
= VNetRoot
->NetRoot
;
3727 /* If it's not stable, wait for it to be stable */
3728 if (NetRoot
->Condition
== Condition_InTransition
)
3730 RxReleasePrefixTableLock(PrefixTable
);
3731 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
3732 RxWaitForStableNetRoot(NetRoot
, RxContext
);
3733 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3734 *LockState
= LHS_ExclusiveLockHeld
;
3736 /* Now that's it's ok, retry lookup to find what we want */
3737 if (NetRoot
->Condition
== Condition_Good
)
3743 /* Is the associated netroot good? */
3744 if (NetRoot
->Condition
== Condition_Good
)
3746 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
3748 /* If it is, and SrvCall as well, then, we have our active connection */
3749 if (SrvCall
->Condition
== Condition_Good
&&
3750 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
3752 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3753 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3754 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3756 Status
= STATUS_CONNECTION_ACTIVE
;
3761 /* If VNetRoot was well constructed, it means the connection is active */
3762 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
3764 Status
= STATUS_CONNECTION_ACTIVE
;
3768 Status
= VNetRoot
->ConstructionStatus
;
3771 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3774 /* Can only be a SrvCall */
3777 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3778 SrvCall
= Container
;
3780 /* Wait for the SRV_CALL to be stable */
3781 if (SrvCall
->Condition
== Condition_InTransition
)
3783 RxReleasePrefixTableLock(PrefixTable
);
3784 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
3785 RxWaitForStableSrvCall(SrvCall
, RxContext
);
3786 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3787 *LockState
= LHS_ExclusiveLockHeld
;
3789 /* It went good, loop again to find what we look for */
3790 if (SrvCall
->Condition
== Condition_Good
)
3796 /* If it's not good... */
3797 if (SrvCall
->Condition
!= Condition_Good
)
3799 /* But SRV_CALL was well constructed, assume a connection was active */
3800 if (SrvCall
->Status
== STATUS_SUCCESS
)
3802 Status
= STATUS_CONNECTION_ACTIVE
;
3806 Status
= SrvCall
->Status
;
3809 RxDereferenceSrvCall(SrvCall
, *LockState
);
3815 /* If we found a SRV_CALL not matching our DO, quit */
3816 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
3817 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3819 RxDereferenceSrvCall(SrvCall
, *LockState
);
3820 Status
= STATUS_BAD_NETWORK_NAME
;
3824 /* Now, we want exclusive lock */
3825 if (*LockState
== LHS_SharedLockHeld
)
3827 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
3829 RxReleasePrefixTableLock(PrefixTable
);
3830 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3831 *LockState
= LHS_ExclusiveLockHeld
;
3835 RxReleasePrefixTableLock(PrefixTable
);
3836 *LockState
= LHS_ExclusiveLockHeld
;
3839 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3841 /* If we reach that point, we found something, no need to create something */
3842 if (Container
!= NULL
)
3847 /* Get the name for the SRV_CALL */
3848 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
3849 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
3850 /* And create the SRV_CALL */
3851 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
3852 if (SrvCall
== NULL
)
3854 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3858 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3859 RxReferenceSrvCall(SrvCall
);
3860 RxContext
->Create
.pVNetRoot
= NULL
;
3861 RxContext
->Create
.pNetRoot
= NULL
;
3862 RxContext
->Create
.pSrvCall
= NULL
;
3863 RxContext
->Create
.Type
= NetRootType
;
3864 Container
= SrvCall
;
3866 /* Construct SRV_CALL, ie, use mini-rdr */
3867 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
3868 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
3869 if (Status
!= STATUS_SUCCESS
)
3871 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
3872 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3873 RxDereferenceSrvCall(SrvCall
, *LockState
);
3874 RxReleasePrefixTableLock(PrefixTable
);
3878 /* Loop again to make use of SRV_CALL stable condition wait */
3881 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3882 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
3883 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
3884 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
3886 /* Call mini-rdr to get NetRoot name */
3887 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
3888 /* And create the NetRoot with that name */
3889 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
3890 if (NetRoot
== NULL
)
3892 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3895 NetRoot
->Type
= NetRootType
;
3897 RxDereferenceSrvCall(SrvCall
, *LockState
);
3899 /* Finally, create the associated VNetRoot */
3900 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
3901 if (VNetRoot
== NULL
)
3903 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
3904 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3907 RxReferenceVNetRoot(VNetRoot
);
3909 /* We're get closer! */
3910 NetRoot
->Condition
= Condition_InTransition
;
3911 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3912 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3913 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3915 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3916 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
3917 if (!NT_SUCCESS(Status
))
3919 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
3920 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
3921 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3923 RxContext
->Create
.pNetRoot
= NULL
;
3924 RxContext
->Create
.pVNetRoot
= NULL
;
3928 PIO_STACK_LOCATION Stack
;
3930 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3932 Stack
= RxContext
->CurrentIrpSp
;
3933 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
3935 RxExclusivePrefixTableLockToShared(PrefixTable
);
3936 *LockState
= LHS_SharedLockHeld
;
3942 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
3944 if (*LockState
!= LHS_LockNotHeld
)
3946 RxReleasePrefixTableLock(PrefixTable
);
3947 *LockState
= LHS_LockNotHeld
;
3953 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
3962 RxFinishFcbInitialization(
3963 IN OUT PMRX_FCB Fcb
,
3964 IN RX_FILE_TYPE FileType
,
3965 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
3967 RX_FILE_TYPE OldType
;
3971 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
3973 OldType
= NodeType(Fcb
);
3974 NodeType(Fcb
) = FileType
;
3975 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
3976 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
3978 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3980 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
3981 else if (InitPacket
!= NULL
)
3983 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
3984 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
3985 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
3986 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
3987 InitPacket
->pValidDataLength
->QuadPart
);
3990 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3991 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3993 /* If our FCB newly points to a file, initiliaze everything related */
3994 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
)
3997 if (OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
3999 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
4000 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, RxLockOperationCompletion
,
4003 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
4004 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
4006 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
4009 /* If not a file, validate type */
4012 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
4021 RxFinishSrvCallConstruction(
4022 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
4026 PRX_CONTEXT Context
;
4027 RX_BLOCK_CONDITION Condition
;
4028 PRX_PREFIX_TABLE PrefixTable
;
4030 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
4032 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
4033 Context
= Calldown
->RxContext
;
4034 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
4036 /* We have a winner, notify him */
4037 if (Calldown
->BestFinisher
!= NULL
)
4039 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
4041 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
4043 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
4044 MRxSrvCallWinnerNotify
,
4045 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
4046 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
4047 if (Status
!= STATUS_SUCCESS
)
4049 Condition
= Condition_Bad
;
4053 Condition
= Condition_Good
;
4056 /* Otherwise, just fail our SRV_CALL */
4059 Status
= Calldown
->CallbackContexts
[0].Status
;
4060 Condition
= Condition_Bad
;
4063 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
4064 RxTransitionSrvCall(SrvCall
, Condition
);
4065 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
4067 /* If async, finish it here, otherwise, caller has already finished the stuff */
4068 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
4070 DPRINT("Finishing async call\n");
4072 RxReleasePrefixTableLock(PrefixTable
);
4074 /* Make sure we weren't cancelled in-between */
4075 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
4077 Status
= STATUS_CANCELLED
;
4080 /* In case that was a create, context can be reused */
4081 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
4083 RxpPrepareCreateContextForReuse(Context
);
4086 /* If that's a failure, reset everything and return failure */
4087 if (Status
!= STATUS_SUCCESS
)
4089 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
4090 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4092 if (Context
->Info
.Buffer
!= NULL
)
4094 RxFreePool(Context
->Info
.Buffer
);
4095 Context
->Info
.Buffer
= NULL
;
4098 Context
->CurrentIrp
->IoStatus
.Information
= 0;
4099 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
4100 RxCompleteRequest(Context
, Status
);
4102 /* Otherwise, call resume routine and done! */
4105 Status
= Context
->ResumeRoutine(Context
);
4106 if (Status
!= STATUS_PENDING
)
4108 RxCompleteRequest(Context
, Status
);
4111 DPRINT("Not completing, pending\n");
4115 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
4124 RxFinishSrvCallConstructionDispatcher(
4128 BOOLEAN Direct
, KeepLoop
;
4130 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
4132 /* In case of failure of starting dispatcher, context is not set
4133 * We keep track of it to fail associated SRV_CALL
4135 Direct
= (Context
== NULL
);
4137 /* Separated thread, loop forever */
4140 PLIST_ENTRY ListEntry
;
4141 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
4143 /* If there are no SRV_CALL to finalize left, just finish thread */
4144 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
4145 if (IsListEmpty(&RxSrvCalldownList
))
4148 RxSrvCallConstructionDispatcherActive
= FALSE
;
4150 /* Otherwise, get the SRV_CALL to finish construction */
4153 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
4156 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
4164 /* If direct is set, reset the finisher to avoid electing a winner
4165 * and fail SRV_CALL (see upper comment)
4167 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
4170 Calldown
->BestFinisher
= NULL
;
4172 /* Finish SRV_CALL construction */
4173 RxFinishSrvCallConstruction(Calldown
);
4181 RxFlushFcbInSystemCache(
4183 IN BOOLEAN SynchronizeWithLazyWriter
)
4185 IO_STATUS_BLOCK IoStatus
;
4190 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &IoStatus
);
4191 /* If we're asked to sync with LW, do it in case of success */
4192 if (SynchronizeWithLazyWriter
&& NT_SUCCESS(IoStatus
.Status
))
4194 RxAcquirePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4195 RxReleasePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4198 DPRINT("Flushing for FCB %p returns %lx\n", Fcb
, IoStatus
.Status
);
4199 return IoStatus
.Status
;
4211 DPRINT("Freeing %p\n", Object
);
4213 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4214 if (NodeType(Object
) == RDBSS_NTC_FOBX
|| NodeType(Object
) == RDBSS_NTC_SRVOPEN
)
4216 RxFreePoolWithTag(Object
, RX_FCB_POOLTAG
);
4218 /* If that's a FCB... */
4219 else if (NodeTypeIsFcb(Object
))
4222 PRDBSS_DEVICE_OBJECT DeviceObject
;
4225 DeviceObject
= Fcb
->RxDeviceObject
;
4227 /* Delete per stream contexts */
4228 FsRtlTeardownPerStreamContexts(&Fcb
->Header
);
4230 SetFlag(Fcb
->Header
.Flags
, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH
);
4232 /* If there was a non-paged FCB allocated, free it */
4233 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
4235 RxFreePoolWithTag(Fcb
->NonPaged
, RX_NONPAGEDFCB_POOLTAG
);
4241 /* Update statistics */
4242 InterlockedDecrement(&RxNumberOfActiveFcbs
);
4243 InterlockedDecrement((volatile long *)&DeviceObject
->NumberOfActiveFcbs
);
4256 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4257 if (NodeType(pObject
) == RDBSS_NTC_SRVCALL
)
4260 PRDBSS_DEVICE_OBJECT DeviceObject
;
4262 SrvCall
= (PSRV_CALL
)pObject
;
4263 DeviceObject
= SrvCall
->RxDeviceObject
;
4264 if (DeviceObject
!= NULL
)
4266 if (!BooleanFlagOn(DeviceObject
->Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
4268 ASSERT(SrvCall
->Context
== NULL
);
4271 ASSERT(SrvCall
->Context2
== NULL
);
4273 SrvCall
->RxDeviceObject
= NULL
;
4276 else if (NodeType(pObject
) == RDBSS_NTC_NETROOT
)
4280 NetRoot
= (PNET_ROOT
)pObject
;
4281 NetRoot
->pSrvCall
= NULL
;
4282 NetRoot
->NodeTypeCode
= NodeType(pObject
) | 0xF000;
4285 /* And just free the object */
4286 RxFreePool(pObject
);
4293 RxGatherRequestsForSrvOpen(
4294 IN OUT PSRV_CALL SrvCall
,
4295 IN PSRV_OPEN SrvOpen
,
4296 IN OUT PLIST_ENTRY RequestsListHead
)
4299 LIST_ENTRY Discarded
, *Entry
;
4300 PCHANGE_BUFFERING_STATE_REQUEST Request
;
4302 /* Dispatch any pending operation first */
4303 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &Discarded
);
4305 /* Then, get any entry related to our key and SRV_OPEN */
4306 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
4307 Entry
= SrvCall
->BufferingManager
.HandlerList
.Flink
;
4308 while (Entry
!= &SrvCall
->BufferingManager
.HandlerList
)
4310 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4311 Entry
= Entry
->Flink
;
4312 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4314 RemoveEntryList(&Request
->ListEntry
);
4315 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4318 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
4320 /* Perform the same search in the last change list */
4321 Entry
= SrvCall
->BufferingManager
.LastChanceHandlerList
.Flink
;
4322 while (Entry
!= &SrvCall
->BufferingManager
.LastChanceHandlerList
)
4324 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4325 Entry
= Entry
->Flink
;
4326 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4328 RemoveEntryList(&Request
->ListEntry
);
4329 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4333 /* Discard the discarded requests */
4334 RxpDiscardChangeBufferingStateRequests(&Discarded
);
4340 PRDBSS_DEVICE_OBJECT
4341 RxGetDeviceObjectOfInstance(
4344 NODE_TYPE_CODE NodeType
;
4345 PRDBSS_DEVICE_OBJECT DeviceObject
;
4349 /* We only handle a few object types */
4350 NodeType
= NodeType(Instance
);
4351 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
4352 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) || (NodeType
== RDBSS_NTC_FOBX
));
4354 /* Get the device object depending on the object */
4357 case RDBSS_NTC_FOBX
:
4361 Fobx
= (PFOBX
)Instance
;
4362 DeviceObject
= Fobx
->RxDeviceObject
;
4366 case RDBSS_NTC_SRVCALL
:
4370 SrvCall
= (PSRV_CALL
)Instance
;
4371 DeviceObject
= SrvCall
->RxDeviceObject
;
4375 case RDBSS_NTC_NETROOT
:
4379 NetRoot
= (PNET_ROOT
)Instance
;
4380 DeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
4384 case RDBSS_NTC_V_NETROOT
:
4386 PV_NET_ROOT VNetRoot
;
4388 VNetRoot
= (PV_NET_ROOT
)Instance
;
4389 DeviceObject
= VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
;
4393 case RDBSS_NTC_SRVOPEN
:
4397 SrvOpen
= (PSRV_OPEN
)Instance
;
4398 DeviceObject
= ((PFCB
)SrvOpen
->pFcb
)->RxDeviceObject
;
4403 DeviceObject
= NULL
;
4408 return DeviceObject
;
4415 RxGetFileSizeWithLock(
4417 OUT PLONGLONG FileSize
)
4421 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
4432 return RxData
.OurProcess
;
4439 RxInitializeBufferingManager(
4442 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
4443 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
4444 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
4445 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
4446 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
4447 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
4448 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
4449 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
4450 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
4451 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
4453 return STATUS_SUCCESS
;
4461 RxInitializeContext(
4463 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
4464 IN ULONG InitialContextFlags
,
4465 IN OUT PRX_CONTEXT RxContext
)
4467 PIO_STACK_LOCATION Stack
;
4469 /* Initialize our various fields */
4470 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
4471 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
4472 RxContext
->ReferenceCount
= 1;
4473 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
4474 RxContext
->RxDeviceObject
= RxDeviceObject
;
4475 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
4476 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
4477 InitializeListHead(&RxContext
->BlockedOperations
);
4478 RxContext
->MRxCancelRoutine
= NULL
;
4479 RxContext
->ResumeRoutine
= NULL
;
4480 RxContext
->Flags
|= InitialContextFlags
;
4481 RxContext
->CurrentIrp
= Irp
;
4482 RxContext
->LastExecutionThread
= PsGetCurrentThread();
4483 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
4485 /* If've got no IRP, mark RX_CONTEXT */
4488 RxContext
->CurrentIrpSp
= NULL
;
4489 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
4490 RxContext
->MinorFunction
= 0;
4494 /* Otherwise, first determine whether we are performing async operation */
4495 Stack
= IoGetCurrentIrpStackLocation(Irp
);
4496 if (Stack
->FileObject
!= NULL
)
4500 Fcb
= Stack
->FileObject
->FsContext
;
4501 if (!IoIsOperationSynchronous(Irp
) ||
4502 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
4503 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
4504 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
4506 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4510 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
4512 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4514 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4516 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4519 /* Set proper flags if TopLevl IRP/Device */
4520 if (!RxIsThisTheTopLevelIrp(Irp
))
4522 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
4524 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
4526 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
4529 /* Copy stack information */
4530 RxContext
->MajorFunction
= Stack
->MajorFunction
;
4531 RxContext
->MinorFunction
= Stack
->MinorFunction
;
4532 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
4533 RxContext
->CurrentIrpSp
= Stack
;
4535 /* If we have a FO associated, learn for more */
4536 if (Stack
->FileObject
!= NULL
)
4541 /* Get the FCB and CCB (FOBX) */
4542 Fcb
= Stack
->FileObject
->FsContext
;
4543 Fobx
= Stack
->FileObject
->FsContext2
;
4544 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
4545 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
4547 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
4550 /* We have a FOBX, this not a DFS opening, keep track of it */
4551 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
4553 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
4554 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
4555 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4557 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
4562 RxContext
->pFobx
= NULL
;
4565 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4566 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
4569 PV_NET_ROOT VNetRoot
= NULL
;
4571 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4573 VNetRoot
= Fcb
->VNetRoot
;
4575 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
4577 VNetRoot
= (PV_NET_ROOT
)Fobx
;
4580 if (VNetRoot
!= NULL
)
4582 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
4586 /* Remember if that's a write through file */
4587 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
4588 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
4590 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
4595 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
4597 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4598 RxContext
, RxContext
->MinorFunction
, Irp
,
4599 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
4600 RxContext
->SerialNumber
);
4609 RxInitializeDispatcher(
4613 HANDLE ThreadHandle
;
4617 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4618 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4620 /* Set appropriate timeouts: 10s & 60s */
4621 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4622 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4623 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4624 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
4626 RxDispatcher
.NumberOfProcessors
= 1;
4627 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
4628 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
4630 /* Initialize our dispatchers */
4631 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
4632 if (!NT_SUCCESS(Status
))
4637 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
4638 if (!NT_SUCCESS(Status
))
4643 /* And start them */
4644 RxDispatcher
.State
= RxDispatcherActive
;
4645 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
4646 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
4647 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
4648 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
4649 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
4650 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
4651 if (NT_SUCCESS(Status
))
4653 ZwClose(ThreadHandle
);
4663 RxInitializeFcbTable(
4664 IN OUT PRX_FCB_TABLE FcbTable
,
4665 IN BOOLEAN CaseInsensitiveMatch
)
4671 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
4672 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
4674 ExInitializeResourceLite(&FcbTable
->TableLock
);
4675 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4676 FcbTable
->Version
= 0;
4677 FcbTable
->TableEntryForNull
= NULL
;
4679 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
4680 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
4682 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
4685 FcbTable
->Lookups
= 0;
4686 FcbTable
->FailedLookups
= 0;
4687 FcbTable
->Compares
= 0;
4695 RxInitializeLowIoContext(
4696 OUT PLOWIO_CONTEXT LowIoContext
,
4699 PRX_CONTEXT RxContext
;
4700 PIO_STACK_LOCATION Stack
;
4704 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
4705 ASSERT(LowIoContext
== &RxContext
->LowIoContext
);
4707 Stack
= RxContext
->CurrentIrpSp
;
4709 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
4710 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
4711 RxContext
->LowIoContext
.Operation
= Operation
;
4716 case LOWIO_OP_WRITE
:
4717 /* In case of RW, set a canary, to make sure these fields are properly set
4718 * they will be asserted when lowio request will be submit to mini-rdr
4721 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
4722 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
4723 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
4725 /* Keep track of paging IOs */
4726 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
4728 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
4732 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
4737 case LOWIO_OP_FSCTL
:
4738 case LOWIO_OP_IOCTL
:
4739 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4740 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
4741 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
4742 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
4743 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
4744 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
4745 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
4748 /* Nothing to do for these */
4749 case LOWIO_OP_SHAREDLOCK
:
4750 case LOWIO_OP_EXCLUSIVELOCK
:
4751 case LOWIO_OP_UNLOCK
:
4752 case LOWIO_OP_UNLOCK_MULTIPLE
:
4753 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4754 case LOWIO_OP_CLEAROUT
:
4758 /* Should never happen */
4768 RxInitializeLowIoPerFcbInfo(
4769 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
4773 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
4774 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
4781 RxInitializeMRxDispatcher(
4782 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
4786 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4787 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4789 return STATUS_SUCCESS
;
4796 RxInitializePrefixTable(
4797 IN OUT PRX_PREFIX_TABLE ThisTable
,
4798 IN ULONG TableSize OPTIONAL
,
4799 IN BOOLEAN CaseInsensitiveMatch
)
4805 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
4808 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
4809 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
4810 InitializeListHead(&ThisTable
->MemberQueue
);
4811 ThisTable
->Version
= 0;
4812 ThisTable
->TableEntryForNull
= NULL
;
4813 ThisTable
->IsNetNameTable
= FALSE
;
4814 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4815 ThisTable
->TableSize
= TableSize
;
4821 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
4823 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
4832 RxInitializePurgeSyncronizationContext(
4833 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
4837 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
4838 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
4842 RxInitializeSrvCallParameters(
4843 IN PRX_CONTEXT RxContext
,
4844 IN OUT PSRV_CALL SrvCall
)
4848 SrvCall
->pPrincipalName
= NULL
;
4850 /* We only have stuff to initialize for file opening from DFS */
4851 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
4853 return STATUS_SUCCESS
;
4856 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
4859 return STATUS_NOT_IMPLEMENTED
;
4867 RxInitializeRxTimer(
4872 RxTimerInterval
.QuadPart
= -550000;
4873 KeInitializeSpinLock(&RxTimerLock
);
4874 InitializeListHead(&RxTimerQueueHead
);
4875 InitializeListHead(&RxRecurrentWorkItemsList
);
4876 KeInitializeDpc(&RxTimerDpc
, RxTimerDispatch
, NULL
);
4877 KeInitializeTimer(&RxTimer
);
4878 RxTimerTickCount
= 0;
4880 return STATUS_SUCCESS
;
4884 RxInitializeVNetRootParameters(
4885 PRX_CONTEXT RxContext
,
4887 OUT PULONG SessionId
,
4888 OUT PUNICODE_STRING
*UserNamePtr
,
4889 OUT PUNICODE_STRING
*UserDomainNamePtr
,
4890 OUT PUNICODE_STRING
*PasswordPtr
,
4894 PACCESS_TOKEN Token
;
4898 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
4899 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
4901 *UserNamePtr
= NULL
;
4902 *UserDomainNamePtr
= NULL
;
4903 *PasswordPtr
= NULL
;
4904 /* By default, that's not CSC instance */
4905 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4907 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
4908 if (SeTokenIsRestricted(Token
))
4910 return STATUS_ACCESS_DENIED
;
4914 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
4915 if (!NT_SUCCESS(Status
))
4921 Status
= SeQuerySessionIdToken(Token
, SessionId
);
4922 if (!NT_SUCCESS(Status
))
4927 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
4930 Status
= STATUS_NOT_IMPLEMENTED
;
4934 /* Deal with connection credentials */
4935 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
4938 Status
= STATUS_NOT_IMPLEMENTED
;
4942 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
4945 Status
= STATUS_NOT_IMPLEMENTED
;
4950 if (NT_SUCCESS(Status
))
4952 /* If that's a CSC instance, mark it as such */
4953 if (RxIsThisACscAgentOpen(RxContext
))
4955 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4967 RxInitializeWorkQueue(
4968 PRX_WORK_QUEUE WorkQueue
,
4969 WORK_QUEUE_TYPE WorkQueueType
,
4970 ULONG MaximumNumberOfWorkerThreads
,
4971 ULONG MinimumNumberOfWorkerThreads
)
4975 WorkQueue
->Type
= WorkQueueType
;
4976 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
4977 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
4979 WorkQueue
->State
= RxWorkQueueActive
;
4980 WorkQueue
->SpinUpRequestPending
= FALSE
;
4981 WorkQueue
->pRundownContext
= NULL
;
4982 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
4983 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
4984 WorkQueue
->CumulativeQueueLength
= 0;
4985 WorkQueue
->NumberOfSpinUpRequests
= 0;
4986 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
4987 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
4988 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
4989 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
4990 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
4991 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
4992 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
4993 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
4994 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
4995 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
4996 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
4997 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
4998 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
4999 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
5000 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
5001 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
5003 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
5004 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
5011 RxInitializeWorkQueueDispatcher(
5012 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
5015 ULONG MaximumNumberOfWorkerThreads
;
5019 /* Number of threads will depend on system capacity */
5020 if (MmQuerySystemSize() != MmLargeSystem
)
5022 MaximumNumberOfWorkerThreads
= 5;
5026 MaximumNumberOfWorkerThreads
= 10;
5029 /* Initialize the work queues */
5030 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
5031 MaximumNumberOfWorkerThreads
, 1);
5032 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
5033 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
5035 /* And start the worker threads */
5036 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
5037 RxBootstrapWorkerThreadDispatcher
,
5038 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
5039 if (!NT_SUCCESS(Status
))
5044 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
5045 RxBootstrapWorkerThreadDispatcher
,
5046 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
5047 if (!NT_SUCCESS(Status
))
5052 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
5053 RxBootstrapWorkerThreadDispatcher
,
5054 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
5062 RxInitiateSrvOpenKeyAssociation(
5063 IN OUT PSRV_OPEN SrvOpen
)
5065 PRX_BUFFERING_MANAGER BufferingManager
;
5069 SrvOpen
->Key
= NULL
;
5071 /* Just keep track of the opening request */
5072 BufferingManager
= &((PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
;
5073 InterlockedIncrement(&BufferingManager
->NumberOfOutstandingOpens
);
5075 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
5082 RxInsertWorkQueueItem(
5083 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
5084 WORK_QUEUE_TYPE WorkQueueType
,
5085 PRX_WORK_QUEUE_ITEM WorkQueueItem
)
5089 BOOLEAN SpinUpThreads
;
5090 PRX_WORK_QUEUE WorkQueue
;
5092 /* No dispatcher, nothing to insert */
5093 if (RxDispatcher
.State
!= RxDispatcherActive
)
5095 return STATUS_UNSUCCESSFUL
;
5098 /* Get the work queue */
5099 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
5101 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
5102 /* Only insert if the work queue is in decent state */
5103 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
5105 Status
= STATUS_UNSUCCESSFUL
;
5109 SpinUpThreads
= FALSE
;
5110 WorkQueueItem
->pDeviceObject
= pMRxDeviceObject
;
5111 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
5112 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
5113 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
5115 /* If required (and possible!), spin up a new worker thread */
5116 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
5117 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
5118 !WorkQueue
->SpinUpRequestPending
)
5120 WorkQueue
->SpinUpRequestPending
= TRUE
;
5121 SpinUpThreads
= TRUE
;
5124 Status
= STATUS_SUCCESS
;
5126 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5128 /* If we failed, return and still not insert item */
5129 if (!NT_SUCCESS(Status
))
5134 /* All fine, insert the item */
5135 KeInsertQueue(&WorkQueue
->Queue
, &WorkQueueItem
->List
);
5137 /* And start a new worker thread if needed */
5140 RxSpinUpWorkerThreads(WorkQueue
);
5147 RxIsThisACscAgentOpen(
5148 IN PRX_CONTEXT RxContext
)
5154 /* Client Side Caching is DFS stuff - we don't support it */
5155 if (RxContext
->Create
.EaLength
!= 0)
5160 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
5161 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
5171 IN PRX_CONTEXT RxContext
,
5172 IN LOCK_OPERATION Operation
,
5173 IN ULONG BufferLength
)
5182 Irp
= RxContext
->CurrentIrp
;
5183 /* If we already have a MDL, make sure it's locked */
5184 if (Irp
->MdlAddress
!= NULL
)
5186 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
5190 /* That likely means the driver asks for buffered IOs - we don't support it! */
5191 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
5193 /* If we have a real length */
5194 if (BufferLength
> 0)
5196 /* Allocate a MDL and lock it */
5197 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
5200 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
5201 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
5204 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
5208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5212 Status
= _SEH2_GetExceptionCode();
5214 /* Free the possible MDL we have allocated */
5216 Irp
->MdlAddress
= NULL
;
5218 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
5221 if (!FsRtlIsNtstatusExpected(Status
))
5223 Status
= STATUS_INVALID_USER_BUFFER
;
5226 RxContext
->IoStatusBlock
.Status
= Status
;
5227 ExRaiseStatus(Status
);
5236 RxLowIoCompletionTail(
5237 IN PRX_CONTEXT RxContext
)
5244 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
5246 /* Only continue if we're at APC_LEVEL or lower */
5247 if (RxShouldPostCompletion() &&
5248 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
5250 return STATUS_MORE_PROCESSING_REQUIRED
;
5253 /* Call the completion routine */
5254 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
5255 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
5256 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
5261 /* If it was a RW operation, for a paging file ... */
5262 Operation
= RxContext
->LowIoContext
.Operation
;
5263 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
5265 /* Remove ourselves from the list and resume operations */
5266 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5268 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5269 RemoveEntryList(&RxContext
->RxContextSerializationQLinks
);
5270 RxContext
->RxContextSerializationQLinks
.Flink
= NULL
;
5271 RxContext
->RxContextSerializationQLinks
.Blink
= NULL
;
5272 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5273 RxResumeBlockedOperations_ALL(RxContext
);
5278 /* Sanity check: we had known operation */
5279 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
5282 /* If not sync operation, complete now. Otherwise, caller has already completed */
5283 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
5285 RxCompleteRequest(RxContext
, Status
);
5288 DPRINT("Status: %x\n", Status
);
5297 RxLowIoPopulateFsctlInfo(
5298 IN PRX_CONTEXT RxContext
)
5303 PIO_STACK_LOCATION Stack
;
5307 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
5309 Irp
= RxContext
->CurrentIrp
;
5310 Stack
= RxContext
->CurrentIrpSp
;
5312 /* Copy stack parameters */
5313 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
5314 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
5315 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
5316 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
5317 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
5319 /* Same buffer in case of buffered */
5320 if (Method
== METHOD_BUFFERED
)
5322 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5323 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5325 return STATUS_SUCCESS
;
5328 /* Two buffers for neither */
5329 if (Method
== METHOD_NEITHER
)
5331 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
5332 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
5334 return STATUS_SUCCESS
;
5337 /* Only IN/OUT remain */
5338 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
5340 /* Use system buffer for input */
5341 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5342 /* And MDL for output */
5343 Mdl
= Irp
->MdlAddress
;
5346 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
5347 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
5349 return STATUS_INSUFFICIENT_RESOURCES
;
5354 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
5357 return STATUS_SUCCESS
;
5363 IN PRX_CONTEXT RxContext
,
5364 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
5368 BOOLEAN Synchronous
;
5369 PLOWIO_CONTEXT LowIoContext
;
5371 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
5375 LowIoContext
= &RxContext
->LowIoContext
;
5376 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
5378 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
5380 Status
= STATUS_SUCCESS
;
5381 Operation
= LowIoContext
->Operation
;
5385 case LOWIO_OP_WRITE
:
5386 /* Check that the parameters were properly set by caller
5387 * See comment in RxInitializeLowIoContext()
5389 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
5390 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
5392 /* Lock the buffer */
5393 RxLockUserBuffer(RxContext
,
5394 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
5395 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
5396 if (RxNewMapUserBuffer(RxContext
) == NULL
)
5398 return STATUS_INSUFFICIENT_RESOURCES
;
5400 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
5402 /* If that's a paging IO, initialize serial operation */
5403 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5407 Fcb
= (PFCB
)RxContext
->pFcb
;
5409 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5410 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
5411 if (Operation
== LOWIO_OP_READ
)
5413 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5417 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5420 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5425 case LOWIO_OP_FSCTL
:
5426 case LOWIO_OP_IOCTL
:
5427 /* Set FSCTL/IOCTL parameters */
5428 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
5429 /* Check whether we're consistent: a length means a buffer */
5430 if (NT_SUCCESS(Status
))
5432 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
5433 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
5434 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
5435 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
5437 Status
= STATUS_INVALID_PARAMETER
;
5443 case LOWIO_OP_SHAREDLOCK
:
5444 case LOWIO_OP_EXCLUSIVELOCK
:
5445 case LOWIO_OP_UNLOCK
:
5446 case LOWIO_OP_UNLOCK_MULTIPLE
:
5447 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
5448 case LOWIO_OP_CLEAROUT
:
5453 Status
= STATUS_INVALID_PARAMETER
;
5457 /* No need to perform extra init in case of posting */
5458 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
5460 /* Preflight checks were OK, time to submit */
5461 if (NT_SUCCESS(Status
))
5463 PMINIRDR_DISPATCH Dispatch
;
5467 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
5468 /* If not synchronous, we're likely to return before the operation is finished */
5469 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5471 IoMarkIrpPending(RxContext
->CurrentIrp
);
5475 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
5476 if (Dispatch
!= NULL
)
5478 /* We'll try to execute until the mini-rdr doesn't return pending */
5481 RxContext
->IoStatusBlock
.Information
= 0;
5483 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
5484 if (Status
== STATUS_PENDING
)
5486 /* Unless it's not synchronous, caller will be happy with pending op */
5492 RxWaitSync(RxContext
);
5493 Status
= RxContext
->IoStatusBlock
.Status
;
5499 /* We had marked the IRP pending, whereas the operation finished, drop that */
5500 if (Status
!= STATUS_RETRY
)
5502 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5504 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
5507 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
5511 } while (Status
== STATUS_PENDING
);
5515 Status
= STATUS_INVALID_PARAMETER
;
5519 /* Call completion and return */
5520 RxContext
->IoStatusBlock
.Status
= Status
;
5521 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
5522 return RxLowIoCompletionTail(RxContext
);
5530 IN PRX_CONTEXT RxContext
)
5536 Irp
= RxContext
->CurrentIrp
;
5537 /* We should have a MDL (buffered IOs are not supported!) */
5538 if (Irp
->MdlAddress
!= NULL
)
5541 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5544 /* Just return system buffer */
5545 return Irp
->AssociatedIrp
.SystemBuffer
;
5552 RxMarkFobxOnCleanup(
5557 PFOBX ScavengerFobx
;
5558 LARGE_INTEGER TickCount
;
5559 PRDBSS_SCAVENGER Scavenger
;
5563 /* No FOBX, nothing to mark */
5569 /* Query time for close */
5570 KeQueryTickCount(&TickCount
);
5572 Fcb
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
5573 ASSERT(NodeTypeIsFcb(Fcb
));
5575 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5576 RxAcquireScavengerMutex();
5578 ScavengerFobx
= NULL
;
5579 /* If that's not a file, or even not a disk resource, just mark as dormant */
5580 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
|| Fcb
->VNetRoot
->pNetRoot
->DeviceType
!= FILE_DEVICE_DISK
)
5582 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5583 InitializeListHead(&pFobx
->ClosePendingList
);
5584 ++Scavenger
->NumberOfDormantFiles
;
5588 ASSERT(Scavenger
->NumberOfDormantFiles
>= 0);
5589 /* If we're about to reach the maximum dormant of FOBX */
5590 if (Scavenger
->NumberOfDormantFiles
>= Scavenger
->MaximumNumberOfDormantFiles
)
5592 /* This should never be wrong... */
5593 if (!IsListEmpty(&Scavenger
->ClosePendingFobxsList
))
5595 /* Then, take the first from the list (oldest) and save it for later purge */
5596 ScavengerFobx
= CONTAINING_RECORD(Scavenger
->ClosePendingFobxsList
.Flink
, FOBX
, ClosePendingList
);
5597 if (ScavengerFobx
->pSrvOpen
!= NULL
&& ScavengerFobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
5600 ScavengerFobx
= NULL
;
5604 RxReferenceNetFobx(ScavengerFobx
);
5609 /* Mark ourselves as dormant */
5610 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5611 pFobx
->CloseTime
.QuadPart
= TickCount
.QuadPart
;
5613 /* And insert us in the list of dormant files */
5614 InsertTailList(&Scavenger
->ClosePendingFobxsList
, &pFobx
->ClosePendingList
);
5615 /* If scavenger was inactive, start it */
5616 if (Scavenger
->NumberOfDormantFiles
++ == 0 && Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
5618 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
5619 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
, RxScavengerTimerRoutine
,
5620 Fcb
->RxDeviceObject
, Scavenger
->TimeLimit
);
5624 RxReleaseScavengerMutex();
5626 /* If we had reached max */
5627 if (ScavengerFobx
!= NULL
)
5631 /* Purge the oldest FOBX */
5632 Status
= RxPurgeFobxFromCache(ScavengerFobx
);
5633 if (Status
!= STATUS_SUCCESS
)
5648 PRDBSS_SCAVENGER Scavenger
;
5652 /* No FOBX, nothing to mark */
5658 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5659 ASSERT(NodeTypeIsFcb(Fcb
));
5661 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5663 RxAcquireScavengerMutex();
5664 /* Only mark it if it was already marked as dormant */
5665 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
))
5667 /* If FCB wasn't already decrement, do it now */
5668 if (!Fobx
->fOpenCountDecremented
)
5670 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5671 ASSERT(NodeTypeIsFcb(Fcb
));
5672 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
5674 Fobx
->fOpenCountDecremented
= TRUE
;
5677 /* We're no longer dormant */
5678 InterlockedDecrement(&Scavenger
->NumberOfDormantFiles
);
5679 ClearFlag(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5682 /* If we were inserted in the scavenger, drop ourselves out */
5683 if (!IsListEmpty(&Fobx
->ClosePendingList
))
5685 RemoveEntryList(&Fobx
->ClosePendingList
);
5686 InitializeListHead(&Fobx
->ClosePendingList
);
5689 RxReleaseScavengerMutex();
5697 PRX_CONTEXT RxContext
)
5703 Irp
= RxContext
->CurrentIrp
;
5704 if (Irp
->MdlAddress
!= NULL
)
5706 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5709 return Irp
->UserBuffer
;
5739 IN PV_NET_ROOT ThisVNetRoot
)
5744 PRX_FCB_TABLE FcbTable
;
5745 PRX_PREFIX_TABLE PrefixTable
;
5749 /* Mailslot won't have any SRV_OPEN (to orphan) */
5750 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
5751 if (NetRoot
->Type
== NET_ROOT_MAILSLOT
)
5756 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
5757 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
5759 FcbTable
= &NetRoot
->FcbTable
;
5760 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
5764 /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
5765 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
5767 PLIST_ENTRY BucketList
, Entry
;
5769 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
5770 Entry
= BucketList
->Flink
;
5771 while (Entry
!= BucketList
)
5773 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
5774 Entry
= Entry
->Flink
;
5776 ASSERT(NodeTypeIsFcb(Fcb
));
5777 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5781 /* Of course, don't forget about NULL-entry */
5782 if (FcbTable
->TableEntryForNull
!= NULL
)
5784 Fcb
= CONTAINING_RECORD(FcbTable
->TableEntryForNull
, FCB
, FcbTableEntry
.HashLinks
);
5785 ASSERT(NodeTypeIsFcb(Fcb
));
5786 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5791 RxReleaseFcbTableLock(FcbTable
);
5797 RxOrphanSrvOpensForThisFcb(
5799 IN PV_NET_ROOT ThisVNetRoot
,
5800 IN BOOLEAN OrphanAll
)
5809 RxpAcquirePrefixTableLockShared(
5810 PRX_PREFIX_TABLE pTable
,
5812 BOOLEAN ProcessBufferingStateChangeRequests
)
5816 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5817 pTable
->TableLock
.ActiveEntries
);
5819 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
5826 RxpAcquirePrefixTableLockExclusive(
5827 PRX_PREFIX_TABLE pTable
,
5829 BOOLEAN ProcessBufferingStateChangeRequests
)
5833 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5834 pTable
->TableLock
.ActiveEntries
);
5836 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
5843 RxpDereferenceAndFinalizeNetFcb(
5845 IN PRX_CONTEXT RxContext
,
5846 IN BOOLEAN RecursiveFinalize
,
5847 IN BOOLEAN ForceFinalize
)
5852 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
5856 ASSERT(!ForceFinalize
);
5857 ASSERT(NodeTypeIsFcb(ThisFcb
));
5858 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
5860 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5861 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
5862 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
5868 Status
= STATUS_SUCCESS
;
5869 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
5870 ResourceAcquired
= FALSE
;
5871 NetRootReferenced
= FALSE
;
5872 /* If FCB isn't orphaned, it still have context attached */
5873 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
5875 /* Don't let NetRoot go away before we're done */
5876 RxReferenceNetRoot(NetRoot
);
5877 NetRootReferenced
= TRUE
;
5879 /* Try to acquire the table lock exclusively */
5880 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
5882 RxReferenceNetFcb(ThisFcb
);
5884 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
5886 if (RxContext
!= NULL
&& RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT
&&
5887 RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
5889 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
5892 RxReleaseFcb(RxContext
, ThisFcb
);
5894 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5896 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
5899 References
= RxDereferenceNetFcb(ThisFcb
);
5901 ResourceAcquired
= TRUE
;
5905 /* If locking was OK (or not needed!), attempt finalization */
5906 if (Status
== STATUS_SUCCESS
)
5908 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
5911 /* Release table lock if acquired */
5912 if (ResourceAcquired
)
5914 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5917 /* We don't need the NetRoot anylonger */
5918 if (NetRootReferenced
)
5920 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
5930 RxpDereferenceNetFcb(
5937 ASSERT(NodeTypeIsFcb(Fcb
));
5939 NewCount
= InterlockedDecrement((volatile long *)&Fcb
->NodeReferenceCount
);
5940 ASSERT(NewCount
>= 0);
5942 PRINT_REF_COUNT(NETFCB
, NewCount
);
5957 BOOLEAN ForceFinalize
;
5958 PRX_PREFIX_TABLE PrefixTable
;
5960 SrvCall
= (PSRV_CALL
)Context
;
5961 /* At this step, RxFinalizeSrvCall already cleaned some fields */
5962 ASSERT(SrvCall
->UpperFinalizationDone
);
5964 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
5965 /* Were we called with ForceFinalize? */
5966 ForceFinalize
= BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
5968 /* Notify mini-rdr */
5969 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
,
5970 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)SrvCall
,
5974 /* Dereference our extra reference (set before queueing) */
5975 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
5976 InterlockedDecrement((volatile long *)&SrvCall
->NodeReferenceCount
);
5977 /* And finalize for real, with the right context */
5978 RxFinalizeSrvCall(SrvCall
, FALSE
, ForceFinalize
);
5979 RxReleasePrefixTableLock(PrefixTable
);
5986 RxpDiscardChangeBufferingStateRequests(
5987 _Inout_ PLIST_ENTRY DiscardedRequests
)
5993 /* No requests to discard */
5994 if (IsListEmpty(DiscardedRequests
))
5999 /* Free all the discarded requests */
6000 Entry
= DiscardedRequests
->Flink
;
6001 while (Entry
!= DiscardedRequests
)
6003 PCHANGE_BUFFERING_STATE_REQUEST Request
;
6005 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
6006 Entry
= Entry
->Flink
;
6008 DPRINT("Req %p for %p (%p) discarded\n", Request
, Request
->SrvOpenKey
, Request
->SrvOpen
);
6010 RxPrepareRequestForReuse(Request
);
6011 RxFreePool(Request
);
6019 RxpDispatchChangeBufferingStateRequests(
6022 PLIST_ENTRY DiscardedRequests
)
6026 BOOLEAN StartDispatcher
;
6027 LIST_ENTRY AcceptedReqs
;
6028 LIST_ENTRY DispatcherList
;
6029 PRX_BUFFERING_MANAGER BufferingManager
;
6031 /* Initialize our lists */
6032 InitializeListHead(&AcceptedReqs
);
6033 InitializeListHead(DiscardedRequests
);
6035 /* Transfer the requests to dispatch locally */
6036 BufferingManager
= &SrvCall
->BufferingManager
;
6037 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
6038 RxTransferList(&DispatcherList
, &BufferingManager
->DispatcherList
);
6039 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6041 /* If there were requests */
6042 if (!IsListEmpty(&DispatcherList
))
6046 /* For each of the entries... */
6047 Entry
= DispatcherList
.Flink
;
6048 while (Entry
!= &DispatcherList
)
6050 PCHANGE_BUFFERING_STATE_REQUEST Request
;
6052 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
6053 Entry
= Entry
->Flink
;
6055 /* If we have been provided a SRV_OPEN, see whether it matches */
6056 if (SrvOpen
!= NULL
)
6058 /* Match, the request is accepted */
6059 if (Request
->SrvOpenKey
== SrvOpen
->Key
)
6061 Request
->SrvOpen
= SrvOpen
;
6062 RxReferenceSrvOpen(SrvOpen
);
6064 RemoveEntryList(&Request
->ListEntry
);
6065 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
6067 /* Move to the next entry */
6072 Status
= STATUS_PENDING
;
6077 /* No SRV_OPEN provided, try to find one */
6078 Status
= RxpLookupSrvOpenForRequestLite(SrvCall
, Request
);
6081 /* We found a matching SRV_OPEN, accept the request */
6082 if (Status
== STATUS_SUCCESS
)
6084 RemoveEntryList(&Request
->ListEntry
);
6085 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
6087 /* Another run might help handling it, don't discard it */
6088 else if (Status
== STATUS_PENDING
)
6092 /* Otherwise, discard the request */
6095 ASSERT(Status
== STATUS_NOT_FOUND
);
6097 RemoveEntryList(&Request
->ListEntry
);
6098 InsertTailList(DiscardedRequests
, &Request
->ListEntry
);
6103 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
6104 /* Nothing to dispatch, no need to start dispatcher */
6105 if (IsListEmpty(&DispatcherList
))
6107 StartDispatcher
= FALSE
;
6111 /* Transfer back the list of the not treated entries to the buffering manager */
6112 RxTransferList(&BufferingManager
->DispatcherList
, &DispatcherList
);
6113 StartDispatcher
= (BufferingManager
->DispatcherActive
== FALSE
);
6114 /* If the dispatcher isn't active, start it */
6115 if (StartDispatcher
)
6117 BufferingManager
->DispatcherActive
= TRUE
;
6121 /* If there were accepted requests, move them to the buffering manager */
6122 if (!IsListEmpty(&AcceptedReqs
))
6124 RxTransferList(&BufferingManager
->HandlerList
, &AcceptedReqs
);
6126 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6128 /* If we're to start the dispatcher, do it */
6129 if (StartDispatcher
)
6131 RxReferenceSrvCall(SrvCall
);
6132 DPRINT("Starting dispatcher\n");
6133 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
6134 &BufferingManager
->DispatcherWorkItem
,
6135 RxDispatchChangeBufferingStateRequests
, SrvCall
);
6143 RxpLookupSrvOpenForRequestLite(
6144 IN PSRV_CALL SrvCall
,
6145 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request
)
6153 Status
= STATUS_SUCCESS
;
6154 /* Browse all our associated SRV_OPENs to find the one! */
6155 for (Entry
= SrvCall
->BufferingManager
.SrvOpenLists
[0].Flink
;
6156 Entry
!= &SrvCall
->BufferingManager
.SrvOpenLists
[0];
6157 Entry
= Entry
->Flink
)
6159 /* Same key, not orphaned, this is ours */
6160 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenKeyList
);
6161 if (SrvOpen
->Key
== Request
->SrvOpenKey
)
6163 if (!BooleanFlagOn(SrvOpen
->pFcb
->FcbState
, FCB_STATE_ORPHANED
))
6165 RxReferenceSrvOpen(SrvOpen
);
6171 /* We didn't manage to find a SRV_OPEN */
6172 if (Entry
== &SrvCall
->BufferingManager
.SrvOpenLists
[0])
6176 /* The coming open might help, mark as pending for later retry */
6177 if (SrvCall
->BufferingManager
.NumberOfOutstandingOpens
!= 0)
6179 Status
= STATUS_PENDING
;
6181 /* Else, it's a complete failure */
6184 Status
= STATUS_NOT_FOUND
;
6188 /* Return the (not) found SRV_OPEN */
6189 Request
->SrvOpen
= SrvOpen
;
6198 RxpMarkInstanceForScavengedFinalization(
6201 NODE_TYPE_CODE NodeType
;
6202 PNODE_TYPE_AND_SIZE Node
;
6203 PRDBSS_SCAVENGER Scavenger
;
6204 PRDBSS_DEVICE_OBJECT DeviceObject
;
6205 PLIST_ENTRY ScavengerHead
, InstEntry
;
6209 /* If still referenced, don't mark it (broken caller) */
6210 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6211 if (Node
->NodeReferenceCount
> 1)
6216 DeviceObject
= RxGetDeviceObjectOfInstance(Instance
);
6217 Scavenger
= DeviceObject
->pRdbssScavenger
;
6220 NodeType
= NodeType(Instance
);
6221 SetFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6222 DPRINT("Node %p has now the scavenger mark!\n", Instance
);
6224 /* Increase the count in the scavenger, and queue it */
6225 ScavengerHead
= NULL
;
6228 case RDBSS_NTC_FOBX
:
6229 ++Scavenger
->FobxsToBeFinalized
;
6230 ScavengerHead
= &Scavenger
->FobxFinalizationList
;
6231 InstEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6234 case RDBSS_NTC_SRVCALL
:
6235 ++Scavenger
->SrvCallsToBeFinalized
;
6236 ScavengerHead
= &Scavenger
->SrvCallFinalizationList
;
6237 InstEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6240 case RDBSS_NTC_NETROOT
:
6241 ++Scavenger
->NetRootsToBeFinalized
;
6242 ScavengerHead
= &Scavenger
->NetRootFinalizationList
;
6243 InstEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6246 case RDBSS_NTC_V_NETROOT
:
6247 ++Scavenger
->VNetRootsToBeFinalized
;
6248 ScavengerHead
= &Scavenger
->VNetRootFinalizationList
;
6249 InstEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6252 case RDBSS_NTC_SRVOPEN
:
6253 ++Scavenger
->SrvOpensToBeFinalized
;
6254 ScavengerHead
= &Scavenger
->SrvOpenFinalizationList
;
6255 InstEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6259 /* Extra ref for scavenger */
6260 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
6262 /* If matching type */
6263 if (ScavengerHead
!= NULL
)
6265 /* Insert in the scavenger list */
6266 InsertTailList(ScavengerHead
, InstEntry
);
6268 /* And if it wasn't started, start it */
6269 if (Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
6271 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
6272 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
6273 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
6283 RxPostOneShotTimerRequest(
6284 IN PRDBSS_DEVICE_OBJECT pDeviceObject
,
6285 IN PRX_WORK_ITEM pWorkItem
,
6286 IN PRX_WORKERTHREAD_ROUTINE Routine
,
6288 IN LARGE_INTEGER TimeInterval
)
6292 ASSERT(pWorkItem
!= NULL
);
6294 /* Prepare the work item */
6295 ExInitializeWorkItem(&pWorkItem
->WorkQueueItem
, Routine
, pContext
);
6296 pWorkItem
->WorkQueueItem
.pDeviceObject
= pDeviceObject
;
6298 /* Last tick can be computed with the number of times it was caller (timertickcount)
6299 * and the interval between calls
6301 KeAcquireSpinLock(&RxTimerLock
, &OldIrql
);
6302 pWorkItem
->LastTick
= (TimeInterval
.QuadPart
/ 550000) + RxTimerTickCount
+ 1;
6303 /* Insert in work queue */
6304 InsertTailList(&RxTimerQueueHead
, &pWorkItem
->WorkQueueItem
.List
);
6305 KeReleaseSpinLock(&RxTimerLock
, OldIrql
);
6307 /* If there are queued events, queue an execution */
6308 if (IsListEmpty(&RxTimerQueueHead
))
6310 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
6313 return STATUS_SUCCESS
;
6321 RxPostToWorkerThread(
6322 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
6323 _In_ WORK_QUEUE_TYPE WorkQueueType
,
6324 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem
,
6325 _In_ PRX_WORKERTHREAD_ROUTINE Routine
,
6326 _In_ PVOID pContext
)
6328 /* Initialize work queue item */
6329 pWorkQueueItem
->List
.Flink
= NULL
;
6330 pWorkQueueItem
->WorkerRoutine
= Routine
;
6331 pWorkQueueItem
->Parameter
= pContext
;
6333 /* And insert it in the work queue */
6334 return RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, pWorkQueueItem
);
6338 RxpProcessChangeBufferingStateRequests(
6340 BOOLEAN UpdateHandlerState
)
6349 RxPrefixTableInsertName(
6350 IN OUT PRX_PREFIX_TABLE ThisTable
,
6351 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
6353 IN PULONG ContainerRefCount
,
6354 IN USHORT CaseInsensitiveLength
,
6355 IN PRX_CONNECTION_ID ConnectionId
6360 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
6362 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
6363 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
6365 /* Copy parameters and compute hash */
6366 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
6367 ThisEntry
->ContainingRecord
= Container
;
6368 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
6369 InterlockedIncrement((volatile long *)ContainerRefCount
);
6370 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
6371 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
6373 /* If no path length: this is entry for null path */
6374 if (ThisEntry
->Prefix
.Length
== 0)
6376 ThisTable
->TableEntryForNull
= ThisEntry
;
6378 /* Otherwise, insert in the appropriate bucket */
6381 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
6384 /* If we had a connection ID, keep track of it */
6385 if (ConnectionId
!= NULL
)
6387 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
6391 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
6392 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
6395 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
6396 /* Reflect the changes */
6397 ++ThisTable
->Version
;
6399 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
6408 RxPrefixTableLookupName(
6409 IN PRX_PREFIX_TABLE ThisTable
,
6410 IN PUNICODE_STRING CanonicalName
,
6411 OUT PUNICODE_STRING RemainingName
,
6412 IN PRX_CONNECTION_ID ConnectionId
)
6418 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
6419 ASSERT(CanonicalName
->Length
> 0);
6421 /* Call the internal helper */
6422 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
6423 if (Container
== NULL
)
6428 /* Reference our container before returning it */
6429 if (RdbssReferenceTracingValue
!= 0)
6431 NODE_TYPE_CODE Type
;
6433 Type
= (NodeType(Container
) & ~RX_SCAVENGER_MASK
);
6436 case RDBSS_NTC_SRVCALL
:
6437 RxReferenceSrvCall(Container
);
6440 case RDBSS_NTC_NETROOT
:
6441 RxReferenceNetRoot(Container
);
6444 case RDBSS_NTC_V_NETROOT
:
6445 RxReferenceVNetRoot(Container
);
6449 DPRINT1("Invalid node type: %x\n", Type
);
6451 RxReference(Container
);
6457 RxReference(Container
);
6474 ASSERT(NodeTypeIsFcb(Fcb
));
6476 NewCount
= InterlockedIncrement((volatile long *)&Fcb
->NodeReferenceCount
);
6478 PRINT_REF_COUNT(NETFCB
, Fcb
->NodeReferenceCount
);
6487 RxpReleasePrefixTableLock(
6488 PRX_PREFIX_TABLE pTable
,
6489 BOOLEAN ProcessBufferingStateChangeRequests
)
6493 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
6494 pTable
->TableLock
.ActiveEntries
);
6496 ExReleaseResourceLite(&pTable
->TableLock
);
6504 RxPrepareContextForReuse(
6505 IN OUT PRX_CONTEXT RxContext
)
6509 /* When we reach that point, make sure mandatory parts are null-ed */
6510 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
6512 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
6513 RxContext
->Create
.RdrFlags
= 0;
6515 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
6517 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
6518 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
6521 RxContext
->ReferenceCount
= 0;
6528 RxPrepareRequestForReuse(
6529 PCHANGE_BUFFERING_STATE_REQUEST Request
)
6535 SrvOpen
= Request
->SrvOpen
;
6537 /* If the request was already prepared for service */
6538 if (BooleanFlagOn(Request
->Flags
, RX_REQUEST_PREPARED_FOR_HANDLING
))
6540 /* We have to dereference the associated SRV_OPEN depending on the lock */
6541 if (RxIsFcbAcquiredExclusive(SrvOpen
->pFcb
))
6543 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
6547 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6550 /* Otherwise, just dereference */
6551 else if (SrvOpen
!= NULL
)
6553 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6556 Request
->SrvOpen
= NULL
;
6564 RxProcessChangeBufferingStateRequests(
6567 /* Call internal routine */
6568 RxUndoScavengerFinalizationMarking(SrvCall
);
6569 RxpProcessChangeBufferingStateRequests(SrvCall
, TRUE
);
6576 RxProcessChangeBufferingStateRequestsForSrvOpen(
6579 LONG NumberOfBufferingChangeRequests
, LockedOldBufferingToken
, OldBufferingToken
;
6581 /* Get the current number of change requests */
6582 NumberOfBufferingChangeRequests
= ((PSRV_CALL
)SrvOpen
->pVNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
.CumulativeNumberOfBufferingChangeRequests
;
6583 /* Get our old token */
6584 OldBufferingToken
= SrvOpen
->BufferingToken
;
6585 LockedOldBufferingToken
= InterlockedCompareExchange(&SrvOpen
->BufferingToken
,
6586 NumberOfBufferingChangeRequests
,
6587 NumberOfBufferingChangeRequests
);
6588 /* If buffering state changed in between, process changes */
6589 if (OldBufferingToken
!= LockedOldBufferingToken
)
6594 /* Acquire the FCB and start processing */
6595 Fcb
= (PFCB
)SrvOpen
->pFcb
;
6596 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
6597 if (Status
== STATUS_SUCCESS
)
6599 RxProcessFcbChangeBufferingStateRequest(Fcb
);
6600 RxReleaseFcb(NULL
, Fcb
);
6606 RxProcessFcbChangeBufferingStateRequest(
6617 PRDBSS_SCAVENGER Scavenger
,
6618 PLIST_ENTRY FobxToScavenge
)
6620 /* Explore the whole list of FOBX to scavenge */
6621 while (!IsListEmpty(FobxToScavenge
))
6627 Entry
= RemoveHeadList(FobxToScavenge
);
6628 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ScavengerFinalizationList
);
6629 Fcb
= (PFCB
)Fobx
->SrvOpen
->pFcb
;
6631 /* Try to acquire the lock exclusively to perform finalization */
6632 if (RxAcquireExclusiveFcb(NULL
, Fcb
) != STATUS_SUCCESS
)
6634 RxDereferenceNetRoot(Fobx
, LHS_LockNotHeld
);
6638 RxReferenceNetFcb(Fcb
);
6639 RxDereferenceNetRoot(Fobx
, LHS_ExclusiveLockHeld
);
6641 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6643 RxReleaseFcb(NULL
, Fcb
);
6650 RxpTrackDereference(
6651 _In_ ULONG TraceType
,
6652 _In_ PCSTR FileName
,
6654 _In_ PVOID Instance
)
6657 ULONG ReferenceCount
;
6661 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6668 case RDBSS_REF_TRACK_SRVCALL
:
6669 InstanceType
= "SrvCall";
6670 ReferenceCount
= ((PSRV_CALL
)Instance
)->NodeReferenceCount
;
6673 case RDBSS_REF_TRACK_NETROOT
:
6674 InstanceType
= "NetRoot";
6675 ReferenceCount
= ((PNET_ROOT
)Instance
)->NodeReferenceCount
;
6678 case RDBSS_REF_TRACK_VNETROOT
:
6679 InstanceType
= "VNetRoot";
6680 ReferenceCount
= ((PV_NET_ROOT
)Instance
)->NodeReferenceCount
;
6683 case RDBSS_REF_TRACK_NETFOBX
:
6684 InstanceType
= "NetFobx";
6685 ReferenceCount
= ((PFOBX
)Instance
)->NodeReferenceCount
;
6688 case RDBSS_REF_TRACK_NETFCB
:
6689 InstanceType
= "NetFcb";
6690 ReferenceCount
= ((PFCB
)Instance
)->NodeReferenceCount
;
6693 case RDBSS_REF_TRACK_SRVOPEN
:
6694 InstanceType
= "SrvOpen";
6695 ReferenceCount
= ((PSRV_OPEN
)Instance
)->NodeReferenceCount
;
6699 DPRINT1("Invalid node type!\n");
6703 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_LOG_REF_TRACKING
))
6708 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_PRINT_REF_TRACKING
))
6710 DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName
, Line
, Instance
, InstanceType
, ReferenceCount
);
6718 _In_ ULONG TraceType
,
6719 _In_ PCSTR FileName
,
6721 _In_ PVOID Instance
)
6724 ULONG ReferenceCount
;
6726 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6733 case RDBSS_REF_TRACK_SRVCALL
:
6734 InstanceType
= "SrvCall";
6735 ReferenceCount
= ((PSRV_CALL
)Instance
)->NodeReferenceCount
;
6738 case RDBSS_REF_TRACK_NETROOT
:
6739 InstanceType
= "NetRoot";
6740 ReferenceCount
= ((PNET_ROOT
)Instance
)->NodeReferenceCount
;
6743 case RDBSS_REF_TRACK_VNETROOT
:
6744 InstanceType
= "VNetRoot";
6745 ReferenceCount
= ((PV_NET_ROOT
)Instance
)->NodeReferenceCount
;
6748 case RDBSS_REF_TRACK_NETFOBX
:
6749 InstanceType
= "NetFobx";
6750 ReferenceCount
= ((PFOBX
)Instance
)->NodeReferenceCount
;
6753 case RDBSS_REF_TRACK_NETFCB
:
6754 InstanceType
= "NetFcb";
6755 ReferenceCount
= ((PFCB
)Instance
)->NodeReferenceCount
;
6758 case RDBSS_REF_TRACK_SRVOPEN
:
6759 InstanceType
= "SrvOpen";
6760 ReferenceCount
= ((PSRV_OPEN
)Instance
)->NodeReferenceCount
;
6764 DPRINT1("Invalid node type!\n");
6768 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_LOG_REF_TRACKING
))
6773 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_PRINT_REF_TRACKING
))
6775 DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName
, Line
, Instance
, InstanceType
, ReferenceCount
);
6783 RxpUndoScavengerFinalizationMarking(
6786 PLIST_ENTRY ListEntry
;
6787 PNODE_TYPE_AND_SIZE Node
;
6788 PRDBSS_SCAVENGER Scavenger
;
6792 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6793 /* There's no marking - nothing to do */
6794 if (!BooleanFlagOn(NodeType(Node
), RX_SCAVENGER_MASK
))
6799 /* First of all, remove the mark */
6800 ClearFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6801 DPRINT("Node %p no longer has the scavenger mark\n");
6803 /* And now, remove from the scavenger */
6804 Scavenger
= RxGetDeviceObjectOfInstance(Instance
)->pRdbssScavenger
;
6805 switch (NodeType(Node
))
6807 case RDBSS_NTC_FOBX
:
6808 --Scavenger
->FobxsToBeFinalized
;
6809 ListEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6812 case RDBSS_NTC_SRVCALL
:
6813 --Scavenger
->SrvCallsToBeFinalized
;
6814 ListEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6817 case RDBSS_NTC_NETROOT
:
6818 --Scavenger
->NetRootsToBeFinalized
;
6819 ListEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6822 case RDBSS_NTC_V_NETROOT
:
6823 --Scavenger
->VNetRootsToBeFinalized
;
6824 ListEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6827 case RDBSS_NTC_SRVOPEN
:
6828 --Scavenger
->SrvOpensToBeFinalized
;
6829 ListEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6833 /* Also, remove the extra ref from the scavenger */
6834 RemoveEntryList(ListEntry
);
6835 InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
6842 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6846 LIST_ENTRY Discarded
;
6850 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
6852 /* Initialize our discarded list */
6853 InitializeListHead(&Discarded
);
6855 SrvCall
= (PSRV_CALL
)SrvOpen
->Fcb
->VNetRoot
->pNetRoot
->pSrvCall
;
6856 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
6858 /* Set the flag, and get the requests */
6859 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
6860 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED
);
6861 RxGatherRequestsForSrvOpen(SrvCall
, SrvOpen
, &Discarded
);
6863 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
6865 /* If there were discarded requests */
6866 if (!IsListEmpty(&Discarded
))
6868 /* And a pending buffering state change */
6869 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
6871 /* Clear the flag, and set the associated event - job done */
6872 RxAcquireSerializationMutex();
6873 ClearFlag(SrvOpen
->Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
6874 if (SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
6876 KeSetEvent(SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
, IO_NETWORK_INCREMENT
, FALSE
);
6878 RxReleaseSerializationMutex();
6881 /* Drop the discarded requests */
6882 RxpDiscardChangeBufferingStateRequests(&Discarded
);
6895 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6897 /* Reference our FCB so that it doesn't disappear */
6898 RxReferenceNetFcb(Fcb
);
6899 /* Purge Cc if required */
6900 if (Fcb
->OpenCount
!= 0)
6902 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
6905 /* If it wasn't freed, release the lock */
6906 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6908 RxReleaseFcb(NULL
, Fcb
);
6916 RxPurgeFcbInSystemCache(
6918 IN PLARGE_INTEGER FileOffset OPTIONAL
,
6920 IN BOOLEAN UninitializeCacheMaps
,
6921 IN BOOLEAN FlushFile
)
6928 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6930 /* Try to flush first, if asked */
6933 /* If flushing failed, just make some noise */
6934 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
6935 if (!NT_SUCCESS(Status
))
6937 PVOID CallersAddress
, CallersCaller
;
6939 RtlGetCallersAddress(&CallersAddress
, &CallersCaller
);
6940 DPRINT1("Flush failed with status %lx for FCB %p\n", Status
, Fcb
);
6941 DPRINT1("Caller was %p %p\n", CallersAddress
, CallersCaller
);
6945 /* Deal with Cc for purge */
6946 Purged
= CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, FileOffset
,
6947 Length
, UninitializeCacheMaps
);
6948 /* If purge failed, force section closing */
6951 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
6953 RxReleaseFcb(NULL
, Fcb
);
6954 Purged
= MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
6955 RxAcquireExclusiveFcb(NULL
, Fcb
);
6958 /* Return appropriate status */
6959 Status
= (Purged
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
6960 DPRINT("Purge for FCB %p returns %lx\n", Fcb
, Status
);
6977 /* Get the associated FCB */
6978 FcbToBePurged
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
6979 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
6980 ASSERT(Status
== STATUS_SUCCESS
);
6983 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
6984 if (Status
!= STATUS_SUCCESS
)
6986 DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged
, pFobx
);
6991 if (!MmFlushImageSection(&FcbToBePurged
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
))
6993 DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged
, pFobx
);
6997 DPRINT("Purge OK for %p (%p)\n", FcbToBePurged
, pFobx
);
7005 RxPurgeFobxFromCache(
7006 PFOBX FobxToBePurged
)
7013 FcbToBePurged
= (PFCB
)FobxToBePurged
->pSrvOpen
->pFcb
;
7014 ASSERT(FcbToBePurged
!= NULL
);
7016 /* If we cannot have our FCB exclusively, give up */
7017 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
7018 if (Status
!= STATUS_SUCCESS
)
7020 RxDereferenceNetFobx(FobxToBePurged
, LHS_LockNotHeld
);
7024 /* Don't let the FCB disappear */
7025 RxReferenceNetFcb(FcbToBePurged
);
7027 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
7028 if (BooleanFlagOn(FobxToBePurged
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
) || FobxToBePurged
->pSrvOpen
->UncleanFobxCount
!= 0)
7030 DPRINT("FCB purge skipped\n");
7034 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
7037 RxDereferenceNetFobx(FobxToBePurged
, LHS_ExclusiveLockHeld
);
7038 /* Drop our extra reference */
7039 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged
, NULL
, FALSE
, FALSE
))
7041 RxReleaseFcb(NULL
, FcbToBePurged
);
7051 RxPurgeRelatedFobxs(
7053 PRX_CONTEXT RxContext
,
7054 BOOLEAN AttemptFinalization
,
7058 ULONG SuccessfullPurge
;
7059 PRDBSS_SCAVENGER Scavenger
;
7060 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7061 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx
;
7065 RxDeviceObject
= RxContext
->RxDeviceObject
;
7066 Scavenger
= RxDeviceObject
->pRdbssScavenger
;
7067 PurgeSyncCtx
= &NetRoot
->PurgeSyncronizationContext
;
7069 RxAcquireScavengerMutex();
7071 /* If there's already a purge in progress */
7072 if (PurgeSyncCtx
->PurgeInProgress
)
7074 /* Add our RX_CONTEXT to the current run */
7075 InsertTailList(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
,
7076 &RxContext
->RxContextSerializationQLinks
);
7078 /* And wait until it's done */
7079 RxReleaseScavengerMutex();
7080 RxWaitSync(RxContext
);
7081 RxAcquireScavengerMutex();
7084 /* Start the purge */
7085 PurgeSyncCtx
->PurgeInProgress
= TRUE
;
7087 /* While the purge is still handling our NET_ROOT, do nothing but wait */
7088 while (Scavenger
->CurrentNetRootForClosePendingProcessing
== NetRoot
)
7090 RxReleaseScavengerMutex();
7091 KeWaitForSingleObject(&Scavenger
->ClosePendingProcessingSyncEvent
, Executive
,
7092 KernelMode
, TRUE
, NULL
);
7093 RxAcquireScavengerMutex();
7096 /* Now, for all the entries */
7097 SuccessfullPurge
= 0;
7098 Entry
= Scavenger
->ClosePendingFobxsList
.Flink
;
7099 while (Entry
!= &Scavenger
->ClosePendingFobxsList
)
7105 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ClosePendingList
);
7106 DPRINT("Dealing with FOBX: %p\n", Fobx
);
7108 Entry
= Entry
->Flink
;
7110 /* If it's not matching our NET_ROOT, ignore */
7111 if (Fobx
->pSrvOpen
== NULL
||
7112 Fobx
->pSrvOpen
->pFcb
== NULL
||
7113 ((PFCB
)Fobx
->pSrvOpen
->pFcb
)->VNetRoot
== NULL
||
7114 (PNET_ROOT
)((PFCB
)Fobx
->pSrvOpen
->pFcb
)->VNetRoot
->pNetRoot
!= NetRoot
)
7119 /* Determine if it matches our FCB */
7120 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
7121 if (PurgingFcb
!= NULL
&& NodeType(PurgingFcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
7126 MINIRDR_CALL_THROUGH(Status
, RxDeviceObject
->Dispatch
, MRxAreFilesAliased
, (Fcb
, PurgingFcb
));
7127 if (Status
== STATUS_SUCCESS
)
7133 /* Matching, we'll purge it */
7134 RemoveEntryList(&Fobx
->ClosePendingList
);
7136 /* Reference it so that it doesn't disappear */
7137 RxReferenceNetFobx(Fobx
);
7139 RxReleaseScavengerMutex();
7142 Success
= RxPurgeFobx(Fobx
);
7148 /* If we don't have to finalize it (or if we cannot acquire lock exclusively
7149 * Just normally dereference
7151 if ((AttemptFinalization
== DONT_ATTEMPT_FINALIZE_ON_PURGE
) ||
7152 RxAcquireExclusiveFcb(NULL
, Fcb
) != STATUS_SUCCESS
)
7154 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
7156 /* Otherwise, finalize */
7159 RxReferenceNetFcb(Fcb
);
7160 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
7161 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
7163 RxReleaseFcb(NULL
, Fcb
);
7169 DPRINT1("Failed purging %p (%p)\n", Fcb
, Fobx
);
7172 RxAcquireScavengerMutex();
7175 /* If no contexts left, purge is not running */
7176 if (IsListEmpty(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
))
7178 PurgeSyncCtx
->PurgeInProgress
= FALSE
;
7180 /* Otherwise, notify a waiter it can start */
7183 PRX_CONTEXT Context
;
7185 Entry
= RemoveHeadList(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
);
7186 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, RxContextSerializationQLinks
);
7188 RxSignalSynchronousWaiter(Context
);
7191 RxReleaseScavengerMutex();
7193 return (SuccessfullPurge
> 0 ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
7200 RxpWorkerThreadDispatcher(
7201 IN PRX_WORK_QUEUE WorkQueue
,
7202 IN PLARGE_INTEGER WaitInterval
)
7206 PETHREAD CurrentThread
;
7207 BOOLEAN KillThread
, Dereference
;
7208 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
7209 PWORKER_THREAD_ROUTINE WorkerRoutine
;
7211 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7213 /* Reference ourselves */
7214 CurrentThread
= PsGetCurrentThread();
7215 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7216 ASSERT(NT_SUCCESS(Status
));
7218 /* Infinite loop for worker */
7220 Dereference
= FALSE
;
7224 PLIST_ENTRY ListEntry
;
7226 /* Remove an entry from the work queue */
7227 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
7228 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
7230 PRDBSS_DEVICE_OBJECT DeviceObject
;
7232 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
7234 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
7235 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
7236 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7238 /* Get the parameters, and null-them in the struct */
7239 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
7240 Parameter
= WorkQueueItem
->Parameter
;
7241 DeviceObject
= WorkQueueItem
->pDeviceObject
;
7243 WorkQueueItem
->List
.Flink
= NULL
;
7244 WorkQueueItem
->WorkerRoutine
= NULL
;
7245 WorkQueueItem
->Parameter
= NULL
;
7246 WorkQueueItem
->pDeviceObject
= NULL
;
7248 /* Call the routine */
7249 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
7250 WorkerRoutine(Parameter
);
7252 /* Are we going down now? */
7253 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
7255 PKEVENT TearDownEvent
;
7257 TearDownEvent
= InterlockedExchangePointer((void * volatile*)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
7258 if (TearDownEvent
!= NULL
)
7260 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
7264 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7267 /* Shall we shutdown... */
7268 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7269 switch (WorkQueue
->State
)
7271 /* Our queue is active, kill it if we have no more items to dispatch
7272 * and more threads than the required minimum
7274 case RxWorkQueueActive
:
7275 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
7277 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
7278 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
7282 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7287 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7292 /* The queue is inactive: kill it we have more threads than the required minimum */
7293 case RxWorkQueueInactive
:
7294 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
7295 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
7299 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7304 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7308 /* Rundown in progress..., kill it for sure! */
7309 case RxWorkQueueRundownInProgress
:
7311 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
7313 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
7315 RundownContext
= WorkQueue
->pRundownContext
;
7316 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
7318 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7320 Dereference
= FALSE
;
7322 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
7324 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
7327 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7334 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
7335 } while (!KillThread
);
7337 DPRINT("Killed worker thread\n");
7339 /* Do we have to dereference ourselves? */
7342 ObDereferenceObject(CurrentThread
);
7345 /* Dump last executed routine */
7346 if (DumpDispatchRoutine
)
7348 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
7351 PsTerminateSystemThread(STATUS_SUCCESS
);
7356 IN OUT PVOID Instance
)
7358 NODE_TYPE_CODE NodeType
;
7359 PNODE_TYPE_AND_SIZE Node
;
7363 RxAcquireScavengerMutex();
7365 /* We can only reference a few structs */
7366 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
7367 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
7368 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
7369 (NodeType
== RDBSS_NTC_FOBX
));
7371 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
7372 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
7374 /* Trace refcount if asked */
7377 case RDBSS_NTC_SRVCALL
:
7378 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
7381 case RDBSS_NTC_NETROOT
:
7382 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
7385 case RDBSS_NTC_V_NETROOT
:
7386 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
7389 case RDBSS_NTC_SRVOPEN
:
7390 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
7393 case RDBSS_NTC_FOBX
:
7394 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
7402 RxpUndoScavengerFinalizationMarking(Instance
);
7403 RxReleaseScavengerMutex();
7411 RxReinitializeContext(
7412 IN OUT PRX_CONTEXT RxContext
)
7415 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7416 ULONG InitialContextFlags
, SavedFlags
;
7420 /* Backup a few flags */
7421 Irp
= RxContext
->CurrentIrp
;
7422 RxDeviceObject
= RxContext
->RxDeviceObject
;
7423 SavedFlags
= RxContext
->Flags
& RX_CONTEXT_PRESERVED_FLAGS
;
7424 InitialContextFlags
= RxContext
->Flags
& RX_CONTEXT_INITIALIZATION_FLAGS
;
7426 /* Reset our context */
7427 RxPrepareContextForReuse(RxContext
);
7429 /* Zero everything */
7430 RtlZeroMemory(&RxContext
->MajorFunction
, sizeof(RX_CONTEXT
) - FIELD_OFFSET(RX_CONTEXT
, MajorFunction
));
7432 /* Restore saved flags */
7433 RxContext
->Flags
= SavedFlags
;
7434 /* And reinit the context */
7435 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, RxContext
);
7443 RxReleaseFcbFromLazyWrite(
7451 /* The received context is a FCB */
7452 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
7453 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
7455 /* Lazy writer is releasing lock, so forget about it */
7456 Fcb
->Specific
.Fcb
.LazyWriteThread
= NULL
;
7458 /* If we were top level IRP, unwind */
7459 if (RxGetTopIrpIfRdbssIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
)
7461 RxUnwindTopLevelIrp(NULL
);
7464 /* And finally, release the lock */
7465 Fcb
->PagingIoResourceFile
= NULL
;
7466 Fcb
->PagingIoResourceLine
= 0;
7467 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
7475 RxReleaseFcbFromReadAhead(
7483 /* The received context is a FCB */
7484 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
7485 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
7487 /* Top Level IRP is CC */
7488 ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
);
7489 RxUnwindTopLevelIrp(NULL
);
7491 ExReleaseResourceLite(Fcb
->Header
.Resource
);
7496 RxReleaseFileForNtCreateSection(
7497 PFILE_OBJECT FileObject
)
7504 RxReleaseForCcFlush(
7505 PFILE_OBJECT FileObject
,
7506 PDEVICE_OBJECT DeviceObject
)
7509 return STATUS_NOT_IMPLEMENTED
;
7523 ASSERT(NodeTypeIsFcb(ThisFcb
));
7525 /* Just remove the entry from the FCB_TABLE */
7526 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
7527 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
7528 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
7530 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
7531 DPRINT("FCB (%p) %wZ removed\n", ThisFcb
, &ThisFcb
->FcbTableEntry
.Path
);
7532 /* Mark, so that we don't try to do it twice */
7533 SetFlag(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
);
7540 RxRemovePrefixTableEntry(
7541 IN OUT PRX_PREFIX_TABLE ThisTable
,
7542 IN OUT PRX_PREFIX_ENTRY Entry
)
7546 ASSERT(NodeType(Entry
) == RDBSS_NTC_PREFIX_ENTRY
);
7547 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
7549 /* Check whether we're asked to remove null entry */
7550 if (Entry
->Prefix
.Length
== 0)
7552 ThisTable
->TableEntryForNull
= NULL
;
7556 RemoveEntryList(&Entry
->HashLinks
);
7559 Entry
->ContainingRecord
= NULL
;
7561 /* Also remove it from global list */
7562 RemoveEntryList(&Entry
->MemberQLinks
);
7564 ++ThisTable
->Version
;
7571 RxRemoveVirtualNetRootFromNetRoot(
7573 PV_NET_ROOT VNetRoot
)
7575 PRX_PREFIX_TABLE PrefixTable
;
7579 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
7580 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
7582 /* Remove the VNetRoot from the list in the NetRoot */
7583 --NetRoot
->NumberOfVirtualNetRoots
;
7584 RemoveEntryList(&VNetRoot
->NetRootListEntry
);
7586 /* Fix the NetRoot if we were the default VNetRoot */
7587 if (NetRoot
->DefaultVNetRoot
== VNetRoot
)
7589 /* Put the first one available */
7590 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7592 NetRoot
->DefaultVNetRoot
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
7594 /* Otherwise, none */
7597 NetRoot
->DefaultVNetRoot
= NULL
;
7601 /* If there are still other VNetRoot available, we're done */
7602 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7607 /* Otherwise, initiate NetRoot finalization */
7608 if (!BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
7610 RxRemovePrefixTableEntry(PrefixTable
, &NetRoot
->PrefixEntry
);
7611 SetFlag(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
);
7614 /* Notify mini-rdr */
7615 if (NetRoot
->pSrvCall
!= NULL
&& NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
7619 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
7620 MRxFinalizeNetRoot
, ((PMRX_NET_ROOT
)NetRoot
, FALSE
));
7626 RxResumeBlockedOperations_ALL(
7627 IN OUT PRX_CONTEXT RxContext
)
7629 LIST_ENTRY BlockedOps
;
7633 /* Get the blocked operations */
7634 RxTransferListWithMutex(&BlockedOps
, &RxContext
->BlockedOperations
, RxContext
->BlockedOpsMutex
);
7636 if (!IsListEmpty(&BlockedOps
))
7644 RxResumeBlockedOperations_Serially(
7645 IN OUT PRX_CONTEXT RxContext
,
7646 IN OUT PLIST_ENTRY BlockingIoQ
)
7650 RxAcquireSerializationMutex();
7652 /* This can only happen on pipes */
7653 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7655 RxReleaseSerializationMutex();
7661 RxReleaseSerializationMutex();
7668 RxSetFileSizeWithLock(
7670 IN PLONGLONG FileSize
)
7674 /* Set attribute and increase version */
7675 Fcb
->Header
.FileSize
.QuadPart
= *FileSize
;
7676 ++Fcb
->ulFileSizeVersion
;
7683 RxScavengeFobxsForNetRoot(
7686 BOOLEAN SynchronizeWithScavenger
)
7688 PRDBSS_SCAVENGER Scavenger
;
7689 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7693 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
7694 Scavenger
= RxDeviceObject
->pRdbssScavenger
;
7696 /* Wait for the scavenger, if asked to */
7697 if (SynchronizeWithScavenger
)
7699 KeWaitForSingleObject(&Scavenger
->SyncEvent
, Executive
, KernelMode
, FALSE
, NULL
);
7702 RxAcquireScavengerMutex();
7704 /* If there's nothing left to do... */
7705 if (Scavenger
->FobxsToBeFinalized
<= 0)
7707 RxReleaseScavengerMutex();
7712 LIST_ENTRY FobxToScavenge
;
7714 InitializeListHead(&FobxToScavenge
);
7716 /* Browse all the FOBXs to finalize */
7717 Entry
= Scavenger
->FobxFinalizationList
.Flink
;
7718 while (Entry
!= &Scavenger
->FobxFinalizationList
)
7722 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ScavengerFinalizationList
);
7723 Entry
= Entry
->Flink
;
7725 if (Fobx
->SrvOpen
!= NULL
)
7729 Fcb
= (PFCB
)Fobx
->SrvOpen
->pFcb
;
7731 /* If it matches our NET_ROOT */
7732 if ((PNET_ROOT
)Fcb
->pNetRoot
== NetRoot
)
7736 /* Check whether it matches our FCB */
7737 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
7738 if (PurgingFcb
!= NULL
&& PurgingFcb
!= Fcb
)
7740 MINIRDR_CALL_THROUGH(Status
, RxDeviceObject
->Dispatch
, MRxAreFilesAliased
, (Fcb
, PurgingFcb
));
7743 /* If so, add it to the list of the FOBXs to scavenge */
7744 if (Status
!= STATUS_SUCCESS
)
7746 RxReferenceNetFobx(Fobx
);
7747 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7749 RemoveEntryList(&Fobx
->ScavengerFinalizationList
);
7750 InsertTailList(&FobxToScavenge
, &Fobx
->ScavengerFinalizationList
);
7756 RxReleaseScavengerMutex();
7758 /* Now, scavenge all the extracted FOBX */
7759 RxpScavengeFobxs(Scavenger
, &FobxToScavenge
);
7762 if (SynchronizeWithScavenger
)
7764 KeSetEvent(&Scavenger
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
7772 RxScavengeRelatedFobxs(
7776 LIST_ENTRY LocalList
;
7777 PLIST_ENTRY NextEntry
;
7778 PRDBSS_SCAVENGER Scavenger
;
7782 /* First of all, check whether there are FOBX to scavenge */
7783 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
7784 RxAcquireScavengerMutex();
7785 if (Scavenger
->FobxsToBeFinalized
<= 0)
7787 RxReleaseScavengerMutex();
7791 /* Initialize our local list which will hold all the FOBX to scavenge so
7792 * that we don't acquire the scavenger mutex too long
7794 InitializeListHead(&LocalList
);
7796 /* Technically, that condition should all be true... */
7797 if (!IsListEmpty(&Scavenger
->FobxFinalizationList
))
7799 PLIST_ENTRY NextEntry
, LastEntry
;
7801 /* Browse all the FCBs to find the matching ones */
7802 NextEntry
= Scavenger
->FobxFinalizationList
.Flink
;
7803 LastEntry
= &Scavenger
->FobxFinalizationList
;
7804 while (NextEntry
!= LastEntry
)
7806 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7807 NextEntry
= NextEntry
->Flink
;
7808 /* Matching our FCB? Let's finalize it */
7809 if (Fobx
->pSrvOpen
!= NULL
&& Fobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
7811 RxpUndoScavengerFinalizationMarking(Fobx
);
7812 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7813 InsertTailList(&LocalList
, &Fobx
->ScavengerFinalizationList
);
7818 RxReleaseScavengerMutex();
7820 /* Nothing to scavenge? Quit */
7821 if (IsListEmpty(&LocalList
))
7826 /* Now, finalize all the extracted FOBX */
7827 while (!IsListEmpty(&LocalList
))
7829 NextEntry
= RemoveHeadList(&LocalList
);
7830 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7831 RxFinalizeNetFobx(Fobx
, TRUE
, TRUE
);
7838 RxScavengerFinalizeEntries(
7839 PRDBSS_DEVICE_OBJECT DeviceObject
)
7849 RxScavengerTimerRoutine(
7853 PRDBSS_DEVICE_OBJECT DeviceObject
;
7854 PRDBSS_SCAVENGER Scavenger
;
7858 DeviceObject
= Context
;
7859 Scavenger
= DeviceObject
->pRdbssScavenger
;
7862 RxAcquireScavengerMutex();
7863 /* If the scavenger was dormant, wake it up! */
7864 if (Scavenger
->State
== RDBSS_SCAVENGER_DORMANT
)
7867 Scavenger
->State
= RDBSS_SCAVENGER_ACTIVE
;
7868 KeResetEvent(&Scavenger
->ScavengeEvent
);
7870 /* Scavenger the entries */
7871 RxReleaseScavengerMutex();
7872 RxScavengerFinalizeEntries(DeviceObject
);
7873 RxAcquireScavengerMutex();
7875 /* If we're still active (race) */
7876 if (Scavenger
->State
== RDBSS_SCAVENGER_ACTIVE
)
7878 /* If there are new entries to scavenge, stay dormant and requeue a run */
7879 if (Scavenger
->NumberOfDormantFiles
+ Scavenger
->SrvCallsToBeFinalized
+
7880 Scavenger
->NetRootsToBeFinalized
+ Scavenger
->VNetRootsToBeFinalized
+
7881 Scavenger
->FcbsToBeFinalized
+ Scavenger
->SrvOpensToBeFinalized
+
7882 Scavenger
->FobxsToBeFinalized
!= 0)
7885 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
7887 /* Otherwise, we're inactive again */
7890 Scavenger
->State
= RDBSS_SCAVENGER_INACTIVE
;
7894 RxReleaseScavengerMutex();
7896 /* Requeue an execution */
7899 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
7900 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
7905 RxReleaseScavengerMutex();
7908 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
7912 RxScavengeVNetRoots(
7913 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7924 RxSpinUpRequestsDispatcher(
7928 PRX_DISPATCHER RxDispatcher
;
7930 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7931 if (!NT_SUCCESS(Status
))
7933 PsTerminateSystemThread(STATUS_SUCCESS
);
7936 RxDispatcher
= Dispatcher
;
7941 PLIST_ENTRY ListEntry
;
7943 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
7944 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
7945 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
7947 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
7948 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
7950 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
7954 ListEntry
= &RxDispatcher
->SpinUpRequests
;
7956 KeResetEvent(&RxDispatcher
->SpinUpRequestsEvent
);
7957 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
7959 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
7961 PWORK_QUEUE_ITEM WorkItem
;
7962 PRX_WORK_QUEUE WorkQueue
;
7964 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
7965 WorkQueue
= WorkItem
->Parameter
;
7967 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
7969 DPRINT("Workqueue: calling %p(%p)\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
7970 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
7972 } while (RxDispatcher
->State
== RxDispatcherActive
);
7974 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
7975 PsTerminateSystemThread(STATUS_SUCCESS
);
7982 RxSpinUpWorkerThread(
7983 PRX_WORK_QUEUE WorkQueue
,
7984 PRX_WORKERTHREAD_ROUTINE Routine
,
7989 HANDLE ThreadHandle
;
7993 /* If work queue is inactive, that cannot work */
7994 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7995 if (WorkQueue
->State
!= RxWorkQueueActive
)
7997 Status
= STATUS_UNSUCCESSFUL
;
7998 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
8002 ++WorkQueue
->NumberOfActiveWorkerThreads
;
8003 Status
= STATUS_SUCCESS
;
8005 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
8007 /* Quit on failure */
8008 if (!NT_SUCCESS(Status
))
8013 /* Spin up the worker thread */
8014 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
8015 if (NT_SUCCESS(Status
))
8017 ZwClose(ThreadHandle
);
8020 /* Read well: we reached that point because it failed! */
8021 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
8023 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
8024 --WorkQueue
->NumberOfActiveWorkerThreads
;
8025 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
8027 /* Rundown, no more active threads, set the event! */
8028 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
8029 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
8031 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
8034 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
8036 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
8042 RxSpinUpWorkerThreads(
8043 PRX_WORK_QUEUE WorkQueue
)
8049 RxSynchronizeWithScavenger(
8050 IN PRX_CONTEXT RxContext
)
8059 RxTableComputeHashValue(
8060 IN PUNICODE_STRING Name
)
8068 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8071 Loops
[1] = MaxChar
- 1;
8072 Loops
[2] = MaxChar
- 2;
8073 Loops
[3] = MaxChar
- 3;
8074 Loops
[4] = MaxChar
- 4;
8075 Loops
[5] = MaxChar
/ 4;
8076 Loops
[6] = 2 * MaxChar
/ 4;
8077 Loops
[7] = 3 * MaxChar
/ 4;
8080 for (i
= 0; i
< 8; ++i
)
8085 if (Idx
>= 0 && Idx
< MaxChar
)
8087 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
8098 RxTableComputePathHashValue(
8099 IN PUNICODE_STRING Name
)
8107 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8110 Loops
[1] = MaxChar
- 1;
8111 Loops
[2] = MaxChar
- 2;
8112 Loops
[3] = MaxChar
- 3;
8113 Loops
[4] = MaxChar
- 4;
8114 Loops
[5] = MaxChar
/ 4;
8115 Loops
[6] = 2 * MaxChar
/ 4;
8116 Loops
[7] = 3 * MaxChar
/ 4;
8119 for (i
= 0; i
< 8; ++i
)
8124 if (Idx
>= 0 && Idx
< MaxChar
)
8126 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
8138 IN PRX_PREFIX_TABLE ThisTable
,
8139 IN PUNICODE_STRING Name
,
8140 OUT PUNICODE_STRING RemainingName
,
8141 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
8145 PRX_PREFIX_ENTRY Entry
;
8146 RX_CONNECTION_ID NullId
;
8147 UNICODE_STRING LookupString
;
8151 /* If caller didn't provide a connection ID, setup one */
8152 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
8154 NullId
.Luid
.LowPart
= 0;
8155 NullId
.Luid
.HighPart
= 0;
8156 RxConnectionId
= &NullId
;
8160 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
8164 LookupString
.Buffer
= Name
->Buffer
;
8165 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8166 /* We'll perform the lookup, path component after another */
8167 for (i
= 1; i
< MaxChar
; ++i
)
8170 PRX_PREFIX_ENTRY CurEntry
;
8172 /* Don't cut in the middle of a path element */
8173 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
8178 /* Perform lookup in the table */
8179 LookupString
.Length
= i
* sizeof(WCHAR
);
8180 Hash
= RxTableComputeHashValue(&LookupString
);
8181 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
8183 ++ThisTable
->Lookups
;
8185 /* Entry not found, move to the next component */
8186 if (CurEntry
== NULL
)
8189 ++ThisTable
->FailedLookups
;
8195 ASSERT(Entry
->ContainingRecord
!= NULL
);
8196 Container
= Entry
->ContainingRecord
;
8198 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
8199 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
8203 NetRoot
= (PNET_ROOT
)Entry
->ContainingRecord
;
8204 /* If there's a default one, perfect, that's a match */
8205 if (NetRoot
->DefaultVNetRoot
!= NULL
)
8207 Container
= NetRoot
->DefaultVNetRoot
;
8209 /* If none (that shouldn't happen!), try to find one */
8212 /* Use the first one in the list */
8213 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
8215 Container
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
8217 /* Really, really, shouldn't happen */
8228 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
8234 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
8238 /* Entry was found */
8243 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
8245 /* Setup remaining name */
8246 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
8247 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
8248 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
8252 /* Otherwise, that's the whole name */
8253 RemainingName
= Name
;
8263 RxTableLookupName_ExactLengthMatch(
8264 IN PRX_PREFIX_TABLE ThisTable
,
8265 IN PUNICODE_STRING Name
,
8267 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
8269 PLIST_ENTRY ListEntry
, HashBucket
;
8273 ASSERT(RxConnectionId
!= NULL
);
8275 /* Select the right bucket */
8276 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
8277 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
8278 /* If bucket is empty, no match */
8279 if (IsListEmpty(HashBucket
))
8284 /* Browse all the entries in the bucket */
8285 for (ListEntry
= HashBucket
->Flink
;
8286 ListEntry
!= HashBucket
;
8287 ListEntry
= ListEntry
->Flink
)
8290 PRX_PREFIX_ENTRY Entry
;
8291 BOOLEAN CaseInsensitive
;
8292 PUNICODE_STRING CmpName
, CmpPrefix
;
8293 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
8295 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
8296 ++ThisTable
->Considers
;
8297 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
8299 Container
= Entry
->ContainingRecord
;
8300 ASSERT(Container
!= NULL
);
8302 /* Not the same hash, not the same length, move on */
8303 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
8308 ++ThisTable
->Compares
;
8309 /* If we have to perform a case insensitive compare on a portion... */
8310 if (Entry
->CaseInsensitiveLength
!= 0)
8312 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
8314 /* Perform the case insensitive check on the asked length */
8315 InsensitiveName
.Buffer
= Name
->Buffer
;
8316 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
8317 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
8318 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
8319 /* No match, move to the next entry */
8320 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
8325 /* Was the case insensitive covering the whole name? */
8326 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
8328 /* If connection ID also matches, that a complete match! */
8329 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
8335 /* Otherwise, we have to continue with the sensitive match.... */
8336 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
8337 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
8338 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
8339 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
8341 CmpName
= &InsensitiveName
;
8342 CmpPrefix
= &InsensitivePrefix
;
8343 CaseInsensitive
= FALSE
;
8348 CmpPrefix
= &Entry
->Prefix
;
8349 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
8352 /* Perform the compare, if there's a match, also check for connection ID */
8353 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
8355 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
8369 RxTearDownBufferingManager(
8375 return STATUS_SUCCESS
;
8384 _In_
struct _KDPC
*Dpc
,
8385 _In_opt_ PVOID DeferredContext
,
8386 _In_opt_ PVOID SystemArgument1
,
8387 _In_opt_ PVOID SystemArgument2
)
8390 LIST_ENTRY LocalList
;
8391 PLIST_ENTRY ListEntry
;
8392 PRX_WORK_ITEM WorkItem
;
8394 InitializeListHead(&LocalList
);
8396 KeAcquireSpinLockAtDpcLevel(&RxTimerLock
);
8399 /* Find any entry matching */
8400 if (!IsListEmpty(&RxTimerQueueHead
))
8402 ListEntry
= RxTimerQueueHead
.Flink
;
8405 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
8406 if (WorkItem
->LastTick
== RxTimerTickCount
)
8408 ListEntry
= ListEntry
->Flink
;
8410 RemoveEntryList(&WorkItem
->WorkQueueItem
.List
);
8411 InsertTailList(&LocalList
, &WorkItem
->WorkQueueItem
.List
);
8415 ListEntry
= ListEntry
->Flink
;
8417 } while (ListEntry
!= &RxTimerQueueHead
);
8419 /* Do we have to requeue a later execution? */
8420 Set
= !IsListEmpty(&RxTimerQueueHead
);
8422 KeReleaseSpinLockFromDpcLevel(&RxTimerLock
);
8424 /* Requeue if list wasn't empty */
8427 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
8430 /* If we had matching entries */
8431 if (!IsListEmpty(&LocalList
))
8433 /* Post them, one after another */
8434 ListEntry
= LocalList
.Flink
;
8437 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
8438 ListEntry
= ListEntry
->Flink
;
8440 WorkItem
->WorkQueueItem
.List
.Flink
= NULL
;
8441 WorkItem
->WorkQueueItem
.List
.Blink
= NULL
;
8442 RxPostToWorkerThread(WorkItem
->WorkQueueItem
.pDeviceObject
, CriticalWorkQueue
,
8443 &WorkItem
->WorkQueueItem
, WorkItem
->WorkQueueItem
.WorkerRoutine
,
8444 WorkItem
->WorkQueueItem
.Parameter
);
8446 while (ListEntry
!= &LocalList
);
8450 #ifdef RDBSS_TRACKER
8455 RxTrackerUpdateHistory(
8456 _Inout_opt_ PRX_CONTEXT RxContext
,
8457 _Inout_ PMRX_FCB MrxFcb
,
8458 _In_ ULONG Operation
,
8459 _In_ ULONG LineNumber
,
8460 _In_ PCSTR FileName
,
8461 _In_ ULONG SerialNumber
)
8464 RX_FCBTRACKER_CASES Case
;
8466 /* Check for null or special context */
8467 if (RxContext
== NULL
)
8469 Case
= RX_FCBTRACKER_CASE_NULLCONTEXT
;
8471 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
)
8473 Case
= RX_FCBTRACKER_CASE_CBS_CONTEXT
;
8475 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
8477 Case
= RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT
;
8481 ASSERT(NodeType(RxContext
) == RDBSS_NTC_RX_CONTEXT
);
8482 Case
= RX_FCBTRACKER_CASE_NORMAL
;
8485 /* If caller provided a FCB, update its history */
8489 ASSERT(NodeTypeIsFcb(Fcb
));
8491 /* Only one acquire operation, so many release operations... */
8492 if (Operation
== TRACKER_ACQUIRE_FCB
)
8494 ++Fcb
->FcbAcquires
[Case
];
8498 ++Fcb
->FcbReleases
[Case
];
8502 /* If we have a normal context, update its history about this function calls */
8503 if (Case
== RX_FCBTRACKER_CASE_NORMAL
)
8505 ULONG TrackerHistoryPointer
;
8507 /* Only one acquire operation, so many release operations... */
8508 if (Operation
== TRACKER_ACQUIRE_FCB
)
8510 InterlockedIncrement(&RxContext
->AcquireReleaseFcbTrackerX
);
8514 InterlockedDecrement(&RxContext
->AcquireReleaseFcbTrackerX
);
8517 /* We only keep track of the 32 first calls */
8518 TrackerHistoryPointer
= InterlockedExchangeAdd((volatile long *)&RxContext
->TrackerHistoryPointer
, 1);
8519 if (TrackerHistoryPointer
< RDBSS_TRACKER_HISTORY_SIZE
)
8521 RxContext
->TrackerHistory
[TrackerHistoryPointer
].AcquireRelease
= Operation
;
8522 RxContext
->TrackerHistory
[TrackerHistoryPointer
].LineNumber
= LineNumber
;
8523 RxContext
->TrackerHistory
[TrackerHistoryPointer
].FileName
= (PSZ
)FileName
;
8524 RxContext
->TrackerHistory
[TrackerHistoryPointer
].SavedTrackerValue
= RxContext
->AcquireReleaseFcbTrackerX
;
8525 RxContext
->TrackerHistory
[TrackerHistoryPointer
].Flags
= RxContext
->Flags
;
8528 /* If it's negative, then we released once more than we acquired it?! */
8529 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
>= 0);
8535 RxTrackPagingIoResource(
8536 _Inout_ PVOID Instance
,
8548 RxUndoScavengerFinalizationMarking(
8551 /* Just call internal routine with mutex held */
8552 RxAcquireScavengerMutex();
8553 RxpUndoScavengerFinalizationMarking(Instance
);
8554 RxReleaseScavengerMutex();
8561 RxUninitializeVNetRootParameters(
8562 IN PUNICODE_STRING UserName
,
8563 IN PUNICODE_STRING UserDomainName
,
8564 IN PUNICODE_STRING Password
,
8569 /* Only free what could have been allocated */
8570 if (UserName
!= NULL
)
8572 RxFreePool(UserName
);
8575 if (UserDomainName
!= NULL
)
8577 RxFreePool(UserDomainName
);
8580 if (Password
!= NULL
)
8582 RxFreePool(Password
);
8585 /* And remove the possibly set CSC agent flag */
8588 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
8597 IN RX_BLOCK_CONDITION NewConditionValue
,
8598 OUT PRX_BLOCK_CONDITION Condition
,
8599 IN OUT PLIST_ENTRY TransitionWaitList
)
8601 PRX_CONTEXT Context
;
8602 LIST_ENTRY SerializationQueue
;
8606 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
8608 /* Set the new condition */
8609 RxAcquireSerializationMutex();
8610 ASSERT(NewConditionValue
!= Condition_InTransition
);
8611 *Condition
= NewConditionValue
;
8612 /* And get the serialization queue for treatment */
8613 RxTransferList(&SerializationQueue
, TransitionWaitList
);
8614 RxReleaseSerializationMutex();
8616 /* Handle the serialization queue */
8617 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
8618 while (Context
!= NULL
)
8620 /* If the caller asked for post, post the request */
8621 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8623 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
8624 RxFsdPostRequest(Context
);
8626 /* Otherwise, wake up sleeping waiters */
8629 RxSignalSynchronousWaiter(Context
);
8632 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
8640 RxVerifyOperationIsLegal(
8641 IN PRX_CONTEXT RxContext
)
8646 PFILE_OBJECT FileObject
;
8647 PIO_STACK_LOCATION Stack
;
8651 Irp
= RxContext
->CurrentIrp
;
8652 Stack
= RxContext
->CurrentIrpSp
;
8653 FileObject
= Stack
->FileObject
;
8655 /* We'll only check stuff on opened files, this requires an IRP and a FO */
8656 if (Irp
== NULL
|| FileObject
== NULL
)
8661 /* Set no exception for breakpoint - remember whether is was already set */
8662 FlagSet
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8663 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8665 /* If we have a CCB, perform a few checks on opened file */
8666 Fobx
= RxContext
->pFobx
;
8669 PMRX_SRV_OPEN SrvOpen
;
8671 SrvOpen
= Fobx
->pSrvOpen
;
8672 if (SrvOpen
!= NULL
)
8674 UCHAR MajorFunction
;
8676 MajorFunction
= RxContext
->MajorFunction
;
8677 /* Only allow closing/cleanup operations on renamed files */
8678 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8679 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
8681 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_RENAMED
;
8682 ExRaiseStatus(STATUS_FILE_RENAMED
);
8685 /* Only allow closing/cleanup operations on deleted files */
8686 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8687 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
))
8689 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_DELETED
;
8690 ExRaiseStatus(STATUS_FILE_DELETED
);
8695 /* If that's an open operation */
8696 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
8698 PFILE_OBJECT RelatedFileObject
;
8700 /* We won't allow an open operation relative to a file to be deleted */
8701 RelatedFileObject
= FileObject
->RelatedFileObject
;
8702 if (RelatedFileObject
!= NULL
)
8706 Fcb
= RelatedFileObject
->FsContext
;
8707 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
8709 RxContext
->IoStatusBlock
.Status
= STATUS_DELETE_PENDING
;
8710 ExRaiseStatus(STATUS_DELETE_PENDING
);
8715 /* If cleanup was completed */
8716 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
8718 if (!BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
))
8720 UCHAR MajorFunction
;
8722 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
8723 MajorFunction
= Stack
->MajorFunction
;
8724 if (MajorFunction
!= IRP_MJ_CLOSE
&& MajorFunction
!= IRP_MJ_QUERY_INFORMATION
&&
8725 MajorFunction
!= IRP_MJ_SET_INFORMATION
)
8727 if ((MajorFunction
!= IRP_MJ_READ
&& MajorFunction
!= IRP_MJ_WRITE
) ||
8728 !BooleanFlagOn(Stack
->MinorFunction
, IRP_MN_COMPLETE
))
8730 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_CLOSED
;
8731 ExRaiseStatus(STATUS_FILE_CLOSED
);
8737 /* If flag was already set, don't clear it */
8740 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8748 RxWaitForStableCondition(
8749 IN PRX_BLOCK_CONDITION Condition
,
8750 IN OUT PLIST_ENTRY TransitionWaitList
,
8751 IN OUT PRX_CONTEXT RxContext
,
8752 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
8755 NTSTATUS LocalStatus
;
8759 /* Make sure to always get status */
8760 if (AsyncStatus
== NULL
)
8762 AsyncStatus
= &LocalStatus
;
8765 /* By default, it's a success */
8766 *AsyncStatus
= STATUS_SUCCESS
;
8769 /* If it's not stable, we've to wait */
8770 if (!StableCondition(*Condition
))
8772 /* Lock the mutex */
8773 RxAcquireSerializationMutex();
8774 /* Still not stable? */
8775 if (!StableCondition(*Condition
))
8777 /* Insert us in the wait list for processing on stable condition */
8778 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
8780 /* If we're asked to post on stable, don't wait, and just return pending */
8781 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8783 *AsyncStatus
= STATUS_PENDING
;
8790 RxReleaseSerializationMutex();
8792 /* We don't post on stable, so, just wait... */
8795 RxWaitSync(RxContext
);
8805 RxWorkItemDispatcher(
8808 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
8810 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
8812 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
8814 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
8822 _RxAllocatePoolWithTag(
8823 _In_ POOL_TYPE PoolType
,
8824 _In_ SIZE_T NumberOfBytes
,
8827 return ExAllocatePoolWithTagPriority(PoolType
, NumberOfBytes
, Tag
, LowPoolPriority
);
8838 ExFreePoolWithTag(Buffer
, 0);
8850 ExFreePoolWithTag(Buffer
, Tag
);
8856 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
8858 #ifdef RDBSS_TRACKER
8860 _In_ ULONG LineNumber
,
8861 _In_ PCSTR FileName
,
8862 _In_ ULONG SerialNumber
8867 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
8871 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
8873 SpecialContext
= FALSE
;
8874 ContextIsPresent
= FALSE
;
8875 /* Check for special context */
8876 if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
|| RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
8878 SpecialContext
= TRUE
;
8881 /* We don't handle buffering state change yet... */
8882 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
8883 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
8888 /* Nor special contexts */
8894 /* If we don't have a context, assume we can wait! */
8895 if (RxContext
== NULL
)
8901 /* That said: we have a real context! */
8902 ContextIsPresent
= TRUE
;
8904 /* If we've been cancelled in between, give up */
8905 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
8906 if (!NT_SUCCESS(Status
))
8912 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8917 /* Assume we cannot lock */
8918 Status
= STATUS_LOCK_NOT_GRANTED
;
8920 /* Lock according to what the caller asked */
8923 case FCB_MODE_EXCLUSIVE
:
8924 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
8927 case FCB_MODE_SHARED
:
8928 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
8931 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
8932 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
8936 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
8937 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
8944 Status
= STATUS_SUCCESS
;
8945 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
8947 /* Handle paging write - not implemented */
8948 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
8954 /* And break, that cool! */
8960 /* If it failed, return immediately */
8961 if (!NT_SUCCESS(Status
))
8967 /* If we don't have to check for valid operation, job done, nothing more to do */
8968 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
8970 if (NT_SUCCESS(Status
))
8972 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
8978 /* Verify operation */
8981 RxVerifyOperationIsLegal(RxContext
);
8985 /* If it failed, release lock and fail */
8986 if (_SEH2_AbnormalTermination())
8988 ExReleaseResourceLite(Fcb
->Header
.Resource
);
8989 Status
= STATUS_LOCK_NOT_GRANTED
;
8994 if (NT_SUCCESS(Status
))
8996 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
8999 DPRINT("Status: %x\n", Status
);
9007 __RxItsTheSameContext(
9008 _In_ PRX_CONTEXT RxContext
,
9009 _In_ ULONG CapturedRxContextSerialNumber
,
9013 /* Check we have a context with the same serial number */
9014 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
9015 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
9018 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
9024 _Inout_opt_ PRX_CONTEXT RxContext
,
9025 _Inout_ PMRX_FCB MrxFcb
9026 #ifdef RDBSS_TRACKER
9028 _In_ ULONG LineNumber
,
9029 _In_ PCSTR FileName
,
9030 _In_ ULONG SerialNumber
9034 BOOLEAN IsExclusive
, BufferingPending
;
9036 RxAcquireSerializationMutex();
9038 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
9039 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
9041 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9042 * then just release the FCB
9044 if (!BufferingPending
|| !IsExclusive
)
9046 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
9047 LineNumber
, FileName
, SerialNumber
);
9048 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
9051 RxReleaseSerializationMutex();
9053 /* And finally leave */
9054 if (!BufferingPending
|| !IsExclusive
)
9059 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
9061 /* Otherwise, handle buffering state and release */
9062 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
9064 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
9065 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
9069 __RxReleaseFcbForThread(
9070 _Inout_opt_ PRX_CONTEXT RxContext
,
9071 _Inout_ PMRX_FCB MrxFcb
,
9072 _In_ ERESOURCE_THREAD ResourceThreadId
9073 #ifdef RDBSS_TRACKER
9075 _In_ ULONG LineNumber
,
9076 _In_ PCSTR FileName
,
9077 _In_ ULONG SerialNumber
9081 BOOLEAN IsExclusive
, BufferingPending
;
9083 RxAcquireSerializationMutex();
9085 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
9086 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
9088 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9089 * then just release the FCB
9091 if (!BufferingPending
|| !IsExclusive
)
9093 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
9094 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
9095 LineNumber
, FileName
, SerialNumber
);
9096 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
9099 RxReleaseSerializationMutex();
9101 /* And finally leave */
9102 if (!BufferingPending
|| !IsExclusive
)
9107 /* Otherwise, handle buffering state and release */
9108 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
9109 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
9110 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);