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
));
504 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
505 NonPagedFcb
->FcbBackPointer
= Fcb
;
508 Fcb
->InternalSrvOpen
= SrvOpen
;
509 Fcb
->InternalFobx
= Fobx
;
511 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
512 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
513 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
515 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
517 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
520 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
522 InterlockedIncrement(&RxNumberOfActiveFcbs
);
523 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
525 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
526 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
529 DPRINT("Allocated %p\n", Buffer
);
539 NODE_TYPE_CODE NodeType
,
540 PMINIRDR_DISPATCH MRxDispatch
,
543 ULONG Tag
, ObjectSize
;
544 PVOID Object
, *Extension
;
545 PRX_PREFIX_ENTRY PrefixEntry
;
546 USHORT StructSize
, ExtensionSize
;
550 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
554 case RDBSS_NTC_SRVCALL
:
555 Tag
= RX_SRVCALL_POOLTAG
;
556 StructSize
= sizeof(SRV_CALL
);
557 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
559 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
563 case RDBSS_NTC_NETROOT
:
564 Tag
= RX_NETROOT_POOLTAG
;
565 StructSize
= sizeof(NET_ROOT
);
566 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
568 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
572 case RDBSS_NTC_V_NETROOT
:
573 Tag
= RX_V_NETROOT_POOLTAG
;
574 StructSize
= sizeof(V_NET_ROOT
);
575 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
577 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
586 /* Now, allocate the object */
587 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
588 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
594 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
596 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
599 case RDBSS_NTC_SRVCALL
:
600 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
601 Extension
= &((PSRV_CALL
)Object
)->Context
;
602 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
605 case RDBSS_NTC_NETROOT
:
606 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
607 Extension
= &((PNET_ROOT
)Object
)->Context
;
608 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
611 case RDBSS_NTC_V_NETROOT
:
612 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
613 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
621 /* Set the prefix table unicode string */
622 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
623 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
624 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
625 PrefixEntry
->Prefix
.Length
= NameLength
;
626 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
627 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
629 /* Return the extension if we are asked to manage it */
630 if (ExtensionSize
!= 0)
632 *Extension
= Add2Ptr(Object
, StructSize
);
651 /* If we're not asked to continue, just stop the system */
652 if (!RxContinueFromAssert
)
654 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
657 /* Otherwise, capture context to offer the user to dump it */
658 RtlCaptureContext(&Context
);
660 /* Loop until the user hits 'i' */
663 /* If no file provided, use empty name */
669 /* If no message provided, use empty one */
675 /* Display the message */
676 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
677 /* And ask the user */
678 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
679 /* If he asks for ignore, quit
680 * In case of invalid input, ask again
682 if (Response
[0] != 'B' && Response
[0] != 'b')
684 if (Response
[0] == 'I' || Response
[0] == 'i')
692 /* Break: offer the user to dump the context and break */
693 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
696 /* Continue looping, so that after dump, execution can continue (with ignore) */
705 RxBootstrapWorkerThreadDispatcher(
708 PRX_WORK_QUEUE RxWorkQueue
;
712 RxWorkQueue
= WorkQueue
;
713 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
721 RxChangeBufferingState(
724 BOOLEAN ComputeNewState
)
727 NTSTATUS Status
, MiniStatus
;
728 ULONG NewBufferingState
, OldBufferingState
;
732 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen
, Context
, ComputeNewState
);
734 Fcb
= (PFCB
)SrvOpen
->pFcb
;
735 ASSERT(NodeTypeIsFcb(Fcb
));
736 /* First of all, mark that buffering state is changing */
737 SetFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
740 Status
= STATUS_SUCCESS
;
743 /* If we're asked to compute a new state, ask the mini-rdr for it */
746 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxComputeNewBufferingState
,
747 ((PMRX_SRV_OPEN
)SrvOpen
, Context
, &NewBufferingState
));
748 if (MiniStatus
!= STATUS_SUCCESS
)
750 NewBufferingState
= 0;
755 /* If not, use SRV_OPEN state */
756 NewBufferingState
= SrvOpen
->BufferingFlags
;
759 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
760 if ((Fcb
->ShareAccess
.SharedRead
+ Fcb
->ShareAccess
.SharedWrite
+ Fcb
->ShareAccess
.SharedDelete
) == 0 && !ComputeNewState
)
762 SetFlag(NewBufferingState
, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES
);
765 /* If there's a lock operation to complete, clear that flag */
766 if (Fcb
->OutstandingLockOperationsCount
!= 0)
768 ClearFlag(NewBufferingState
, FCB_STATE_LOCK_BUFFERING_ENABLED
);
771 /* Get the old state */
772 OldBufferingState
= Fcb
->FcbState
& FCB_STATE_BUFFERING_STATE_MASK
;
773 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState
, NewBufferingState
, SrvOpen
->BufferingFlags
);
775 /* If we're dropping write cache, then flush the FCB */
776 if (BooleanFlagOn(OldBufferingState
, FCB_STATE_WRITECACHING_ENABLED
) &&
777 !BooleanFlagOn(NewBufferingState
, FCB_STATE_WRITECACHING_ENABLED
))
779 DPRINT("Flushing\n");
781 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
784 /* If we're dropping read cache, then purge */
785 if (Fcb
->UncleanCount
== 0 ||
786 (BooleanFlagOn(OldBufferingState
, FCB_STATE_READCACHING_ENABLED
) &&
787 !BooleanFlagOn(NewBufferingState
, FCB_STATE_READCACHING_ENABLED
)) ||
788 BooleanFlagOn(NewBufferingState
, FCB_STATE_DELETE_ON_CLOSE
))
792 if (!NT_SUCCESS(Status
))
794 DPRINT("Previous flush failed with status: %lx\n", Status
);
797 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, TRUE
);
800 /* If there's already a change pending in SRV_OPEN */
801 if (ComputeNewState
&& BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
803 /* If there's a FOBX at least */
804 if (!IsListEmpty(&SrvOpen
->FobxList
))
806 PRX_CONTEXT RxContext
;
808 /* Create a fake context to pass to the mini-rdr */
809 RxContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
810 if (RxContext
!= NULL
)
814 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
816 /* Give the first FOBX */
817 Fobx
= CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
);
818 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
819 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
821 /* If there was a delayed close, perform it */
822 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
824 DPRINT("Oplock break close for %p\n", SrvOpen
);
826 RxCloseAssociatedSrvOpen(Fobx
, RxContext
);
828 /* Otherwise, inform the mini-rdr about completion */
831 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxCompleteBufferingStateChangeRequest
,
832 (RxContext
, (PMRX_SRV_OPEN
)SrvOpen
, Context
));
836 RxDereferenceAndDeleteRxContext(RxContext
);
841 /* Set the new state */
842 Fcb
->FcbState
^= (NewBufferingState
^ Fcb
->FcbState
) & FCB_STATE_BUFFERING_STATE_MASK
;
846 /* Job done, clear the flag */
847 ClearFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
849 if (!BooleanFlagOn(NewBufferingState
, FCB_STATE_FILETIMECACHEING_ENABLED
))
851 ClearFlag(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
);
860 RxCheckVNetRootCredentials(
861 PRX_CONTEXT RxContext
,
862 PV_NET_ROOT VNetRoot
,
864 PUNICODE_STRING UserName
,
865 PUNICODE_STRING UserDomain
,
866 PUNICODE_STRING Password
,
871 /* If that's a UNC name, there's nothing to process */
872 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
873 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
876 return STATUS_MORE_PROCESSING_REQUIRED
;
879 /* Compare the logon ID in the VNetRoot with the one provided */
880 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
882 return STATUS_MORE_PROCESSING_REQUIRED
;
885 /* No credential provided? That's OK */
886 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
888 return STATUS_SUCCESS
;
893 return STATUS_NOT_IMPLEMENTED
;
905 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
907 ASSERT(Context
!= NULL
);
908 ASSERT(Context
->CurrentIrp
!= NULL
);
909 Irp
= Context
->CurrentIrp
;
911 /* Debug what the caller asks for */
912 if (Context
->LoudCompletionString
!= NULL
)
914 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
915 /* Does the user asks to stop on failed completion */
916 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
918 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
922 /* Complete for real */
923 Context
->CurrentIrp
= NULL
;
924 RxCompleteRequest_Real(Context
, Irp
, Status
);
926 DPRINT("Status: %lx\n", Status
);
934 RxCompleteRequest_Real(
935 IN PRX_CONTEXT RxContext
,
941 PIO_STACK_LOCATION Stack
;
943 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
945 /* Nothing to complete, just free context */
948 DPRINT("NULL IRP for %p\n", RxContext
);
949 if (RxContext
!= NULL
)
951 RxDereferenceAndDeleteRxContext_Real(RxContext
);
957 /* Remove cancel routine */
958 IoAcquireCancelSpinLock(&OldIrql
);
959 IoSetCancelRoutine(Irp
, NULL
);
960 IoReleaseCancelSpinLock(OldIrql
);
962 /* Select the boost, given the success/paging operation */
963 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
965 Boost
= IO_DISK_INCREMENT
;
969 Irp
->IoStatus
.Information
= 0;
970 Boost
= IO_NO_INCREMENT
;
972 Irp
->IoStatus
.Status
= Status
;
974 if (RxContext
!= NULL
)
976 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
977 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
979 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
980 RxContext
->MinorFunction
, RxContext
, Irp
,
981 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
985 /* If that's an opening, there might be a canonical name allocated,
986 * if completion isn't pending, release it
988 Stack
= IoGetCurrentIrpStackLocation(Irp
);
989 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
992 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
994 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
997 RxpPrepareCreateContextForReuse(RxContext
);
998 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
1001 /* If it's a write, validate the correct behavior of the operation */
1002 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
1004 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
1006 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
1010 /* If it's pending, make sure IRP is marked as such */
1011 if (RxContext
!= NULL
)
1013 if (RxContext
->PendingReturned
)
1015 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
1020 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
1021 IoCompleteRequest(Irp
, Boost
);
1023 /* If there's a context, dereference it */
1024 if (RxContext
!= NULL
)
1026 RxDereferenceAndDeleteRxContext_Real(RxContext
);
1034 RxCompleteSrvOpenKeyAssociation(
1035 IN OUT PSRV_OPEN SrvOpen
)
1039 SrvCall
= (PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
;
1040 /* Only handle requests if opening was a success */
1041 if (SrvOpen
->Condition
== Condition_Good
)
1044 BOOLEAN ProcessChange
;
1045 LIST_ENTRY DiscardedRequests
;
1047 /* Initialize our discarded requests list */
1048 InitializeListHead(&DiscardedRequests
);
1050 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
1052 /* Transfer our requests in the SRV_CALL */
1053 RxTransferList(&SrvCall
->BufferingManager
.SrvOpenLists
[0], &SrvOpen
->SrvOpenKeyList
);
1055 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
1056 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
1058 /* Dispatch requests and get the discarded ones */
1059 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &DiscardedRequests
);
1061 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
1063 /* Is there still anything to process? */
1064 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
1065 if (IsListEmpty(&SrvCall
->BufferingManager
.HandlerList
))
1067 ProcessChange
= FALSE
;
1071 ProcessChange
= (SrvCall
->BufferingManager
.HandlerInactive
== FALSE
);
1074 SrvCall
->BufferingManager
.HandlerInactive
= TRUE
;
1077 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
1079 /* Yes? Go ahead! */
1082 RxReferenceSrvCall(SrvCall
);
1083 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
1084 &SrvCall
->BufferingManager
.HandlerWorkItem
,
1085 RxProcessChangeBufferingStateRequests
, SrvCall
);
1088 /* And discard left requests */
1089 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests
);
1093 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
1102 IN PRX_CONTEXT RxContext
,
1103 IN PSRV_CALL SrvCall
,
1104 IN PNET_ROOT NetRoot
,
1105 IN PV_NET_ROOT VirtualNetRoot
,
1106 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1109 PRX_PREFIX_TABLE PrefixTable
;
1110 PMRX_CREATENETROOT_CONTEXT Context
;
1111 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
1115 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
1116 VirtualNetRoot
, LockHoldingState
);
1118 /* Validate the lock is exclusively held */
1119 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
1120 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1122 /* Allocate the context */
1123 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
1124 if (Context
== NULL
)
1126 return STATUS_INSUFFICIENT_RESOURCES
;
1129 /* We can release lock now */
1130 RxReleasePrefixTableLock(PrefixTable
);
1131 *LockHoldingState
= LHS_LockNotHeld
;
1133 RootCondition
= Condition_Bad
;
1134 VRootCondition
= Condition_Bad
;
1136 /* Initialize the context */
1137 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
1138 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
1139 Context
->RxContext
= RxContext
;
1140 Context
->pVNetRoot
= VirtualNetRoot
;
1141 Context
->Callback
= RxCreateNetRootCallBack
;
1143 /* And call the mini-rdr */
1144 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
1145 if (Status
== STATUS_PENDING
)
1147 /* Wait for the mini-rdr to be done */
1148 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1149 /* Update the structures condition according to mini-rdr return */
1150 if (NT_SUCCESS(Context
->NetRootStatus
))
1152 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
1154 RootCondition
= Condition_Good
;
1155 VRootCondition
= Condition_Good
;
1156 Status
= STATUS_SUCCESS
;
1160 RootCondition
= Condition_Good
;
1161 Status
= Context
->VirtualNetRootStatus
;
1166 Status
= Context
->VirtualNetRootStatus
;
1167 if (NT_SUCCESS(Status
))
1169 Status
= Context
->NetRootStatus
;
1175 /* It has to return STATUS_PENDING! */
1179 /* Acquire lock again - for caller lock status will remain unchanged */
1180 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
1181 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
1182 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1184 /* Do the transition to the condition got from mini-rdr */
1185 RxTransitionNetRoot(NetRoot
, RootCondition
);
1186 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
1188 /* Context is not longer needed */
1189 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
1191 DPRINT("Status: %x\n", Status
);
1201 IN PRX_CONTEXT RxContext
,
1202 IN PSRV_CALL SrvCall
,
1203 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1206 PRX_PREFIX_TABLE PrefixTable
;
1207 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1208 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1209 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
1213 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
1215 /* Validate the lock is exclusively held */
1216 RxDeviceObject
= RxContext
->RxDeviceObject
;
1217 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
1218 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1220 /* Allocate the context for mini-rdr */
1221 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
1222 if (Calldown
== NULL
)
1224 SrvCall
->Context
= NULL
;
1225 SrvCall
->Condition
= Condition_Bad
;
1226 RxReleasePrefixTableLock(PrefixTable
);
1227 *LockHoldingState
= LHS_LockNotHeld
;
1228 return STATUS_INSUFFICIENT_RESOURCES
;
1232 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
1234 SrvCall
->Context
= NULL
;
1235 SrvCall
->Condition
= Condition_InTransition
;
1237 RxReleasePrefixTableLock(PrefixTable
);
1238 *LockHoldingState
= LHS_LockNotHeld
;
1240 CallbackContext
= &Calldown
->CallbackContexts
[0];
1241 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
1242 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
1243 CallbackContext
->SrvCalldownStructure
= Calldown
;
1244 CallbackContext
->CallbackContextOrdinal
= 0;
1245 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
1247 RxReferenceSrvCall(SrvCall
);
1249 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1250 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1252 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
1256 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
1259 Calldown
->NumberToWait
= 1;
1260 Calldown
->NumberRemaining
= 1;
1261 Calldown
->RxContext
= RxContext
;
1262 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
1263 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
1264 Calldown
->BestFinisher
= NULL
;
1265 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
1266 InitializeListHead(&Calldown
->SrvCalldownList
);
1268 /* Call the mini-rdr */
1269 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
1270 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
1271 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
1272 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
1273 /* It has to return STATUS_PENDING! */
1274 ASSERT(Status
== STATUS_PENDING
);
1276 /* No async, start completion */
1277 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1279 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1281 /* Finish construction - we'll notify mini-rdr it's the winner */
1282 Status
= RxFinishSrvCallConstruction(Calldown
);
1283 if (!NT_SUCCESS(Status
))
1285 RxReleasePrefixTableLock(PrefixTable
);
1286 *LockHoldingState
= LHS_LockNotHeld
;
1290 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
1291 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1295 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
1303 RxConstructVirtualNetRoot(
1304 IN PRX_CONTEXT RxContext
,
1305 IN PUNICODE_STRING CanonicalName
,
1306 IN NET_ROOT_TYPE NetRootType
,
1307 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
1308 OUT PLOCK_HOLDING_STATE LockHoldingState
,
1309 OUT PRX_CONNECTION_ID RxConnectionId
)
1312 PV_NET_ROOT VNetRoot
;
1313 RX_BLOCK_CONDITION Condition
;
1314 UNICODE_STRING LocalNetRootName
, FilePathName
;
1318 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1321 Condition
= Condition_Bad
;
1322 /* Before creating the VNetRoot, try to find the appropriate connection */
1323 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
1324 &LocalNetRootName
, &FilePathName
,
1325 LockHoldingState
, RxConnectionId
);
1326 /* Found and active */
1327 if (Status
== STATUS_CONNECTION_ACTIVE
)
1329 /* We need a new VNetRoot */
1330 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
1331 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
1332 if (VNetRoot
!= NULL
)
1334 RxReferenceVNetRoot(VNetRoot
);
1337 /* Dereference previous VNetRoot */
1338 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
1339 /* Reset and start construct (new structures will replace old ones) */
1340 RxContext
->Create
.pSrvCall
= NULL
;
1341 RxContext
->Create
.pNetRoot
= NULL
;
1342 RxContext
->Create
.pVNetRoot
= NULL
;
1344 /* Construct new NetRoot */
1345 if (VNetRoot
!= NULL
)
1347 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
1348 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
1349 if (NT_SUCCESS(Status
))
1351 Condition
= Condition_Good
;
1356 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1361 /* If it failed creating the connection, leave */
1362 if (Status
!= STATUS_SUCCESS
)
1364 if (*LockHoldingState
!= LHS_LockNotHeld
)
1366 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1367 *LockHoldingState
= LHS_LockNotHeld
;
1370 *VirtualNetRootPointer
= VNetRoot
;
1371 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1375 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1377 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1378 Condition
= Condition_Good
;
1381 /* We have a non stable VNetRoot - transition it */
1382 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1384 RxTransitionVNetRoot(VNetRoot
, Condition
);
1387 /* If recreation failed */
1388 if (Status
!= STATUS_SUCCESS
)
1390 /* Dereference potential VNetRoot */
1391 if (VNetRoot
!= NULL
)
1393 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1394 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1399 if (*LockHoldingState
!= LHS_LockNotHeld
)
1401 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1402 *LockHoldingState
= LHS_LockNotHeld
;
1406 *VirtualNetRootPointer
= VNetRoot
;
1410 /* Return the allocated VNetRoot */
1411 *VirtualNetRootPointer
= VNetRoot
;
1420 IN PRX_CONTEXT RxContext
,
1421 IN PV_NET_ROOT VNetRoot
,
1422 IN PUNICODE_STRING Name
)
1428 NODE_TYPE_CODE NodeType
;
1429 PIO_STACK_LOCATION Stack
;
1430 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1434 /* We need a decent VNetRoot */
1435 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1437 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1438 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1439 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1441 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1442 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1444 Stack
= RxContext
->CurrentIrpSp
;
1446 /* Do we need to create a fake FCB? Like for renaming */
1447 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1448 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1449 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1451 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1452 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1454 /* Allocate the FCB */
1455 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1456 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1462 /* Initialize the FCB */
1463 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1464 Fcb
->RxDeviceObject
= RxDeviceObject
;
1465 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1466 Fcb
->VNetRoot
= VNetRoot
;
1467 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1469 InitializeListHead(&Fcb
->SrvOpenList
);
1470 Fcb
->SrvOpenListVersion
= 0;
1472 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1473 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1474 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1475 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1476 NetRoot
->InnerNamePrefix
.Length
);
1477 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1479 /* Copy back parameters from RxContext */
1480 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1482 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1485 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1487 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1489 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1492 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1494 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1497 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1498 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1500 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1501 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1503 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1504 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1506 /* Fake FCB doesn't go in prefix table */
1509 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1510 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1511 DPRINT("Fake FCB: %p\n", Fcb
);
1515 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1518 RxReferenceVNetRoot(VNetRoot
);
1519 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1521 Fcb
->ulFileSizeVersion
= 0;
1523 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1524 RxReferenceNetFcb(Fcb
);
1535 OUT PRX_CONTEXT RxContext
,
1536 IN PMRX_SRV_OPEN MrxSrvOpen
)
1547 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1548 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1549 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1550 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1553 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1554 /* Can we use pre-allocated FOBX? */
1555 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1557 Fobx
= Fcb
->InternalFobx
;
1558 /* Call allocate to initialize the FOBX */
1559 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1560 /* Mark it used now */
1561 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1562 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1564 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1566 Fobx
= SrvOpen
->InternalFobx
;
1567 /* Call allocate to initialize the FOBX */
1568 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1569 /* Mark it used now */
1570 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1571 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1575 /* Last case, we cannot, allocate a FOBX */
1576 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1580 /* Allocation failed! */
1587 Fobx
->Flags
= Flags
;
1589 /* Initialize throttling */
1590 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1591 if (NetRoot
!= NULL
)
1593 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1595 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1596 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1597 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1599 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1601 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1602 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1603 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1607 /* Propagate flags fron RxContext */
1608 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1610 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1613 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1615 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1619 Fobx
->FobxSerialNumber
= 0;
1620 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1621 Fobx
->NodeReferenceCount
= 1;
1622 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1624 RxReferenceSrvOpen(SrvOpen
);
1625 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1627 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1628 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1629 InitializeListHead(&Fobx
->ClosePendingList
);
1631 Fobx
->CloseTime
.QuadPart
= 0;
1632 Fobx
->fOpenCountDecremented
= FALSE
;
1634 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1636 return (PMRX_FOBX
)Fobx
;
1644 IN PSRV_CALL SrvCall
,
1645 IN PUNICODE_STRING Name
,
1646 IN ULONG NetRootFlags
,
1647 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1650 USHORT CaseInsensitiveLength
;
1651 PRX_PREFIX_TABLE PrefixTable
;
1653 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1657 /* We need a SRV_CALL */
1658 ASSERT(SrvCall
!= NULL
);
1660 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1661 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1663 /* Get name length */
1664 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1665 if (CaseInsensitiveLength
> MAXUSHORT
)
1670 /* Allocate the NetRoot */
1671 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1672 CaseInsensitiveLength
);
1673 if (NetRoot
== NULL
)
1678 /* Construct name */
1679 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1680 Name
->Buffer
, Name
->Length
);
1681 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1683 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1684 SrvCall
->PrefixEntry
.Prefix
.Length
);
1687 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1689 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1691 /* Inisert in prefix table */
1692 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1693 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1696 /* Prepare the FCB table */
1697 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1699 InitializeListHead(&NetRoot
->TransitionWaitList
);
1700 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1701 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1703 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1705 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1706 NetRoot
->Flags
|= NetRootFlags
;
1707 NetRoot
->DiskParameters
.ClusterSize
= 1;
1708 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1709 NetRoot
->SrvCall
= SrvCall
;
1711 RxReferenceSrvCall(SrvCall
);
1713 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1722 RxCreateNetRootCallBack(
1723 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1727 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1737 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1738 IN ULONG InitialContextFlags
)
1741 PRX_CONTEXT Context
;
1743 ASSERT(RxDeviceObject
!= NULL
);
1745 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1748 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1750 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1752 /* Allocate the context from our lookaside list */
1753 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1754 if (Context
== NULL
)
1760 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1762 /* It was allocated on NP pool, keep track of it! */
1763 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
1764 /* And initialize it */
1765 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1766 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1768 /* Add it to our global list */
1769 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1770 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1771 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1773 DPRINT("Context: %p\n", Context
);
1782 IN PRX_CONTEXT RxContext
,
1783 IN PUNICODE_STRING Name
,
1784 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1785 IN PRX_CONNECTION_ID RxConnectionId
)
1792 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1794 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1796 /* Get the name length */
1797 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1798 if (InnerNamePrefix
!= NULL
)
1800 NameLength
+= InnerNamePrefix
->Length
;
1803 /* Allocate the object */
1804 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1805 if (SrvCall
== NULL
)
1811 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1812 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1813 RxInitializeBufferingManager(SrvCall
);
1814 InitializeListHead(&SrvCall
->TransitionWaitList
);
1815 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1816 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1817 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1818 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1819 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1820 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1821 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1822 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1824 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1833 RxCreateSrvCallCallBack(
1834 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1838 PRX_CONTEXT RxContext
;
1839 ULONG NumberRemaining
;
1840 BOOLEAN StartDispatcher
;
1841 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1843 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1845 /* Get our context structures */
1846 Calldown
= Context
->SrvCalldownStructure
;
1847 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1849 /* If it is a success, that's the winner */
1850 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1851 if (Context
->Status
== STATUS_SUCCESS
)
1853 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1854 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1856 NumberRemaining
= --Calldown
->NumberRemaining
;
1857 SrvCall
->Status
= Context
->Status
;
1858 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1860 /* Still some to ask, keep going */
1861 if (NumberRemaining
!= 0)
1866 /* If that's not async, signal we're done */
1867 RxContext
= Calldown
->RxContext
;
1868 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1870 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1873 /* If that's a mailslot, finish construction, no more to do */
1874 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1876 RxFinishSrvCallConstruction(Calldown
);
1880 /* Queue our finish call for delayed completion */
1881 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1882 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1883 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1884 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1885 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1887 /* If we have to start dispatcher, go ahead */
1888 if (StartDispatcher
)
1892 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1893 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1894 if (!NT_SUCCESS(Status
))
1896 /* It failed - run it manually.... */
1897 RxFinishSrvCallConstructionDispatcher(NULL
);
1907 IN PV_NET_ROOT VNetRoot
,
1916 ASSERT(NodeTypeIsFcb(Fcb
));
1917 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1919 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1923 SrvOpen
= Fcb
->InternalSrvOpen
;
1924 /* Check whethet we have to allocate a new SRV_OPEN */
1925 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1926 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1927 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1930 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1931 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1936 /* Otherwise, just use internal one and initialize it */
1937 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1938 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1939 Fcb
->InternalSrvOpen
);
1940 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1941 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1944 /* If SrvOpen was properly allocated, initialize it */
1945 if (SrvOpen
!= NULL
)
1947 SrvOpen
->Flags
= Flags
;
1948 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1949 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1950 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1951 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1952 SrvOpen
->NodeReferenceCount
= 1;
1954 RxReferenceVNetRoot(VNetRoot
);
1955 RxReferenceNetFcb(Fcb
);
1957 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1958 ++Fcb
->SrvOpenListVersion
;
1960 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1961 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1962 InitializeListHead(&SrvOpen
->FobxList
);
1963 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1968 if (_SEH2_AbnormalTermination())
1970 if (SrvOpen
!= NULL
)
1972 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1978 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1991 IN PRX_CONTEXT RxContext
,
1992 IN PNET_ROOT NetRoot
,
1993 IN PUNICODE_STRING CanonicalName
,
1994 IN PUNICODE_STRING LocalNetRootName
,
1995 IN PUNICODE_STRING FilePath
,
1996 IN PRX_CONNECTION_ID RxConnectionId
)
1999 PV_NET_ROOT VNetRoot
;
2000 USHORT CaseInsensitiveLength
;
2004 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
2005 LocalNetRootName
, FilePath
, RxConnectionId
);
2007 /* Lock must be held exclusively */
2008 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
2010 /* Check for overflow */
2011 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
2016 /* Get name length and allocate VNetRoot */
2017 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
2018 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
2019 CaseInsensitiveLength
);
2020 if (VNetRoot
== NULL
)
2025 /* Initialize its connection parameters */
2026 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
2027 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
2028 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
2029 if (!NT_SUCCESS(Status
))
2031 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
2032 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
2033 RxFreeObject(VNetRoot
);
2039 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2041 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
2042 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
2043 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
2044 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
2046 InitializeListHead(&VNetRoot
->TransitionWaitList
);
2047 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
2049 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
2053 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
2055 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
2059 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
2062 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
2064 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
2070 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
2073 /* Insert in prefix table */
2074 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
2075 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
2078 RxReferenceNetRoot(NetRoot
);
2079 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
2082 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
2083 VNetRoot
->UpperFinalizationDone
= FALSE
;
2084 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
2085 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2087 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
2088 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
2098 IN OUT PVOID Instance
,
2099 IN LOCK_HOLDING_STATE LockHoldingState
)
2102 NODE_TYPE_CODE NodeType
;
2103 PNODE_TYPE_AND_SIZE Node
;
2107 RxAcquireScavengerMutex();
2109 /* Check we have a node we can handle */
2110 NodeType
= NodeType(Instance
);
2111 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
2112 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
2113 (NodeType
== RDBSS_NTC_FOBX
));
2115 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
2116 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
2117 ASSERT(RefCount
>= 0);
2119 /* Trace refcount */
2122 case RDBSS_NTC_SRVCALL
:
2123 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
2126 case RDBSS_NTC_NETROOT
:
2127 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
2130 case RDBSS_NTC_V_NETROOT
:
2131 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
2134 case RDBSS_NTC_SRVOPEN
:
2135 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
2138 case RDBSS_NTC_FOBX
:
2139 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
2147 /* No need to free - still in use */
2150 RxReleaseScavengerMutex();
2154 /* We have to be locked exclusively */
2155 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
2157 if ((NodeType
== RDBSS_NTC_FOBX
&& RefCount
== 0) ||
2158 (NodeType
>= RDBSS_NTC_SRVCALL
&& NodeType
<= RDBSS_NTC_V_NETROOT
))
2160 RxpMarkInstanceForScavengedFinalization(Instance
);
2163 RxReleaseScavengerMutex();
2168 if (BooleanFlagOn(NodeType
, RX_SCAVENGER_MASK
))
2170 RxpUndoScavengerFinalizationMarking(Instance
);
2174 RxReleaseScavengerMutex();
2176 /* Now, deallocate the memory */
2179 case RDBSS_NTC_SRVCALL
:
2183 SrvCall
= (PSRV_CALL
)Instance
;
2185 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
2186 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
2187 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
2191 case RDBSS_NTC_NETROOT
:
2195 NetRoot
= (PNET_ROOT
)Instance
;
2197 ASSERT(NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2198 ASSERT(RxIsPrefixTableLockAcquired(NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2199 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2203 case RDBSS_NTC_V_NETROOT
:
2205 PV_NET_ROOT VNetRoot
;
2207 VNetRoot
= (PV_NET_ROOT
)Instance
;
2209 ASSERT(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2210 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2211 RxFinalizeVNetRoot(VNetRoot
, TRUE
, TRUE
);
2215 case RDBSS_NTC_SRVOPEN
:
2219 SrvOpen
= (PSRV_OPEN
)Instance
;
2221 ASSERT(RxIsFcbAcquired(SrvOpen
->Fcb
));
2222 if (SrvOpen
->OpenCount
== 0)
2224 RxFinalizeSrvOpen(SrvOpen
, FALSE
, FALSE
);
2229 case RDBSS_NTC_FOBX
:
2233 Fobx
= (PFOBX
)Instance
;
2235 ASSERT(RxIsFcbAcquired(Fobx
->SrvOpen
->Fcb
));
2236 RxFinalizeNetFobx(Fobx
, TRUE
, FALSE
);
2247 RxDereferenceAndDeleteRxContext_Real(
2248 IN PRX_CONTEXT RxContext
)
2253 PRX_CONTEXT StopContext
= NULL
;
2255 /* Make sure we really have a context */
2256 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
2257 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
2258 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
2259 /* If refcount is 0, start releasing stuff that needs spinlock held */
2262 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2264 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
2266 /* If that's stop context from DO, remove it */
2267 RxDeviceObject
= RxContext
->RxDeviceObject
;
2268 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
2270 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
2274 /* Remove it from the list */
2275 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
2276 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
2277 RemoveEntryList(&RxContext
->ContextListEntry
);
2279 /* If that was the last active context, save the stop context */
2280 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
2282 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
2284 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
2289 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
2291 /* Now, deal with what can be done without spinlock held */
2294 /* Refcount shouldn't have changed */
2295 ASSERT(RxContext
->ReferenceCount
== 0);
2296 /* Reset everything that can be */
2297 RxPrepareContextForReuse(RxContext
);
2299 #ifdef RDBSS_TRACKER
2300 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
2302 /* If that was the last active, set the event */
2303 if (StopContext
!= NULL
)
2305 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
2306 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
2310 /* Is ShadowCrit still owned? Shouldn't happen! */
2311 if (RxContext
->ShadowCritOwner
!= 0)
2313 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
2318 /* If it was allocated, free it */
2321 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
2328 RxDispatchChangeBufferingStateRequests(
2339 RxDispatchToWorkerThread(
2340 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
2341 IN WORK_QUEUE_TYPE WorkQueueType
,
2342 IN PRX_WORKERTHREAD_ROUTINE Routine
,
2346 PRX_WORK_DISPATCH_ITEM DispatchItem
;
2348 /* Allocate a bit of context */
2349 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
2350 if (DispatchItem
== NULL
)
2352 return STATUS_INSUFFICIENT_RESOURCES
;
2355 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2356 DispatchItem
->DispatchRoutine
= Routine
;
2357 DispatchItem
->DispatchRoutineParameter
= pContext
;
2358 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
2359 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
2362 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, &DispatchItem
->WorkQueueItem
);
2363 if (!NT_SUCCESS(Status
))
2365 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
2366 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
2369 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
2378 RxExclusivePrefixTableLockToShared(
2379 PRX_PREFIX_TABLE Table
)
2383 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
2390 RxExtractServerName(
2391 IN PUNICODE_STRING FilePathName
,
2392 OUT PUNICODE_STRING SrvCallName
,
2393 OUT PUNICODE_STRING RestOfName
)
2399 ASSERT(SrvCallName
!= NULL
);
2401 /* SrvCall name will start from the begin up to the first separator */
2402 SrvCallName
->Buffer
= FilePathName
->Buffer
;
2403 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2405 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2411 /* Compute length */
2412 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
2413 SrvCallName
->MaximumLength
= Length
;
2414 SrvCallName
->Length
= Length
;
2416 /* Return the rest if asked */
2417 if (RestOfName
!= NULL
)
2419 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
2420 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2421 RestOfName
->MaximumLength
= Length
;
2422 RestOfName
->Length
= Length
;
2430 RxFcbTableInsertFcb(
2431 IN OUT PRX_FCB_TABLE FcbTable
,
2436 /* We deal with the table, make sure it's locked */
2437 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2439 /* Compute the hash */
2440 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2442 RxReferenceNetFcb(Fcb
);
2444 /* If no length, it will be our null entry */
2445 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2447 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2449 /* Otherwise, insert in the appropriate bucket */
2452 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2453 &Fcb
->FcbTableEntry
.HashLinks
);
2456 /* Propagate the change by incrementing the version number */
2457 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2459 return STATUS_SUCCESS
;
2466 RxFcbTableLookupFcb(
2467 IN PRX_FCB_TABLE FcbTable
,
2468 IN PUNICODE_STRING Path
)
2471 PRX_FCB_TABLE_ENTRY TableEntry
;
2475 /* No path - easy, that's null entry */
2478 TableEntry
= FcbTable
->TableEntryForNull
;
2483 PLIST_ENTRY HashBucket
, ListEntry
;
2485 /* Otherwise, compute the hash value and find the associated bucket */
2486 Hash
= RxTableComputePathHashValue(Path
);
2487 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2488 /* If the bucket is empty, it means there's no entry yet */
2489 if (IsListEmpty(HashBucket
))
2495 /* Otherwise, browse all the entry */
2496 for (ListEntry
= HashBucket
->Flink
;
2497 ListEntry
!= HashBucket
;
2498 ListEntry
= ListEntry
->Flink
)
2500 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2501 InterlockedIncrement(&FcbTable
->Compares
);
2503 /* If entry hash and string are equal, thatt's the one! */
2504 if (TableEntry
->HashValue
== Hash
&&
2505 TableEntry
->Path
.Length
== Path
->Length
&&
2506 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2512 /* We reached the end? Not found */
2513 if (ListEntry
== HashBucket
)
2520 InterlockedIncrement(&FcbTable
->Lookups
);
2522 /* If table entry isn't null, return the FCB */
2523 if (TableEntry
!= NULL
)
2525 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2526 RxReferenceNetFcb(Fcb
);
2531 InterlockedIncrement(&FcbTable
->FailedLookups
);
2541 RxFcbTableRemoveFcb(
2542 IN OUT PRX_FCB_TABLE FcbTable
,
2547 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2549 /* If no path, then remove entry for null */
2550 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2552 FcbTable
->TableEntryForNull
= NULL
;
2554 /* Otherwise, remove from the bucket */
2557 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2560 /* Reset its list entry */
2561 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2563 /* Propagate the change by incrementing the version number */
2564 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2566 return STATUS_SUCCESS
;
2574 RxFinalizeConnection(
2575 IN OUT PNET_ROOT NetRoot
,
2576 IN OUT PV_NET_ROOT VNetRoot OPTIONAL
,
2577 IN LOGICAL ForceFilesClosed
)
2580 PRX_PREFIX_TABLE PrefixTable
;
2581 ULONG UncleanAny
, UncleanDir
;
2582 LONG FilesOpen
, AdditionalRef
;
2583 BOOLEAN PrefixLocked
, FcbTableLocked
, ForceClose
;
2587 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
2589 /* Get a BOOLEAN out of LOGICAL
2590 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2592 ForceClose
= (ForceFilesClosed
== TRUE
? TRUE
: FALSE
);
2594 /* First, delete any notification change */
2595 Status
= RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot
, ForceClose
);
2596 /* If it failed, continue if forced */
2597 if (Status
!= STATUS_SUCCESS
&& !ForceFilesClosed
)
2601 /* Reset status, in case notification deletion failed */
2602 Status
= STATUS_SUCCESS
;
2604 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2606 PrefixLocked
= FALSE
;
2607 FcbTableLocked
= FALSE
;
2614 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2615 PrefixLocked
= TRUE
;
2617 RxReferenceNetRoot(NetRoot
);
2619 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2620 FcbTableLocked
= TRUE
;
2622 /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2623 if (!VNetRoot
->ConnectionFinalizationDone
)
2626 PRX_FCB_TABLE FcbTable
;
2628 DPRINT("Finalizing connection %p: %wZ\n", NetRoot
, &NetRoot
->PrefixEntry
.Prefix
);
2630 /* We'll browse all its associated FCB to check whether they're open/orphaned */
2631 FcbTable
= &NetRoot
->FcbTable
;
2632 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2634 PLIST_ENTRY BucketList
, Entry
;
2636 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
2637 Entry
= BucketList
->Flink
;
2638 while (Entry
!= BucketList
)
2642 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
2643 Entry
= Entry
->Flink
;
2645 /* FCB for this connection, go ahead */
2646 if (Fcb
->VNetRoot
== VNetRoot
)
2648 /* It's still open, and no force? Fail and keep track */
2649 if (Fcb
->UncleanCount
> 0 && !ForceClose
)
2651 Status
= STATUS_CONNECTION_IN_USE
;
2652 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2663 /* Else, force purge */
2664 ASSERT(NodeTypeIsFcb(Fcb
));
2666 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
2667 ASSERT(Status
== STATUS_SUCCESS
);
2669 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2671 RxScavengeRelatedFobxs(Fcb
);
2674 /* We don't need to release FCB lock, FCB finalize will take care of it */
2680 /* No files left, our V_NET_ROOT is finalized */
2681 if (VNetRoot
->NumberOfFobxs
== 0)
2683 VNetRoot
->ConnectionFinalizationDone
= TRUE
;
2687 /* Keep Number of open files and track of the extra reference */
2688 FilesOpen
= VNetRoot
->NumberOfFobxs
;
2689 AdditionalRef
= VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
;
2690 /* If force close, caller doesn't want to keep connection alive
2691 * and wants it totally close, so drop the V_NET_ROOT too
2695 RxFinalizeVNetRoot(VNetRoot
, FALSE
, TRUE
);
2700 /* Release what was acquired */
2703 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2706 /* If close is forced, only fix status if there are open files */
2709 if (Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0)
2711 Status
= STATUS_FILES_OPEN
;
2714 /* Else, fix status and fail closing if there are open files */
2717 if ((Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0) || FilesOpen
> 0)
2719 Status
= STATUS_FILES_OPEN
;
2723 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny
, UncleanDir
, FilesOpen
);
2725 /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2726 * only if it was still referenced!
2728 if ((ForceFilesClosed
== 0xFF || Status
== STATUS_SUCCESS
) && AdditionalRef
!= 0)
2730 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2731 RxDereferenceVNetRoot(VNetRoot
, LHS_ExclusiveLockHeld
);
2736 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2737 RxReleasePrefixTableLock(PrefixTable
);
2750 IN OUT PRX_FCB_TABLE FcbTable
)
2756 /* Just delete the lock */
2757 ExDeleteResourceLite(&FcbTable
->TableLock
);
2759 /* And make sure (checked) that the table is really empty... */
2760 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2762 ASSERT(IsListEmpty(&FcbTable
->HashBuckets
[Bucket
]));
2772 IN BOOLEAN RecursiveFinalize
,
2773 IN BOOLEAN ForceFinalize
,
2774 IN LONG ReferenceCount
)
2778 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2779 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2781 /* Make sure we have an exclusively acquired FCB */
2782 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2783 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2785 /* We shouldn't force finalization... */
2786 ASSERT(!ForceFinalize
);
2788 /* If recurisve, finalize all the associated SRV_OPEN */
2789 if (RecursiveFinalize
)
2791 PLIST_ENTRY ListEntry
;
2793 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2794 ListEntry
!= &ThisFcb
->SrvOpenList
;
2795 ListEntry
= ListEntry
->Flink
)
2799 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2800 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2803 /* If FCB is still in use, that's over */
2806 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2808 ASSERT(ReferenceCount
> 0);
2814 ASSERT(ReferenceCount
>= 1);
2816 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2817 if (ReferenceCount
!= 1 && !ForceFinalize
)
2822 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2824 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb
->OpenCount
, ForceFinalize
);
2826 /* If finalization was not already initiated, go ahead */
2827 if (!ThisFcb
->UpperFinalizationDone
)
2829 /* Free any FCB_LOCK */
2830 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2832 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2834 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2838 Entry
= ThisFcb
->BufferedLocks
.List
;
2839 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2845 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2846 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2850 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2852 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2854 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2856 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2860 ThisFcb
->UpperFinalizationDone
= TRUE
;
2863 ASSERT(ReferenceCount
>= 1);
2865 /* Even if forced, don't allow broken free */
2866 if (ReferenceCount
!= 1)
2871 /* Now, release everything */
2872 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2874 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2877 if (ThisFcb
->MRxDispatch
!= NULL
)
2879 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2882 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2883 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2884 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2886 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2887 RxDereferenceVNetRoot(ThisFcb
->VNetRoot
, LHS_LockNotHeld
);
2889 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2890 ASSERT(!ThisFcb
->fMiniInited
);
2892 /* And free the object */
2893 RxFreeFcbObject(ThisFcb
);
2903 _Out_ PFOBX ThisFobx
,
2904 _In_ BOOLEAN RecursiveFinalize
,
2905 _In_ BOOLEAN ForceFinalize
)
2912 ASSERT(NodeType(ThisFobx
) == RDBSS_NTC_FOBX
);
2914 /* Only finalize if forced or if there's no ref left */
2915 if (ThisFobx
->NodeReferenceCount
!= 0 &&
2921 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx
, ThisFobx
->NodeReferenceCount
, ForceFinalize
);
2923 SrvOpen
= ThisFobx
->SrvOpen
;
2925 /* If it wasn't finalized yet, do it */
2926 if (!ThisFobx
->UpperFinalizationDone
)
2928 ASSERT(NodeType(SrvOpen
->Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
2929 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
2931 /* Remove it from the SRV_OPEN */
2932 RemoveEntryList(&ThisFobx
->FobxQLinks
);
2934 /* If we were used to browse a directory, free the query buffer */
2935 if (BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_FREE_UNICODE
))
2937 RxFreePoolWithTag(ThisFobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
2940 /* Notify the mini-rdr */
2941 if (Fcb
->MRxDispatch
!= NULL
&& Fcb
->MRxDispatch
->MRxDeallocateForFobx
!= NULL
)
2943 Fcb
->MRxDispatch
->MRxDeallocateForFobx((PMRX_FOBX
)ThisFobx
);
2946 /* If the SRV_OPEN wasn't closed yet, do it */
2947 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
2951 Status
= RxCloseAssociatedSrvOpen(ThisFobx
, FALSE
);
2952 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen
, ThisFobx
, Status
);
2955 /* Finalization done */
2956 ThisFobx
->UpperFinalizationDone
= TRUE
;
2959 /* If we're still referenced, don't go any further! */
2960 if (ThisFobx
->NodeReferenceCount
!= 0)
2965 /* At that point, everything should be closed */
2966 ASSERT(IsListEmpty(&ThisFobx
->ClosePendingList
));
2968 /* Was the FOBX allocated with another object?
2969 * If so, mark the buffer free in said object
2971 if (ThisFobx
== Fcb
->InternalFobx
)
2973 ClearFlag(Fcb
->FcbState
, FCB_STATE_FOBX_USED
);
2975 else if (ThisFobx
== SrvOpen
->InternalFobx
)
2977 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
);
2980 ThisFobx
->pSrvOpen
= NULL
;
2983 InterlockedDecrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
2985 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
2987 /* If it wasn't allocated with another object, free the FOBX */
2988 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_ENCLOSED_ALLOCATED
))
2990 RxFreeFcbObject(ThisFobx
);
3001 OUT PNET_ROOT ThisNetRoot
,
3002 IN BOOLEAN RecursiveFinalize
,
3003 IN BOOLEAN ForceFinalize
)
3006 PRX_FCB_TABLE FcbTable
;
3007 PRX_PREFIX_TABLE PrefixTable
;
3011 ASSERT(NodeType(ThisNetRoot
) == RDBSS_NTC_NETROOT
);
3013 PrefixTable
= ThisNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3014 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3016 /* If sme finalization is already ongoing, leave */
3017 if (BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
))
3022 /* Mark we're finalizing */
3023 SetFlag(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
);
3025 FcbTable
= &ThisNetRoot
->FcbTable
;
3026 /* Did caller asked us to finalize any associated FCB? */
3027 if (RecursiveFinalize
)
3031 /* Browse all the FCBs in our FCB table */
3032 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
3033 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
3035 PLIST_ENTRY HashBucket
, ListEntry
;
3037 HashBucket
= &FcbTable
->HashBuckets
[Bucket
];
3038 ListEntry
= HashBucket
->Flink
;
3039 while (ListEntry
!= HashBucket
)
3043 Fcb
= CONTAINING_RECORD(ListEntry
, FCB
, FcbTableEntry
.HashLinks
);
3044 ASSERT(NodeTypeIsFcb(Fcb
));
3046 ListEntry
= ListEntry
->Flink
;
3048 /* If the FCB isn't orphaned, then, it's time to purge it */
3049 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3053 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
3054 ASSERT(Status
== STATUS_SUCCESS
);
3059 RxReleaseFcbTableLock(FcbTable
);
3062 /* Only finalize if forced or if there's a single ref left */
3063 if (ThisNetRoot
->NodeReferenceCount
!= 1 && !ForceFinalize
)
3068 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot
, &ThisNetRoot
->PrefixEntry
.Prefix
);
3070 /* If we're still referenced, don't go any further! */
3071 if (ThisNetRoot
->NodeReferenceCount
!= 1)
3076 /* Finalize the FCB table (and make sure it's empty!) */
3077 RxFinalizeFcbTable(FcbTable
);
3079 /* If name wasn't remove already, do it now */
3080 if (!BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
3082 RxRemovePrefixTableEntry(PrefixTable
, &ThisNetRoot
->PrefixEntry
);
3085 /* Delete the object */
3086 SrvCall
= (PSRV_CALL
)ThisNetRoot
->pSrvCall
;
3087 RxFreeObject(ThisNetRoot
);
3089 /* And dereference the associated SRV_CALL */
3090 if (SrvCall
!= NULL
)
3092 RxDereferenceSrvCall(SrvCall
, LHS_ExclusiveLockHeld
);
3103 OUT PSRV_CALL ThisSrvCall
,
3104 IN BOOLEAN RecursiveFinalize
,
3105 IN BOOLEAN ForceFinalize
)
3107 PRX_PREFIX_TABLE PrefixTable
;
3111 ASSERT(NodeType(ThisSrvCall
) == RDBSS_NTC_SRVCALL
);
3113 PrefixTable
= ThisSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3114 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3116 /* Only finalize if forced or if there's a single ref left */
3117 if (ThisSrvCall
->NodeReferenceCount
!= 1 &&
3123 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall
, &ThisSrvCall
->PrefixEntry
.Prefix
);
3125 /* If it wasn't finalized yet, do it */
3126 if (!ThisSrvCall
->UpperFinalizationDone
)
3130 /* Remove ourselves from prefix table */
3131 RxRemovePrefixTableEntry(PrefixTable
, &ThisSrvCall
->PrefixEntry
);
3133 /* Remember our third arg, in case we get queued for later execution */
3136 SetFlag(ThisSrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
3140 ThisSrvCall
->UpperFinalizationDone
= TRUE
;
3142 /* Would defered execution free the object? */
3143 WillFree
= (ThisSrvCall
->NodeReferenceCount
== 1);
3145 /* If we have a device object */
3146 if (ThisSrvCall
->RxDeviceObject
!= NULL
)
3150 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3151 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3153 /* Extra ref, as usual */
3154 InterlockedIncrement((volatile long *)&ThisSrvCall
->NodeReferenceCount
);
3156 RxDispatchToWorkerThread(ThisSrvCall
->RxDeviceObject
, DelayedWorkQueue
, RxpDestroySrvCall
, ThisSrvCall
);
3158 /* Return to the caller, in advance, whether we're freeing the object or not */
3162 /* If in the right thread already, call the mini-rdr */
3163 MINIRDR_CALL_THROUGH(Status
, ThisSrvCall
->RxDeviceObject
->Dispatch
,
3164 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)ThisSrvCall
, ForceFinalize
));
3169 /* If we're still referenced, don't go any further! */
3170 if (ThisSrvCall
->NodeReferenceCount
!= 1)
3176 if (ThisSrvCall
->pDomainName
!= NULL
)
3178 RxFreePool(ThisSrvCall
->pDomainName
);
3182 RxTearDownBufferingManager(ThisSrvCall
);
3183 RxFreeObject(ThisSrvCall
);
3193 OUT PSRV_OPEN ThisSrvOpen
,
3194 IN BOOLEAN RecursiveFinalize
,
3195 IN BOOLEAN ForceFinalize
)
3201 /* We have to have a SRV_OPEN */
3202 ASSERT(NodeType(ThisSrvOpen
) == RDBSS_NTC_SRVOPEN
);
3204 /* If that's a recursive finalization, finalize any related FOBX */
3205 if (RecursiveFinalize
)
3207 PLIST_ENTRY ListEntry
;
3209 ListEntry
= ThisSrvOpen
->FobxList
.Flink
;
3210 while (ListEntry
!= &ThisSrvOpen
->FobxList
)
3214 Fobx
= CONTAINING_RECORD(ListEntry
, FOBX
, FobxQLinks
);
3215 ListEntry
= ListEntry
->Flink
;
3216 RxFinalizeNetFobx(Fobx
, TRUE
, ForceFinalize
);
3220 /* If we have still references, don't finalize unless forced */
3221 if (ThisSrvOpen
->NodeReferenceCount
!= 0 &&
3227 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen
, ThisSrvOpen
->NodeReferenceCount
, ForceFinalize
);
3229 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3230 Fcb
= (PFCB
)ThisSrvOpen
->pFcb
;
3231 if ((!ThisSrvOpen
->UpperFinalizationDone
&& ThisSrvOpen
->Condition
!= Condition_Good
) ||
3232 BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
3234 PV_NET_ROOT VNetRoot
;
3236 /* Associated FCB can't be fake one */
3237 ASSERT(NodeType(Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
3238 ASSERT(RxIsFcbAcquiredExclusive (Fcb
));
3240 /* Purge any pending operation */
3241 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen
);
3243 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3244 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3248 MINIRDR_CALL_THROUGH(Status
, Fcb
->MRxDispatch
, MRxForceClosed
, ((PMRX_SRV_OPEN
)ThisSrvOpen
));
3252 /* Remove ourselves from the FCB */
3253 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3254 InitializeListHead(&ThisSrvOpen
->SrvOpenQLinks
);
3255 ++Fcb
->SrvOpenListVersion
;
3257 /* If we have a V_NET_ROOT, dereference it */
3258 VNetRoot
= (PV_NET_ROOT
)ThisSrvOpen
->pVNetRoot
;
3259 if (VNetRoot
!= NULL
)
3261 InterlockedDecrement((volatile long *)&VNetRoot
->pNetRoot
->NumberOfSrvOpens
);
3262 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3263 ThisSrvOpen
->pVNetRoot
= NULL
;
3266 /* Finalization done */
3267 ThisSrvOpen
->UpperFinalizationDone
= TRUE
;
3270 /* Don't free memory if still referenced */
3271 if (ThisSrvOpen
->NodeReferenceCount
!= 0)
3276 /* No key association left */
3277 ASSERT(IsListEmpty(&ThisSrvOpen
->SrvOpenKeyList
));
3279 /* If we're still in some FCB, remove us */
3280 if (!IsListEmpty(&ThisSrvOpen
->SrvOpenQLinks
))
3282 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3285 /* If enclosed allocation, mark the memory zone free */
3286 if (BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
))
3288 ClearFlag(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
);
3290 /* Otherwise, free the memory */
3293 RxFreeFcbObject(ThisSrvOpen
);
3296 RxDereferenceNetFcb(Fcb
);
3306 OUT PV_NET_ROOT ThisVNetRoot
,
3307 IN BOOLEAN RecursiveFinalize
,
3308 IN BOOLEAN ForceFinalize
)
3311 PRX_PREFIX_TABLE PrefixTable
;
3315 ASSERT(NodeType(ThisVNetRoot
) == RDBSS_NTC_V_NETROOT
);
3317 PrefixTable
= ThisVNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3318 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3320 /* Only finalize if forced or if there's a single ref left */
3321 if (ThisVNetRoot
->NodeReferenceCount
!= 1 &&
3327 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot
, &ThisVNetRoot
->PrefixEntry
.Prefix
);
3329 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
3330 /* If it wasn't finalized yet, do it */
3331 if (!ThisVNetRoot
->UpperFinalizationDone
)
3333 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
3335 /* Reference the NetRoot so that it doesn't disappear */
3336 RxReferenceNetRoot(NetRoot
);
3337 RxOrphanSrvOpens(ThisVNetRoot
);
3338 /* Remove us from the available VNetRoot for NetRoot */
3339 RxRemoveVirtualNetRootFromNetRoot(NetRoot
, ThisVNetRoot
);
3340 /* Remove extra ref */
3341 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3343 /* Remove ourselves from prefix table */
3344 RxRemovePrefixTableEntry(PrefixTable
, &ThisVNetRoot
->PrefixEntry
);
3346 /* Finalization done */
3347 ThisVNetRoot
->UpperFinalizationDone
= TRUE
;
3350 /* If we're still referenced, don't go any further! */
3351 if (ThisVNetRoot
->NodeReferenceCount
!= 1)
3356 /* If there's an associated device, notify mini-rdr */
3357 if (NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
3361 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
3362 MRxFinalizeVNetRoot
, ((PMRX_V_NET_ROOT
)ThisVNetRoot
, FALSE
));
3366 /* Free parameters */
3367 RxUninitializeVNetRootParameters(ThisVNetRoot
->pUserName
, ThisVNetRoot
->pUserDomainName
,
3368 ThisVNetRoot
->pPassword
, &ThisVNetRoot
->Flags
);
3369 /* Dereference our NetRoot, we won't reference it anymore */
3370 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3372 /* And free the object! */
3373 RxFreePoolWithTag(ThisVNetRoot
, RX_V_NETROOT_POOLTAG
);
3379 RxFindOrConstructVirtualNetRoot(
3380 IN PRX_CONTEXT RxContext
,
3381 IN PUNICODE_STRING CanonicalName
,
3382 IN NET_ROOT_TYPE NetRootType
,
3383 IN PUNICODE_STRING RemainingName
)
3389 PV_NET_ROOT VNetRoot
;
3390 RX_CONNECTION_ID ConnectionID
;
3391 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3392 LOCK_HOLDING_STATE LockHoldingState
;
3396 RxDeviceObject
= RxContext
->RxDeviceObject
;
3397 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
3398 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
3400 /* Ask the mini-rdr for connection ID */
3401 ConnectionID
.SessionID
= 0;
3402 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
3404 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
3405 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
3407 /* mini-rdr is expected not to fail - unless it's not implemented */
3408 DPRINT1("Failed to initialize connection ID\n");
3413 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
3415 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
3416 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3417 LockHoldingState
= LHS_SharedLockHeld
;
3421 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3425 PV_NET_ROOT SavedVNetRoot
;
3427 /* Look in prefix table */
3428 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
3429 if (Container
!= NULL
)
3431 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3432 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
3434 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3435 RxDereferenceSrvCall(Container
, LockHoldingState
);
3439 VNetRoot
= Container
;
3440 NetRoot
= VNetRoot
->NetRoot
;
3442 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3443 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
3444 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3446 Status
= STATUS_BAD_NETWORK_PATH
;
3447 SavedVNetRoot
= NULL
;
3453 PUNICODE_STRING UserName
, UserDomain
, Password
;
3455 /* We can reuse if we use same credentials */
3456 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
3457 &SessionId
, &UserName
,
3458 &UserDomain
, &Password
,
3460 if (NT_SUCCESS(Status
))
3462 SavedVNetRoot
= VNetRoot
;
3463 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
3465 UserDomain
, Password
,
3467 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
3469 PLIST_ENTRY ListEntry
;
3471 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
3472 ListEntry
!= &NetRoot
->VirtualNetRoots
;
3473 ListEntry
= ListEntry
->Flink
)
3475 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
3476 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
3478 UserDomain
, Password
,
3480 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3486 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
3488 SavedVNetRoot
= NULL
;
3492 if (!NT_SUCCESS(Status
))
3494 SavedVNetRoot
= NULL
;
3497 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
3501 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3502 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
3504 if (SavedVNetRoot
== NULL
)
3506 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3509 /* Reference VNetRoot we'll keep, and dereference current */
3510 else if (SavedVNetRoot
!= VNetRoot
)
3512 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3513 if (SavedVNetRoot
!= NULL
)
3515 RxReferenceVNetRoot(SavedVNetRoot
);
3520 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3521 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3528 /* If we're locked exclusive, we won't loop again, it was the second pass */
3529 if (LockHoldingState
!= LHS_SharedLockHeld
)
3534 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3535 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
3537 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3538 LockHoldingState
= LHS_ExclusiveLockHeld
;
3542 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3543 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3544 LockHoldingState
= LHS_ExclusiveLockHeld
;
3547 /* We didn't fail, and didn't find any VNetRoot, construct one */
3550 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
3552 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
3553 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
3555 if (Status
== STATUS_SUCCESS
)
3557 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
3558 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3559 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
3561 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3562 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
3563 RemainingName
->MaximumLength
= RemainingName
->Length
;
3565 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
3567 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
3569 VNetRoot
->Flags
|= Flags
;
3573 /* Release the prefix table - caller expects it to be released */
3574 if (LockHoldingState
!= LHS_LockNotHeld
)
3576 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3579 /* If we failed creating, quit */
3580 if (Status
!= STATUS_SUCCESS
)
3582 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
3586 /* Otherwise, wait until the VNetRoot is stable */
3587 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
3588 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
3589 /* It's all good, update the RX_CONTEXT with all our structs */
3590 if (VNetRoot
->Condition
== Condition_Good
)
3594 NetRoot
= VNetRoot
->NetRoot
;
3595 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3596 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3597 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
3601 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3602 RxContext
->Create
.pVNetRoot
= NULL
;
3603 Status
= STATUS_BAD_NETWORK_PATH
;
3613 RxFindOrCreateConnections(
3614 _In_ PRX_CONTEXT RxContext
,
3615 _In_ PUNICODE_STRING CanonicalName
,
3616 _In_ NET_ROOT_TYPE NetRootType
,
3617 _Out_ PUNICODE_STRING LocalNetRootName
,
3618 _Out_ PUNICODE_STRING FilePathName
,
3619 _Inout_ PLOCK_HOLDING_STATE LockState
,
3620 _In_ PRX_CONNECTION_ID RxConnectionId
)
3625 PV_NET_ROOT VNetRoot
;
3626 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
3627 PRX_PREFIX_TABLE PrefixTable
;
3628 UNICODE_STRING RemainingName
, NetRootName
;
3632 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3633 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
3634 FilePathName
, LockState
, RxConnectionId
);
3636 *FilePathName
= *CanonicalName
;
3637 LocalNetRootName
->Length
= 0;
3638 LocalNetRootName
->MaximumLength
= 0;
3639 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
3641 /* UNC path, split it */
3642 if (FilePathName
->Buffer
[1] == ';')
3648 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
3650 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
3659 return STATUS_OBJECT_NAME_INVALID
;
3662 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
3663 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
3664 LocalNetRootName
->Length
= Length
;
3665 LocalNetRootName
->MaximumLength
= Length
;
3666 FilePathName
->Length
-= Length
;
3668 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
3669 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
3670 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
3674 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
3679 ASSERT(*LockState
!= LHS_LockNotHeld
);
3681 /* If previous lookup left something, dereference it */
3682 if (Container
!= NULL
)
3684 switch (NodeType(Container
))
3686 case RDBSS_NTC_SRVCALL
:
3687 RxDereferenceSrvCall(Container
, *LockState
);
3690 case RDBSS_NTC_NETROOT
:
3691 RxDereferenceNetRoot(Container
, *LockState
);
3694 case RDBSS_NTC_V_NETROOT
:
3695 RxDereferenceVNetRoot(Container
, *LockState
);
3699 /* Should never happen */
3705 /* Look for our NetRoot in prefix table */
3706 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
3707 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
3711 UNICODE_STRING SrvCallName
;
3717 /* Assume we didn't succeed */
3718 RxContext
->Create
.pVNetRoot
= NULL
;
3719 RxContext
->Create
.pNetRoot
= NULL
;
3720 RxContext
->Create
.pSrvCall
= NULL
;
3721 RxContext
->Create
.Type
= NetRootType
;
3723 /* If we found something */
3724 if (Container
!= NULL
)
3727 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
3729 VNetRoot
= Container
;
3730 /* Use its NetRoot */
3731 NetRoot
= VNetRoot
->NetRoot
;
3733 /* If it's not stable, wait for it to be stable */
3734 if (NetRoot
->Condition
== Condition_InTransition
)
3736 RxReleasePrefixTableLock(PrefixTable
);
3737 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
3738 RxWaitForStableNetRoot(NetRoot
, RxContext
);
3739 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3740 *LockState
= LHS_ExclusiveLockHeld
;
3742 /* Now that's it's ok, retry lookup to find what we want */
3743 if (NetRoot
->Condition
== Condition_Good
)
3749 /* Is the associated netroot good? */
3750 if (NetRoot
->Condition
== Condition_Good
)
3752 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
3754 /* If it is, and SrvCall as well, then, we have our active connection */
3755 if (SrvCall
->Condition
== Condition_Good
&&
3756 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
3758 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3759 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3760 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3762 Status
= STATUS_CONNECTION_ACTIVE
;
3767 /* If VNetRoot was well constructed, it means the connection is active */
3768 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
3770 Status
= STATUS_CONNECTION_ACTIVE
;
3774 Status
= VNetRoot
->ConstructionStatus
;
3777 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3780 /* Can only be a SrvCall */
3783 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3784 SrvCall
= Container
;
3786 /* Wait for the SRV_CALL to be stable */
3787 if (SrvCall
->Condition
== Condition_InTransition
)
3789 RxReleasePrefixTableLock(PrefixTable
);
3790 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
3791 RxWaitForStableSrvCall(SrvCall
, RxContext
);
3792 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3793 *LockState
= LHS_ExclusiveLockHeld
;
3795 /* It went good, loop again to find what we look for */
3796 if (SrvCall
->Condition
== Condition_Good
)
3802 /* If it's not good... */
3803 if (SrvCall
->Condition
!= Condition_Good
)
3805 /* But SRV_CALL was well constructed, assume a connection was active */
3806 if (SrvCall
->Status
== STATUS_SUCCESS
)
3808 Status
= STATUS_CONNECTION_ACTIVE
;
3812 Status
= SrvCall
->Status
;
3815 RxDereferenceSrvCall(SrvCall
, *LockState
);
3821 /* If we found a SRV_CALL not matching our DO, quit */
3822 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
3823 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3825 RxDereferenceSrvCall(SrvCall
, *LockState
);
3826 Status
= STATUS_BAD_NETWORK_NAME
;
3830 /* Now, we want exclusive lock */
3831 if (*LockState
== LHS_SharedLockHeld
)
3833 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
3835 RxReleasePrefixTableLock(PrefixTable
);
3836 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3837 *LockState
= LHS_ExclusiveLockHeld
;
3841 RxReleasePrefixTableLock(PrefixTable
);
3842 *LockState
= LHS_ExclusiveLockHeld
;
3845 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3847 /* If we reach that point, we found something, no need to create something */
3848 if (Container
!= NULL
)
3853 /* Get the name for the SRV_CALL */
3854 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
3855 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
3856 /* And create the SRV_CALL */
3857 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
3858 if (SrvCall
== NULL
)
3860 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3864 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3865 RxReferenceSrvCall(SrvCall
);
3866 RxContext
->Create
.pVNetRoot
= NULL
;
3867 RxContext
->Create
.pNetRoot
= NULL
;
3868 RxContext
->Create
.pSrvCall
= NULL
;
3869 RxContext
->Create
.Type
= NetRootType
;
3870 Container
= SrvCall
;
3872 /* Construct SRV_CALL, ie, use mini-rdr */
3873 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
3874 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
3875 if (Status
!= STATUS_SUCCESS
)
3877 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
3878 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3879 RxDereferenceSrvCall(SrvCall
, *LockState
);
3880 RxReleasePrefixTableLock(PrefixTable
);
3884 /* Loop again to make use of SRV_CALL stable condition wait */
3887 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3888 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
3889 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
3890 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
3892 /* Call mini-rdr to get NetRoot name */
3893 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
3894 /* And create the NetRoot with that name */
3895 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
3896 if (NetRoot
== NULL
)
3898 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3901 NetRoot
->Type
= NetRootType
;
3903 RxDereferenceSrvCall(SrvCall
, *LockState
);
3905 /* Finally, create the associated VNetRoot */
3906 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
3907 if (VNetRoot
== NULL
)
3909 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
3910 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3913 RxReferenceVNetRoot(VNetRoot
);
3915 /* We're get closer! */
3916 NetRoot
->Condition
= Condition_InTransition
;
3917 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3918 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3919 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3921 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3922 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
3923 if (!NT_SUCCESS(Status
))
3925 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
3926 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
3927 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3929 RxContext
->Create
.pNetRoot
= NULL
;
3930 RxContext
->Create
.pVNetRoot
= NULL
;
3934 PIO_STACK_LOCATION Stack
;
3936 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3938 Stack
= RxContext
->CurrentIrpSp
;
3939 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
3941 RxExclusivePrefixTableLockToShared(PrefixTable
);
3942 *LockState
= LHS_SharedLockHeld
;
3948 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
3950 if (*LockState
!= LHS_LockNotHeld
)
3952 RxReleasePrefixTableLock(PrefixTable
);
3953 *LockState
= LHS_LockNotHeld
;
3959 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
3968 RxFinishFcbInitialization(
3969 IN OUT PMRX_FCB Fcb
,
3970 IN RX_FILE_TYPE FileType
,
3971 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
3973 RX_FILE_TYPE OldType
;
3977 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
3979 OldType
= NodeType(Fcb
);
3980 NodeType(Fcb
) = FileType
;
3981 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
3982 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
3984 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3986 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
3987 else if (InitPacket
!= NULL
)
3989 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
3990 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
3991 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
3992 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
3993 InitPacket
->pValidDataLength
->QuadPart
);
3996 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3997 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3999 /* If our FCB newly points to a file, initiliaze everything related */
4000 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
)
4003 if (OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
4005 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
4006 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, RxLockOperationCompletion
,
4009 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
4010 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
4012 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
4015 /* If not a file, validate type */
4018 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
4027 RxFinishSrvCallConstruction(
4028 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
4032 PRX_CONTEXT Context
;
4033 RX_BLOCK_CONDITION Condition
;
4034 PRX_PREFIX_TABLE PrefixTable
;
4036 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
4038 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
4039 Context
= Calldown
->RxContext
;
4040 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
4042 /* We have a winner, notify him */
4043 if (Calldown
->BestFinisher
!= NULL
)
4045 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
4047 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
4049 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
4050 MRxSrvCallWinnerNotify
,
4051 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
4052 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
4053 if (Status
!= STATUS_SUCCESS
)
4055 Condition
= Condition_Bad
;
4059 Condition
= Condition_Good
;
4062 /* Otherwise, just fail our SRV_CALL */
4065 Status
= Calldown
->CallbackContexts
[0].Status
;
4066 Condition
= Condition_Bad
;
4069 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
4070 RxTransitionSrvCall(SrvCall
, Condition
);
4071 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
4073 /* If async, finish it here, otherwise, caller has already finished the stuff */
4074 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
4076 DPRINT("Finishing async call\n");
4078 RxReleasePrefixTableLock(PrefixTable
);
4080 /* Make sure we weren't cancelled in-between */
4081 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
4083 Status
= STATUS_CANCELLED
;
4086 /* In case that was a create, context can be reused */
4087 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
4089 RxpPrepareCreateContextForReuse(Context
);
4092 /* If that's a failure, reset everything and return failure */
4093 if (Status
!= STATUS_SUCCESS
)
4095 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
4096 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4098 if (Context
->Info
.Buffer
!= NULL
)
4100 RxFreePool(Context
->Info
.Buffer
);
4101 Context
->Info
.Buffer
= NULL
;
4104 Context
->CurrentIrp
->IoStatus
.Information
= 0;
4105 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
4106 RxCompleteRequest(Context
, Status
);
4108 /* Otherwise, call resume routine and done! */
4111 Status
= Context
->ResumeRoutine(Context
);
4112 if (Status
!= STATUS_PENDING
)
4114 RxCompleteRequest(Context
, Status
);
4117 DPRINT("Not completing, pending\n");
4121 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
4130 RxFinishSrvCallConstructionDispatcher(
4134 BOOLEAN Direct
, KeepLoop
;
4136 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
4138 /* In case of failure of starting dispatcher, context is not set
4139 * We keep track of it to fail associated SRV_CALL
4141 Direct
= (Context
== NULL
);
4143 /* Separated thread, loop forever */
4146 PLIST_ENTRY ListEntry
;
4147 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
4149 /* If there are no SRV_CALL to finalize left, just finish thread */
4150 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
4151 if (IsListEmpty(&RxSrvCalldownList
))
4154 RxSrvCallConstructionDispatcherActive
= FALSE
;
4156 /* Otherwise, get the SRV_CALL to finish construction */
4159 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
4162 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
4170 /* If direct is set, reset the finisher to avoid electing a winner
4171 * and fail SRV_CALL (see upper comment)
4173 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
4176 Calldown
->BestFinisher
= NULL
;
4178 /* Finish SRV_CALL construction */
4179 RxFinishSrvCallConstruction(Calldown
);
4187 RxFlushFcbInSystemCache(
4189 IN BOOLEAN SynchronizeWithLazyWriter
)
4191 IO_STATUS_BLOCK IoStatus
;
4196 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &IoStatus
);
4197 /* If we're asked to sync with LW, do it in case of success */
4198 if (SynchronizeWithLazyWriter
&& NT_SUCCESS(IoStatus
.Status
))
4200 RxAcquirePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4201 RxReleasePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4204 DPRINT("Flushing for FCB %p returns %lx\n", Fcb
, IoStatus
.Status
);
4205 return IoStatus
.Status
;
4217 DPRINT("Freeing %p\n", Object
);
4219 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4220 if (NodeType(Object
) == RDBSS_NTC_FOBX
|| NodeType(Object
) == RDBSS_NTC_SRVOPEN
)
4222 RxFreePoolWithTag(Object
, RX_FCB_POOLTAG
);
4224 /* If that's a FCB... */
4225 else if (NodeTypeIsFcb(Object
))
4228 PRDBSS_DEVICE_OBJECT DeviceObject
;
4231 DeviceObject
= Fcb
->RxDeviceObject
;
4233 /* Delete per stream contexts */
4234 FsRtlTeardownPerStreamContexts(&Fcb
->Header
);
4236 SetFlag(Fcb
->Header
.Flags
, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH
);
4238 /* If there was a non-paged FCB allocated, free it */
4239 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
4241 RxFreePoolWithTag(Fcb
->NonPaged
, RX_NONPAGEDFCB_POOLTAG
);
4247 /* Update statistics */
4248 InterlockedDecrement(&RxNumberOfActiveFcbs
);
4249 InterlockedDecrement((volatile long *)&DeviceObject
->NumberOfActiveFcbs
);
4262 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4263 if (NodeType(pObject
) == RDBSS_NTC_SRVCALL
)
4266 PRDBSS_DEVICE_OBJECT DeviceObject
;
4268 SrvCall
= (PSRV_CALL
)pObject
;
4269 DeviceObject
= SrvCall
->RxDeviceObject
;
4270 if (DeviceObject
!= NULL
)
4272 if (!BooleanFlagOn(DeviceObject
->Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
4274 ASSERT(SrvCall
->Context
== NULL
);
4277 ASSERT(SrvCall
->Context2
== NULL
);
4279 SrvCall
->RxDeviceObject
= NULL
;
4282 else if (NodeType(pObject
) == RDBSS_NTC_NETROOT
)
4286 NetRoot
= (PNET_ROOT
)pObject
;
4287 NetRoot
->pSrvCall
= NULL
;
4288 NetRoot
->NodeTypeCode
= NodeType(pObject
) | 0xF000;
4291 /* And just free the object */
4292 RxFreePool(pObject
);
4299 RxGatherRequestsForSrvOpen(
4300 IN OUT PSRV_CALL SrvCall
,
4301 IN PSRV_OPEN SrvOpen
,
4302 IN OUT PLIST_ENTRY RequestsListHead
)
4305 LIST_ENTRY Discarded
, *Entry
;
4306 PCHANGE_BUFFERING_STATE_REQUEST Request
;
4308 /* Dispatch any pending operation first */
4309 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &Discarded
);
4311 /* Then, get any entry related to our key and SRV_OPEN */
4312 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
4313 Entry
= SrvCall
->BufferingManager
.HandlerList
.Flink
;
4314 while (Entry
!= &SrvCall
->BufferingManager
.HandlerList
)
4316 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4317 Entry
= Entry
->Flink
;
4318 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4320 RemoveEntryList(&Request
->ListEntry
);
4321 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4324 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
4326 /* Perform the same search in the last change list */
4327 Entry
= SrvCall
->BufferingManager
.LastChanceHandlerList
.Flink
;
4328 while (Entry
!= &SrvCall
->BufferingManager
.LastChanceHandlerList
)
4330 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4331 Entry
= Entry
->Flink
;
4332 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4334 RemoveEntryList(&Request
->ListEntry
);
4335 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4339 /* Discard the discarded requests */
4340 RxpDiscardChangeBufferingStateRequests(&Discarded
);
4346 PRDBSS_DEVICE_OBJECT
4347 RxGetDeviceObjectOfInstance(
4350 NODE_TYPE_CODE NodeType
;
4351 PRDBSS_DEVICE_OBJECT DeviceObject
;
4355 /* We only handle a few object types */
4356 NodeType
= NodeType(Instance
);
4357 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
4358 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) || (NodeType
== RDBSS_NTC_FOBX
));
4360 /* Get the device object depending on the object */
4363 case RDBSS_NTC_FOBX
:
4367 Fobx
= (PFOBX
)Instance
;
4368 DeviceObject
= Fobx
->RxDeviceObject
;
4372 case RDBSS_NTC_SRVCALL
:
4376 SrvCall
= (PSRV_CALL
)Instance
;
4377 DeviceObject
= SrvCall
->RxDeviceObject
;
4381 case RDBSS_NTC_NETROOT
:
4385 NetRoot
= (PNET_ROOT
)Instance
;
4386 DeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
4390 case RDBSS_NTC_V_NETROOT
:
4392 PV_NET_ROOT VNetRoot
;
4394 VNetRoot
= (PV_NET_ROOT
)Instance
;
4395 DeviceObject
= VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
;
4399 case RDBSS_NTC_SRVOPEN
:
4403 SrvOpen
= (PSRV_OPEN
)Instance
;
4404 DeviceObject
= ((PFCB
)SrvOpen
->pFcb
)->RxDeviceObject
;
4409 DeviceObject
= NULL
;
4414 return DeviceObject
;
4421 RxGetFileSizeWithLock(
4423 OUT PLONGLONG FileSize
)
4427 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
4438 return RxData
.OurProcess
;
4445 RxInitializeBufferingManager(
4448 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
4449 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
4450 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
4451 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
4452 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
4453 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
4454 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
4455 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
4456 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
4457 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
4459 return STATUS_SUCCESS
;
4467 RxInitializeContext(
4469 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
4470 IN ULONG InitialContextFlags
,
4471 IN OUT PRX_CONTEXT RxContext
)
4473 PIO_STACK_LOCATION Stack
;
4475 /* Initialize our various fields */
4476 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
4477 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
4478 RxContext
->ReferenceCount
= 1;
4479 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
4480 RxContext
->RxDeviceObject
= RxDeviceObject
;
4481 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
4482 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
4483 InitializeListHead(&RxContext
->BlockedOperations
);
4484 RxContext
->MRxCancelRoutine
= NULL
;
4485 RxContext
->ResumeRoutine
= NULL
;
4486 RxContext
->Flags
|= InitialContextFlags
;
4487 RxContext
->CurrentIrp
= Irp
;
4488 RxContext
->LastExecutionThread
= PsGetCurrentThread();
4489 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
4491 /* If've got no IRP, mark RX_CONTEXT */
4494 RxContext
->CurrentIrpSp
= NULL
;
4495 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
4496 RxContext
->MinorFunction
= 0;
4500 /* Otherwise, first determine whether we are performing async operation */
4501 Stack
= IoGetCurrentIrpStackLocation(Irp
);
4502 if (Stack
->FileObject
!= NULL
)
4506 Fcb
= Stack
->FileObject
->FsContext
;
4507 if (!IoIsOperationSynchronous(Irp
) ||
4508 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
4509 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
4510 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
4512 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4516 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
4518 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4520 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4522 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4525 /* Set proper flags if TopLevl IRP/Device */
4526 if (!RxIsThisTheTopLevelIrp(Irp
))
4528 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
4530 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
4532 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
4535 /* Copy stack information */
4536 RxContext
->MajorFunction
= Stack
->MajorFunction
;
4537 RxContext
->MinorFunction
= Stack
->MinorFunction
;
4538 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
4539 RxContext
->CurrentIrpSp
= Stack
;
4541 /* If we have a FO associated, learn for more */
4542 if (Stack
->FileObject
!= NULL
)
4547 /* Get the FCB and CCB (FOBX) */
4548 Fcb
= Stack
->FileObject
->FsContext
;
4549 Fobx
= Stack
->FileObject
->FsContext2
;
4550 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
4551 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
4553 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
4556 /* We have a FOBX, this not a DFS opening, keep track of it */
4557 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
4559 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
4560 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
4561 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4563 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
4568 RxContext
->pFobx
= NULL
;
4571 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4572 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
4575 PV_NET_ROOT VNetRoot
= NULL
;
4577 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4579 VNetRoot
= Fcb
->VNetRoot
;
4581 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
4583 VNetRoot
= (PV_NET_ROOT
)Fobx
;
4586 if (VNetRoot
!= NULL
)
4588 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
4592 /* Remember if that's a write through file */
4593 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
4594 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
4596 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
4601 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
4603 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4604 RxContext
, RxContext
->MinorFunction
, Irp
,
4605 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
4606 RxContext
->SerialNumber
);
4615 RxInitializeDispatcher(
4619 HANDLE ThreadHandle
;
4623 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4624 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4626 /* Set appropriate timeouts: 10s & 60s */
4627 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4628 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4629 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4630 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
4632 RxDispatcher
.NumberOfProcessors
= 1;
4633 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
4634 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
4636 /* Initialize our dispatchers */
4637 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
4638 if (!NT_SUCCESS(Status
))
4643 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
4644 if (!NT_SUCCESS(Status
))
4649 /* And start them */
4650 RxDispatcher
.State
= RxDispatcherActive
;
4651 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
4652 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
4653 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
4654 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
4655 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
4656 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
4657 if (NT_SUCCESS(Status
))
4659 ZwClose(ThreadHandle
);
4669 RxInitializeFcbTable(
4670 IN OUT PRX_FCB_TABLE FcbTable
,
4671 IN BOOLEAN CaseInsensitiveMatch
)
4677 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
4678 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
4680 ExInitializeResourceLite(&FcbTable
->TableLock
);
4681 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4682 FcbTable
->Version
= 0;
4683 FcbTable
->TableEntryForNull
= NULL
;
4685 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
4686 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
4688 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
4691 FcbTable
->Lookups
= 0;
4692 FcbTable
->FailedLookups
= 0;
4693 FcbTable
->Compares
= 0;
4701 RxInitializeLowIoContext(
4702 OUT PLOWIO_CONTEXT LowIoContext
,
4705 PRX_CONTEXT RxContext
;
4706 PIO_STACK_LOCATION Stack
;
4710 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
4711 ASSERT(LowIoContext
== &RxContext
->LowIoContext
);
4713 Stack
= RxContext
->CurrentIrpSp
;
4715 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
4716 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
4717 RxContext
->LowIoContext
.Operation
= Operation
;
4722 case LOWIO_OP_WRITE
:
4723 /* In case of RW, set a canary, to make sure these fields are properly set
4724 * they will be asserted when lowio request will be submit to mini-rdr
4727 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
4728 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
4729 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
4731 /* Keep track of paging IOs */
4732 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
4734 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
4738 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
4743 case LOWIO_OP_FSCTL
:
4744 case LOWIO_OP_IOCTL
:
4745 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4746 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
4747 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
4748 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
4749 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
4750 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
4751 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
4754 /* Nothing to do for these */
4755 case LOWIO_OP_SHAREDLOCK
:
4756 case LOWIO_OP_EXCLUSIVELOCK
:
4757 case LOWIO_OP_UNLOCK
:
4758 case LOWIO_OP_UNLOCK_MULTIPLE
:
4759 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4760 case LOWIO_OP_CLEAROUT
:
4764 /* Should never happen */
4774 RxInitializeLowIoPerFcbInfo(
4775 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
4779 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
4780 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
4787 RxInitializeMRxDispatcher(
4788 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
4792 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4793 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4795 return STATUS_SUCCESS
;
4802 RxInitializePrefixTable(
4803 IN OUT PRX_PREFIX_TABLE ThisTable
,
4804 IN ULONG TableSize OPTIONAL
,
4805 IN BOOLEAN CaseInsensitiveMatch
)
4811 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
4814 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
4815 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
4816 InitializeListHead(&ThisTable
->MemberQueue
);
4817 ThisTable
->Version
= 0;
4818 ThisTable
->TableEntryForNull
= NULL
;
4819 ThisTable
->IsNetNameTable
= FALSE
;
4820 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4821 ThisTable
->TableSize
= TableSize
;
4827 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
4829 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
4838 RxInitializePurgeSyncronizationContext(
4839 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
4843 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
4844 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
4848 RxInitializeSrvCallParameters(
4849 IN PRX_CONTEXT RxContext
,
4850 IN OUT PSRV_CALL SrvCall
)
4854 SrvCall
->pPrincipalName
= NULL
;
4856 /* We only have stuff to initialize for file opening from DFS */
4857 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
4859 return STATUS_SUCCESS
;
4862 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
4865 return STATUS_NOT_IMPLEMENTED
;
4873 RxInitializeRxTimer(
4878 RxTimerInterval
.QuadPart
= -550000;
4879 KeInitializeSpinLock(&RxTimerLock
);
4880 InitializeListHead(&RxTimerQueueHead
);
4881 InitializeListHead(&RxRecurrentWorkItemsList
);
4882 KeInitializeDpc(&RxTimerDpc
, RxTimerDispatch
, NULL
);
4883 KeInitializeTimer(&RxTimer
);
4884 RxTimerTickCount
= 0;
4886 return STATUS_SUCCESS
;
4890 RxInitializeVNetRootParameters(
4891 PRX_CONTEXT RxContext
,
4893 OUT PULONG SessionId
,
4894 OUT PUNICODE_STRING
*UserNamePtr
,
4895 OUT PUNICODE_STRING
*UserDomainNamePtr
,
4896 OUT PUNICODE_STRING
*PasswordPtr
,
4900 PACCESS_TOKEN Token
;
4904 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
4905 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
4907 *UserNamePtr
= NULL
;
4908 *UserDomainNamePtr
= NULL
;
4909 *PasswordPtr
= NULL
;
4910 /* By default, that's not CSC instance */
4911 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4913 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
4914 if (SeTokenIsRestricted(Token
))
4916 return STATUS_ACCESS_DENIED
;
4920 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
4921 if (!NT_SUCCESS(Status
))
4927 Status
= SeQuerySessionIdToken(Token
, SessionId
);
4928 if (!NT_SUCCESS(Status
))
4933 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
4936 Status
= STATUS_NOT_IMPLEMENTED
;
4940 /* Deal with connection credentials */
4941 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
4944 Status
= STATUS_NOT_IMPLEMENTED
;
4948 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
4951 Status
= STATUS_NOT_IMPLEMENTED
;
4956 if (NT_SUCCESS(Status
))
4958 /* If that's a CSC instance, mark it as such */
4959 if (RxIsThisACscAgentOpen(RxContext
))
4961 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4973 RxInitializeWorkQueue(
4974 PRX_WORK_QUEUE WorkQueue
,
4975 WORK_QUEUE_TYPE WorkQueueType
,
4976 ULONG MaximumNumberOfWorkerThreads
,
4977 ULONG MinimumNumberOfWorkerThreads
)
4981 WorkQueue
->Type
= WorkQueueType
;
4982 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
4983 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
4985 WorkQueue
->State
= RxWorkQueueActive
;
4986 WorkQueue
->SpinUpRequestPending
= FALSE
;
4987 WorkQueue
->pRundownContext
= NULL
;
4988 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
4989 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
4990 WorkQueue
->CumulativeQueueLength
= 0;
4991 WorkQueue
->NumberOfSpinUpRequests
= 0;
4992 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
4993 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
4994 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
4995 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
4996 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
4997 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
4998 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
4999 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
5000 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
5001 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
5002 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
5003 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
5004 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
5005 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
5006 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
5007 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
5009 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
5010 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
5017 RxInitializeWorkQueueDispatcher(
5018 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
5021 ULONG MaximumNumberOfWorkerThreads
;
5025 /* Number of threads will depend on system capacity */
5026 if (MmQuerySystemSize() != MmLargeSystem
)
5028 MaximumNumberOfWorkerThreads
= 5;
5032 MaximumNumberOfWorkerThreads
= 10;
5035 /* Initialize the work queues */
5036 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
5037 MaximumNumberOfWorkerThreads
, 1);
5038 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
5039 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
5041 /* And start the worker threads */
5042 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
5043 RxBootstrapWorkerThreadDispatcher
,
5044 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
5045 if (!NT_SUCCESS(Status
))
5050 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
5051 RxBootstrapWorkerThreadDispatcher
,
5052 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
5053 if (!NT_SUCCESS(Status
))
5058 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
5059 RxBootstrapWorkerThreadDispatcher
,
5060 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
5068 RxInitiateSrvOpenKeyAssociation(
5069 IN OUT PSRV_OPEN SrvOpen
)
5071 PRX_BUFFERING_MANAGER BufferingManager
;
5075 SrvOpen
->Key
= NULL
;
5077 /* Just keep track of the opening request */
5078 BufferingManager
= &((PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
;
5079 InterlockedIncrement(&BufferingManager
->NumberOfOutstandingOpens
);
5081 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
5088 RxInsertWorkQueueItem(
5089 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
5090 WORK_QUEUE_TYPE WorkQueueType
,
5091 PRX_WORK_QUEUE_ITEM WorkQueueItem
)
5095 BOOLEAN SpinUpThreads
;
5096 PRX_WORK_QUEUE WorkQueue
;
5098 /* No dispatcher, nothing to insert */
5099 if (RxDispatcher
.State
!= RxDispatcherActive
)
5101 return STATUS_UNSUCCESSFUL
;
5104 /* Get the work queue */
5105 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
5107 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
5108 /* Only insert if the work queue is in decent state */
5109 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
5111 Status
= STATUS_UNSUCCESSFUL
;
5115 SpinUpThreads
= FALSE
;
5116 WorkQueueItem
->pDeviceObject
= pMRxDeviceObject
;
5117 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
5118 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
5119 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
5121 /* If required (and possible!), spin up a new worker thread */
5122 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
5123 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
5124 !WorkQueue
->SpinUpRequestPending
)
5126 WorkQueue
->SpinUpRequestPending
= TRUE
;
5127 SpinUpThreads
= TRUE
;
5130 Status
= STATUS_SUCCESS
;
5132 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5134 /* If we failed, return and still not insert item */
5135 if (!NT_SUCCESS(Status
))
5140 /* All fine, insert the item */
5141 KeInsertQueue(&WorkQueue
->Queue
, &WorkQueueItem
->List
);
5143 /* And start a new worker thread if needed */
5146 RxSpinUpWorkerThreads(WorkQueue
);
5153 RxIsThisACscAgentOpen(
5154 IN PRX_CONTEXT RxContext
)
5160 /* Client Side Caching is DFS stuff - we don't support it */
5161 if (RxContext
->Create
.EaLength
!= 0)
5166 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
5167 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
5177 IN PRX_CONTEXT RxContext
,
5178 IN LOCK_OPERATION Operation
,
5179 IN ULONG BufferLength
)
5188 Irp
= RxContext
->CurrentIrp
;
5189 /* If we already have a MDL, make sure it's locked */
5190 if (Irp
->MdlAddress
!= NULL
)
5192 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
5196 /* That likely means the driver asks for buffered IOs - we don't support it! */
5197 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
5199 /* If we have a real length */
5200 if (BufferLength
> 0)
5202 /* Allocate a MDL and lock it */
5203 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
5206 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
5207 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
5210 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
5214 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5218 Status
= _SEH2_GetExceptionCode();
5220 /* Free the possible MDL we have allocated */
5222 Irp
->MdlAddress
= NULL
;
5224 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
5227 if (!FsRtlIsNtstatusExpected(Status
))
5229 Status
= STATUS_INVALID_USER_BUFFER
;
5232 RxContext
->IoStatusBlock
.Status
= Status
;
5233 ExRaiseStatus(Status
);
5242 RxLowIoCompletionTail(
5243 IN PRX_CONTEXT RxContext
)
5250 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
5252 /* Only continue if we're at APC_LEVEL or lower */
5253 if (RxShouldPostCompletion() &&
5254 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
5256 return STATUS_MORE_PROCESSING_REQUIRED
;
5259 /* Call the completion routine */
5260 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
5261 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
5262 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
5267 /* If it was a RW operation, for a paging file ... */
5268 Operation
= RxContext
->LowIoContext
.Operation
;
5269 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
5271 /* Remove ourselves from the list and resume operations */
5272 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5274 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5275 RemoveEntryList(&RxContext
->RxContextSerializationQLinks
);
5276 RxContext
->RxContextSerializationQLinks
.Flink
= NULL
;
5277 RxContext
->RxContextSerializationQLinks
.Blink
= NULL
;
5278 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5279 RxResumeBlockedOperations_ALL(RxContext
);
5284 /* Sanity check: we had known operation */
5285 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
5288 /* If not sync operation, complete now. Otherwise, caller has already completed */
5289 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
5291 RxCompleteRequest(RxContext
, Status
);
5294 DPRINT("Status: %x\n", Status
);
5303 RxLowIoPopulateFsctlInfo(
5304 IN PRX_CONTEXT RxContext
)
5309 PIO_STACK_LOCATION Stack
;
5313 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
5315 Irp
= RxContext
->CurrentIrp
;
5316 Stack
= RxContext
->CurrentIrpSp
;
5318 /* Copy stack parameters */
5319 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
5320 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
5321 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
5322 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
5323 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
5325 /* Same buffer in case of buffered */
5326 if (Method
== METHOD_BUFFERED
)
5328 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5329 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5331 return STATUS_SUCCESS
;
5334 /* Two buffers for neither */
5335 if (Method
== METHOD_NEITHER
)
5337 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
5338 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
5340 return STATUS_SUCCESS
;
5343 /* Only IN/OUT remain */
5344 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
5346 /* Use system buffer for input */
5347 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5348 /* And MDL for output */
5349 Mdl
= Irp
->MdlAddress
;
5352 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
5353 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
5355 return STATUS_INSUFFICIENT_RESOURCES
;
5360 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
5363 return STATUS_SUCCESS
;
5369 IN PRX_CONTEXT RxContext
,
5370 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
5374 BOOLEAN Synchronous
;
5375 PLOWIO_CONTEXT LowIoContext
;
5377 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
5381 LowIoContext
= &RxContext
->LowIoContext
;
5382 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
5384 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
5386 Status
= STATUS_SUCCESS
;
5387 Operation
= LowIoContext
->Operation
;
5391 case LOWIO_OP_WRITE
:
5392 /* Check that the parameters were properly set by caller
5393 * See comment in RxInitializeLowIoContext()
5395 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
5396 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
5398 /* Lock the buffer */
5399 RxLockUserBuffer(RxContext
,
5400 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
5401 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
5402 if (RxNewMapUserBuffer(RxContext
) == NULL
)
5404 return STATUS_INSUFFICIENT_RESOURCES
;
5406 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
5408 /* If that's a paging IO, initialize serial operation */
5409 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5413 Fcb
= (PFCB
)RxContext
->pFcb
;
5415 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5416 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
5417 if (Operation
== LOWIO_OP_READ
)
5419 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5423 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5426 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5431 case LOWIO_OP_FSCTL
:
5432 case LOWIO_OP_IOCTL
:
5433 /* Set FSCTL/IOCTL parameters */
5434 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
5435 /* Check whether we're consistent: a length means a buffer */
5436 if (NT_SUCCESS(Status
))
5438 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
5439 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
5440 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
5441 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
5443 Status
= STATUS_INVALID_PARAMETER
;
5449 case LOWIO_OP_SHAREDLOCK
:
5450 case LOWIO_OP_EXCLUSIVELOCK
:
5451 case LOWIO_OP_UNLOCK
:
5452 case LOWIO_OP_UNLOCK_MULTIPLE
:
5453 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
5454 case LOWIO_OP_CLEAROUT
:
5459 Status
= STATUS_INVALID_PARAMETER
;
5463 /* No need to perform extra init in case of posting */
5464 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
5466 /* Preflight checks were OK, time to submit */
5467 if (NT_SUCCESS(Status
))
5469 PMINIRDR_DISPATCH Dispatch
;
5473 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
5474 /* If not synchronous, we're likely to return before the operation is finished */
5475 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5477 IoMarkIrpPending(RxContext
->CurrentIrp
);
5481 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
5482 if (Dispatch
!= NULL
)
5484 /* We'll try to execute until the mini-rdr doesn't return pending */
5487 RxContext
->IoStatusBlock
.Information
= 0;
5489 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
5490 if (Status
== STATUS_PENDING
)
5492 /* Unless it's not synchronous, caller will be happy with pending op */
5498 RxWaitSync(RxContext
);
5499 Status
= RxContext
->IoStatusBlock
.Status
;
5505 /* We had marked the IRP pending, whereas the operation finished, drop that */
5506 if (Status
!= STATUS_RETRY
)
5508 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5510 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
5513 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
5517 } while (Status
== STATUS_PENDING
);
5521 Status
= STATUS_INVALID_PARAMETER
;
5525 /* Call completion and return */
5526 RxContext
->IoStatusBlock
.Status
= Status
;
5527 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
5528 return RxLowIoCompletionTail(RxContext
);
5536 IN PRX_CONTEXT RxContext
)
5542 Irp
= RxContext
->CurrentIrp
;
5543 /* We should have a MDL (buffered IOs are not supported!) */
5544 if (Irp
->MdlAddress
!= NULL
)
5547 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5550 /* Just return system buffer */
5551 return Irp
->AssociatedIrp
.SystemBuffer
;
5558 RxMarkFobxOnCleanup(
5563 PFOBX ScavengerFobx
;
5564 LARGE_INTEGER TickCount
;
5565 PRDBSS_SCAVENGER Scavenger
;
5569 /* No FOBX, nothing to mark */
5575 /* Query time for close */
5576 KeQueryTickCount(&TickCount
);
5578 Fcb
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
5579 ASSERT(NodeTypeIsFcb(Fcb
));
5581 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5582 RxAcquireScavengerMutex();
5584 ScavengerFobx
= NULL
;
5585 /* If that's not a file, or even not a disk resource, just mark as dormant */
5586 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
|| Fcb
->VNetRoot
->pNetRoot
->DeviceType
!= FILE_DEVICE_DISK
)
5588 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5589 InitializeListHead(&pFobx
->ClosePendingList
);
5590 ++Scavenger
->NumberOfDormantFiles
;
5594 ASSERT(Scavenger
->NumberOfDormantFiles
>= 0);
5595 /* If we're about to reach the maximum dormant of FOBX */
5596 if (Scavenger
->NumberOfDormantFiles
>= Scavenger
->MaximumNumberOfDormantFiles
)
5598 /* This should never be wrong... */
5599 if (!IsListEmpty(&Scavenger
->ClosePendingFobxsList
))
5601 /* Then, take the first from the list (oldest) and save it for later purge */
5602 ScavengerFobx
= CONTAINING_RECORD(Scavenger
->ClosePendingFobxsList
.Flink
, FOBX
, ClosePendingList
);
5603 if (ScavengerFobx
->pSrvOpen
!= NULL
&& ScavengerFobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
5606 ScavengerFobx
= NULL
;
5610 RxReferenceNetFobx(ScavengerFobx
);
5615 /* Mark ourselves as dormant */
5616 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5617 pFobx
->CloseTime
.QuadPart
= TickCount
.QuadPart
;
5619 /* And insert us in the list of dormant files */
5620 InsertTailList(&Scavenger
->ClosePendingFobxsList
, &pFobx
->ClosePendingList
);
5621 /* If scavenger was inactive, start it */
5622 if (Scavenger
->NumberOfDormantFiles
++ == 0 && Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
5624 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
5625 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
, RxScavengerTimerRoutine
,
5626 Fcb
->RxDeviceObject
, Scavenger
->TimeLimit
);
5630 RxReleaseScavengerMutex();
5632 /* If we had reached max */
5633 if (ScavengerFobx
!= NULL
)
5637 /* Purge the oldest FOBX */
5638 Status
= RxPurgeFobxFromCache(ScavengerFobx
);
5639 if (Status
!= STATUS_SUCCESS
)
5654 PRDBSS_SCAVENGER Scavenger
;
5658 /* No FOBX, nothing to mark */
5664 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5665 ASSERT(NodeTypeIsFcb(Fcb
));
5667 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5669 RxAcquireScavengerMutex();
5670 /* Only mark it if it was already marked as dormant */
5671 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
))
5673 /* If FCB wasn't already decrement, do it now */
5674 if (!Fobx
->fOpenCountDecremented
)
5676 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5677 ASSERT(NodeTypeIsFcb(Fcb
));
5678 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
5680 Fobx
->fOpenCountDecremented
= TRUE
;
5683 /* We're no longer dormant */
5684 InterlockedDecrement(&Scavenger
->NumberOfDormantFiles
);
5685 ClearFlag(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5688 /* If we were inserted in the scavenger, drop ourselves out */
5689 if (!IsListEmpty(&Fobx
->ClosePendingList
))
5691 RemoveEntryList(&Fobx
->ClosePendingList
);
5692 InitializeListHead(&Fobx
->ClosePendingList
);
5695 RxReleaseScavengerMutex();
5703 PRX_CONTEXT RxContext
)
5709 Irp
= RxContext
->CurrentIrp
;
5710 if (Irp
->MdlAddress
!= NULL
)
5712 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5715 return Irp
->UserBuffer
;
5745 IN PV_NET_ROOT ThisVNetRoot
)
5750 PRX_FCB_TABLE FcbTable
;
5751 PRX_PREFIX_TABLE PrefixTable
;
5755 /* Mailslot won't have any SRV_OPEN (to orphan) */
5756 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
5757 if (NetRoot
->Type
== NET_ROOT_MAILSLOT
)
5762 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
5763 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
5765 FcbTable
= &NetRoot
->FcbTable
;
5766 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
5770 /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
5771 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
5773 PLIST_ENTRY BucketList
, Entry
;
5775 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
5776 Entry
= BucketList
->Flink
;
5777 while (Entry
!= BucketList
)
5779 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
5780 Entry
= Entry
->Flink
;
5782 ASSERT(NodeTypeIsFcb(Fcb
));
5783 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5787 /* Of course, don't forget about NULL-entry */
5788 if (FcbTable
->TableEntryForNull
!= NULL
)
5790 Fcb
= CONTAINING_RECORD(FcbTable
->TableEntryForNull
, FCB
, FcbTableEntry
.HashLinks
);
5791 ASSERT(NodeTypeIsFcb(Fcb
));
5792 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5797 RxReleaseFcbTableLock(FcbTable
);
5803 RxOrphanSrvOpensForThisFcb(
5805 IN PV_NET_ROOT ThisVNetRoot
,
5806 IN BOOLEAN OrphanAll
)
5815 RxpAcquirePrefixTableLockShared(
5816 PRX_PREFIX_TABLE pTable
,
5818 BOOLEAN ProcessBufferingStateChangeRequests
)
5822 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5823 pTable
->TableLock
.ActiveEntries
);
5825 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
5832 RxpAcquirePrefixTableLockExclusive(
5833 PRX_PREFIX_TABLE pTable
,
5835 BOOLEAN ProcessBufferingStateChangeRequests
)
5839 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5840 pTable
->TableLock
.ActiveEntries
);
5842 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
5849 RxpDereferenceAndFinalizeNetFcb(
5851 IN PRX_CONTEXT RxContext
,
5852 IN BOOLEAN RecursiveFinalize
,
5853 IN BOOLEAN ForceFinalize
)
5858 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
5862 ASSERT(!ForceFinalize
);
5863 ASSERT(NodeTypeIsFcb(ThisFcb
));
5864 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
5866 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5867 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
5868 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
5874 Status
= STATUS_SUCCESS
;
5875 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
5876 ResourceAcquired
= FALSE
;
5877 NetRootReferenced
= FALSE
;
5878 /* If FCB isn't orphaned, it still have context attached */
5879 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
5881 /* Don't let NetRoot go away before we're done */
5882 RxReferenceNetRoot(NetRoot
);
5883 NetRootReferenced
= TRUE
;
5885 /* Try to acquire the table lock exclusively */
5886 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
5888 RxReferenceNetFcb(ThisFcb
);
5890 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
5892 if (RxContext
!= NULL
&& RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT
&&
5893 RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
5895 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
5898 RxReleaseFcb(RxContext
, ThisFcb
);
5900 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5902 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
5905 References
= RxDereferenceNetFcb(ThisFcb
);
5907 ResourceAcquired
= TRUE
;
5911 /* If locking was OK (or not needed!), attempt finalization */
5912 if (Status
== STATUS_SUCCESS
)
5914 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
5917 /* Release table lock if acquired */
5918 if (ResourceAcquired
)
5920 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5923 /* We don't need the NetRoot anylonger */
5924 if (NetRootReferenced
)
5926 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
5936 RxpDereferenceNetFcb(
5943 ASSERT(NodeTypeIsFcb(Fcb
));
5945 NewCount
= InterlockedDecrement((volatile long *)&Fcb
->NodeReferenceCount
);
5946 ASSERT(NewCount
>= 0);
5948 PRINT_REF_COUNT(NETFCB
, NewCount
);
5963 BOOLEAN ForceFinalize
;
5964 PRX_PREFIX_TABLE PrefixTable
;
5966 SrvCall
= (PSRV_CALL
)Context
;
5967 /* At this step, RxFinalizeSrvCall already cleaned some fields */
5968 ASSERT(SrvCall
->UpperFinalizationDone
);
5970 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
5971 /* Were we called with ForceFinalize? */
5972 ForceFinalize
= BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
5974 /* Notify mini-rdr */
5975 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
,
5976 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)SrvCall
,
5980 /* Dereference our extra reference (set before queueing) */
5981 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
5982 InterlockedDecrement((volatile long *)&SrvCall
->NodeReferenceCount
);
5983 /* And finalize for real, with the right context */
5984 RxFinalizeSrvCall(SrvCall
, FALSE
, ForceFinalize
);
5985 RxReleasePrefixTableLock(PrefixTable
);
5992 RxpDiscardChangeBufferingStateRequests(
5993 _Inout_ PLIST_ENTRY DiscardedRequests
)
5999 /* No requests to discard */
6000 if (IsListEmpty(DiscardedRequests
))
6005 /* Free all the discarded requests */
6006 Entry
= DiscardedRequests
->Flink
;
6007 while (Entry
!= DiscardedRequests
)
6009 PCHANGE_BUFFERING_STATE_REQUEST Request
;
6011 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
6012 Entry
= Entry
->Flink
;
6014 DPRINT("Req %p for %p (%p) discarded\n", Request
, Request
->SrvOpenKey
, Request
->SrvOpen
);
6016 RxPrepareRequestForReuse(Request
);
6017 RxFreePool(Request
);
6025 RxpDispatchChangeBufferingStateRequests(
6028 PLIST_ENTRY DiscardedRequests
)
6032 BOOLEAN StartDispatcher
;
6033 LIST_ENTRY AcceptedReqs
;
6034 LIST_ENTRY DispatcherList
;
6035 PRX_BUFFERING_MANAGER BufferingManager
;
6037 /* Initialize our lists */
6038 InitializeListHead(&AcceptedReqs
);
6039 InitializeListHead(DiscardedRequests
);
6041 /* Transfer the requests to dispatch locally */
6042 BufferingManager
= &SrvCall
->BufferingManager
;
6043 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
6044 RxTransferList(&DispatcherList
, &BufferingManager
->DispatcherList
);
6045 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6047 /* If there were requests */
6048 if (!IsListEmpty(&DispatcherList
))
6052 /* For each of the entries... */
6053 Entry
= DispatcherList
.Flink
;
6054 while (Entry
!= &DispatcherList
)
6056 PCHANGE_BUFFERING_STATE_REQUEST Request
;
6058 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
6059 Entry
= Entry
->Flink
;
6061 /* If we have been provided a SRV_OPEN, see whether it matches */
6062 if (SrvOpen
!= NULL
)
6064 /* Match, the request is accepted */
6065 if (Request
->SrvOpenKey
== SrvOpen
->Key
)
6067 Request
->SrvOpen
= SrvOpen
;
6068 RxReferenceSrvOpen(SrvOpen
);
6070 RemoveEntryList(&Request
->ListEntry
);
6071 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
6073 /* Move to the next entry */
6078 Status
= STATUS_PENDING
;
6083 /* No SRV_OPEN provided, try to find one */
6084 Status
= RxpLookupSrvOpenForRequestLite(SrvCall
, Request
);
6087 /* We found a matching SRV_OPEN, accept the request */
6088 if (Status
== STATUS_SUCCESS
)
6090 RemoveEntryList(&Request
->ListEntry
);
6091 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
6093 /* Another run might help handling it, don't discard it */
6094 else if (Status
== STATUS_PENDING
)
6098 /* Otherwise, discard the request */
6101 ASSERT(Status
== STATUS_NOT_FOUND
);
6103 RemoveEntryList(&Request
->ListEntry
);
6104 InsertTailList(DiscardedRequests
, &Request
->ListEntry
);
6109 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
6110 /* Nothing to dispatch, no need to start dispatcher */
6111 if (IsListEmpty(&DispatcherList
))
6113 StartDispatcher
= FALSE
;
6117 /* Transfer back the list of the not treated entries to the buffering manager */
6118 RxTransferList(&BufferingManager
->DispatcherList
, &DispatcherList
);
6119 StartDispatcher
= (BufferingManager
->DispatcherActive
== FALSE
);
6120 /* If the dispatcher isn't active, start it */
6121 if (StartDispatcher
)
6123 BufferingManager
->DispatcherActive
= TRUE
;
6127 /* If there were accepted requests, move them to the buffering manager */
6128 if (!IsListEmpty(&AcceptedReqs
))
6130 RxTransferList(&BufferingManager
->HandlerList
, &AcceptedReqs
);
6132 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6134 /* If we're to start the dispatcher, do it */
6135 if (StartDispatcher
)
6137 RxReferenceSrvCall(SrvCall
);
6138 DPRINT("Starting dispatcher\n");
6139 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
6140 &BufferingManager
->DispatcherWorkItem
,
6141 RxDispatchChangeBufferingStateRequests
, SrvCall
);
6149 RxpLookupSrvOpenForRequestLite(
6150 IN PSRV_CALL SrvCall
,
6151 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request
)
6159 Status
= STATUS_SUCCESS
;
6160 /* Browse all our associated SRV_OPENs to find the one! */
6161 for (Entry
= SrvCall
->BufferingManager
.SrvOpenLists
[0].Flink
;
6162 Entry
!= &SrvCall
->BufferingManager
.SrvOpenLists
[0];
6163 Entry
= Entry
->Flink
)
6165 /* Same key, not orphaned, this is ours */
6166 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenKeyList
);
6167 if (SrvOpen
->Key
== Request
->SrvOpenKey
)
6169 if (!BooleanFlagOn(SrvOpen
->pFcb
->FcbState
, FCB_STATE_ORPHANED
))
6171 RxReferenceSrvOpen(SrvOpen
);
6177 /* We didn't manage to find a SRV_OPEN */
6178 if (Entry
== &SrvCall
->BufferingManager
.SrvOpenLists
[0])
6182 /* The coming open might help, mark as pending for later retry */
6183 if (SrvCall
->BufferingManager
.NumberOfOutstandingOpens
!= 0)
6185 Status
= STATUS_PENDING
;
6187 /* Else, it's a complete failure */
6190 Status
= STATUS_NOT_FOUND
;
6194 /* Return the (not) found SRV_OPEN */
6195 Request
->SrvOpen
= SrvOpen
;
6204 RxpMarkInstanceForScavengedFinalization(
6207 NODE_TYPE_CODE NodeType
;
6208 PNODE_TYPE_AND_SIZE Node
;
6209 PRDBSS_SCAVENGER Scavenger
;
6210 PRDBSS_DEVICE_OBJECT DeviceObject
;
6211 PLIST_ENTRY ScavengerHead
, InstEntry
;
6215 /* If still referenced, don't mark it (broken caller) */
6216 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6217 if (Node
->NodeReferenceCount
> 1)
6222 DeviceObject
= RxGetDeviceObjectOfInstance(Instance
);
6223 Scavenger
= DeviceObject
->pRdbssScavenger
;
6226 NodeType
= NodeType(Instance
);
6227 SetFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6228 DPRINT("Node %p has now the scavenger mark!\n", Instance
);
6230 /* Increase the count in the scavenger, and queue it */
6231 ScavengerHead
= NULL
;
6234 case RDBSS_NTC_FOBX
:
6235 ++Scavenger
->FobxsToBeFinalized
;
6236 ScavengerHead
= &Scavenger
->FobxFinalizationList
;
6237 InstEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6240 case RDBSS_NTC_SRVCALL
:
6241 ++Scavenger
->SrvCallsToBeFinalized
;
6242 ScavengerHead
= &Scavenger
->SrvCallFinalizationList
;
6243 InstEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6246 case RDBSS_NTC_NETROOT
:
6247 ++Scavenger
->NetRootsToBeFinalized
;
6248 ScavengerHead
= &Scavenger
->NetRootFinalizationList
;
6249 InstEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6252 case RDBSS_NTC_V_NETROOT
:
6253 ++Scavenger
->VNetRootsToBeFinalized
;
6254 ScavengerHead
= &Scavenger
->VNetRootFinalizationList
;
6255 InstEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6258 case RDBSS_NTC_SRVOPEN
:
6259 ++Scavenger
->SrvOpensToBeFinalized
;
6260 ScavengerHead
= &Scavenger
->SrvOpenFinalizationList
;
6261 InstEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6265 /* Extra ref for scavenger */
6266 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
6268 /* If matching type */
6269 if (ScavengerHead
!= NULL
)
6271 /* Insert in the scavenger list */
6272 InsertTailList(ScavengerHead
, InstEntry
);
6274 /* And if it wasn't started, start it */
6275 if (Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
6277 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
6278 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
6279 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
6289 RxPostOneShotTimerRequest(
6290 IN PRDBSS_DEVICE_OBJECT pDeviceObject
,
6291 IN PRX_WORK_ITEM pWorkItem
,
6292 IN PRX_WORKERTHREAD_ROUTINE Routine
,
6294 IN LARGE_INTEGER TimeInterval
)
6298 ASSERT(pWorkItem
!= NULL
);
6300 /* Prepare the work item */
6301 ExInitializeWorkItem(&pWorkItem
->WorkQueueItem
, Routine
, pContext
);
6302 pWorkItem
->WorkQueueItem
.pDeviceObject
= pDeviceObject
;
6304 /* Last tick can be computed with the number of times it was caller (timertickcount)
6305 * and the interval between calls
6307 KeAcquireSpinLock(&RxTimerLock
, &OldIrql
);
6308 pWorkItem
->LastTick
= (TimeInterval
.QuadPart
/ 550000) + RxTimerTickCount
+ 1;
6309 /* Insert in work queue */
6310 InsertTailList(&RxTimerQueueHead
, &pWorkItem
->WorkQueueItem
.List
);
6311 KeReleaseSpinLock(&RxTimerLock
, OldIrql
);
6313 /* If there are queued events, queue an execution */
6314 if (IsListEmpty(&RxTimerQueueHead
))
6316 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
6319 return STATUS_SUCCESS
;
6327 RxPostToWorkerThread(
6328 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
6329 _In_ WORK_QUEUE_TYPE WorkQueueType
,
6330 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem
,
6331 _In_ PRX_WORKERTHREAD_ROUTINE Routine
,
6332 _In_ PVOID pContext
)
6334 /* Initialize work queue item */
6335 pWorkQueueItem
->List
.Flink
= NULL
;
6336 pWorkQueueItem
->WorkerRoutine
= Routine
;
6337 pWorkQueueItem
->Parameter
= pContext
;
6339 /* And insert it in the work queue */
6340 return RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, pWorkQueueItem
);
6344 RxpProcessChangeBufferingStateRequests(
6346 BOOLEAN UpdateHandlerState
)
6355 RxPrefixTableInsertName(
6356 IN OUT PRX_PREFIX_TABLE ThisTable
,
6357 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
6359 IN PULONG ContainerRefCount
,
6360 IN USHORT CaseInsensitiveLength
,
6361 IN PRX_CONNECTION_ID ConnectionId
6366 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
6368 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
6369 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
6371 /* Copy parameters and compute hash */
6372 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
6373 ThisEntry
->ContainingRecord
= Container
;
6374 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
6375 InterlockedIncrement((volatile long *)ContainerRefCount
);
6376 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
6377 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
6379 /* If no path length: this is entry for null path */
6380 if (ThisEntry
->Prefix
.Length
== 0)
6382 ThisTable
->TableEntryForNull
= ThisEntry
;
6384 /* Otherwise, insert in the appropriate bucket */
6387 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
6390 /* If we had a connection ID, keep track of it */
6391 if (ConnectionId
!= NULL
)
6393 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
6397 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
6398 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
6401 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
6402 /* Reflect the changes */
6403 ++ThisTable
->Version
;
6405 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
6414 RxPrefixTableLookupName(
6415 IN PRX_PREFIX_TABLE ThisTable
,
6416 IN PUNICODE_STRING CanonicalName
,
6417 OUT PUNICODE_STRING RemainingName
,
6418 IN PRX_CONNECTION_ID ConnectionId
)
6424 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
6425 ASSERT(CanonicalName
->Length
> 0);
6427 /* Call the internal helper */
6428 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
6429 if (Container
== NULL
)
6434 /* Reference our container before returning it */
6435 if (RdbssReferenceTracingValue
!= 0)
6437 NODE_TYPE_CODE Type
;
6439 Type
= (NodeType(Container
) & ~RX_SCAVENGER_MASK
);
6442 case RDBSS_NTC_SRVCALL
:
6443 RxReferenceSrvCall(Container
);
6446 case RDBSS_NTC_NETROOT
:
6447 RxReferenceNetRoot(Container
);
6450 case RDBSS_NTC_V_NETROOT
:
6451 RxReferenceVNetRoot(Container
);
6455 DPRINT1("Invalid node type: %x\n", Type
);
6457 RxReference(Container
);
6463 RxReference(Container
);
6480 ASSERT(NodeTypeIsFcb(Fcb
));
6482 NewCount
= InterlockedIncrement((volatile long *)&Fcb
->NodeReferenceCount
);
6484 PRINT_REF_COUNT(NETFCB
, Fcb
->NodeReferenceCount
);
6493 RxpReleasePrefixTableLock(
6494 PRX_PREFIX_TABLE pTable
,
6495 BOOLEAN ProcessBufferingStateChangeRequests
)
6499 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
6500 pTable
->TableLock
.ActiveEntries
);
6502 ExReleaseResourceLite(&pTable
->TableLock
);
6510 RxPrepareContextForReuse(
6511 IN OUT PRX_CONTEXT RxContext
)
6515 /* When we reach that point, make sure mandatory parts are null-ed */
6516 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
6518 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
6519 RxContext
->Create
.RdrFlags
= 0;
6521 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
6523 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
6524 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
6527 RxContext
->ReferenceCount
= 0;
6534 RxPrepareRequestForReuse(
6535 PCHANGE_BUFFERING_STATE_REQUEST Request
)
6541 SrvOpen
= Request
->SrvOpen
;
6543 /* If the request was already prepared for service */
6544 if (BooleanFlagOn(Request
->Flags
, RX_REQUEST_PREPARED_FOR_HANDLING
))
6546 /* We have to dereference the associated SRV_OPEN depending on the lock */
6547 if (RxIsFcbAcquiredExclusive(SrvOpen
->pFcb
))
6549 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
6553 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6556 /* Otherwise, just dereference */
6557 else if (SrvOpen
!= NULL
)
6559 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6562 Request
->SrvOpen
= NULL
;
6570 RxProcessChangeBufferingStateRequests(
6573 /* Call internal routine */
6574 RxUndoScavengerFinalizationMarking(SrvCall
);
6575 RxpProcessChangeBufferingStateRequests(SrvCall
, TRUE
);
6582 RxProcessChangeBufferingStateRequestsForSrvOpen(
6585 LONG NumberOfBufferingChangeRequests
, LockedOldBufferingToken
, OldBufferingToken
;
6587 /* Get the current number of change requests */
6588 NumberOfBufferingChangeRequests
= ((PSRV_CALL
)SrvOpen
->pVNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
.CumulativeNumberOfBufferingChangeRequests
;
6589 /* Get our old token */
6590 OldBufferingToken
= SrvOpen
->BufferingToken
;
6591 LockedOldBufferingToken
= InterlockedCompareExchange(&SrvOpen
->BufferingToken
,
6592 NumberOfBufferingChangeRequests
,
6593 NumberOfBufferingChangeRequests
);
6594 /* If buffering state changed in between, process changes */
6595 if (OldBufferingToken
!= LockedOldBufferingToken
)
6600 /* Acquire the FCB and start processing */
6601 Fcb
= (PFCB
)SrvOpen
->pFcb
;
6602 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
6603 if (Status
== STATUS_SUCCESS
)
6605 RxProcessFcbChangeBufferingStateRequest(Fcb
);
6606 RxReleaseFcb(NULL
, Fcb
);
6612 RxProcessFcbChangeBufferingStateRequest(
6623 PRDBSS_SCAVENGER Scavenger
,
6624 PLIST_ENTRY FobxToScavenge
)
6626 /* Explore the whole list of FOBX to scavenge */
6627 while (!IsListEmpty(FobxToScavenge
))
6633 Entry
= RemoveHeadList(FobxToScavenge
);
6634 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ScavengerFinalizationList
);
6635 Fcb
= (PFCB
)Fobx
->SrvOpen
->pFcb
;
6637 /* Try to acquire the lock exclusively to perform finalization */
6638 if (RxAcquireExclusiveFcb(NULL
, Fcb
) != STATUS_SUCCESS
)
6640 RxDereferenceNetRoot(Fobx
, LHS_LockNotHeld
);
6644 RxReferenceNetFcb(Fcb
);
6645 RxDereferenceNetRoot(Fobx
, LHS_ExclusiveLockHeld
);
6647 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6649 RxReleaseFcb(NULL
, Fcb
);
6656 RxpTrackDereference(
6657 _In_ ULONG TraceType
,
6658 _In_ PCSTR FileName
,
6660 _In_ PVOID Instance
)
6663 ULONG ReferenceCount
;
6667 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6674 case RDBSS_REF_TRACK_SRVCALL
:
6675 InstanceType
= "SrvCall";
6676 ReferenceCount
= ((PSRV_CALL
)Instance
)->NodeReferenceCount
;
6679 case RDBSS_REF_TRACK_NETROOT
:
6680 InstanceType
= "NetRoot";
6681 ReferenceCount
= ((PNET_ROOT
)Instance
)->NodeReferenceCount
;
6684 case RDBSS_REF_TRACK_VNETROOT
:
6685 InstanceType
= "VNetRoot";
6686 ReferenceCount
= ((PV_NET_ROOT
)Instance
)->NodeReferenceCount
;
6689 case RDBSS_REF_TRACK_NETFOBX
:
6690 InstanceType
= "NetFobx";
6691 ReferenceCount
= ((PFOBX
)Instance
)->NodeReferenceCount
;
6694 case RDBSS_REF_TRACK_NETFCB
:
6695 InstanceType
= "NetFcb";
6696 ReferenceCount
= ((PFCB
)Instance
)->NodeReferenceCount
;
6699 case RDBSS_REF_TRACK_SRVOPEN
:
6700 InstanceType
= "SrvOpen";
6701 ReferenceCount
= ((PSRV_OPEN
)Instance
)->NodeReferenceCount
;
6705 DPRINT1("Invalid node type!\n");
6709 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_LOG_REF_TRACKING
))
6714 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_PRINT_REF_TRACKING
))
6716 DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName
, Line
, Instance
, InstanceType
, ReferenceCount
);
6724 _In_ ULONG TraceType
,
6725 _In_ PCSTR FileName
,
6727 _In_ PVOID Instance
)
6730 ULONG ReferenceCount
;
6732 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6739 case RDBSS_REF_TRACK_SRVCALL
:
6740 InstanceType
= "SrvCall";
6741 ReferenceCount
= ((PSRV_CALL
)Instance
)->NodeReferenceCount
;
6744 case RDBSS_REF_TRACK_NETROOT
:
6745 InstanceType
= "NetRoot";
6746 ReferenceCount
= ((PNET_ROOT
)Instance
)->NodeReferenceCount
;
6749 case RDBSS_REF_TRACK_VNETROOT
:
6750 InstanceType
= "VNetRoot";
6751 ReferenceCount
= ((PV_NET_ROOT
)Instance
)->NodeReferenceCount
;
6754 case RDBSS_REF_TRACK_NETFOBX
:
6755 InstanceType
= "NetFobx";
6756 ReferenceCount
= ((PFOBX
)Instance
)->NodeReferenceCount
;
6759 case RDBSS_REF_TRACK_NETFCB
:
6760 InstanceType
= "NetFcb";
6761 ReferenceCount
= ((PFCB
)Instance
)->NodeReferenceCount
;
6764 case RDBSS_REF_TRACK_SRVOPEN
:
6765 InstanceType
= "SrvOpen";
6766 ReferenceCount
= ((PSRV_OPEN
)Instance
)->NodeReferenceCount
;
6770 DPRINT1("Invalid node type!\n");
6774 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_LOG_REF_TRACKING
))
6779 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_PRINT_REF_TRACKING
))
6781 DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName
, Line
, Instance
, InstanceType
, ReferenceCount
);
6789 RxpUndoScavengerFinalizationMarking(
6792 PLIST_ENTRY ListEntry
;
6793 PNODE_TYPE_AND_SIZE Node
;
6794 PRDBSS_SCAVENGER Scavenger
;
6798 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6799 /* There's no marking - nothing to do */
6800 if (!BooleanFlagOn(NodeType(Node
), RX_SCAVENGER_MASK
))
6805 /* First of all, remove the mark */
6806 ClearFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6807 DPRINT("Node %p no longer has the scavenger mark\n");
6809 /* And now, remove from the scavenger */
6810 Scavenger
= RxGetDeviceObjectOfInstance(Instance
)->pRdbssScavenger
;
6811 switch (NodeType(Node
))
6813 case RDBSS_NTC_FOBX
:
6814 --Scavenger
->FobxsToBeFinalized
;
6815 ListEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6818 case RDBSS_NTC_SRVCALL
:
6819 --Scavenger
->SrvCallsToBeFinalized
;
6820 ListEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6823 case RDBSS_NTC_NETROOT
:
6824 --Scavenger
->NetRootsToBeFinalized
;
6825 ListEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6828 case RDBSS_NTC_V_NETROOT
:
6829 --Scavenger
->VNetRootsToBeFinalized
;
6830 ListEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6833 case RDBSS_NTC_SRVOPEN
:
6834 --Scavenger
->SrvOpensToBeFinalized
;
6835 ListEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6839 /* Also, remove the extra ref from the scavenger */
6840 RemoveEntryList(ListEntry
);
6841 InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
6848 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6852 LIST_ENTRY Discarded
;
6856 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
6858 /* Initialize our discarded list */
6859 InitializeListHead(&Discarded
);
6861 SrvCall
= (PSRV_CALL
)SrvOpen
->Fcb
->VNetRoot
->pNetRoot
->pSrvCall
;
6862 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
6864 /* Set the flag, and get the requests */
6865 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
6866 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED
);
6867 RxGatherRequestsForSrvOpen(SrvCall
, SrvOpen
, &Discarded
);
6869 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
6871 /* If there were discarded requests */
6872 if (!IsListEmpty(&Discarded
))
6874 /* And a pending buffering state change */
6875 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
6877 /* Clear the flag, and set the associated event - job done */
6878 RxAcquireSerializationMutex();
6879 ClearFlag(SrvOpen
->Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
6880 if (SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
6882 KeSetEvent(SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
, IO_NETWORK_INCREMENT
, FALSE
);
6884 RxReleaseSerializationMutex();
6887 /* Drop the discarded requests */
6888 RxpDiscardChangeBufferingStateRequests(&Discarded
);
6901 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6903 /* Reference our FCB so that it doesn't disappear */
6904 RxReferenceNetFcb(Fcb
);
6905 /* Purge Cc if required */
6906 if (Fcb
->OpenCount
!= 0)
6908 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
6911 /* If it wasn't freed, release the lock */
6912 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6914 RxReleaseFcb(NULL
, Fcb
);
6922 RxPurgeFcbInSystemCache(
6924 IN PLARGE_INTEGER FileOffset OPTIONAL
,
6926 IN BOOLEAN UninitializeCacheMaps
,
6927 IN BOOLEAN FlushFile
)
6934 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6936 /* Try to flush first, if asked */
6939 /* If flushing failed, just make some noise */
6940 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
6941 if (!NT_SUCCESS(Status
))
6943 PVOID CallersAddress
, CallersCaller
;
6945 RtlGetCallersAddress(&CallersAddress
, &CallersCaller
);
6946 DPRINT1("Flush failed with status %lx for FCB %p\n", Status
, Fcb
);
6947 DPRINT1("Caller was %p %p\n", CallersAddress
, CallersCaller
);
6951 /* Deal with Cc for purge */
6952 Purged
= CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, FileOffset
,
6953 Length
, UninitializeCacheMaps
);
6954 /* If purge failed, force section closing */
6957 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
6959 RxReleaseFcb(NULL
, Fcb
);
6960 Purged
= MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
6961 RxAcquireExclusiveFcb(NULL
, Fcb
);
6964 /* Return appropriate status */
6965 Status
= (Purged
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
6966 DPRINT("Purge for FCB %p returns %lx\n", Fcb
, Status
);
6983 /* Get the associated FCB */
6984 FcbToBePurged
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
6985 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
6986 ASSERT(Status
== STATUS_SUCCESS
);
6989 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
6990 if (Status
!= STATUS_SUCCESS
)
6992 DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged
, pFobx
);
6997 if (!MmFlushImageSection(&FcbToBePurged
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
))
6999 DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged
, pFobx
);
7003 DPRINT("Purge OK for %p (%p)\n", FcbToBePurged
, pFobx
);
7011 RxPurgeFobxFromCache(
7012 PFOBX FobxToBePurged
)
7019 FcbToBePurged
= (PFCB
)FobxToBePurged
->pSrvOpen
->pFcb
;
7020 ASSERT(FcbToBePurged
!= NULL
);
7022 /* If we cannot have our FCB exclusively, give up */
7023 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
7024 if (Status
!= STATUS_SUCCESS
)
7026 RxDereferenceNetFobx(FobxToBePurged
, LHS_LockNotHeld
);
7030 /* Don't let the FCB disappear */
7031 RxReferenceNetFcb(FcbToBePurged
);
7033 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
7034 if (BooleanFlagOn(FobxToBePurged
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
) || FobxToBePurged
->pSrvOpen
->UncleanFobxCount
!= 0)
7036 DPRINT("FCB purge skipped\n");
7040 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
7043 RxDereferenceNetFobx(FobxToBePurged
, LHS_ExclusiveLockHeld
);
7044 /* Drop our extra reference */
7045 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged
, NULL
, FALSE
, FALSE
))
7047 RxReleaseFcb(NULL
, FcbToBePurged
);
7057 RxPurgeRelatedFobxs(
7059 PRX_CONTEXT RxContext
,
7060 BOOLEAN AttemptFinalization
,
7064 ULONG SuccessfullPurge
;
7065 PRDBSS_SCAVENGER Scavenger
;
7066 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7067 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx
;
7071 RxDeviceObject
= RxContext
->RxDeviceObject
;
7072 Scavenger
= RxDeviceObject
->pRdbssScavenger
;
7073 PurgeSyncCtx
= &NetRoot
->PurgeSyncronizationContext
;
7075 RxAcquireScavengerMutex();
7077 /* If there's already a purge in progress */
7078 if (PurgeSyncCtx
->PurgeInProgress
)
7080 /* Add our RX_CONTEXT to the current run */
7081 InsertTailList(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
,
7082 &RxContext
->RxContextSerializationQLinks
);
7084 /* And wait until it's done */
7085 RxReleaseScavengerMutex();
7086 RxWaitSync(RxContext
);
7087 RxAcquireScavengerMutex();
7090 /* Start the purge */
7091 PurgeSyncCtx
->PurgeInProgress
= TRUE
;
7093 /* While the purge is still handling our NET_ROOT, do nothing but wait */
7094 while (Scavenger
->CurrentNetRootForClosePendingProcessing
== NetRoot
)
7096 RxReleaseScavengerMutex();
7097 KeWaitForSingleObject(&Scavenger
->ClosePendingProcessingSyncEvent
, Executive
,
7098 KernelMode
, TRUE
, NULL
);
7099 RxAcquireScavengerMutex();
7102 /* Now, for all the entries */
7103 SuccessfullPurge
= 0;
7104 Entry
= Scavenger
->ClosePendingFobxsList
.Flink
;
7105 while (Entry
!= &Scavenger
->ClosePendingFobxsList
)
7111 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ClosePendingList
);
7112 DPRINT("Dealing with FOBX: %p\n", Fobx
);
7114 Entry
= Entry
->Flink
;
7116 /* If it's not matching our NET_ROOT, ignore */
7117 if (Fobx
->pSrvOpen
== NULL
||
7118 Fobx
->pSrvOpen
->pFcb
== NULL
||
7119 ((PFCB
)Fobx
->pSrvOpen
->pFcb
)->VNetRoot
== NULL
||
7120 (PNET_ROOT
)((PFCB
)Fobx
->pSrvOpen
->pFcb
)->VNetRoot
->pNetRoot
!= NetRoot
)
7125 /* Determine if it matches our FCB */
7126 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
7127 if (PurgingFcb
!= NULL
&& NodeType(PurgingFcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
7132 MINIRDR_CALL_THROUGH(Status
, RxDeviceObject
->Dispatch
, MRxAreFilesAliased
, (Fcb
, PurgingFcb
));
7133 if (Status
== STATUS_SUCCESS
)
7139 /* Matching, we'll purge it */
7140 RemoveEntryList(&Fobx
->ClosePendingList
);
7142 /* Reference it so that it doesn't disappear */
7143 RxReferenceNetFobx(Fobx
);
7145 RxReleaseScavengerMutex();
7148 Success
= RxPurgeFobx(Fobx
);
7154 /* If we don't have to finalize it (or if we cannot acquire lock exclusively
7155 * Just normally dereference
7157 if ((AttemptFinalization
== DONT_ATTEMPT_FINALIZE_ON_PURGE
) ||
7158 RxAcquireExclusiveFcb(NULL
, Fcb
) != STATUS_SUCCESS
)
7160 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
7162 /* Otherwise, finalize */
7165 RxReferenceNetFcb(Fcb
);
7166 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
7167 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
7169 RxReleaseFcb(NULL
, Fcb
);
7175 DPRINT1("Failed purging %p (%p)\n", Fcb
, Fobx
);
7178 RxAcquireScavengerMutex();
7181 /* If no contexts left, purge is not running */
7182 if (IsListEmpty(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
))
7184 PurgeSyncCtx
->PurgeInProgress
= FALSE
;
7186 /* Otherwise, notify a waiter it can start */
7189 PRX_CONTEXT Context
;
7191 Entry
= RemoveHeadList(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
);
7192 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, RxContextSerializationQLinks
);
7194 RxSignalSynchronousWaiter(Context
);
7197 RxReleaseScavengerMutex();
7199 return (SuccessfullPurge
> 0 ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
7206 RxpWorkerThreadDispatcher(
7207 IN PRX_WORK_QUEUE WorkQueue
,
7208 IN PLARGE_INTEGER WaitInterval
)
7212 PETHREAD CurrentThread
;
7213 BOOLEAN KillThread
, Dereference
;
7214 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
7215 PWORKER_THREAD_ROUTINE WorkerRoutine
;
7217 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7219 /* Reference ourselves */
7220 CurrentThread
= PsGetCurrentThread();
7221 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7222 ASSERT(NT_SUCCESS(Status
));
7224 /* Infinite loop for worker */
7226 Dereference
= FALSE
;
7230 PLIST_ENTRY ListEntry
;
7232 /* Remove an entry from the work queue */
7233 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
7234 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
7236 PRDBSS_DEVICE_OBJECT DeviceObject
;
7238 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
7240 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
7241 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
7242 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7244 /* Get the parameters, and null-them in the struct */
7245 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
7246 Parameter
= WorkQueueItem
->Parameter
;
7247 DeviceObject
= WorkQueueItem
->pDeviceObject
;
7249 WorkQueueItem
->List
.Flink
= NULL
;
7250 WorkQueueItem
->WorkerRoutine
= NULL
;
7251 WorkQueueItem
->Parameter
= NULL
;
7252 WorkQueueItem
->pDeviceObject
= NULL
;
7254 /* Call the routine */
7255 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
7256 WorkerRoutine(Parameter
);
7258 /* Are we going down now? */
7259 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
7261 PKEVENT TearDownEvent
;
7263 TearDownEvent
= InterlockedExchangePointer((void * volatile*)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
7264 if (TearDownEvent
!= NULL
)
7266 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
7270 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7273 /* Shall we shutdown... */
7274 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7275 switch (WorkQueue
->State
)
7277 /* Our queue is active, kill it if we have no more items to dispatch
7278 * and more threads than the required minimum
7280 case RxWorkQueueActive
:
7281 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
7283 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
7284 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
7288 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7293 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7298 /* The queue is inactive: kill it we have more threads than the required minimum */
7299 case RxWorkQueueInactive
:
7300 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
7301 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
7305 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7310 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7314 /* Rundown in progress..., kill it for sure! */
7315 case RxWorkQueueRundownInProgress
:
7317 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
7319 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
7321 RundownContext
= WorkQueue
->pRundownContext
;
7322 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
7324 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7326 Dereference
= FALSE
;
7328 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
7330 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
7333 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7340 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
7341 } while (!KillThread
);
7343 DPRINT("Killed worker thread\n");
7345 /* Do we have to dereference ourselves? */
7348 ObDereferenceObject(CurrentThread
);
7351 /* Dump last executed routine */
7352 if (DumpDispatchRoutine
)
7354 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
7357 PsTerminateSystemThread(STATUS_SUCCESS
);
7362 IN OUT PVOID Instance
)
7364 NODE_TYPE_CODE NodeType
;
7365 PNODE_TYPE_AND_SIZE Node
;
7369 RxAcquireScavengerMutex();
7371 /* We can only reference a few structs */
7372 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
7373 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
7374 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
7375 (NodeType
== RDBSS_NTC_FOBX
));
7377 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
7378 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
7380 /* Trace refcount if asked */
7383 case RDBSS_NTC_SRVCALL
:
7384 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
7387 case RDBSS_NTC_NETROOT
:
7388 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
7391 case RDBSS_NTC_V_NETROOT
:
7392 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
7395 case RDBSS_NTC_SRVOPEN
:
7396 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
7399 case RDBSS_NTC_FOBX
:
7400 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
7408 RxpUndoScavengerFinalizationMarking(Instance
);
7409 RxReleaseScavengerMutex();
7417 RxReinitializeContext(
7418 IN OUT PRX_CONTEXT RxContext
)
7421 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7422 ULONG InitialContextFlags
, SavedFlags
;
7426 /* Backup a few flags */
7427 Irp
= RxContext
->CurrentIrp
;
7428 RxDeviceObject
= RxContext
->RxDeviceObject
;
7429 SavedFlags
= RxContext
->Flags
& RX_CONTEXT_PRESERVED_FLAGS
;
7430 InitialContextFlags
= RxContext
->Flags
& RX_CONTEXT_INITIALIZATION_FLAGS
;
7432 /* Reset our context */
7433 RxPrepareContextForReuse(RxContext
);
7435 /* Zero everything */
7436 RtlZeroMemory(&RxContext
->MajorFunction
, sizeof(RX_CONTEXT
) - FIELD_OFFSET(RX_CONTEXT
, MajorFunction
));
7438 /* Restore saved flags */
7439 RxContext
->Flags
= SavedFlags
;
7440 /* And reinit the context */
7441 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, RxContext
);
7449 RxReleaseFcbFromLazyWrite(
7457 /* The received context is a FCB */
7458 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
7459 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
7461 /* Lazy writer is releasing lock, so forget about it */
7462 Fcb
->Specific
.Fcb
.LazyWriteThread
= NULL
;
7464 /* If we were top level IRP, unwind */
7465 if (RxGetTopIrpIfRdbssIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
)
7467 RxUnwindTopLevelIrp(NULL
);
7470 /* And finally, release the lock */
7471 Fcb
->PagingIoResourceFile
= NULL
;
7472 Fcb
->PagingIoResourceLine
= 0;
7473 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
7481 RxReleaseFcbFromReadAhead(
7489 /* The received context is a FCB */
7490 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
7491 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
7493 /* Top Level IRP is CC */
7494 ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
);
7495 RxUnwindTopLevelIrp(NULL
);
7497 ExReleaseResourceLite(Fcb
->Header
.Resource
);
7502 RxReleaseFileForNtCreateSection(
7503 PFILE_OBJECT FileObject
)
7510 RxReleaseForCcFlush(
7511 PFILE_OBJECT FileObject
,
7512 PDEVICE_OBJECT DeviceObject
)
7515 return STATUS_NOT_IMPLEMENTED
;
7529 ASSERT(NodeTypeIsFcb(ThisFcb
));
7531 /* Just remove the entry from the FCB_TABLE */
7532 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
7533 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
7534 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
7537 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
7540 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
7541 DPRINT("FCB (%p) %wZ removed\n", ThisFcb
, &ThisFcb
->FcbTableEntry
.Path
);
7542 /* Mark, so that we don't try to do it twice */
7543 SetFlag(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
);
7553 RxRemovePrefixTableEntry(
7554 IN OUT PRX_PREFIX_TABLE ThisTable
,
7555 IN OUT PRX_PREFIX_ENTRY Entry
)
7559 ASSERT(NodeType(Entry
) == RDBSS_NTC_PREFIX_ENTRY
);
7560 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
7562 /* Check whether we're asked to remove null entry */
7563 if (Entry
->Prefix
.Length
== 0)
7565 ThisTable
->TableEntryForNull
= NULL
;
7569 RemoveEntryList(&Entry
->HashLinks
);
7572 Entry
->ContainingRecord
= NULL
;
7574 /* Also remove it from global list */
7575 RemoveEntryList(&Entry
->MemberQLinks
);
7577 ++ThisTable
->Version
;
7584 RxRemoveVirtualNetRootFromNetRoot(
7586 PV_NET_ROOT VNetRoot
)
7588 PRX_PREFIX_TABLE PrefixTable
;
7592 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
7593 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
7595 /* Remove the VNetRoot from the list in the NetRoot */
7596 --NetRoot
->NumberOfVirtualNetRoots
;
7597 RemoveEntryList(&VNetRoot
->NetRootListEntry
);
7599 /* Fix the NetRoot if we were the default VNetRoot */
7600 if (NetRoot
->DefaultVNetRoot
== VNetRoot
)
7602 /* Put the first one available */
7603 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7605 NetRoot
->DefaultVNetRoot
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
7607 /* Otherwise, none */
7610 NetRoot
->DefaultVNetRoot
= NULL
;
7614 /* If there are still other VNetRoot available, we're done */
7615 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7620 /* Otherwise, initiate NetRoot finalization */
7621 if (!BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
7623 RxRemovePrefixTableEntry(PrefixTable
, &NetRoot
->PrefixEntry
);
7624 SetFlag(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
);
7627 /* Notify mini-rdr */
7628 if (NetRoot
->pSrvCall
!= NULL
&& NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
7632 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
7633 MRxFinalizeNetRoot
, ((PMRX_NET_ROOT
)NetRoot
, FALSE
));
7639 RxResumeBlockedOperations_ALL(
7640 IN OUT PRX_CONTEXT RxContext
)
7642 LIST_ENTRY BlockedOps
;
7646 /* Get the blocked operations */
7647 RxTransferListWithMutex(&BlockedOps
, &RxContext
->BlockedOperations
, RxContext
->BlockedOpsMutex
);
7649 if (!IsListEmpty(&BlockedOps
))
7657 RxResumeBlockedOperations_Serially(
7658 IN OUT PRX_CONTEXT RxContext
,
7659 IN OUT PLIST_ENTRY BlockingIoQ
)
7663 RxAcquireSerializationMutex();
7665 /* This can only happen on pipes */
7666 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7668 RxReleaseSerializationMutex();
7674 RxReleaseSerializationMutex();
7681 RxSetFileSizeWithLock(
7683 IN PLONGLONG FileSize
)
7687 /* Set attribute and increase version */
7688 Fcb
->Header
.FileSize
.QuadPart
= *FileSize
;
7689 ++Fcb
->ulFileSizeVersion
;
7696 RxScavengeFobxsForNetRoot(
7699 BOOLEAN SynchronizeWithScavenger
)
7701 PRDBSS_SCAVENGER Scavenger
;
7702 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7706 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
7707 Scavenger
= RxDeviceObject
->pRdbssScavenger
;
7709 /* Wait for the scavenger, if asked to */
7710 if (SynchronizeWithScavenger
)
7712 KeWaitForSingleObject(&Scavenger
->ScavengeEvent
, Executive
, KernelMode
, FALSE
, NULL
);
7715 RxAcquireScavengerMutex();
7717 /* If there's nothing left to do... */
7718 if (Scavenger
->FobxsToBeFinalized
<= 0)
7720 RxReleaseScavengerMutex();
7725 LIST_ENTRY FobxToScavenge
;
7727 InitializeListHead(&FobxToScavenge
);
7729 /* Browse all the FOBXs to finalize */
7730 Entry
= Scavenger
->FobxFinalizationList
.Flink
;
7731 while (Entry
!= &Scavenger
->FobxFinalizationList
)
7735 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ScavengerFinalizationList
);
7736 Entry
= Entry
->Flink
;
7738 if (Fobx
->SrvOpen
!= NULL
)
7742 Fcb
= (PFCB
)Fobx
->SrvOpen
->pFcb
;
7744 /* If it matches our NET_ROOT */
7745 if ((PNET_ROOT
)Fcb
->pNetRoot
== NetRoot
)
7749 /* Check whether it matches our FCB */
7750 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
7751 if (PurgingFcb
!= NULL
&& PurgingFcb
!= Fcb
)
7753 MINIRDR_CALL_THROUGH(Status
, RxDeviceObject
->Dispatch
, MRxAreFilesAliased
, (Fcb
, PurgingFcb
));
7756 /* If so, add it to the list of the FOBXs to scavenge */
7757 if (Status
!= STATUS_SUCCESS
)
7759 RxReferenceNetFobx(Fobx
);
7760 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7762 RemoveEntryList(&Fobx
->ScavengerFinalizationList
);
7763 InsertTailList(&FobxToScavenge
, &Fobx
->ScavengerFinalizationList
);
7769 RxReleaseScavengerMutex();
7771 /* Now, scavenge all the extracted FOBX */
7772 RxpScavengeFobxs(Scavenger
, &FobxToScavenge
);
7775 if (SynchronizeWithScavenger
)
7777 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
7785 RxScavengeRelatedFobxs(
7789 LIST_ENTRY LocalList
;
7790 PLIST_ENTRY NextEntry
;
7791 PRDBSS_SCAVENGER Scavenger
;
7795 /* First of all, check whether there are FOBX to scavenge */
7796 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
7797 RxAcquireScavengerMutex();
7798 if (Scavenger
->FobxsToBeFinalized
<= 0)
7800 RxReleaseScavengerMutex();
7804 /* Initialize our local list which will hold all the FOBX to scavenge so
7805 * that we don't acquire the scavenger mutex too long
7807 InitializeListHead(&LocalList
);
7809 /* Technically, that condition should all be true... */
7810 if (!IsListEmpty(&Scavenger
->FobxFinalizationList
))
7812 PLIST_ENTRY NextEntry
, LastEntry
;
7814 /* Browse all the FCBs to find the matching ones */
7815 NextEntry
= Scavenger
->FobxFinalizationList
.Flink
;
7816 LastEntry
= &Scavenger
->FobxFinalizationList
;
7817 while (NextEntry
!= LastEntry
)
7819 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7820 NextEntry
= NextEntry
->Flink
;
7821 /* Matching our FCB? Let's finalize it */
7822 if (Fobx
->pSrvOpen
!= NULL
&& Fobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
7824 RxpUndoScavengerFinalizationMarking(Fobx
);
7825 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7826 InsertTailList(&LocalList
, &Fobx
->ScavengerFinalizationList
);
7831 RxReleaseScavengerMutex();
7833 /* Nothing to scavenge? Quit */
7834 if (IsListEmpty(&LocalList
))
7839 /* Now, finalize all the extracted FOBX */
7840 while (!IsListEmpty(&LocalList
))
7842 NextEntry
= RemoveHeadList(&LocalList
);
7843 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7844 RxFinalizeNetFobx(Fobx
, TRUE
, TRUE
);
7851 RxScavengerFinalizeEntries(
7852 PRDBSS_DEVICE_OBJECT DeviceObject
)
7862 RxScavengerTimerRoutine(
7866 PRDBSS_DEVICE_OBJECT DeviceObject
;
7867 PRDBSS_SCAVENGER Scavenger
;
7871 DeviceObject
= Context
;
7872 Scavenger
= DeviceObject
->pRdbssScavenger
;
7875 RxAcquireScavengerMutex();
7876 /* If the scavenger was dormant, wake it up! */
7877 if (Scavenger
->State
== RDBSS_SCAVENGER_DORMANT
)
7880 Scavenger
->State
= RDBSS_SCAVENGER_ACTIVE
;
7881 KeResetEvent(&Scavenger
->ScavengeEvent
);
7883 /* Scavenger the entries */
7884 RxReleaseScavengerMutex();
7885 RxScavengerFinalizeEntries(DeviceObject
);
7886 RxAcquireScavengerMutex();
7888 /* If we're still active (race) */
7889 if (Scavenger
->State
== RDBSS_SCAVENGER_ACTIVE
)
7891 /* If there are new entries to scavenge, stay dormant and requeue a run */
7892 if (Scavenger
->NumberOfDormantFiles
+ Scavenger
->SrvCallsToBeFinalized
+
7893 Scavenger
->NetRootsToBeFinalized
+ Scavenger
->VNetRootsToBeFinalized
+
7894 Scavenger
->FcbsToBeFinalized
+ Scavenger
->SrvOpensToBeFinalized
+
7895 Scavenger
->FobxsToBeFinalized
!= 0)
7898 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
7900 /* Otherwise, we're inactive again */
7903 Scavenger
->State
= RDBSS_SCAVENGER_INACTIVE
;
7907 RxReleaseScavengerMutex();
7909 /* Requeue an execution */
7912 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
7913 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
7918 RxReleaseScavengerMutex();
7921 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
7925 RxScavengeVNetRoots(
7926 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7937 RxSpinUpRequestsDispatcher(
7941 PRX_DISPATCHER RxDispatcher
;
7943 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7944 if (!NT_SUCCESS(Status
))
7946 PsTerminateSystemThread(STATUS_SUCCESS
);
7949 RxDispatcher
= Dispatcher
;
7954 PLIST_ENTRY ListEntry
;
7956 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
7957 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
7958 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
7960 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
7961 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
7963 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
7967 ListEntry
= &RxDispatcher
->SpinUpRequests
;
7969 KeResetEvent(&RxDispatcher
->SpinUpRequestsEvent
);
7970 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
7972 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
7974 PWORK_QUEUE_ITEM WorkItem
;
7975 PRX_WORK_QUEUE WorkQueue
;
7977 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
7978 WorkQueue
= WorkItem
->Parameter
;
7980 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
7982 DPRINT("Workqueue: calling %p(%p)\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
7983 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
7985 } while (RxDispatcher
->State
== RxDispatcherActive
);
7987 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
7988 PsTerminateSystemThread(STATUS_SUCCESS
);
7995 RxSpinUpWorkerThread(
7996 PRX_WORK_QUEUE WorkQueue
,
7997 PRX_WORKERTHREAD_ROUTINE Routine
,
8002 HANDLE ThreadHandle
;
8006 /* If work queue is inactive, that cannot work */
8007 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
8008 if (WorkQueue
->State
!= RxWorkQueueActive
)
8010 Status
= STATUS_UNSUCCESSFUL
;
8011 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
8015 ++WorkQueue
->NumberOfActiveWorkerThreads
;
8016 Status
= STATUS_SUCCESS
;
8018 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
8020 /* Quit on failure */
8021 if (!NT_SUCCESS(Status
))
8026 /* Spin up the worker thread */
8027 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
8028 if (NT_SUCCESS(Status
))
8030 ZwClose(ThreadHandle
);
8033 /* Read well: we reached that point because it failed! */
8034 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
8036 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
8037 --WorkQueue
->NumberOfActiveWorkerThreads
;
8038 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
8040 /* Rundown, no more active threads, set the event! */
8041 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
8042 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
8044 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
8047 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
8049 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
8055 RxSpinUpWorkerThreads(
8056 PRX_WORK_QUEUE WorkQueue
)
8062 RxSynchronizeWithScavenger(
8063 IN PRX_CONTEXT RxContext
)
8072 RxTableComputeHashValue(
8073 IN PUNICODE_STRING Name
)
8081 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8084 Loops
[1] = MaxChar
- 1;
8085 Loops
[2] = MaxChar
- 2;
8086 Loops
[3] = MaxChar
- 3;
8087 Loops
[4] = MaxChar
- 4;
8088 Loops
[5] = MaxChar
/ 4;
8089 Loops
[6] = 2 * MaxChar
/ 4;
8090 Loops
[7] = 3 * MaxChar
/ 4;
8093 for (i
= 0; i
< 8; ++i
)
8098 if (Idx
>= 0 && Idx
< MaxChar
)
8100 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
8111 RxTableComputePathHashValue(
8112 IN PUNICODE_STRING Name
)
8120 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8123 Loops
[1] = MaxChar
- 1;
8124 Loops
[2] = MaxChar
- 2;
8125 Loops
[3] = MaxChar
- 3;
8126 Loops
[4] = MaxChar
- 4;
8127 Loops
[5] = MaxChar
/ 4;
8128 Loops
[6] = 2 * MaxChar
/ 4;
8129 Loops
[7] = 3 * MaxChar
/ 4;
8132 for (i
= 0; i
< 8; ++i
)
8137 if (Idx
>= 0 && Idx
< MaxChar
)
8139 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
8151 IN PRX_PREFIX_TABLE ThisTable
,
8152 IN PUNICODE_STRING Name
,
8153 OUT PUNICODE_STRING RemainingName
,
8154 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
8158 PRX_PREFIX_ENTRY Entry
;
8159 RX_CONNECTION_ID NullId
;
8160 UNICODE_STRING LookupString
;
8164 /* If caller didn't provide a connection ID, setup one */
8165 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
8167 NullId
.Luid
.LowPart
= 0;
8168 NullId
.Luid
.HighPart
= 0;
8169 RxConnectionId
= &NullId
;
8173 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
8177 LookupString
.Buffer
= Name
->Buffer
;
8178 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8179 /* We'll perform the lookup, path component after another */
8180 for (i
= 1; i
< MaxChar
; ++i
)
8183 PRX_PREFIX_ENTRY CurEntry
;
8185 /* Don't cut in the middle of a path element */
8186 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
8191 /* Perform lookup in the table */
8192 LookupString
.Length
= i
* sizeof(WCHAR
);
8193 Hash
= RxTableComputeHashValue(&LookupString
);
8194 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
8196 ++ThisTable
->Lookups
;
8198 /* Entry not found, move to the next component */
8199 if (CurEntry
== NULL
)
8202 ++ThisTable
->FailedLookups
;
8208 ASSERT(Entry
->ContainingRecord
!= NULL
);
8209 Container
= Entry
->ContainingRecord
;
8211 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
8212 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
8216 NetRoot
= (PNET_ROOT
)Entry
->ContainingRecord
;
8217 /* If there's a default one, perfect, that's a match */
8218 if (NetRoot
->DefaultVNetRoot
!= NULL
)
8220 Container
= NetRoot
->DefaultVNetRoot
;
8222 /* If none (that shouldn't happen!), try to find one */
8225 /* Use the first one in the list */
8226 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
8228 Container
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
8230 /* Really, really, shouldn't happen */
8241 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
8247 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
8251 /* Entry was found */
8256 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
8258 /* Setup remaining name */
8259 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
8260 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
8261 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
8265 /* Otherwise, that's the whole name */
8266 RemainingName
= Name
;
8276 RxTableLookupName_ExactLengthMatch(
8277 IN PRX_PREFIX_TABLE ThisTable
,
8278 IN PUNICODE_STRING Name
,
8280 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
8282 PLIST_ENTRY ListEntry
, HashBucket
;
8286 ASSERT(RxConnectionId
!= NULL
);
8288 /* Select the right bucket */
8289 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
8290 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
8291 /* If bucket is empty, no match */
8292 if (IsListEmpty(HashBucket
))
8297 /* Browse all the entries in the bucket */
8298 for (ListEntry
= HashBucket
->Flink
;
8299 ListEntry
!= HashBucket
;
8300 ListEntry
= ListEntry
->Flink
)
8303 PRX_PREFIX_ENTRY Entry
;
8304 BOOLEAN CaseInsensitive
;
8305 PUNICODE_STRING CmpName
, CmpPrefix
;
8306 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
8308 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
8310 ++ThisTable
->Considers
;
8312 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
8314 Container
= Entry
->ContainingRecord
;
8315 ASSERT(Container
!= NULL
);
8317 /* Not the same hash, not the same length, move on */
8318 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
8324 ++ThisTable
->Compares
;
8326 /* If we have to perform a case insensitive compare on a portion... */
8327 if (Entry
->CaseInsensitiveLength
!= 0)
8329 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
8331 /* Perform the case insensitive check on the asked length */
8332 InsensitiveName
.Buffer
= Name
->Buffer
;
8333 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
8334 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
8335 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
8336 /* No match, move to the next entry */
8337 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
8342 /* Was the case insensitive covering the whole name? */
8343 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
8345 /* If connection ID also matches, that a complete match! */
8346 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
8352 /* Otherwise, we have to continue with the sensitive match.... */
8353 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
8354 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
8355 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
8356 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
8358 CmpName
= &InsensitiveName
;
8359 CmpPrefix
= &InsensitivePrefix
;
8360 CaseInsensitive
= FALSE
;
8365 CmpPrefix
= &Entry
->Prefix
;
8366 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
8369 /* Perform the compare, if there's a match, also check for connection ID */
8370 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
8372 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
8386 RxTearDownBufferingManager(
8392 return STATUS_SUCCESS
;
8401 _In_
struct _KDPC
*Dpc
,
8402 _In_opt_ PVOID DeferredContext
,
8403 _In_opt_ PVOID SystemArgument1
,
8404 _In_opt_ PVOID SystemArgument2
)
8407 LIST_ENTRY LocalList
;
8408 PLIST_ENTRY ListEntry
;
8409 PRX_WORK_ITEM WorkItem
;
8411 InitializeListHead(&LocalList
);
8413 KeAcquireSpinLockAtDpcLevel(&RxTimerLock
);
8416 /* Find any entry matching */
8417 if (!IsListEmpty(&RxTimerQueueHead
))
8419 ListEntry
= RxTimerQueueHead
.Flink
;
8422 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
8423 if (WorkItem
->LastTick
== RxTimerTickCount
)
8425 ListEntry
= ListEntry
->Flink
;
8427 RemoveEntryList(&WorkItem
->WorkQueueItem
.List
);
8428 InsertTailList(&LocalList
, &WorkItem
->WorkQueueItem
.List
);
8432 ListEntry
= ListEntry
->Flink
;
8434 } while (ListEntry
!= &RxTimerQueueHead
);
8436 /* Do we have to requeue a later execution? */
8437 Set
= !IsListEmpty(&RxTimerQueueHead
);
8439 KeReleaseSpinLockFromDpcLevel(&RxTimerLock
);
8441 /* Requeue if list wasn't empty */
8444 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
8447 /* If we had matching entries */
8448 if (!IsListEmpty(&LocalList
))
8450 /* Post them, one after another */
8451 ListEntry
= LocalList
.Flink
;
8454 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
8455 ListEntry
= ListEntry
->Flink
;
8457 WorkItem
->WorkQueueItem
.List
.Flink
= NULL
;
8458 WorkItem
->WorkQueueItem
.List
.Blink
= NULL
;
8459 RxPostToWorkerThread(WorkItem
->WorkQueueItem
.pDeviceObject
, CriticalWorkQueue
,
8460 &WorkItem
->WorkQueueItem
, WorkItem
->WorkQueueItem
.WorkerRoutine
,
8461 WorkItem
->WorkQueueItem
.Parameter
);
8463 while (ListEntry
!= &LocalList
);
8467 #ifdef RDBSS_TRACKER
8472 RxTrackerUpdateHistory(
8473 _Inout_opt_ PRX_CONTEXT RxContext
,
8474 _Inout_ PMRX_FCB MrxFcb
,
8475 _In_ ULONG Operation
,
8476 _In_ ULONG LineNumber
,
8477 _In_ PCSTR FileName
,
8478 _In_ ULONG SerialNumber
)
8481 RX_FCBTRACKER_CASES Case
;
8483 /* Check for null or special context */
8484 if (RxContext
== NULL
)
8486 Case
= RX_FCBTRACKER_CASE_NULLCONTEXT
;
8488 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
)
8490 Case
= RX_FCBTRACKER_CASE_CBS_CONTEXT
;
8492 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
8494 Case
= RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT
;
8498 ASSERT(NodeType(RxContext
) == RDBSS_NTC_RX_CONTEXT
);
8499 Case
= RX_FCBTRACKER_CASE_NORMAL
;
8502 /* If caller provided a FCB, update its history */
8506 ASSERT(NodeTypeIsFcb(Fcb
));
8508 /* Only one acquire operation, so many release operations... */
8509 if (Operation
== TRACKER_ACQUIRE_FCB
)
8511 ++Fcb
->FcbAcquires
[Case
];
8515 ++Fcb
->FcbReleases
[Case
];
8519 /* If we have a normal context, update its history about this function calls */
8520 if (Case
== RX_FCBTRACKER_CASE_NORMAL
)
8522 ULONG TrackerHistoryPointer
;
8524 /* Only one acquire operation, so many release operations... */
8525 if (Operation
== TRACKER_ACQUIRE_FCB
)
8527 InterlockedIncrement(&RxContext
->AcquireReleaseFcbTrackerX
);
8531 InterlockedDecrement(&RxContext
->AcquireReleaseFcbTrackerX
);
8534 /* We only keep track of the 32 first calls */
8535 TrackerHistoryPointer
= InterlockedExchangeAdd((volatile long *)&RxContext
->TrackerHistoryPointer
, 1);
8536 if (TrackerHistoryPointer
< RDBSS_TRACKER_HISTORY_SIZE
)
8538 RxContext
->TrackerHistory
[TrackerHistoryPointer
].AcquireRelease
= Operation
;
8539 RxContext
->TrackerHistory
[TrackerHistoryPointer
].LineNumber
= LineNumber
;
8540 RxContext
->TrackerHistory
[TrackerHistoryPointer
].FileName
= (PSZ
)FileName
;
8541 RxContext
->TrackerHistory
[TrackerHistoryPointer
].SavedTrackerValue
= RxContext
->AcquireReleaseFcbTrackerX
;
8542 RxContext
->TrackerHistory
[TrackerHistoryPointer
].Flags
= RxContext
->Flags
;
8545 /* If it's negative, then we released once more than we acquired it?! */
8546 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
>= 0);
8552 RxTrackPagingIoResource(
8553 _Inout_ PVOID Instance
,
8565 RxUndoScavengerFinalizationMarking(
8568 /* Just call internal routine with mutex held */
8569 RxAcquireScavengerMutex();
8570 RxpUndoScavengerFinalizationMarking(Instance
);
8571 RxReleaseScavengerMutex();
8578 RxUninitializeVNetRootParameters(
8579 IN PUNICODE_STRING UserName
,
8580 IN PUNICODE_STRING UserDomainName
,
8581 IN PUNICODE_STRING Password
,
8586 /* Only free what could have been allocated */
8587 if (UserName
!= NULL
)
8589 RxFreePool(UserName
);
8592 if (UserDomainName
!= NULL
)
8594 RxFreePool(UserDomainName
);
8597 if (Password
!= NULL
)
8599 RxFreePool(Password
);
8602 /* And remove the possibly set CSC agent flag */
8605 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
8614 IN RX_BLOCK_CONDITION NewConditionValue
,
8615 OUT PRX_BLOCK_CONDITION Condition
,
8616 IN OUT PLIST_ENTRY TransitionWaitList
)
8618 PRX_CONTEXT Context
;
8619 LIST_ENTRY SerializationQueue
;
8623 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
8625 /* Set the new condition */
8626 RxAcquireSerializationMutex();
8627 ASSERT(NewConditionValue
!= Condition_InTransition
);
8628 *Condition
= NewConditionValue
;
8629 /* And get the serialization queue for treatment */
8630 RxTransferList(&SerializationQueue
, TransitionWaitList
);
8631 RxReleaseSerializationMutex();
8633 /* Handle the serialization queue */
8634 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
8635 while (Context
!= NULL
)
8637 /* If the caller asked for post, post the request */
8638 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8640 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
8641 RxFsdPostRequest(Context
);
8643 /* Otherwise, wake up sleeping waiters */
8646 RxSignalSynchronousWaiter(Context
);
8649 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
8657 RxVerifyOperationIsLegal(
8658 IN PRX_CONTEXT RxContext
)
8663 PFILE_OBJECT FileObject
;
8664 PIO_STACK_LOCATION Stack
;
8668 Irp
= RxContext
->CurrentIrp
;
8669 Stack
= RxContext
->CurrentIrpSp
;
8670 FileObject
= Stack
->FileObject
;
8672 /* We'll only check stuff on opened files, this requires an IRP and a FO */
8673 if (Irp
== NULL
|| FileObject
== NULL
)
8678 /* Set no exception for breakpoint - remember whether is was already set */
8679 FlagSet
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8680 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8682 /* If we have a CCB, perform a few checks on opened file */
8683 Fobx
= RxContext
->pFobx
;
8686 PMRX_SRV_OPEN SrvOpen
;
8688 SrvOpen
= Fobx
->pSrvOpen
;
8689 if (SrvOpen
!= NULL
)
8691 UCHAR MajorFunction
;
8693 MajorFunction
= RxContext
->MajorFunction
;
8694 /* Only allow closing/cleanup operations on renamed files */
8695 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8696 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
8698 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_RENAMED
;
8699 ExRaiseStatus(STATUS_FILE_RENAMED
);
8702 /* Only allow closing/cleanup operations on deleted files */
8703 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8704 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
))
8706 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_DELETED
;
8707 ExRaiseStatus(STATUS_FILE_DELETED
);
8712 /* If that's an open operation */
8713 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
8715 PFILE_OBJECT RelatedFileObject
;
8717 /* We won't allow an open operation relative to a file to be deleted */
8718 RelatedFileObject
= FileObject
->RelatedFileObject
;
8719 if (RelatedFileObject
!= NULL
)
8723 Fcb
= RelatedFileObject
->FsContext
;
8724 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
8726 RxContext
->IoStatusBlock
.Status
= STATUS_DELETE_PENDING
;
8727 ExRaiseStatus(STATUS_DELETE_PENDING
);
8732 /* If cleanup was completed */
8733 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
8735 if (!BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
))
8737 UCHAR MajorFunction
;
8739 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
8740 MajorFunction
= Stack
->MajorFunction
;
8741 if (MajorFunction
!= IRP_MJ_CLOSE
&& MajorFunction
!= IRP_MJ_QUERY_INFORMATION
&&
8742 MajorFunction
!= IRP_MJ_SET_INFORMATION
)
8744 if ((MajorFunction
!= IRP_MJ_READ
&& MajorFunction
!= IRP_MJ_WRITE
) ||
8745 !BooleanFlagOn(Stack
->MinorFunction
, IRP_MN_COMPLETE
))
8747 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_CLOSED
;
8748 ExRaiseStatus(STATUS_FILE_CLOSED
);
8754 /* If flag was already set, don't clear it */
8757 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8765 RxWaitForStableCondition(
8766 IN PRX_BLOCK_CONDITION Condition
,
8767 IN OUT PLIST_ENTRY TransitionWaitList
,
8768 IN OUT PRX_CONTEXT RxContext
,
8769 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
8772 NTSTATUS LocalStatus
;
8776 /* Make sure to always get status */
8777 if (AsyncStatus
== NULL
)
8779 AsyncStatus
= &LocalStatus
;
8782 /* By default, it's a success */
8783 *AsyncStatus
= STATUS_SUCCESS
;
8786 /* If it's not stable, we've to wait */
8787 if (!StableCondition(*Condition
))
8789 /* Lock the mutex */
8790 RxAcquireSerializationMutex();
8791 /* Still not stable? */
8792 if (!StableCondition(*Condition
))
8794 /* Insert us in the wait list for processing on stable condition */
8795 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
8797 /* If we're asked to post on stable, don't wait, and just return pending */
8798 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8800 *AsyncStatus
= STATUS_PENDING
;
8807 RxReleaseSerializationMutex();
8809 /* We don't post on stable, so, just wait... */
8812 RxWaitSync(RxContext
);
8822 RxWorkItemDispatcher(
8825 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
8827 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
8829 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
8831 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
8839 _RxAllocatePoolWithTag(
8840 _In_ POOL_TYPE PoolType
,
8841 _In_ SIZE_T NumberOfBytes
,
8844 return ExAllocatePoolWithTagPriority(PoolType
, NumberOfBytes
, Tag
, LowPoolPriority
);
8855 ExFreePoolWithTag(Buffer
, 0);
8867 ExFreePoolWithTag(Buffer
, Tag
);
8873 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
8875 #ifdef RDBSS_TRACKER
8877 _In_ ULONG LineNumber
,
8878 _In_ PCSTR FileName
,
8879 _In_ ULONG SerialNumber
8884 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
8888 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
8890 SpecialContext
= FALSE
;
8891 ContextIsPresent
= FALSE
;
8892 /* Check for special context */
8893 if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
|| RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
8895 SpecialContext
= TRUE
;
8898 /* We don't handle buffering state change yet... */
8899 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
8900 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
8905 /* Nor special contexts */
8911 /* If we don't have a context, assume we can wait! */
8912 if (RxContext
== NULL
)
8918 /* That said: we have a real context! */
8919 ContextIsPresent
= TRUE
;
8921 /* If we've been cancelled in between, give up */
8922 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
8923 if (!NT_SUCCESS(Status
))
8929 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8934 /* Assume we cannot lock */
8935 Status
= STATUS_LOCK_NOT_GRANTED
;
8937 /* Lock according to what the caller asked */
8940 case FCB_MODE_EXCLUSIVE
:
8941 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
8944 case FCB_MODE_SHARED
:
8945 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
8948 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
8949 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
8953 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
8954 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
8961 Status
= STATUS_SUCCESS
;
8962 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
8964 /* Handle paging write - not implemented */
8965 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
8971 /* And break, that cool! */
8977 /* If it failed, return immediately */
8978 if (!NT_SUCCESS(Status
))
8984 /* If we don't have to check for valid operation, job done, nothing more to do */
8985 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
8987 if (NT_SUCCESS(Status
))
8989 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
8995 /* Verify operation */
8998 RxVerifyOperationIsLegal(RxContext
);
9002 /* If it failed, release lock and fail */
9003 if (_SEH2_AbnormalTermination())
9005 ExReleaseResourceLite(Fcb
->Header
.Resource
);
9006 Status
= STATUS_LOCK_NOT_GRANTED
;
9011 if (NT_SUCCESS(Status
))
9013 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
9016 DPRINT("Status: %x\n", Status
);
9024 __RxItsTheSameContext(
9025 _In_ PRX_CONTEXT RxContext
,
9026 _In_ ULONG CapturedRxContextSerialNumber
,
9030 /* Check we have a context with the same serial number */
9031 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
9032 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
9035 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
9041 _Inout_opt_ PRX_CONTEXT RxContext
,
9042 _Inout_ PMRX_FCB MrxFcb
9043 #ifdef RDBSS_TRACKER
9045 _In_ ULONG LineNumber
,
9046 _In_ PCSTR FileName
,
9047 _In_ ULONG SerialNumber
9051 BOOLEAN IsExclusive
, BufferingPending
;
9053 RxAcquireSerializationMutex();
9055 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
9056 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
9058 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9059 * then just release the FCB
9061 if (!BufferingPending
|| !IsExclusive
)
9063 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
9064 LineNumber
, FileName
, SerialNumber
);
9065 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
9068 RxReleaseSerializationMutex();
9070 /* And finally leave */
9071 if (!BufferingPending
|| !IsExclusive
)
9076 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
9078 /* Otherwise, handle buffering state and release */
9079 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
9081 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
9082 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
9086 __RxReleaseFcbForThread(
9087 _Inout_opt_ PRX_CONTEXT RxContext
,
9088 _Inout_ PMRX_FCB MrxFcb
,
9089 _In_ ERESOURCE_THREAD ResourceThreadId
9090 #ifdef RDBSS_TRACKER
9092 _In_ ULONG LineNumber
,
9093 _In_ PCSTR FileName
,
9094 _In_ ULONG SerialNumber
9098 BOOLEAN IsExclusive
, BufferingPending
;
9100 RxAcquireSerializationMutex();
9102 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
9103 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
9105 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9106 * then just release the FCB
9108 if (!BufferingPending
|| !IsExclusive
)
9110 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
9111 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
9112 LineNumber
, FileName
, SerialNumber
);
9113 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
9116 RxReleaseSerializationMutex();
9118 /* And finally leave */
9119 if (!BufferingPending
|| !IsExclusive
)
9124 /* Otherwise, handle buffering state and release */
9125 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
9126 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
9127 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);