3 * Copyright (C) 2017 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rxce/rxce.c
23 * PURPOSE: RXCE library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
);
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown
);
54 RxFinishSrvCallConstructionDispatcher(
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
60 WORK_QUEUE_TYPE WorkQueueType
,
61 PRX_WORK_QUEUE_ITEM WorkQueueItem
);
65 PRX_CONTEXT RxContext
);
73 RxpDispatchChangeBufferingStateRequests(
76 PLIST_ENTRY DiscardedRequests
);
80 RxScavengerTimerRoutine(
86 _In_
struct _KDPC
*Dpc
,
87 _In_opt_ PVOID DeferredContext
,
88 _In_opt_ PVOID SystemArgument1
,
89 _In_opt_ PVOID SystemArgument2
);
98 _RxAllocatePoolWithTag(
99 _In_ POOL_TYPE PoolType
,
100 _In_ SIZE_T NumberOfBytes
,
114 extern ULONG ReadAheadGranularity
;
116 volatile LONG RxNumberOfActiveFcbs
= 0;
117 ULONG SerialNumber
= 1;
119 volatile ULONG RxContextSerialNumberCounter
;
120 BOOLEAN RxStopOnLoudCompletion
= TRUE
;
121 BOOLEAN RxSrvCallConstructionDispatcherActive
= FALSE
;
122 LIST_ENTRY RxSrvCalldownList
;
123 RX_SPIN_LOCK RxStrucSupSpinLock
;
124 ULONG RdbssReferenceTracingValue
;
125 LARGE_INTEGER RxWorkQueueWaitInterval
[RxMaximumWorkQueue
];
126 LARGE_INTEGER RxSpinUpDispatcherWaitInterval
;
127 RX_DISPATCHER RxDispatcher
;
128 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues
;
129 FAST_MUTEX RxLowIoPagingIoSyncMutex
;
130 BOOLEAN RxContinueFromAssert
= TRUE
;
131 ULONG RxExplodePoolTags
= 1;
132 LARGE_INTEGER RxTimerInterval
;
133 RX_SPIN_LOCK RxTimerLock
;
134 LIST_ENTRY RxTimerQueueHead
;
135 LIST_ENTRY RxRecurrentWorkItemsList
;
138 ULONG RxTimerTickCount
;
140 BOOLEAN DumpDispatchRoutine
= TRUE
;
142 BOOLEAN DumpDispatchRoutine
= FALSE
;
150 #define ASSERT(exp) \
153 RxAssert(#exp, __FILE__, __LINE__, NULL); \
158 #undef RxAllocatePool
159 #undef RxAllocatePoolWithTag
162 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
163 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
164 #define RxFreePool _RxFreePool
165 #define RxFreePoolWithTag _RxFreePoolWithTag
168 /* FUNCTIONS ****************************************************************/
174 RxAddVirtualNetRootToNetRoot(
176 PV_NET_ROOT VNetRoot
)
180 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
182 /* Insert in the VNetRoot list - make sure lock is held */
183 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
185 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
186 ++NetRoot
->NumberOfVirtualNetRoots
;
187 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
195 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
196 NODE_TYPE_CODE NodeType
,
199 PVOID AlreadyAllocatedObject
)
204 PVOID Buffer
, PAPNBuffer
;
205 PNON_PAGED_FCB NonPagedFcb
;
206 PMINIRDR_DISPATCH Dispatch
;
207 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
211 Dispatch
= RxDeviceObject
->Dispatch
;
224 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
225 if (NodeType
== RDBSS_NTC_FOBX
)
227 FobxSize
= sizeof(FOBX
);
228 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
230 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
233 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
234 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
236 SrvOpenSize
= sizeof(SRV_OPEN
);
237 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
239 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
242 FobxSize
= sizeof(FOBX
);
243 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
245 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
248 /* Otherwise, we're asked to allocate a FCB */
251 /* So, allocate the FCB and its extension if asked */
252 FcbSize
= sizeof(FCB
);
253 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
255 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
258 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
259 * Otherwise, it will be allocated later on, specifically
261 if (PoolType
== NonPagedPool
)
263 NonPagedSize
= sizeof(NON_PAGED_FCB
);
266 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
267 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
269 SrvOpenSize
= sizeof(SRV_OPEN
);
270 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
272 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
275 FobxSize
= sizeof(FOBX
);
276 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
278 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
283 /* If we already have a buffer, go ahead */
284 if (AlreadyAllocatedObject
!= NULL
)
286 Buffer
= AlreadyAllocatedObject
;
288 /* Otherwise, allocate it */
291 Buffer
= RxAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
298 /* Now, get the pointers - FOBX is easy */
299 if (NodeType
== RDBSS_NTC_FOBX
)
303 /* SRV_OPEN first, FOBX next */
304 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
307 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
309 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
315 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
317 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
319 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
320 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
323 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
324 if (PoolType
!= NonPagedPool
)
326 NonPagedFcb
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
327 if (NonPagedFcb
== NULL
)
329 RxFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
333 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
335 /* Otherwise, just point at the right place in what has been allocated previously */
338 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
339 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
343 /* If we have allocated a SRV_OPEN, initialize it */
346 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
348 if (NodeType
== RDBSS_NTC_SRVOPEN
)
350 SrvOpen
->InternalFobx
= Fobx
;
354 SrvOpen
->InternalFobx
= NULL
;
355 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
358 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
360 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
363 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
366 /* If we have allocated a FOBX, initialize it */
369 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
371 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
373 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
377 /* If we have allocated a FCB, initialize it */
380 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
382 Fcb
->NonPaged
= NonPagedFcb
;
383 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
384 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
385 NonPagedFcb
->FcbBackPointer
= Fcb
;
387 Fcb
->InternalSrvOpen
= SrvOpen
;
388 Fcb
->InternalFobx
= Fobx
;
390 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
391 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
392 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
394 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
396 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
399 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
401 InterlockedIncrement(&RxNumberOfActiveFcbs
);
402 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
404 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
405 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
416 NODE_TYPE_CODE NodeType
,
417 PMINIRDR_DISPATCH MRxDispatch
,
420 ULONG Tag
, ObjectSize
;
421 PVOID Object
, *Extension
;
422 PRX_PREFIX_ENTRY PrefixEntry
;
423 USHORT StructSize
, ExtensionSize
;
427 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
431 case RDBSS_NTC_SRVCALL
:
432 Tag
= RX_SRVCALL_POOLTAG
;
433 StructSize
= sizeof(SRV_CALL
);
434 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
436 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
440 case RDBSS_NTC_NETROOT
:
441 Tag
= RX_NETROOT_POOLTAG
;
442 StructSize
= sizeof(NET_ROOT
);
443 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
445 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
449 case RDBSS_NTC_V_NETROOT
:
450 Tag
= RX_V_NETROOT_POOLTAG
;
451 StructSize
= sizeof(V_NET_ROOT
);
452 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
454 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
463 /* Now, allocate the object */
464 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
465 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
471 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
473 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
476 case RDBSS_NTC_SRVCALL
:
477 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
478 Extension
= &((PSRV_CALL
)Object
)->Context
;
479 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
482 case RDBSS_NTC_NETROOT
:
483 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
484 Extension
= &((PNET_ROOT
)Object
)->Context
;
485 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
488 case RDBSS_NTC_V_NETROOT
:
489 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
490 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
498 /* Set the prefix table unicode string */
499 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
500 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
501 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
502 PrefixEntry
->Prefix
.Length
= NameLength
;
503 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
504 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
506 /* Return the extension if we are asked to manage it */
507 if (ExtensionSize
!= 0)
509 *Extension
= Add2Ptr(Object
, StructSize
);
528 /* If we're not asked to continue, just stop the system */
529 if (!RxContinueFromAssert
)
531 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
534 /* Otherwise, capture context to offer the user to dump it */
535 RtlCaptureContext(&Context
);
537 /* Loop until the user hits 'i' */
540 /* If no file provided, use empty name */
546 /* If no message provided, use empty one */
552 /* Display the message */
553 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
554 /* And ask the user */
555 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
556 /* If he asks for ignore, quit
557 * In case of invalid input, ask again
559 if (Response
[0] != 'B' && Response
[0] != 'b')
561 if (Response
[0] == 'I' || Response
[0] == 'i')
569 /* Break: offer the user to dump the context and break */
570 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
573 /* Continue looping, so that after dump, execution can continue (with ignore) */
582 RxBootstrapWorkerThreadDispatcher(
585 PRX_WORK_QUEUE RxWorkQueue
;
589 RxWorkQueue
= WorkQueue
;
590 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
598 RxChangeBufferingState(
601 BOOLEAN ComputeNewState
)
604 NTSTATUS Status
, MiniStatus
;
605 ULONG NewBufferingState
, OldBufferingState
;
609 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen
, Context
, ComputeNewState
);
611 Fcb
= (PFCB
)SrvOpen
->pFcb
;
612 ASSERT(NodeTypeIsFcb(Fcb
));
613 /* First of all, mark that buffering state is changing */
614 SetFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
617 Status
= STATUS_SUCCESS
;
620 /* If we're asked to compute a new state, ask the mini-rdr for it */
623 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxComputeNewBufferingState
,
624 ((PMRX_SRV_OPEN
)SrvOpen
, Context
, &NewBufferingState
));
625 if (MiniStatus
!= STATUS_SUCCESS
)
627 NewBufferingState
= 0;
632 /* If not, use SRV_OPEN state */
633 NewBufferingState
= SrvOpen
->BufferingFlags
;
636 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
637 if ((Fcb
->ShareAccess
.SharedRead
+ Fcb
->ShareAccess
.SharedWrite
+ Fcb
->ShareAccess
.SharedDelete
) == 0 && !ComputeNewState
)
639 SetFlag(NewBufferingState
, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES
);
642 /* If there's a lock operation to complete, clear that flag */
643 if (Fcb
->OutstandingLockOperationsCount
!= 0)
645 ClearFlag(NewBufferingState
, FCB_STATE_LOCK_BUFFERING_ENABLED
);
648 /* Get the old state */
649 OldBufferingState
= Fcb
->FcbState
& FCB_STATE_BUFFERING_STATE_MASK
;
650 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState
, NewBufferingState
, SrvOpen
->BufferingFlags
);
652 /* If we're dropping write cache, then flush the FCB */
653 if (BooleanFlagOn(OldBufferingState
, FCB_STATE_WRITECACHING_ENABLED
) &&
654 !BooleanFlagOn(NewBufferingState
, FCB_STATE_WRITECACHING_ENABLED
))
656 DPRINT("Flushing\n");
658 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
661 /* If we're dropping read cache, then purge */
662 if (Fcb
->UncleanCount
== 0 ||
663 (BooleanFlagOn(OldBufferingState
, FCB_STATE_READCACHING_ENABLED
) &&
664 !BooleanFlagOn(NewBufferingState
, FCB_STATE_READCACHING_ENABLED
)) ||
665 BooleanFlagOn(NewBufferingState
, FCB_STATE_DELETE_ON_CLOSE
))
669 if (!NT_SUCCESS(Status
))
671 DPRINT("Previous flush failed with status: %lx\n", Status
);
674 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, TRUE
);
677 /* If there's already a change pending in SRV_OPEN */
678 if (ComputeNewState
&& BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
680 /* If there's a FOBX at least */
681 if (!IsListEmpty(&SrvOpen
->FobxList
))
683 PRX_CONTEXT RxContext
;
685 /* Create a fake context to pass to the mini-rdr */
686 RxContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
687 if (RxContext
!= NULL
)
691 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
693 /* Give the first FOBX */
694 Fobx
= CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
);
695 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
696 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
698 /* If there was a delayed close, perform it */
699 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
701 DPRINT("Oplock break close for %p\n", SrvOpen
);
703 RxCloseAssociatedSrvOpen(Fobx
, RxContext
);
705 /* Otherwise, inform the mini-rdr about completion */
708 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxCompleteBufferingStateChangeRequest
,
709 (RxContext
, (PMRX_SRV_OPEN
)SrvOpen
, Context
));
713 RxDereferenceAndDeleteRxContext(RxContext
);
718 /* Set the new state */
719 Fcb
->FcbState
^= (NewBufferingState
^ Fcb
->FcbState
) & FCB_STATE_BUFFERING_STATE_MASK
;
723 /* Job done, clear the flag */
724 ClearFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
726 if (!BooleanFlagOn(NewBufferingState
, FCB_STATE_FILETIMECACHEING_ENABLED
))
728 ClearFlag(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
);
737 RxCheckVNetRootCredentials(
738 PRX_CONTEXT RxContext
,
739 PV_NET_ROOT VNetRoot
,
741 PUNICODE_STRING UserName
,
742 PUNICODE_STRING UserDomain
,
743 PUNICODE_STRING Password
,
748 /* If that's a UNC name, there's nothing to process */
749 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
750 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
753 return STATUS_MORE_PROCESSING_REQUIRED
;
756 /* Compare the logon ID in the VNetRoot with the one provided */
757 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
759 return STATUS_MORE_PROCESSING_REQUIRED
;
762 /* No credential provided? That's OK */
763 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
765 return STATUS_SUCCESS
;
770 return STATUS_NOT_IMPLEMENTED
;
782 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
784 ASSERT(Context
!= NULL
);
785 ASSERT(Context
->CurrentIrp
!= NULL
);
786 Irp
= Context
->CurrentIrp
;
788 /* Debug what the caller asks for */
789 if (Context
->LoudCompletionString
!= NULL
)
791 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
792 /* Does the user asks to stop on failed completion */
793 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
795 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
799 /* Complete for real */
800 Context
->CurrentIrp
= NULL
;
801 RxCompleteRequest_Real(Context
, Irp
, Status
);
803 DPRINT("Status: %lx\n", Status
);
811 RxCompleteRequest_Real(
812 IN PRX_CONTEXT RxContext
,
818 PIO_STACK_LOCATION Stack
;
820 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
822 /* Nothing to complete, just free context */
825 DPRINT("NULL IRP for %p\n", RxContext
);
826 if (RxContext
!= NULL
)
828 RxDereferenceAndDeleteRxContext_Real(RxContext
);
834 /* Remove cancel routine */
835 IoAcquireCancelSpinLock(&OldIrql
);
836 IoSetCancelRoutine(Irp
, NULL
);
837 IoReleaseCancelSpinLock(OldIrql
);
839 /* Select the boost, given the success/paging operation */
840 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
842 Boost
= IO_DISK_INCREMENT
;
846 Irp
->IoStatus
.Information
= 0;
847 Boost
= IO_NO_INCREMENT
;
849 Irp
->IoStatus
.Status
= Status
;
851 if (RxContext
!= NULL
)
853 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
854 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
856 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
857 RxContext
->MinorFunction
, RxContext
, Irp
,
858 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
862 /* If that's an opening, there might be a canonical name allocated,
863 * if completion isn't pending, release it
865 Stack
= IoGetCurrentIrpStackLocation(Irp
);
866 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
869 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
871 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
874 RxpPrepareCreateContextForReuse(RxContext
);
875 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
878 /* If it's a write, validate the correct behavior of the operation */
879 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
881 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
883 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
887 /* If it's pending, make sure IRP is marked as such */
888 if (RxContext
!= NULL
)
890 if (RxContext
->PendingReturned
)
892 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
897 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
898 IoCompleteRequest(Irp
, Boost
);
900 /* If there's a context, dereference it */
901 if (RxContext
!= NULL
)
903 RxDereferenceAndDeleteRxContext_Real(RxContext
);
911 RxCompleteSrvOpenKeyAssociation(
912 IN OUT PSRV_OPEN SrvOpen
)
916 SrvCall
= (PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
;
917 /* Only handle requests if opening was a success */
918 if (SrvOpen
->Condition
== Condition_Good
)
921 BOOLEAN ProcessChange
;
922 LIST_ENTRY DiscardedRequests
;
924 /* Initialize our discarded requests list */
925 InitializeListHead(&DiscardedRequests
);
927 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
929 /* Transfer our requests in the SRV_CALL */
930 RxTransferList(&SrvCall
->BufferingManager
.SrvOpenLists
[0], &SrvOpen
->SrvOpenKeyList
);
932 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
933 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
935 /* Dispatch requests and get the discarded ones */
936 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &DiscardedRequests
);
938 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
940 /* Is there still anything to process? */
941 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
942 if (IsListEmpty(&SrvCall
->BufferingManager
.HandlerList
))
944 ProcessChange
= FALSE
;
948 ProcessChange
= (SrvCall
->BufferingManager
.HandlerInactive
== FALSE
);
951 SrvCall
->BufferingManager
.HandlerInactive
= TRUE
;
954 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
959 RxReferenceSrvCall(SrvCall
);
960 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
961 &SrvCall
->BufferingManager
.HandlerWorkItem
,
962 RxProcessChangeBufferingStateRequests
, SrvCall
);
965 /* And discard left requests */
966 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests
);
970 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
979 IN PRX_CONTEXT RxContext
,
980 IN PSRV_CALL SrvCall
,
981 IN PNET_ROOT NetRoot
,
982 IN PV_NET_ROOT VirtualNetRoot
,
983 OUT PLOCK_HOLDING_STATE LockHoldingState
)
986 PRX_PREFIX_TABLE PrefixTable
;
987 PMRX_CREATENETROOT_CONTEXT Context
;
988 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
992 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
993 VirtualNetRoot
, LockHoldingState
);
995 /* Validate the lock is exclusively held */
996 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
997 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
999 /* Allocate the context */
1000 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
1001 if (Context
== NULL
)
1003 return STATUS_INSUFFICIENT_RESOURCES
;
1006 /* We can release lock now */
1007 RxReleasePrefixTableLock(PrefixTable
);
1008 *LockHoldingState
= LHS_LockNotHeld
;
1010 RootCondition
= Condition_Bad
;
1011 VRootCondition
= Condition_Bad
;
1013 /* Initialize the context */
1014 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
1015 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
1016 Context
->RxContext
= RxContext
;
1017 Context
->pVNetRoot
= VirtualNetRoot
;
1018 Context
->Callback
= RxCreateNetRootCallBack
;
1020 /* And call the mini-rdr */
1021 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
1022 if (Status
== STATUS_PENDING
)
1024 /* Wait for the mini-rdr to be done */
1025 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1026 /* Update the structures condition according to mini-rdr return */
1027 if (NT_SUCCESS(Context
->NetRootStatus
))
1029 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
1031 RootCondition
= Condition_Good
;
1032 VRootCondition
= Condition_Good
;
1033 Status
= STATUS_SUCCESS
;
1037 RootCondition
= Condition_Good
;
1038 Status
= Context
->VirtualNetRootStatus
;
1043 Status
= Context
->VirtualNetRootStatus
;
1044 if (NT_SUCCESS(Status
))
1046 Status
= Context
->NetRootStatus
;
1052 /* It has to return STATUS_PENDING! */
1056 /* Acquire lock again - for caller lock status will remain unchanged */
1057 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
1058 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
1059 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1061 /* Do the transition to the condition got from mini-rdr */
1062 RxTransitionNetRoot(NetRoot
, RootCondition
);
1063 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
1065 /* Context is not longer needed */
1066 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
1068 DPRINT("Status: %x\n", Status
);
1078 IN PRX_CONTEXT RxContext
,
1079 IN PSRV_CALL SrvCall
,
1080 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1083 PRX_PREFIX_TABLE PrefixTable
;
1084 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1085 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1086 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
1090 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
1092 /* Validate the lock is exclusively held */
1093 RxDeviceObject
= RxContext
->RxDeviceObject
;
1094 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
1095 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1097 /* Allocate the context for mini-rdr */
1098 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
1099 if (Calldown
== NULL
)
1101 SrvCall
->Context
= NULL
;
1102 SrvCall
->Condition
= Condition_Bad
;
1103 RxReleasePrefixTableLock(PrefixTable
);
1104 *LockHoldingState
= LHS_LockNotHeld
;
1105 return STATUS_INSUFFICIENT_RESOURCES
;
1109 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
1111 SrvCall
->Context
= NULL
;
1112 SrvCall
->Condition
= Condition_InTransition
;
1114 RxReleasePrefixTableLock(PrefixTable
);
1115 *LockHoldingState
= LHS_LockNotHeld
;
1117 CallbackContext
= &Calldown
->CallbackContexts
[0];
1118 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
1119 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
1120 CallbackContext
->SrvCalldownStructure
= Calldown
;
1121 CallbackContext
->CallbackContextOrdinal
= 0;
1122 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
1124 RxReferenceSrvCall(SrvCall
);
1126 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1127 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1129 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
1133 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
1136 Calldown
->NumberToWait
= 1;
1137 Calldown
->NumberRemaining
= 1;
1138 Calldown
->RxContext
= RxContext
;
1139 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
1140 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
1141 Calldown
->BestFinisher
= NULL
;
1142 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
1143 InitializeListHead(&Calldown
->SrvCalldownList
);
1145 /* Call the mini-rdr */
1146 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
1147 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
1148 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
1149 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
1150 /* It has to return STATUS_PENDING! */
1151 ASSERT(Status
== STATUS_PENDING
);
1153 /* No async, start completion */
1154 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1156 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1158 /* Finish construction - we'll notify mini-rdr it's the winner */
1159 Status
= RxFinishSrvCallConstruction(Calldown
);
1160 if (!NT_SUCCESS(Status
))
1162 RxReleasePrefixTableLock(PrefixTable
);
1163 *LockHoldingState
= LHS_LockNotHeld
;
1167 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
1168 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1172 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
1180 RxConstructVirtualNetRoot(
1181 IN PRX_CONTEXT RxContext
,
1182 IN PUNICODE_STRING CanonicalName
,
1183 IN NET_ROOT_TYPE NetRootType
,
1184 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
1185 OUT PLOCK_HOLDING_STATE LockHoldingState
,
1186 OUT PRX_CONNECTION_ID RxConnectionId
)
1189 PV_NET_ROOT VNetRoot
;
1190 RX_BLOCK_CONDITION Condition
;
1191 UNICODE_STRING LocalNetRootName
, FilePathName
;
1195 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1198 Condition
= Condition_Bad
;
1199 /* Before creating the VNetRoot, try to find the appropriate connection */
1200 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
1201 &LocalNetRootName
, &FilePathName
,
1202 LockHoldingState
, RxConnectionId
);
1203 /* Found and active */
1204 if (Status
== STATUS_CONNECTION_ACTIVE
)
1206 /* We need a new VNetRoot */
1207 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
1208 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
1209 if (VNetRoot
!= NULL
)
1211 RxReferenceVNetRoot(VNetRoot
);
1214 /* Dereference previous VNetRoot */
1215 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
1216 /* Reset and start construct (new structures will replace old ones) */
1217 RxContext
->Create
.pSrvCall
= NULL
;
1218 RxContext
->Create
.pNetRoot
= NULL
;
1219 RxContext
->Create
.pVNetRoot
= NULL
;
1221 /* Construct new NetRoot */
1222 if (VNetRoot
!= NULL
)
1224 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
1225 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
1226 if (NT_SUCCESS(Status
))
1228 Condition
= Condition_Good
;
1233 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1238 /* If it failed creating the connection, leave */
1239 if (Status
!= STATUS_SUCCESS
)
1241 if (*LockHoldingState
!= LHS_LockNotHeld
)
1243 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1244 *LockHoldingState
= LHS_LockNotHeld
;
1247 *VirtualNetRootPointer
= VNetRoot
;
1248 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1252 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1254 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1255 Condition
= Condition_Good
;
1258 /* We have a non stable VNetRoot - transition it */
1259 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1261 RxTransitionVNetRoot(VNetRoot
, Condition
);
1264 /* If recreation failed */
1265 if (Status
!= STATUS_SUCCESS
)
1267 /* Dereference potential VNetRoot */
1268 if (VNetRoot
!= NULL
)
1270 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1271 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1276 if (*LockHoldingState
!= LHS_LockNotHeld
)
1278 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1279 *LockHoldingState
= LHS_LockNotHeld
;
1283 *VirtualNetRootPointer
= VNetRoot
;
1287 /* Return the allocated VNetRoot */
1288 *VirtualNetRootPointer
= VNetRoot
;
1297 IN PRX_CONTEXT RxContext
,
1298 IN PV_NET_ROOT VNetRoot
,
1299 IN PUNICODE_STRING Name
)
1305 NODE_TYPE_CODE NodeType
;
1306 PIO_STACK_LOCATION Stack
;
1307 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1311 /* We need a decent VNetRoot */
1312 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1314 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1315 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1316 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1318 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1319 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1321 Stack
= RxContext
->CurrentIrpSp
;
1323 /* Do we need to create a fake FCB? Like for renaming */
1324 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1325 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1326 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1328 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1329 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1331 /* Allocate the FCB */
1332 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1333 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1339 /* Initialize the FCB */
1340 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1341 Fcb
->RxDeviceObject
= RxDeviceObject
;
1342 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1343 Fcb
->VNetRoot
= VNetRoot
;
1344 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1346 InitializeListHead(&Fcb
->SrvOpenList
);
1347 Fcb
->SrvOpenListVersion
= 0;
1349 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1350 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1351 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1352 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1353 NetRoot
->InnerNamePrefix
.Length
);
1354 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1356 /* Copy back parameters from RxContext */
1357 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1359 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1362 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1364 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1366 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1369 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1371 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1374 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1375 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1377 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1378 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1380 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1381 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1383 /* Fake FCB doesn't go in prefix table */
1386 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1387 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1388 DPRINT("Fake FCB: %p\n", Fcb
);
1392 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1395 RxReferenceVNetRoot(VNetRoot
);
1396 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1398 Fcb
->ulFileSizeVersion
= 0;
1400 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1401 RxReferenceNetFcb(Fcb
);
1412 OUT PRX_CONTEXT RxContext
,
1413 IN PMRX_SRV_OPEN MrxSrvOpen
)
1424 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1425 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1426 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1427 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1430 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1431 /* Can we use pre-allocated FOBX? */
1432 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1434 Fobx
= Fcb
->InternalFobx
;
1435 /* Call allocate to initialize the FOBX */
1436 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1437 /* Mark it used now */
1438 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1439 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1441 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1443 Fobx
= SrvOpen
->InternalFobx
;
1444 /* Call allocate to initialize the FOBX */
1445 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1446 /* Mark it used now */
1447 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1448 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1452 /* Last case, we cannot, allocate a FOBX */
1453 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1457 /* Allocation failed! */
1464 Fobx
->Flags
= Flags
;
1466 /* Initialize throttling */
1467 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1468 if (NetRoot
!= NULL
)
1470 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1472 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1473 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1474 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1476 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1478 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1479 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1480 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1484 /* Propagate flags fron RxContext */
1485 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1487 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1490 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1492 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1496 Fobx
->FobxSerialNumber
= 0;
1497 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1498 Fobx
->NodeReferenceCount
= 1;
1499 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1501 RxReferenceSrvOpen(SrvOpen
);
1502 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1504 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1505 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1506 InitializeListHead(&Fobx
->ClosePendingList
);
1508 Fobx
->CloseTime
.QuadPart
= 0;
1509 Fobx
->fOpenCountDecremented
= FALSE
;
1511 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1513 return (PMRX_FOBX
)Fobx
;
1521 IN PSRV_CALL SrvCall
,
1522 IN PUNICODE_STRING Name
,
1523 IN ULONG NetRootFlags
,
1524 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1527 USHORT CaseInsensitiveLength
;
1528 PRX_PREFIX_TABLE PrefixTable
;
1530 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1534 /* We need a SRV_CALL */
1535 ASSERT(SrvCall
!= NULL
);
1537 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1538 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1540 /* Get name length */
1541 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1542 if (CaseInsensitiveLength
> MAXUSHORT
)
1547 /* Allocate the NetRoot */
1548 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1549 CaseInsensitiveLength
);
1550 if (NetRoot
== NULL
)
1555 /* Construct name */
1556 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1557 Name
->Buffer
, Name
->Length
);
1558 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1560 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1561 SrvCall
->PrefixEntry
.Prefix
.Length
);
1564 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1566 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1568 /* Inisert in prefix table */
1569 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1570 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1573 /* Prepare the FCB table */
1574 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1576 InitializeListHead(&NetRoot
->TransitionWaitList
);
1577 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1578 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1580 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1582 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1583 NetRoot
->Flags
|= NetRootFlags
;
1584 NetRoot
->DiskParameters
.ClusterSize
= 1;
1585 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1586 NetRoot
->SrvCall
= SrvCall
;
1588 RxReferenceSrvCall(SrvCall
);
1590 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1599 RxCreateNetRootCallBack(
1600 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1604 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1614 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1615 IN ULONG InitialContextFlags
)
1618 PRX_CONTEXT Context
;
1620 ASSERT(RxDeviceObject
!= NULL
);
1622 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1624 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1625 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1627 /* Allocate the context from our lookaside list */
1628 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1629 if (Context
== NULL
)
1634 /* And initialize it */
1635 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1636 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1637 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1639 /* Add it to our global list */
1640 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1641 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1642 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1644 DPRINT("Context: %p\n", Context
);
1653 IN PRX_CONTEXT RxContext
,
1654 IN PUNICODE_STRING Name
,
1655 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1656 IN PRX_CONNECTION_ID RxConnectionId
)
1663 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1665 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1667 /* Get the name length */
1668 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1669 if (InnerNamePrefix
!= NULL
)
1671 NameLength
+= InnerNamePrefix
->Length
;
1674 /* Allocate the object */
1675 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1676 if (SrvCall
== NULL
)
1682 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1683 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1684 RxInitializeBufferingManager(SrvCall
);
1685 InitializeListHead(&SrvCall
->TransitionWaitList
);
1686 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1687 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1688 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1689 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1690 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1691 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1692 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1693 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1695 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1704 RxCreateSrvCallCallBack(
1705 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1709 PRX_CONTEXT RxContext
;
1710 ULONG NumberRemaining
;
1711 BOOLEAN StartDispatcher
;
1712 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1714 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1716 /* Get our context structures */
1717 Calldown
= Context
->SrvCalldownStructure
;
1718 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1720 /* If it is a success, that's the winner */
1721 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1722 if (Context
->Status
== STATUS_SUCCESS
)
1724 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1725 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1727 NumberRemaining
= --Calldown
->NumberRemaining
;
1728 SrvCall
->Status
= Context
->Status
;
1729 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1731 /* Still some to ask, keep going */
1732 if (NumberRemaining
!= 0)
1737 /* If that's not async, signal we're done */
1738 RxContext
= Calldown
->RxContext
;
1739 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1741 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1744 /* If that's a mailslot, finish construction, no more to do */
1745 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1747 RxFinishSrvCallConstruction(Calldown
);
1751 /* Queue our finish call for delayed completion */
1752 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1753 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1754 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1755 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1756 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1758 /* If we have to start dispatcher, go ahead */
1759 if (StartDispatcher
)
1763 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1764 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1765 if (!NT_SUCCESS(Status
))
1767 /* It failed - run it manually.... */
1768 RxFinishSrvCallConstructionDispatcher(NULL
);
1778 IN PV_NET_ROOT VNetRoot
,
1787 ASSERT(NodeTypeIsFcb(Fcb
));
1788 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1790 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1794 SrvOpen
= Fcb
->InternalSrvOpen
;
1795 /* Check whethet we have to allocate a new SRV_OPEN */
1796 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1797 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1798 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1801 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1802 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
1807 /* Otherwise, just use internal one and initialize it */
1808 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1809 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
1810 Fcb
->InternalSrvOpen
);
1811 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
1812 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
1815 /* If SrvOpen was properly allocated, initialize it */
1816 if (SrvOpen
!= NULL
)
1818 SrvOpen
->Flags
= Flags
;
1819 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
1820 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
1821 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
1822 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
1823 SrvOpen
->NodeReferenceCount
= 1;
1825 RxReferenceVNetRoot(VNetRoot
);
1826 RxReferenceNetFcb(Fcb
);
1828 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
1829 ++Fcb
->SrvOpenListVersion
;
1831 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
1832 InitializeListHead(&SrvOpen
->TransitionWaitList
);
1833 InitializeListHead(&SrvOpen
->FobxList
);
1834 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
1839 if (_SEH2_AbnormalTermination())
1841 if (SrvOpen
!= NULL
)
1843 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
1849 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
1862 IN PRX_CONTEXT RxContext
,
1863 IN PNET_ROOT NetRoot
,
1864 IN PUNICODE_STRING CanonicalName
,
1865 IN PUNICODE_STRING LocalNetRootName
,
1866 IN PUNICODE_STRING FilePath
,
1867 IN PRX_CONNECTION_ID RxConnectionId
)
1870 PV_NET_ROOT VNetRoot
;
1871 USHORT CaseInsensitiveLength
;
1875 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
1876 LocalNetRootName
, FilePath
, RxConnectionId
);
1878 /* Lock must be held exclusively */
1879 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1881 /* Check for overflow */
1882 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
1887 /* Get name length and allocate VNetRoot */
1888 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1889 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
1890 CaseInsensitiveLength
);
1891 if (VNetRoot
== NULL
)
1896 /* Initialize its connection parameters */
1897 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
1898 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
1899 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1900 if (!NT_SUCCESS(Status
))
1902 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
1903 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
1904 RxFreeObject(VNetRoot
);
1910 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
1912 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
1913 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
1914 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1915 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
1917 InitializeListHead(&VNetRoot
->TransitionWaitList
);
1918 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
1920 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
1924 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1926 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
1930 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1933 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
1935 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
1941 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
1944 /* Insert in prefix table */
1945 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
1946 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1949 RxReferenceNetRoot(NetRoot
);
1950 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
1953 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
1954 VNetRoot
->UpperFinalizationDone
= FALSE
;
1955 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
1956 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
1958 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
1959 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
1969 IN OUT PVOID Instance
,
1970 IN LOCK_HOLDING_STATE LockHoldingState
)
1973 NODE_TYPE_CODE NodeType
;
1974 PNODE_TYPE_AND_SIZE Node
;
1978 RxAcquireScavengerMutex();
1980 /* Check we have a node we can handle */
1981 NodeType
= NodeType(Instance
);
1982 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
1983 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
1984 (NodeType
== RDBSS_NTC_FOBX
));
1986 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
1987 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
1988 ASSERT(RefCount
>= 0);
1990 /* Trace refcount */
1993 case RDBSS_NTC_SRVCALL
:
1994 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
1997 case RDBSS_NTC_NETROOT
:
1998 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
2001 case RDBSS_NTC_V_NETROOT
:
2002 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
2005 case RDBSS_NTC_SRVOPEN
:
2006 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
2009 case RDBSS_NTC_FOBX
:
2010 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
2018 /* No need to free - still in use */
2021 RxReleaseScavengerMutex();
2025 /* We have to be locked exclusively */
2026 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
2028 if ((NodeType
== RDBSS_NTC_FOBX
&& RefCount
== 0) ||
2029 (NodeType
>= RDBSS_NTC_SRVCALL
&& NodeType
<= RDBSS_NTC_V_NETROOT
))
2031 RxpMarkInstanceForScavengedFinalization(Instance
);
2034 RxReleaseScavengerMutex();
2039 if (BooleanFlagOn(NodeType
, RX_SCAVENGER_MASK
))
2041 RxpUndoScavengerFinalizationMarking(Instance
);
2045 RxReleaseScavengerMutex();
2047 /* Now, deallocate the memory */
2050 case RDBSS_NTC_SRVCALL
:
2054 SrvCall
= (PSRV_CALL
)Instance
;
2056 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
2057 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
2058 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
2062 case RDBSS_NTC_NETROOT
:
2066 NetRoot
= (PNET_ROOT
)Instance
;
2068 ASSERT(NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2069 ASSERT(RxIsPrefixTableLockAcquired(NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2070 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2074 case RDBSS_NTC_V_NETROOT
:
2076 PV_NET_ROOT VNetRoot
;
2078 VNetRoot
= (PV_NET_ROOT
)Instance
;
2080 ASSERT(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2081 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2082 RxFinalizeVNetRoot(VNetRoot
, TRUE
, TRUE
);
2086 case RDBSS_NTC_SRVOPEN
:
2090 SrvOpen
= (PSRV_OPEN
)Instance
;
2092 ASSERT(RxIsFcbAcquired(SrvOpen
->Fcb
));
2093 if (SrvOpen
->OpenCount
== 0)
2095 RxFinalizeSrvOpen(SrvOpen
, FALSE
, FALSE
);
2100 case RDBSS_NTC_FOBX
:
2104 Fobx
= (PFOBX
)Instance
;
2106 ASSERT(RxIsFcbAcquired(Fobx
->SrvOpen
->Fcb
));
2107 RxFinalizeNetFobx(Fobx
, TRUE
, FALSE
);
2118 RxDereferenceAndDeleteRxContext_Real(
2119 IN PRX_CONTEXT RxContext
)
2124 PRX_CONTEXT StopContext
= NULL
;
2126 /* Make sure we really have a context */
2127 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
2128 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
2129 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
2130 /* If refcount is 0, start releasing stuff that needs spinlock held */
2133 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2135 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
2137 /* If that's stop context from DO, remove it */
2138 RxDeviceObject
= RxContext
->RxDeviceObject
;
2139 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
2141 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
2145 /* Remove it from the list */
2146 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
2147 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
2148 RemoveEntryList(&RxContext
->ContextListEntry
);
2150 /* If that was the last active context, save the stop context */
2151 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
2153 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
2155 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
2160 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
2162 /* Now, deal with what can be done without spinlock held */
2165 /* Refcount shouldn't have changed */
2166 ASSERT(RxContext
->ReferenceCount
== 0);
2167 /* Reset everything that can be */
2168 RxPrepareContextForReuse(RxContext
);
2170 #ifdef RDBSS_TRACKER
2171 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
2173 /* If that was the last active, set the event */
2174 if (StopContext
!= NULL
)
2176 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
2177 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
2180 /* Is ShadowCrit still owned? Shouldn't happen! */
2181 if (RxContext
->ShadowCritOwner
!= 0)
2183 DPRINT1("ShadowCritOwner not null! %p\n", (PVOID
)RxContext
->ShadowCritOwner
);
2187 /* If it was allocated, free it */
2190 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
2197 RxDispatchChangeBufferingStateRequests(
2208 RxDispatchToWorkerThread(
2209 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
2210 IN WORK_QUEUE_TYPE WorkQueueType
,
2211 IN PRX_WORKERTHREAD_ROUTINE Routine
,
2215 PRX_WORK_DISPATCH_ITEM DispatchItem
;
2217 /* Allocate a bit of context */
2218 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
2219 if (DispatchItem
== NULL
)
2221 return STATUS_INSUFFICIENT_RESOURCES
;
2224 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2225 DispatchItem
->DispatchRoutine
= Routine
;
2226 DispatchItem
->DispatchRoutineParameter
= pContext
;
2227 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
2228 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
2231 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, &DispatchItem
->WorkQueueItem
);
2232 if (!NT_SUCCESS(Status
))
2234 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
2235 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
2238 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
2247 RxExclusivePrefixTableLockToShared(
2248 PRX_PREFIX_TABLE Table
)
2252 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
2259 RxExtractServerName(
2260 IN PUNICODE_STRING FilePathName
,
2261 OUT PUNICODE_STRING SrvCallName
,
2262 OUT PUNICODE_STRING RestOfName
)
2268 ASSERT(SrvCallName
!= NULL
);
2270 /* SrvCall name will start from the begin up to the first separator */
2271 SrvCallName
->Buffer
= FilePathName
->Buffer
;
2272 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2274 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2280 /* Compute length */
2281 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
2282 SrvCallName
->MaximumLength
= Length
;
2283 SrvCallName
->Length
= Length
;
2285 /* Return the rest if asked */
2286 if (RestOfName
!= NULL
)
2288 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
2289 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2290 RestOfName
->MaximumLength
= Length
;
2291 RestOfName
->Length
= Length
;
2299 RxFcbTableInsertFcb(
2300 IN OUT PRX_FCB_TABLE FcbTable
,
2305 /* We deal with the table, make sure it's locked */
2306 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2308 /* Compute the hash */
2309 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2311 RxReferenceNetFcb(Fcb
);
2313 /* If no length, it will be our null entry */
2314 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2316 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2318 /* Otherwise, insert in the appropriate bucket */
2321 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2322 &Fcb
->FcbTableEntry
.HashLinks
);
2325 /* Propagate the change by incrementing the version number */
2326 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2328 return STATUS_SUCCESS
;
2335 RxFcbTableLookupFcb(
2336 IN PRX_FCB_TABLE FcbTable
,
2337 IN PUNICODE_STRING Path
)
2340 PRX_FCB_TABLE_ENTRY TableEntry
;
2344 /* No path - easy, that's null entry */
2347 TableEntry
= FcbTable
->TableEntryForNull
;
2352 PLIST_ENTRY HashBucket
, ListEntry
;
2354 /* Otherwise, compute the hash value and find the associated bucket */
2355 Hash
= RxTableComputePathHashValue(Path
);
2356 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2357 /* If the bucket is empty, it means there's no entry yet */
2358 if (IsListEmpty(HashBucket
))
2364 /* Otherwise, browse all the entry */
2365 for (ListEntry
= HashBucket
->Flink
;
2366 ListEntry
!= HashBucket
;
2367 ListEntry
= ListEntry
->Flink
)
2369 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2370 InterlockedIncrement(&FcbTable
->Compares
);
2372 /* If entry hash and string are equal, thatt's the one! */
2373 if (TableEntry
->HashValue
== Hash
&&
2374 TableEntry
->Path
.Length
== Path
->Length
&&
2375 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2381 /* We reached the end? Not found */
2382 if (ListEntry
== HashBucket
)
2389 InterlockedIncrement(&FcbTable
->Lookups
);
2391 /* If table entry isn't null, return the FCB */
2392 if (TableEntry
!= NULL
)
2394 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2395 RxReferenceNetFcb(Fcb
);
2400 InterlockedIncrement(&FcbTable
->FailedLookups
);
2410 RxFcbTableRemoveFcb(
2411 IN OUT PRX_FCB_TABLE FcbTable
,
2416 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2418 /* If no path, then remove entry for null */
2419 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2421 FcbTable
->TableEntryForNull
= NULL
;
2423 /* Otherwise, remove from the bucket */
2426 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2429 /* Reset its list entry */
2430 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2432 /* Propagate the change by incrementing the version number */
2433 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2435 return STATUS_SUCCESS
;
2443 IN OUT PRX_FCB_TABLE FcbTable
)
2449 /* Just delete the lock */
2450 ExDeleteResourceLite(&FcbTable
->TableLock
);
2452 /* And make sure (checked) that the table is really empty... */
2453 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2455 ASSERT(IsListEmpty(&FcbTable
->HashBuckets
[Bucket
]));
2465 IN BOOLEAN RecursiveFinalize
,
2466 IN BOOLEAN ForceFinalize
,
2467 IN LONG ReferenceCount
)
2471 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2472 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2474 /* Make sure we have an exclusively acquired FCB */
2475 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2476 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2478 /* We shouldn't force finalization... */
2479 ASSERT(!ForceFinalize
);
2481 /* If recurisve, finalize all the associated SRV_OPEN */
2482 if (RecursiveFinalize
)
2484 PLIST_ENTRY ListEntry
;
2486 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2487 ListEntry
!= &ThisFcb
->SrvOpenList
;
2488 ListEntry
= ListEntry
->Flink
)
2492 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2493 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2496 /* If FCB is still in use, that's over */
2499 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2501 ASSERT(ReferenceCount
> 0);
2507 ASSERT(ReferenceCount
>= 1);
2509 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2510 if (ReferenceCount
!= 1 && !ForceFinalize
)
2515 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2517 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb
->OpenCount
, ForceFinalize
);
2519 /* If finalization was not already initiated, go ahead */
2520 if (!ThisFcb
->UpperFinalizationDone
)
2522 /* Free any FCB_LOCK */
2523 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2525 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2527 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2531 Entry
= ThisFcb
->BufferedLocks
.List
;
2532 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2538 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2539 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2543 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2545 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2547 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2549 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2553 ThisFcb
->UpperFinalizationDone
= TRUE
;
2556 ASSERT(ReferenceCount
>= 1);
2558 /* Even if forced, don't allow broken free */
2559 if (ReferenceCount
!= 1)
2564 /* Now, release everything */
2565 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2567 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2570 if (ThisFcb
->MRxDispatch
!= NULL
)
2572 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2575 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2576 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2577 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2579 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2580 RxDereferenceVNetRoot(ThisFcb
->VNetRoot
, LHS_LockNotHeld
);
2582 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2583 ASSERT(!ThisFcb
->fMiniInited
);
2585 /* And free the object */
2586 RxFreeFcbObject(ThisFcb
);
2596 _Out_ PFOBX ThisFobx
,
2597 _In_ BOOLEAN RecursiveFinalize
,
2598 _In_ BOOLEAN ForceFinalize
)
2605 ASSERT(NodeType(ThisFobx
) == RDBSS_NTC_FOBX
);
2607 /* Only finalize if forced or if there's no ref left */
2608 if (ThisFobx
->NodeReferenceCount
!= 0 &&
2614 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx
, ThisFobx
->NodeReferenceCount
, ForceFinalize
);
2616 SrvOpen
= ThisFobx
->SrvOpen
;
2618 /* If it wasn't finalized yet, do it */
2619 if (!ThisFobx
->UpperFinalizationDone
)
2621 ASSERT(NodeType(SrvOpen
->Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
2622 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
2624 /* Remove it from the SRV_OPEN */
2625 RemoveEntryList(&ThisFobx
->FobxQLinks
);
2627 /* If we were used to browse a directory, free the query buffer */
2628 if (BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_FREE_UNICODE
))
2630 RxFreePoolWithTag(ThisFobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
2633 /* Notify the mini-rdr */
2634 if (Fcb
->MRxDispatch
!= NULL
&& Fcb
->MRxDispatch
->MRxDeallocateForFobx
!= NULL
)
2636 Fcb
->MRxDispatch
->MRxDeallocateForFobx((PMRX_FOBX
)ThisFobx
);
2639 /* If the SRV_OPEN wasn't closed yet, do it */
2640 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
2644 Status
= RxCloseAssociatedSrvOpen(ThisFobx
, FALSE
);
2645 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen
, ThisFobx
, Status
);
2648 /* Finalization done */
2649 ThisFobx
->UpperFinalizationDone
= TRUE
;
2652 /* If we're still referenced, don't go any further! */
2653 if (ThisFobx
->NodeReferenceCount
!= 0)
2658 /* At that point, everything should be closed */
2659 ASSERT(IsListEmpty(&ThisFobx
->ClosePendingList
));
2661 /* Was the FOBX allocated with another object?
2662 * If so, mark the buffer free in said object
2664 if (ThisFobx
== Fcb
->InternalFobx
)
2666 ClearFlag(Fcb
->FcbState
, FCB_STATE_FOBX_USED
);
2668 else if (ThisFobx
== SrvOpen
->InternalFobx
)
2670 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
);
2673 ThisFobx
->pSrvOpen
= NULL
;
2676 InterlockedDecrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
2678 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
2680 /* If it wasn't allocated with another object, free the FOBX */
2681 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_ENCLOSED_ALLOCATED
))
2683 RxFreeFcbObject(ThisFobx
);
2694 OUT PNET_ROOT ThisNetRoot
,
2695 IN BOOLEAN RecursiveFinalize
,
2696 IN BOOLEAN ForceFinalize
)
2699 PRX_FCB_TABLE FcbTable
;
2700 PRX_PREFIX_TABLE PrefixTable
;
2704 ASSERT(NodeType(ThisNetRoot
) == RDBSS_NTC_NETROOT
);
2706 PrefixTable
= ThisNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2707 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
2709 /* If sme finalization is already ongoing, leave */
2710 if (BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
))
2715 /* Mark we're finalizing */
2716 SetFlag(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
);
2718 FcbTable
= &ThisNetRoot
->FcbTable
;
2719 /* Did caller asked us to finalize any associated FCB? */
2720 if (RecursiveFinalize
)
2724 /* Browse all the FCBs in our FCB table */
2725 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
2726 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2728 PLIST_ENTRY HashBucket
, ListEntry
;
2730 HashBucket
= &FcbTable
->HashBuckets
[Bucket
];
2731 ListEntry
= HashBucket
->Flink
;
2732 while (ListEntry
!= HashBucket
)
2736 Fcb
= CONTAINING_RECORD(ListEntry
, FCB
, FcbTableEntry
.HashLinks
);
2737 ASSERT(NodeTypeIsFcb(Fcb
));
2739 ListEntry
= ListEntry
->Flink
;
2741 /* If the FCB isn't orphaned, then, it's time to purge it */
2742 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
2746 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
2747 ASSERT(Status
== STATUS_SUCCESS
);
2752 RxReleaseFcbTableLock(FcbTable
);
2755 /* Only finalize if forced or if there's a single ref left */
2756 if (ThisNetRoot
->NodeReferenceCount
!= 1 && !ForceFinalize
)
2761 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot
, &ThisNetRoot
->PrefixEntry
.Prefix
);
2763 /* If we're still referenced, don't go any further! */
2764 if (ThisNetRoot
->NodeReferenceCount
!= 1)
2769 /* Finalize the FCB table (and make sure it's empty!) */
2770 RxFinalizeFcbTable(FcbTable
);
2772 /* If name wasn't remove already, do it now */
2773 if (!BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
2775 RxRemovePrefixTableEntry(PrefixTable
, &ThisNetRoot
->PrefixEntry
);
2778 /* Delete the object */
2779 SrvCall
= (PSRV_CALL
)ThisNetRoot
->pSrvCall
;
2780 RxFreeObject(ThisNetRoot
);
2782 /* And dereference the associated SRV_CALL */
2783 if (SrvCall
!= NULL
)
2785 RxDereferenceSrvCall(SrvCall
, LHS_ExclusiveLockHeld
);
2796 OUT PSRV_CALL ThisSrvCall
,
2797 IN BOOLEAN RecursiveFinalize
,
2798 IN BOOLEAN ForceFinalize
)
2800 PRX_PREFIX_TABLE PrefixTable
;
2804 ASSERT(NodeType(ThisSrvCall
) == RDBSS_NTC_SRVCALL
);
2806 PrefixTable
= ThisSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2807 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
2809 /* Only finalize if forced or if there's a single ref left */
2810 if (ThisSrvCall
->NodeReferenceCount
!= 1 &&
2816 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall
, &ThisSrvCall
->PrefixEntry
.Prefix
);
2818 /* If it wasn't finalized yet, do it */
2819 if (!ThisSrvCall
->UpperFinalizationDone
)
2823 /* Remove ourselves from prefix table */
2824 RxRemovePrefixTableEntry(PrefixTable
, &ThisSrvCall
->PrefixEntry
);
2826 /* Remember our third arg, in case we get queued for later execution */
2829 SetFlag(ThisSrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
2833 ThisSrvCall
->UpperFinalizationDone
= TRUE
;
2835 /* Would defered execution free the object? */
2836 WillFree
= (ThisSrvCall
->NodeReferenceCount
== 1);
2838 /* If we have a device object */
2839 if (ThisSrvCall
->RxDeviceObject
!= NULL
)
2843 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
2844 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
2846 /* Extra ref, as usual */
2847 InterlockedIncrement((volatile long *)&ThisSrvCall
->NodeReferenceCount
);
2849 RxDispatchToWorkerThread(ThisSrvCall
->RxDeviceObject
, DelayedWorkQueue
, RxpDestroySrvCall
, ThisSrvCall
);
2851 /* Return to the caller, in advance, whether we're freeing the object or not */
2855 /* If in the right thread already, call the mini-rdr */
2856 MINIRDR_CALL_THROUGH(Status
, ThisSrvCall
->RxDeviceObject
->Dispatch
,
2857 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)ThisSrvCall
, ForceFinalize
));
2862 /* If we're still referenced, don't go any further! */
2863 if (ThisSrvCall
->NodeReferenceCount
!= 1)
2869 if (ThisSrvCall
->pDomainName
!= NULL
)
2871 RxFreePool(ThisSrvCall
->pDomainName
);
2875 RxTearDownBufferingManager(ThisSrvCall
);
2876 RxFreeObject(ThisSrvCall
);
2886 OUT PSRV_OPEN ThisSrvOpen
,
2887 IN BOOLEAN RecursiveFinalize
,
2888 IN BOOLEAN ForceFinalize
)
2894 /* We have to have a SRV_OPEN */
2895 ASSERT(NodeType(ThisSrvOpen
) == RDBSS_NTC_SRVOPEN
);
2897 /* If that's a recursive finalization, finalize any related FOBX */
2898 if (RecursiveFinalize
)
2900 PLIST_ENTRY ListEntry
;
2902 ListEntry
= ThisSrvOpen
->FobxList
.Flink
;
2903 while (ListEntry
!= &ThisSrvOpen
->FobxList
)
2907 Fobx
= CONTAINING_RECORD(ListEntry
, FOBX
, FobxQLinks
);
2908 ListEntry
= ListEntry
->Flink
;
2909 RxFinalizeNetFobx(Fobx
, TRUE
, ForceFinalize
);
2913 /* If we have still references, don't finalize unless forced */
2914 if (ThisSrvOpen
->NodeReferenceCount
!= 0 &&
2920 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen
, ThisSrvOpen
->NodeReferenceCount
, ForceFinalize
);
2922 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
2923 Fcb
= (PFCB
)ThisSrvOpen
->pFcb
;
2924 if ((!ThisSrvOpen
->UpperFinalizationDone
&& ThisSrvOpen
->Condition
!= Condition_Good
) ||
2925 BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
2927 PV_NET_ROOT VNetRoot
;
2929 /* Associated FCB can't be fake one */
2930 ASSERT(NodeType(Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
2931 ASSERT(RxIsFcbAcquiredExclusive (Fcb
));
2933 /* Purge any pending operation */
2934 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen
);
2936 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
2937 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
2941 MINIRDR_CALL_THROUGH(Status
, Fcb
->MRxDispatch
, MRxForceClosed
, ((PMRX_SRV_OPEN
)ThisSrvOpen
));
2945 /* Remove ourselves from the FCB */
2946 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
2947 InitializeListHead(&ThisSrvOpen
->SrvOpenQLinks
);
2948 ++Fcb
->SrvOpenListVersion
;
2950 /* If we have a V_NET_ROOT, dereference it */
2951 VNetRoot
= (PV_NET_ROOT
)ThisSrvOpen
->pVNetRoot
;
2952 if (VNetRoot
!= NULL
)
2954 InterlockedDecrement((volatile long *)&VNetRoot
->pNetRoot
->NumberOfSrvOpens
);
2955 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
2956 ThisSrvOpen
->pVNetRoot
= NULL
;
2959 /* Finalization done */
2960 ThisSrvOpen
->UpperFinalizationDone
= TRUE
;
2963 /* Don't free memory if still referenced */
2964 if (ThisSrvOpen
->NodeReferenceCount
!= 0)
2969 /* No key association left */
2970 ASSERT(IsListEmpty(&ThisSrvOpen
->SrvOpenKeyList
));
2972 /* If we're still in some FCB, remove us */
2973 if (!IsListEmpty(&ThisSrvOpen
->SrvOpenQLinks
))
2975 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
2978 /* If enclosed allocation, mark the memory zone free and dereference FCB */
2979 if (BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
))
2981 ClearFlag(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
);
2982 RxDereferenceNetFcb(Fcb
);
2984 /* Otherwise, free the memory */
2987 RxFreeFcbObject(ThisSrvOpen
);
2998 OUT PV_NET_ROOT ThisVNetRoot
,
2999 IN BOOLEAN RecursiveFinalize
,
3000 IN BOOLEAN ForceFinalize
)
3003 PRX_PREFIX_TABLE PrefixTable
;
3007 ASSERT(NodeType(ThisVNetRoot
) == RDBSS_NTC_V_NETROOT
);
3009 PrefixTable
= ThisVNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3010 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3012 /* Only finalize if forced or if there's a single ref left */
3013 if (ThisVNetRoot
->NodeReferenceCount
!= 1 &&
3019 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot
, &ThisVNetRoot
->PrefixEntry
.Prefix
);
3021 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
3022 /* If it wasn't finalized yet, do it */
3023 if (!ThisVNetRoot
->UpperFinalizationDone
)
3025 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
3027 /* Reference the NetRoot so that it doesn't disappear */
3028 RxReferenceNetRoot(NetRoot
);
3029 RxOrphanSrvOpens(ThisVNetRoot
);
3030 /* Remove us from the available VNetRoot for NetRoot */
3031 RxRemoveVirtualNetRootFromNetRoot(NetRoot
, ThisVNetRoot
);
3032 /* Remove extra ref */
3033 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3035 /* Remove ourselves from prefix table */
3036 RxRemovePrefixTableEntry(PrefixTable
, &ThisVNetRoot
->PrefixEntry
);
3038 /* Finalization done */
3039 ThisVNetRoot
->UpperFinalizationDone
= TRUE
;
3042 /* If we're still referenced, don't go any further! */
3043 if (ThisVNetRoot
->NodeReferenceCount
!= 1)
3048 /* If there's an associated device, notify mini-rdr */
3049 if (NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
3053 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
3054 MRxFinalizeVNetRoot
, ((PMRX_V_NET_ROOT
)ThisVNetRoot
, FALSE
));
3058 /* Free parameters */
3059 RxUninitializeVNetRootParameters(ThisVNetRoot
->pUserName
, ThisVNetRoot
->pUserDomainName
,
3060 ThisVNetRoot
->pPassword
, &ThisVNetRoot
->Flags
);
3061 /* Dereference our NetRoot, we won't reference it anymore */
3062 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3064 /* And free the object! */
3065 RxFreePoolWithTag(ThisVNetRoot
, RX_V_NETROOT_POOLTAG
);
3071 RxFindOrConstructVirtualNetRoot(
3072 IN PRX_CONTEXT RxContext
,
3073 IN PUNICODE_STRING CanonicalName
,
3074 IN NET_ROOT_TYPE NetRootType
,
3075 IN PUNICODE_STRING RemainingName
)
3081 PV_NET_ROOT VNetRoot
;
3082 RX_CONNECTION_ID ConnectionID
;
3083 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3084 LOCK_HOLDING_STATE LockHoldingState
;
3088 RxDeviceObject
= RxContext
->RxDeviceObject
;
3089 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
3090 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
3092 /* Ask the mini-rdr for connection ID */
3093 ConnectionID
.SessionID
= 0;
3094 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
3096 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
3097 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
3099 /* mini-rdr is expected not to fail - unless it's not implemented */
3100 DPRINT1("Failed to initialize connection ID\n");
3105 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
3107 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
3108 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3109 LockHoldingState
= LHS_SharedLockHeld
;
3113 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3117 PV_NET_ROOT SavedVNetRoot
;
3119 /* Look in prefix table */
3120 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
3121 if (Container
!= NULL
)
3123 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3124 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
3126 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3127 RxDereferenceSrvCall(Container
, LockHoldingState
);
3131 VNetRoot
= Container
;
3132 NetRoot
= VNetRoot
->NetRoot
;
3134 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3135 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
3136 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3138 Status
= STATUS_BAD_NETWORK_PATH
;
3139 SavedVNetRoot
= NULL
;
3145 PUNICODE_STRING UserName
, UserDomain
, Password
;
3147 /* We can reuse if we use same credentials */
3148 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
3149 &SessionId
, &UserName
,
3150 &UserDomain
, &Password
,
3152 if (NT_SUCCESS(Status
))
3154 SavedVNetRoot
= VNetRoot
;
3155 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
3157 UserDomain
, Password
,
3159 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
3161 PLIST_ENTRY ListEntry
;
3163 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
3164 ListEntry
!= &NetRoot
->VirtualNetRoots
;
3165 ListEntry
= ListEntry
->Flink
)
3167 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
3168 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
3170 UserDomain
, Password
,
3172 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3178 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
3180 SavedVNetRoot
= NULL
;
3184 if (!NT_SUCCESS(Status
))
3186 SavedVNetRoot
= NULL
;
3189 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
3193 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3194 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
3196 if (SavedVNetRoot
== NULL
)
3198 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3201 /* Reference VNetRoot we'll keep, and dereference current */
3202 else if (SavedVNetRoot
!= VNetRoot
)
3204 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3205 if (SavedVNetRoot
!= NULL
)
3207 RxReferenceVNetRoot(SavedVNetRoot
);
3212 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3213 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3220 /* If we're locked exclusive, we won't loop again, it was the second pass */
3221 if (LockHoldingState
!= LHS_SharedLockHeld
)
3226 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3227 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
3229 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3230 LockHoldingState
= LHS_ExclusiveLockHeld
;
3234 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3235 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3236 LockHoldingState
= LHS_ExclusiveLockHeld
;
3239 /* We didn't fail, and didn't find any VNetRoot, construct one */
3242 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
3244 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
3245 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
3247 if (Status
== STATUS_SUCCESS
)
3249 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
3250 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3251 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
3253 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3254 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
3255 RemainingName
->MaximumLength
= RemainingName
->Length
;
3257 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
3259 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
3261 VNetRoot
->Flags
|= Flags
;
3265 /* Release the prefix table - caller expects it to be released */
3266 if (LockHoldingState
!= LHS_LockNotHeld
)
3268 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3271 /* If we failed creating, quit */
3272 if (Status
!= STATUS_SUCCESS
)
3274 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
3278 /* Otherwise, wait until the VNetRoot is stable */
3279 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
3280 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
3281 /* It's all good, update the RX_CONTEXT with all our structs */
3282 if (VNetRoot
->Condition
== Condition_Good
)
3286 NetRoot
= VNetRoot
->NetRoot
;
3287 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3288 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3289 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
3293 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3294 RxContext
->Create
.pVNetRoot
= NULL
;
3295 Status
= STATUS_BAD_NETWORK_PATH
;
3305 RxFindOrCreateConnections(
3306 _In_ PRX_CONTEXT RxContext
,
3307 _In_ PUNICODE_STRING CanonicalName
,
3308 _In_ NET_ROOT_TYPE NetRootType
,
3309 _Out_ PUNICODE_STRING LocalNetRootName
,
3310 _Out_ PUNICODE_STRING FilePathName
,
3311 _Inout_ PLOCK_HOLDING_STATE LockState
,
3312 _In_ PRX_CONNECTION_ID RxConnectionId
)
3317 PV_NET_ROOT VNetRoot
;
3318 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
3319 PRX_PREFIX_TABLE PrefixTable
;
3320 UNICODE_STRING RemainingName
, NetRootName
;
3324 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3325 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
3326 FilePathName
, LockState
, RxConnectionId
);
3328 *FilePathName
= *CanonicalName
;
3329 LocalNetRootName
->Length
= 0;
3330 LocalNetRootName
->MaximumLength
= 0;
3331 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
3333 /* UNC path, split it */
3334 if (FilePathName
->Buffer
[1] == ';')
3340 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
3342 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
3351 return STATUS_OBJECT_NAME_INVALID
;
3354 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
3355 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
3356 LocalNetRootName
->Length
= Length
;
3357 LocalNetRootName
->MaximumLength
= Length
;
3358 FilePathName
->Length
-= Length
;
3360 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
3361 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
3362 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
3366 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
3371 ASSERT(*LockState
!= LHS_LockNotHeld
);
3373 /* If previous lookup left something, dereference it */
3374 if (Container
!= NULL
)
3376 switch (NodeType(Container
))
3378 case RDBSS_NTC_SRVCALL
:
3379 RxDereferenceSrvCall(Container
, *LockState
);
3382 case RDBSS_NTC_NETROOT
:
3383 RxDereferenceNetRoot(Container
, *LockState
);
3386 case RDBSS_NTC_V_NETROOT
:
3387 RxDereferenceVNetRoot(Container
, *LockState
);
3391 /* Should never happen */
3397 /* Look for our NetRoot in prefix table */
3398 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
3399 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
3403 UNICODE_STRING SrvCallName
;
3409 /* Assume we didn't succeed */
3410 RxContext
->Create
.pVNetRoot
= NULL
;
3411 RxContext
->Create
.pNetRoot
= NULL
;
3412 RxContext
->Create
.pSrvCall
= NULL
;
3413 RxContext
->Create
.Type
= NetRootType
;
3415 /* If we found something */
3416 if (Container
!= NULL
)
3419 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
3421 VNetRoot
= Container
;
3422 /* Use its NetRoot */
3423 NetRoot
= VNetRoot
->NetRoot
;
3425 /* If it's not stable, wait for it to be stable */
3426 if (NetRoot
->Condition
== Condition_InTransition
)
3428 RxReleasePrefixTableLock(PrefixTable
);
3429 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
3430 RxWaitForStableNetRoot(NetRoot
, RxContext
);
3431 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3432 *LockState
= LHS_ExclusiveLockHeld
;
3434 /* Now that's it's ok, retry lookup to find what we want */
3435 if (NetRoot
->Condition
== Condition_Good
)
3441 /* Is the associated netroot good? */
3442 if (NetRoot
->Condition
== Condition_Good
)
3444 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
3446 /* If it is, and SrvCall as well, then, we have our active connection */
3447 if (SrvCall
->Condition
== Condition_Good
&&
3448 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
3450 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3451 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3452 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3454 Status
= STATUS_CONNECTION_ACTIVE
;
3459 /* If VNetRoot was well constructed, it means the connection is active */
3460 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
3462 Status
= STATUS_CONNECTION_ACTIVE
;
3466 Status
= VNetRoot
->ConstructionStatus
;
3469 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3472 /* Can only be a SrvCall */
3475 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3476 SrvCall
= Container
;
3478 /* Wait for the SRV_CALL to be stable */
3479 if (SrvCall
->Condition
== Condition_InTransition
)
3481 RxReleasePrefixTableLock(PrefixTable
);
3482 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
3483 RxWaitForStableSrvCall(SrvCall
, RxContext
);
3484 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3485 *LockState
= LHS_ExclusiveLockHeld
;
3487 /* It went good, loop again to find what we look for */
3488 if (SrvCall
->Condition
== Condition_Good
)
3494 /* If it's not good... */
3495 if (SrvCall
->Condition
!= Condition_Good
)
3497 /* But SRV_CALL was well constructed, assume a connection was active */
3498 if (SrvCall
->Status
== STATUS_SUCCESS
)
3500 Status
= STATUS_CONNECTION_ACTIVE
;
3504 Status
= SrvCall
->Status
;
3507 RxDereferenceSrvCall(SrvCall
, *LockState
);
3513 /* If we found a SRV_CALL not matching our DO, quit */
3514 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
3515 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3517 RxDereferenceSrvCall(SrvCall
, *LockState
);
3518 Status
= STATUS_BAD_NETWORK_NAME
;
3522 /* Now, we want exclusive lock */
3523 if (*LockState
== LHS_SharedLockHeld
)
3525 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
3527 RxReleasePrefixTableLock(PrefixTable
);
3528 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3529 *LockState
= LHS_ExclusiveLockHeld
;
3533 RxReleasePrefixTableLock(PrefixTable
);
3534 *LockState
= LHS_ExclusiveLockHeld
;
3537 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3539 /* If we reach that point, we found something, no need to create something */
3540 if (Container
!= NULL
)
3545 /* Get the name for the SRV_CALL */
3546 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
3547 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
3548 /* And create the SRV_CALL */
3549 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
3550 if (SrvCall
== NULL
)
3552 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3556 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3557 RxReferenceSrvCall(SrvCall
);
3558 RxContext
->Create
.pVNetRoot
= NULL
;
3559 RxContext
->Create
.pNetRoot
= NULL
;
3560 RxContext
->Create
.pSrvCall
= NULL
;
3561 RxContext
->Create
.Type
= NetRootType
;
3562 Container
= SrvCall
;
3564 /* Construct SRV_CALL, ie, use mini-rdr */
3565 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
3566 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
3567 if (Status
!= STATUS_SUCCESS
)
3569 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
3570 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3571 RxDereferenceSrvCall(SrvCall
, *LockState
);
3572 RxReleasePrefixTableLock(PrefixTable
);
3576 /* Loop again to make use of SRV_CALL stable condition wait */
3579 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3580 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
3581 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
3582 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
3584 /* Call mini-rdr to get NetRoot name */
3585 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
3586 /* And create the NetRoot with that name */
3587 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
3588 if (NetRoot
== NULL
)
3590 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3593 NetRoot
->Type
= NetRootType
;
3595 RxDereferenceSrvCall(SrvCall
, *LockState
);
3597 /* Finally, create the associated VNetRoot */
3598 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
3599 if (VNetRoot
== NULL
)
3601 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
3602 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3605 RxReferenceVNetRoot(VNetRoot
);
3607 /* We're get closer! */
3608 NetRoot
->Condition
= Condition_InTransition
;
3609 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3610 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3611 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3613 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3614 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
3615 if (!NT_SUCCESS(Status
))
3617 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
3618 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
3619 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3621 RxContext
->Create
.pNetRoot
= NULL
;
3622 RxContext
->Create
.pVNetRoot
= NULL
;
3626 PIO_STACK_LOCATION Stack
;
3628 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3630 Stack
= RxContext
->CurrentIrpSp
;
3631 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
3633 RxExclusivePrefixTableLockToShared(PrefixTable
);
3634 *LockState
= LHS_SharedLockHeld
;
3640 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
3642 if (*LockState
!= LHS_LockNotHeld
)
3644 RxReleasePrefixTableLock(PrefixTable
);
3645 *LockState
= LHS_LockNotHeld
;
3651 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
3660 RxFinishFcbInitialization(
3661 IN OUT PMRX_FCB Fcb
,
3662 IN RX_FILE_TYPE FileType
,
3663 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
3665 RX_FILE_TYPE OldType
;
3669 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
3671 OldType
= NodeType(Fcb
);
3672 NodeType(Fcb
) = FileType
;
3673 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
3674 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
3676 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3678 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
3679 else if (InitPacket
!= NULL
)
3681 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
3682 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
3683 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
3684 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
3685 InitPacket
->pValidDataLength
->QuadPart
);
3688 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
3689 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
3691 /* If our FCB newly points to a file, initiliaze everything related */
3692 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
)
3695 if (OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
3697 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
3698 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, RxLockOperationCompletion
,
3701 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
3702 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
3704 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
3707 /* If not a file, validate type */
3710 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
3719 RxFinishSrvCallConstruction(
3720 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
3724 PRX_CONTEXT Context
;
3725 RX_BLOCK_CONDITION Condition
;
3726 PRX_PREFIX_TABLE PrefixTable
;
3728 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
3730 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
3731 Context
= Calldown
->RxContext
;
3732 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
3734 /* We have a winner, notify him */
3735 if (Calldown
->BestFinisher
!= NULL
)
3737 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
3739 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
3741 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
3742 MRxSrvCallWinnerNotify
,
3743 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
3744 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
3745 if (Status
!= STATUS_SUCCESS
)
3747 Condition
= Condition_Bad
;
3751 Condition
= Condition_Good
;
3754 /* Otherwise, just fail our SRV_CALL */
3757 Status
= Calldown
->CallbackContexts
[0].Status
;
3758 Condition
= Condition_Bad
;
3761 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3762 RxTransitionSrvCall(SrvCall
, Condition
);
3763 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
3765 /* If async, finish it here, otherwise, caller has already finished the stuff */
3766 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
3768 DPRINT("Finishing async call\n");
3770 RxReleasePrefixTableLock(PrefixTable
);
3772 /* Make sure we weren't cancelled in-between */
3773 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
3775 Status
= STATUS_CANCELLED
;
3778 /* In case that was a create, context can be reused */
3779 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
3781 RxpPrepareCreateContextForReuse(Context
);
3784 /* If that's a failure, reset everything and return failure */
3785 if (Status
!= STATUS_SUCCESS
)
3787 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
3788 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
3790 if (Context
->Info
.Buffer
!= NULL
)
3792 RxFreePool(Context
->Info
.Buffer
);
3793 Context
->Info
.Buffer
= NULL
;
3796 Context
->CurrentIrp
->IoStatus
.Information
= 0;
3797 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
3798 RxCompleteRequest(Context
, Status
);
3800 /* Otherwise, call resume routine and done! */
3803 Status
= Context
->ResumeRoutine(Context
);
3804 if (Status
!= STATUS_PENDING
)
3806 RxCompleteRequest(Context
, Status
);
3809 DPRINT("Not completing, pending\n");
3813 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
3822 RxFinishSrvCallConstructionDispatcher(
3826 BOOLEAN Direct
, KeepLoop
;
3828 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
3830 /* In case of failure of starting dispatcher, context is not set
3831 * We keep track of it to fail associated SRV_CALL
3833 Direct
= (Context
== NULL
);
3835 /* Separated thread, loop forever */
3838 PLIST_ENTRY ListEntry
;
3839 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
3841 /* If there are no SRV_CALL to finalize left, just finish thread */
3842 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
3843 if (IsListEmpty(&RxSrvCalldownList
))
3846 RxSrvCallConstructionDispatcherActive
= FALSE
;
3848 /* Otherwise, get the SRV_CALL to finish construction */
3851 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
3854 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
3862 /* If direct is set, reset the finisher to avoid electing a winner
3863 * and fail SRV_CALL (see upper comment)
3865 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
3868 Calldown
->BestFinisher
= NULL
;
3870 /* Finish SRV_CALL construction */
3871 RxFinishSrvCallConstruction(Calldown
);
3879 RxFlushFcbInSystemCache(
3881 IN BOOLEAN SynchronizeWithLazyWriter
)
3883 IO_STATUS_BLOCK IoStatus
;
3888 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &IoStatus
);
3889 /* If we're asked to sync with LW, do it in case of success */
3890 if (SynchronizeWithLazyWriter
&& NT_SUCCESS(IoStatus
.Status
))
3892 RxAcquirePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
3893 RxReleasePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
3896 DPRINT("Flushing for FCB %p returns %lx\n", Fcb
, IoStatus
.Status
);
3897 return IoStatus
.Status
;
3909 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
3910 if (NodeType(Object
) == RDBSS_NTC_FOBX
|| NodeType(Object
) == RDBSS_NTC_SRVOPEN
)
3912 RxFreePoolWithTag(Object
, RX_FCB_POOLTAG
);
3914 /* If that's a FCB... */
3915 else if (NodeTypeIsFcb(Object
))
3918 PRDBSS_DEVICE_OBJECT DeviceObject
;
3921 DeviceObject
= Fcb
->RxDeviceObject
;
3923 /* Delete per stream contexts */
3924 FsRtlTeardownPerStreamContexts(&Fcb
->Header
);
3926 SetFlag(Fcb
->Header
.Flags
, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH
);
3928 /* If there was a non-paged FCB allocated, free it */
3929 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
3931 RxFreePoolWithTag(Fcb
->NonPaged
, RX_NONPAGEDFCB_POOLTAG
);
3937 /* Update statistics */
3938 InterlockedDecrement(&RxNumberOfActiveFcbs
);
3939 InterlockedDecrement((volatile long *)&DeviceObject
->NumberOfActiveFcbs
);
3952 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
3953 if (NodeType(pObject
) == RDBSS_NTC_SRVCALL
)
3956 PRDBSS_DEVICE_OBJECT DeviceObject
;
3958 SrvCall
= (PSRV_CALL
)pObject
;
3959 DeviceObject
= SrvCall
->RxDeviceObject
;
3960 if (DeviceObject
!= NULL
)
3962 if (!BooleanFlagOn(DeviceObject
->Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
3964 ASSERT(SrvCall
->Context
== NULL
);
3967 ASSERT(SrvCall
->Context2
== NULL
);
3969 SrvCall
->RxDeviceObject
= NULL
;
3972 else if (NodeType(pObject
) == RDBSS_NTC_NETROOT
)
3976 NetRoot
= (PNET_ROOT
)pObject
;
3977 NetRoot
->pSrvCall
= NULL
;
3978 NetRoot
->NodeTypeCode
= NodeType(pObject
) | 0xF000;
3981 /* And just free the object */
3982 RxFreePool(pObject
);
3989 RxGatherRequestsForSrvOpen(
3990 IN OUT PSRV_CALL SrvCall
,
3991 IN PSRV_OPEN SrvOpen
,
3992 IN OUT PLIST_ENTRY RequestsListHead
)
3995 LIST_ENTRY Discarded
, *Entry
;
3996 PCHANGE_BUFFERING_STATE_REQUEST Request
;
3998 /* Dispatch any pending operation first */
3999 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &Discarded
);
4001 /* Then, get any entry related to our key and SRV_OPEN */
4002 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
4003 Entry
= SrvCall
->BufferingManager
.HandlerList
.Flink
;
4004 while (Entry
!= &SrvCall
->BufferingManager
.HandlerList
)
4006 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4007 Entry
= Entry
->Flink
;
4008 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4010 RemoveEntryList(&Request
->ListEntry
);
4011 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4014 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
4016 /* Perform the same search in the last change list */
4017 Entry
= SrvCall
->BufferingManager
.LastChanceHandlerList
.Flink
;
4018 while (Entry
!= &SrvCall
->BufferingManager
.LastChanceHandlerList
)
4020 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4021 Entry
= Entry
->Flink
;
4022 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4024 RemoveEntryList(&Request
->ListEntry
);
4025 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4029 /* Discard the discarded requests */
4030 RxpDiscardChangeBufferingStateRequests(&Discarded
);
4036 PRDBSS_DEVICE_OBJECT
4037 RxGetDeviceObjectOfInstance(
4040 NODE_TYPE_CODE NodeType
;
4041 PRDBSS_DEVICE_OBJECT DeviceObject
;
4045 /* We only handle a few object types */
4046 NodeType
= NodeType(Instance
);
4047 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
4048 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) || (NodeType
== RDBSS_NTC_FOBX
));
4050 /* Get the device object depending on the object */
4053 case RDBSS_NTC_FOBX
:
4057 Fobx
= (PFOBX
)Instance
;
4058 DeviceObject
= Fobx
->RxDeviceObject
;
4062 case RDBSS_NTC_SRVCALL
:
4066 SrvCall
= (PSRV_CALL
)Instance
;
4067 DeviceObject
= SrvCall
->RxDeviceObject
;
4071 case RDBSS_NTC_NETROOT
:
4075 NetRoot
= (PNET_ROOT
)Instance
;
4076 DeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
4080 case RDBSS_NTC_V_NETROOT
:
4082 PV_NET_ROOT VNetRoot
;
4084 VNetRoot
= (PV_NET_ROOT
)Instance
;
4085 DeviceObject
= VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
;
4089 case RDBSS_NTC_SRVOPEN
:
4093 SrvOpen
= (PSRV_OPEN
)Instance
;
4094 DeviceObject
= ((PFCB
)SrvOpen
->pFcb
)->RxDeviceObject
;
4099 DeviceObject
= NULL
;
4104 return DeviceObject
;
4111 RxGetFileSizeWithLock(
4113 OUT PLONGLONG FileSize
)
4117 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
4128 return RxData
.OurProcess
;
4135 RxInitializeBufferingManager(
4138 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
4139 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
4140 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
4141 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
4142 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
4143 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
4144 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
4145 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
4146 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
4147 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
4149 return STATUS_SUCCESS
;
4157 RxInitializeContext(
4159 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
4160 IN ULONG InitialContextFlags
,
4161 IN OUT PRX_CONTEXT RxContext
)
4163 PIO_STACK_LOCATION Stack
;
4165 /* Initialize our various fields */
4166 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
4167 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
4168 RxContext
->ReferenceCount
= 1;
4169 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
4170 RxContext
->RxDeviceObject
= RxDeviceObject
;
4171 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
4172 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
4173 InitializeListHead(&RxContext
->BlockedOperations
);
4174 RxContext
->MRxCancelRoutine
= NULL
;
4175 RxContext
->ResumeRoutine
= NULL
;
4176 RxContext
->Flags
|= InitialContextFlags
;
4177 RxContext
->CurrentIrp
= Irp
;
4178 RxContext
->LastExecutionThread
= PsGetCurrentThread();
4179 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
4181 /* If've got no IRP, mark RX_CONTEXT */
4184 RxContext
->CurrentIrpSp
= NULL
;
4185 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
4186 RxContext
->MinorFunction
= 0;
4190 /* Otherwise, first determine whether we are performing async operation */
4191 Stack
= IoGetCurrentIrpStackLocation(Irp
);
4192 if (Stack
->FileObject
!= NULL
)
4196 Fcb
= Stack
->FileObject
->FsContext
;
4197 if (!IoIsOperationSynchronous(Irp
) ||
4198 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
4199 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
4200 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
4202 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4206 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
4208 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4210 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4212 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4215 /* Set proper flags if TopLevl IRP/Device */
4216 if (!RxIsThisTheTopLevelIrp(Irp
))
4218 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
4220 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
4222 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
4225 /* Copy stack information */
4226 RxContext
->MajorFunction
= Stack
->MajorFunction
;
4227 RxContext
->MinorFunction
= Stack
->MinorFunction
;
4228 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
4229 RxContext
->CurrentIrpSp
= Stack
;
4231 /* If we have a FO associated, learn for more */
4232 if (Stack
->FileObject
!= NULL
)
4237 /* Get the FCB and CCB (FOBX) */
4238 Fcb
= Stack
->FileObject
->FsContext
;
4239 Fobx
= Stack
->FileObject
->FsContext2
;
4240 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
4241 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
4243 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
4246 /* We have a FOBX, this not a DFS opening, keep track of it */
4247 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
4249 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
4250 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
4251 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4253 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
4258 RxContext
->pFobx
= NULL
;
4261 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4262 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
4265 PV_NET_ROOT VNetRoot
= NULL
;
4267 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4269 VNetRoot
= Fcb
->VNetRoot
;
4271 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
4273 VNetRoot
= (PV_NET_ROOT
)Fobx
;
4276 if (VNetRoot
!= NULL
)
4278 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
4282 /* Remember if that's a write through file */
4283 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
4284 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
4286 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
4291 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
4293 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4294 RxContext
, RxContext
->MinorFunction
, Irp
,
4295 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
4296 RxContext
->SerialNumber
);
4305 RxInitializeDispatcher(
4309 HANDLE ThreadHandle
;
4313 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4314 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4316 /* Set appropriate timeouts: 10s & 60s */
4317 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4318 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4319 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4320 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
4322 RxDispatcher
.NumberOfProcessors
= 1;
4323 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
4324 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
4326 /* Initialize our dispatchers */
4327 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
4328 if (!NT_SUCCESS(Status
))
4333 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
4334 if (!NT_SUCCESS(Status
))
4339 /* And start them */
4340 RxDispatcher
.State
= RxDispatcherActive
;
4341 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
4342 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
4343 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
4344 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
4345 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
4346 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
4347 if (NT_SUCCESS(Status
))
4349 ZwClose(ThreadHandle
);
4359 RxInitializeFcbTable(
4360 IN OUT PRX_FCB_TABLE FcbTable
,
4361 IN BOOLEAN CaseInsensitiveMatch
)
4367 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
4368 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
4370 ExInitializeResourceLite(&FcbTable
->TableLock
);
4371 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4372 FcbTable
->Version
= 0;
4373 FcbTable
->TableEntryForNull
= NULL
;
4375 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
4376 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
4378 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
4381 FcbTable
->Lookups
= 0;
4382 FcbTable
->FailedLookups
= 0;
4383 FcbTable
->Compares
= 0;
4391 RxInitializeLowIoContext(
4392 OUT PLOWIO_CONTEXT LowIoContext
,
4395 PRX_CONTEXT RxContext
;
4396 PIO_STACK_LOCATION Stack
;
4400 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
4401 ASSERT(LowIoContext
== &RxContext
->LowIoContext
);
4403 Stack
= RxContext
->CurrentIrpSp
;
4405 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
4406 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
4407 RxContext
->LowIoContext
.Operation
= Operation
;
4412 case LOWIO_OP_WRITE
:
4413 /* In case of RW, set a canary, to make sure these fields are properly set
4414 * they will be asserted when lowio request will be submit to mini-rdr
4417 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
4418 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
4419 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
4421 /* Keep track of paging IOs */
4422 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
4424 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
4428 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
4433 case LOWIO_OP_FSCTL
:
4434 case LOWIO_OP_IOCTL
:
4435 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4436 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
4437 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
4438 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
4439 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
4440 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
4441 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
4444 /* Nothing to do for these */
4445 case LOWIO_OP_SHAREDLOCK
:
4446 case LOWIO_OP_EXCLUSIVELOCK
:
4447 case LOWIO_OP_UNLOCK
:
4448 case LOWIO_OP_UNLOCK_MULTIPLE
:
4449 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4450 case LOWIO_OP_CLEAROUT
:
4454 /* Should never happen */
4464 RxInitializeLowIoPerFcbInfo(
4465 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
4469 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
4470 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
4477 RxInitializeMRxDispatcher(
4478 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
4482 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4483 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4485 return STATUS_SUCCESS
;
4492 RxInitializePrefixTable(
4493 IN OUT PRX_PREFIX_TABLE ThisTable
,
4494 IN ULONG TableSize OPTIONAL
,
4495 IN BOOLEAN CaseInsensitiveMatch
)
4501 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
4504 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
4505 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
4506 InitializeListHead(&ThisTable
->MemberQueue
);
4507 ThisTable
->Version
= 0;
4508 ThisTable
->TableEntryForNull
= NULL
;
4509 ThisTable
->IsNetNameTable
= FALSE
;
4510 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4511 ThisTable
->TableSize
= TableSize
;
4517 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
4519 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
4528 RxInitializePurgeSyncronizationContext(
4529 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
4533 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
4534 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
4538 RxInitializeSrvCallParameters(
4539 IN PRX_CONTEXT RxContext
,
4540 IN OUT PSRV_CALL SrvCall
)
4544 SrvCall
->pPrincipalName
= NULL
;
4546 /* We only have stuff to initialize for file opening from DFS */
4547 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
4549 return STATUS_SUCCESS
;
4552 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
4555 return STATUS_NOT_IMPLEMENTED
;
4563 RxInitializeRxTimer(
4568 RxTimerInterval
.QuadPart
= -550000;
4569 KeInitializeSpinLock(&RxTimerLock
);
4570 InitializeListHead(&RxTimerQueueHead
);
4571 InitializeListHead(&RxRecurrentWorkItemsList
);
4572 KeInitializeDpc(&RxTimerDpc
, RxTimerDispatch
, NULL
);
4573 KeInitializeTimer(&RxTimer
);
4574 RxTimerTickCount
= 0;
4576 return STATUS_SUCCESS
;
4580 RxInitializeVNetRootParameters(
4581 PRX_CONTEXT RxContext
,
4583 OUT PULONG SessionId
,
4584 OUT PUNICODE_STRING
*UserNamePtr
,
4585 OUT PUNICODE_STRING
*UserDomainNamePtr
,
4586 OUT PUNICODE_STRING
*PasswordPtr
,
4590 PACCESS_TOKEN Token
;
4594 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
4595 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
4597 *UserNamePtr
= NULL
;
4598 *UserDomainNamePtr
= NULL
;
4599 *PasswordPtr
= NULL
;
4600 /* By default, that's not CSC instance */
4601 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4603 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
4604 if (SeTokenIsRestricted(Token
))
4606 return STATUS_ACCESS_DENIED
;
4610 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
4611 if (!NT_SUCCESS(Status
))
4617 Status
= SeQuerySessionIdToken(Token
, SessionId
);
4618 if (!NT_SUCCESS(Status
))
4623 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
4626 Status
= STATUS_NOT_IMPLEMENTED
;
4630 /* Deal with connection credentials */
4631 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
4634 Status
= STATUS_NOT_IMPLEMENTED
;
4638 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
4641 Status
= STATUS_NOT_IMPLEMENTED
;
4646 if (NT_SUCCESS(Status
))
4648 /* If that's a CSC instance, mark it as such */
4649 if (RxIsThisACscAgentOpen(RxContext
))
4651 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4663 RxInitializeWorkQueue(
4664 PRX_WORK_QUEUE WorkQueue
,
4665 WORK_QUEUE_TYPE WorkQueueType
,
4666 ULONG MaximumNumberOfWorkerThreads
,
4667 ULONG MinimumNumberOfWorkerThreads
)
4671 WorkQueue
->Type
= WorkQueueType
;
4672 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
4673 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
4675 WorkQueue
->State
= RxWorkQueueActive
;
4676 WorkQueue
->SpinUpRequestPending
= FALSE
;
4677 WorkQueue
->pRundownContext
= NULL
;
4678 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
4679 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
4680 WorkQueue
->CumulativeQueueLength
= 0;
4681 WorkQueue
->NumberOfSpinUpRequests
= 0;
4682 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
4683 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
4684 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
4685 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
4686 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
4687 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
4688 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
4689 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
4690 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
4691 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
4692 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
4693 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
4694 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
4695 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
4696 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
4697 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
4699 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
4700 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
4707 RxInitializeWorkQueueDispatcher(
4708 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
4711 ULONG MaximumNumberOfWorkerThreads
;
4715 /* Number of threads will depend on system capacity */
4716 if (MmQuerySystemSize() != MmLargeSystem
)
4718 MaximumNumberOfWorkerThreads
= 5;
4722 MaximumNumberOfWorkerThreads
= 10;
4725 /* Initialize the work queues */
4726 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
4727 MaximumNumberOfWorkerThreads
, 1);
4728 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
4729 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
4731 /* And start the worker threads */
4732 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
4733 RxBootstrapWorkerThreadDispatcher
,
4734 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
4735 if (!NT_SUCCESS(Status
))
4740 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
4741 RxBootstrapWorkerThreadDispatcher
,
4742 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
4743 if (!NT_SUCCESS(Status
))
4748 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
4749 RxBootstrapWorkerThreadDispatcher
,
4750 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
4758 RxInitiateSrvOpenKeyAssociation(
4759 IN OUT PSRV_OPEN SrvOpen
)
4761 PRX_BUFFERING_MANAGER BufferingManager
;
4765 SrvOpen
->Key
= NULL
;
4767 /* Just keep track of the opening request */
4768 BufferingManager
= &((PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
;
4769 InterlockedIncrement(&BufferingManager
->NumberOfOutstandingOpens
);
4771 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
4778 RxInsertWorkQueueItem(
4779 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
4780 WORK_QUEUE_TYPE WorkQueueType
,
4781 PRX_WORK_QUEUE_ITEM WorkQueueItem
)
4785 BOOLEAN SpinUpThreads
;
4786 PRX_WORK_QUEUE WorkQueue
;
4788 /* No dispatcher, nothing to insert */
4789 if (RxDispatcher
.State
!= RxDispatcherActive
)
4791 return STATUS_UNSUCCESSFUL
;
4794 /* Get the work queue */
4795 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
4797 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
4798 /* Only insert if the work queue is in decent state */
4799 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
4801 Status
= STATUS_UNSUCCESSFUL
;
4805 SpinUpThreads
= FALSE
;
4806 WorkQueueItem
->pDeviceObject
= pMRxDeviceObject
;
4807 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
4808 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
4809 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
4811 /* If required (and possible!), spin up a new worker thread */
4812 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
4813 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
4814 !WorkQueue
->SpinUpRequestPending
)
4816 WorkQueue
->SpinUpRequestPending
= TRUE
;
4817 SpinUpThreads
= TRUE
;
4820 Status
= STATUS_SUCCESS
;
4822 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
4824 /* If we failed, return and still not insert item */
4825 if (!NT_SUCCESS(Status
))
4830 /* All fine, insert the item */
4831 KeInsertQueue(&WorkQueue
->Queue
, &WorkQueueItem
->List
);
4833 /* And start a new worker thread if needed */
4836 RxSpinUpWorkerThreads(WorkQueue
);
4843 RxIsThisACscAgentOpen(
4844 IN PRX_CONTEXT RxContext
)
4850 /* Client Side Caching is DFS stuff - we don't support it */
4851 if (RxContext
->Create
.EaLength
!= 0)
4856 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
4857 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
4867 IN PRX_CONTEXT RxContext
,
4868 IN LOCK_OPERATION Operation
,
4869 IN ULONG BufferLength
)
4878 Irp
= RxContext
->CurrentIrp
;
4879 /* If we already have a MDL, make sure it's locked */
4880 if (Irp
->MdlAddress
!= NULL
)
4882 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
4886 /* That likely means the driver asks for buffered IOs - we don't support it! */
4887 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
4889 /* If we have a real length */
4890 if (BufferLength
> 0)
4892 /* Allocate a MDL and lock it */
4893 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
4896 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
4897 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
4900 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
4904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4908 Status
= _SEH2_GetExceptionCode();
4910 /* Free the possible MDL we have allocated */
4912 Irp
->MdlAddress
= NULL
;
4914 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
4917 if (!FsRtlIsNtstatusExpected(Status
))
4919 Status
= STATUS_INVALID_USER_BUFFER
;
4922 RxContext
->IoStatusBlock
.Status
= Status
;
4923 ExRaiseStatus(Status
);
4932 RxLowIoCompletionTail(
4933 IN PRX_CONTEXT RxContext
)
4940 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
4942 /* Only continue if we're at APC_LEVEL or lower */
4943 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
&&
4944 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
4946 return STATUS_MORE_PROCESSING_REQUIRED
;
4949 /* Call the completion routine */
4950 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
4951 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
4952 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
4957 /* If it was a RW operation, for a paging file ... */
4958 Operation
= RxContext
->LowIoContext
.Operation
;
4959 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
4961 /* Remove ourselves from the list and resume operations */
4962 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
4964 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
4965 RemoveEntryList(&RxContext
->RxContextSerializationQLinks
);
4966 RxContext
->RxContextSerializationQLinks
.Flink
= NULL
;
4967 RxContext
->RxContextSerializationQLinks
.Blink
= NULL
;
4968 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
4969 RxResumeBlockedOperations_ALL(RxContext
);
4974 /* Sanity check: we had known operation */
4975 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
4978 /* If not sync operation, complete now. Otherwise, caller has already completed */
4979 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
4981 RxCompleteRequest(RxContext
, Status
);
4984 DPRINT("Status: %x\n", Status
);
4993 RxLowIoPopulateFsctlInfo(
4994 IN PRX_CONTEXT RxContext
)
4999 PIO_STACK_LOCATION Stack
;
5003 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
5005 Irp
= RxContext
->CurrentIrp
;
5006 Stack
= RxContext
->CurrentIrpSp
;
5008 /* Copy stack parameters */
5009 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
5010 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
5011 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
5012 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
5013 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
5015 /* Same buffer in case of buffered */
5016 if (Method
== METHOD_BUFFERED
)
5018 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5019 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5021 return STATUS_SUCCESS
;
5024 /* Two buffers for neither */
5025 if (Method
== METHOD_NEITHER
)
5027 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
5028 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
5030 return STATUS_SUCCESS
;
5033 /* Only IN/OUT remain */
5034 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
5036 /* Use system buffer for input */
5037 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5038 /* And MDL for output */
5039 Mdl
= Irp
->MdlAddress
;
5042 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
5043 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
5045 return STATUS_INSUFFICIENT_RESOURCES
;
5050 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
5053 return STATUS_SUCCESS
;
5059 IN PRX_CONTEXT RxContext
,
5060 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
5064 BOOLEAN Synchronous
;
5065 PLOWIO_CONTEXT LowIoContext
;
5067 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
5071 LowIoContext
= &RxContext
->LowIoContext
;
5072 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
5074 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
5076 Status
= STATUS_SUCCESS
;
5077 Operation
= LowIoContext
->Operation
;
5081 case LOWIO_OP_WRITE
:
5082 /* Check that the parameters were properly set by caller
5083 * See comment in RxInitializeLowIoContext()
5085 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
5086 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
5088 /* Lock the buffer */
5089 RxLockUserBuffer(RxContext
,
5090 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
5091 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
5092 if (RxNewMapUserBuffer(RxContext
) == NULL
)
5094 return STATUS_INSUFFICIENT_RESOURCES
;
5096 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
5098 /* If that's a paging IO, initialize serial operation */
5099 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5103 Fcb
= (PFCB
)RxContext
->pFcb
;
5105 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5106 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
5107 if (Operation
== LOWIO_OP_READ
)
5109 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5113 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5116 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5121 case LOWIO_OP_FSCTL
:
5122 case LOWIO_OP_IOCTL
:
5123 /* Set FSCTL/IOCTL parameters */
5124 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
5125 /* Check whether we're consistent: a length means a buffer */
5126 if (NT_SUCCESS(Status
))
5128 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
5129 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
5130 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
5131 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
5133 Status
= STATUS_INVALID_PARAMETER
;
5139 case LOWIO_OP_SHAREDLOCK
:
5140 case LOWIO_OP_EXCLUSIVELOCK
:
5141 case LOWIO_OP_UNLOCK
:
5142 case LOWIO_OP_UNLOCK_MULTIPLE
:
5143 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
5144 case LOWIO_OP_CLEAROUT
:
5149 Status
= STATUS_INVALID_PARAMETER
;
5153 /* No need to perform extra init in case of posting */
5154 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
5156 /* Preflight checks were OK, time to submit */
5157 if (NT_SUCCESS(Status
))
5159 PMINIRDR_DISPATCH Dispatch
;
5163 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
5164 /* If not synchronous, we're likely to return before the operation is finished */
5165 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5167 IoMarkIrpPending(RxContext
->CurrentIrp
);
5171 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
5172 if (Dispatch
!= NULL
)
5174 /* We'll try to execute until the mini-rdr doesn't return pending */
5177 RxContext
->IoStatusBlock
.Information
= 0;
5179 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
5180 if (Status
== STATUS_PENDING
)
5182 /* Unless it's not synchronous, caller will be happy with pending op */
5188 RxWaitSync(RxContext
);
5189 Status
= RxContext
->IoStatusBlock
.Status
;
5195 /* We had marked the IRP pending, whereas the operation finished, drop that */
5196 if (Status
!= STATUS_RETRY
)
5198 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5200 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
5203 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
5207 } while (Status
== STATUS_PENDING
);
5211 Status
= STATUS_INVALID_PARAMETER
;
5215 /* Call completion and return */
5216 RxContext
->IoStatusBlock
.Status
= Status
;
5217 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
5218 return RxLowIoCompletionTail(RxContext
);
5226 IN PRX_CONTEXT RxContext
)
5232 Irp
= RxContext
->CurrentIrp
;
5233 /* We should have a MDL (buffered IOs are not supported!) */
5234 if (Irp
->MdlAddress
!= NULL
)
5237 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5240 /* Just return system buffer */
5241 return Irp
->AssociatedIrp
.SystemBuffer
;
5248 RxMarkFobxOnCleanup(
5253 PFOBX ScavengerFobx
;
5254 LARGE_INTEGER TickCount
;
5255 PRDBSS_SCAVENGER Scavenger
;
5259 /* No FOBX, nothing to mark */
5265 /* Query time for close */
5266 KeQueryTickCount(&TickCount
);
5268 Fcb
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
5269 ASSERT(NodeTypeIsFcb(Fcb
));
5271 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5272 RxAcquireScavengerMutex();
5274 ScavengerFobx
= NULL
;
5275 /* If that's not a file, or even not a disk resource, just mark as dormant */
5276 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
|| Fcb
->VNetRoot
->pNetRoot
->DeviceType
!= FILE_DEVICE_DISK
)
5278 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5279 InitializeListHead(&pFobx
->ClosePendingList
);
5280 ++Scavenger
->NumberOfDormantFiles
;
5284 ASSERT(Scavenger
->NumberOfDormantFiles
>= 0);
5285 /* If we're about to reach the maximum dormant of FOBX */
5286 if (Scavenger
->NumberOfDormantFiles
>= Scavenger
->MaximumNumberOfDormantFiles
)
5288 /* This should never be wrong... */
5289 if (!IsListEmpty(&Scavenger
->ClosePendingFobxsList
))
5291 /* Then, take the first from the list (oldest) and save it for later purge */
5292 ScavengerFobx
= CONTAINING_RECORD(Scavenger
->ClosePendingFobxsList
.Flink
, FOBX
, ClosePendingList
);
5293 if (ScavengerFobx
->pSrvOpen
!= NULL
&& ScavengerFobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
5296 ScavengerFobx
= NULL
;
5300 RxReferenceNetFobx(ScavengerFobx
);
5305 /* Mark ourselves as dormant */
5306 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5307 pFobx
->CloseTime
.QuadPart
= TickCount
.QuadPart
;
5309 /* And insert us in the list of dormant files */
5310 InsertTailList(&Scavenger
->ClosePendingFobxsList
, &pFobx
->ClosePendingList
);
5311 /* If scavenger was inactive, start it */
5312 if (Scavenger
->NumberOfDormantFiles
++ == 0 && Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
5314 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
5315 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
, RxScavengerTimerRoutine
,
5316 Fcb
->RxDeviceObject
, Scavenger
->TimeLimit
);
5320 RxReleaseScavengerMutex();
5322 /* If we had reached max */
5323 if (ScavengerFobx
!= NULL
)
5327 /* Purge the oldest FOBX */
5328 Status
= RxPurgeFobxFromCache(ScavengerFobx
);
5329 if (Status
!= STATUS_SUCCESS
)
5344 PRDBSS_SCAVENGER Scavenger
;
5348 /* No FOBX, nothing to mark */
5354 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5355 ASSERT(NodeTypeIsFcb(Fcb
));
5357 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5359 RxAcquireScavengerMutex();
5360 /* Only mark it if it was already marked as dormant */
5361 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
))
5363 /* If FCB wasn't already decrement, do it now */
5364 if (!Fobx
->fOpenCountDecremented
)
5366 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5367 ASSERT(NodeTypeIsFcb(Fcb
));
5368 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
5370 Fobx
->fOpenCountDecremented
= TRUE
;
5373 /* We're no longer dormant */
5374 InterlockedDecrement(&Scavenger
->NumberOfDormantFiles
);
5375 ClearFlag(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5378 /* If we were inserted in the scavenger, drop ourselves out */
5379 if (!IsListEmpty(&Fobx
->ClosePendingList
))
5381 RemoveEntryList(&Fobx
->ClosePendingList
);
5382 InitializeListHead(&Fobx
->ClosePendingList
);
5385 RxReleaseScavengerMutex();
5393 PRX_CONTEXT RxContext
)
5399 Irp
= RxContext
->CurrentIrp
;
5400 if (Irp
->MdlAddress
!= NULL
)
5402 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5405 return Irp
->UserBuffer
;
5435 IN PV_NET_ROOT ThisVNetRoot
)
5444 RxpAcquirePrefixTableLockShared(
5445 PRX_PREFIX_TABLE pTable
,
5447 BOOLEAN ProcessBufferingStateChangeRequests
)
5451 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5452 pTable
->TableLock
.ActiveEntries
);
5454 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
5461 RxpAcquirePrefixTableLockExclusive(
5462 PRX_PREFIX_TABLE pTable
,
5464 BOOLEAN ProcessBufferingStateChangeRequests
)
5468 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5469 pTable
->TableLock
.ActiveEntries
);
5471 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
5478 RxpDereferenceAndFinalizeNetFcb(
5480 IN PRX_CONTEXT RxContext
,
5481 IN BOOLEAN RecursiveFinalize
,
5482 IN BOOLEAN ForceFinalize
)
5487 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
5491 ASSERT(!ForceFinalize
);
5492 ASSERT(NodeTypeIsFcb(ThisFcb
));
5493 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
5495 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5496 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
5497 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
5503 Status
= STATUS_SUCCESS
;
5504 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
5505 ResourceAcquired
= FALSE
;
5506 NetRootReferenced
= FALSE
;
5507 /* If FCB isn't orphaned, it still have context attached */
5508 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
5510 /* Don't let NetRoot go away before we're done */
5511 RxReferenceNetRoot(NetRoot
);
5512 NetRootReferenced
= TRUE
;
5514 /* Try to acquire the table lock exclusively */
5515 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
5517 RxReferenceNetFcb(ThisFcb
);
5519 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
5521 if (RxContext
!= NULL
&& RxContext
!= (PVOID
)-1 && RxContext
!= (PVOID
)-2)
5523 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
5526 RxReleaseFcb(RxContext
, ThisFcb
);
5528 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5530 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
5533 References
= RxDereferenceNetFcb(ThisFcb
);
5535 ResourceAcquired
= TRUE
;
5539 /* If locking was OK (or not needed!), attempt finalization */
5540 if (Status
== STATUS_SUCCESS
)
5542 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
5545 /* Release table lock if acquired */
5546 if (ResourceAcquired
)
5548 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
5551 /* We don't need the NetRoot anylonger */
5552 if (NetRootReferenced
)
5554 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
5564 RxpDereferenceNetFcb(
5571 ASSERT(NodeTypeIsFcb(Fcb
));
5573 NewCount
= InterlockedDecrement((volatile long *)&Fcb
->NodeReferenceCount
);
5574 ASSERT(NewCount
>= 0);
5576 PRINT_REF_COUNT(NETFCB
, NewCount
);
5591 BOOLEAN ForceFinalize
;
5592 PRX_PREFIX_TABLE PrefixTable
;
5594 SrvCall
= (PSRV_CALL
)Context
;
5595 /* At this step, RxFinalizeSrvCall already cleaned some fields */
5596 ASSERT(SrvCall
->UpperFinalizationDone
);
5598 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
5599 /* Were we called with ForceFinalize? */
5600 ForceFinalize
= BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
5602 /* Notify mini-rdr */
5603 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
,
5604 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)SrvCall
,
5608 /* Dereference our extra reference (set before queueing) */
5609 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
5610 InterlockedDecrement((volatile long *)&SrvCall
->NodeReferenceCount
);
5611 /* And finalize for real, with the right context */
5612 RxFinalizeSrvCall(SrvCall
, FALSE
, ForceFinalize
);
5613 RxReleasePrefixTableLock(PrefixTable
);
5620 RxpDiscardChangeBufferingStateRequests(
5621 _Inout_ PLIST_ENTRY DiscardedRequests
)
5627 /* No requests to discard */
5628 if (IsListEmpty(DiscardedRequests
))
5633 /* Free all the discarded requests */
5634 Entry
= DiscardedRequests
->Flink
;
5635 while (Entry
!= DiscardedRequests
)
5637 PCHANGE_BUFFERING_STATE_REQUEST Request
;
5639 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
5640 Entry
= Entry
->Flink
;
5642 DPRINT("Req %p for %p (%p) discarded\n", Request
, Request
->SrvOpenKey
, Request
->SrvOpen
);
5644 RxPrepareRequestForReuse(Request
);
5645 RxFreePool(Request
);
5653 RxpDispatchChangeBufferingStateRequests(
5656 PLIST_ENTRY DiscardedRequests
)
5660 BOOLEAN StartDispatcher
;
5661 LIST_ENTRY AcceptedReqs
;
5662 LIST_ENTRY DispatcherList
;
5663 PRX_BUFFERING_MANAGER BufferingManager
;
5665 /* Initialize our lists */
5666 InitializeListHead(&AcceptedReqs
);
5667 InitializeListHead(DiscardedRequests
);
5669 /* Transfer the requests to dispatch locally */
5670 BufferingManager
= &SrvCall
->BufferingManager
;
5671 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
5672 RxTransferList(&DispatcherList
, &BufferingManager
->DispatcherList
);
5673 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
5675 /* If there were requests */
5676 if (!IsListEmpty(&DispatcherList
))
5680 /* For each of the entries... */
5681 Entry
= DispatcherList
.Flink
;
5682 while (Entry
!= &DispatcherList
)
5684 PCHANGE_BUFFERING_STATE_REQUEST Request
;
5686 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
5687 Entry
= Entry
->Flink
;
5689 /* If we have been provided a SRV_OPEN, see whether it matches */
5690 if (SrvOpen
!= NULL
)
5692 /* Match, the request is accepted */
5693 if (Request
->SrvOpenKey
== SrvOpen
->Key
)
5695 Request
->SrvOpen
= SrvOpen
;
5696 RxReferenceSrvOpen(SrvOpen
);
5698 RemoveEntryList(&Request
->ListEntry
);
5699 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
5701 /* Move to the next entry */
5706 Status
= STATUS_PENDING
;
5711 /* No SRV_OPEN provided, try to find one */
5712 Status
= RxpLookupSrvOpenForRequestLite(SrvCall
, Request
);
5715 /* We found a matching SRV_OPEN, accept the request */
5716 if (Status
== STATUS_SUCCESS
)
5718 RemoveEntryList(&Request
->ListEntry
);
5719 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
5721 /* Another run might help handling it, don't discard it */
5722 else if (Status
== STATUS_PENDING
)
5726 /* Otherwise, discard the request */
5729 ASSERT(Status
== STATUS_NOT_FOUND
);
5731 RemoveEntryList(&Request
->ListEntry
);
5732 InsertTailList(DiscardedRequests
, &Request
->ListEntry
);
5737 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
5738 /* Nothing to dispatch, no need to start dispatcher */
5739 if (IsListEmpty(&DispatcherList
))
5741 StartDispatcher
= FALSE
;
5745 /* Transfer back the list of the not treated entries to the buffering manager */
5746 RxTransferList(&BufferingManager
->DispatcherList
, &DispatcherList
);
5747 StartDispatcher
= (BufferingManager
->DispatcherActive
== FALSE
);
5748 /* If the dispatcher isn't active, start it */
5749 if (StartDispatcher
)
5751 BufferingManager
->DispatcherActive
= TRUE
;
5755 /* If there were accepted requests, move them to the buffering manager */
5756 if (!IsListEmpty(&AcceptedReqs
))
5758 RxTransferList(&BufferingManager
->HandlerList
, &AcceptedReqs
);
5760 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
5762 /* If we're to start the dispatcher, do it */
5763 if (StartDispatcher
)
5765 RxReferenceSrvCall(SrvCall
);
5766 DPRINT("Starting dispatcher\n");
5767 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
5768 &BufferingManager
->DispatcherWorkItem
,
5769 RxDispatchChangeBufferingStateRequests
, SrvCall
);
5777 RxpLookupSrvOpenForRequestLite(
5778 IN PSRV_CALL SrvCall
,
5779 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request
)
5787 Status
= STATUS_SUCCESS
;
5788 /* Browse all our associated SRV_OPENs to find the one! */
5789 for (Entry
= SrvCall
->BufferingManager
.SrvOpenLists
[0].Flink
;
5790 Entry
!= &SrvCall
->BufferingManager
.SrvOpenLists
[0];
5791 Entry
= Entry
->Flink
)
5793 /* Same key, not orphaned, this is ours */
5794 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenKeyList
);
5795 if (SrvOpen
->Key
== Request
->SrvOpenKey
)
5797 if (!BooleanFlagOn(SrvOpen
->pFcb
->FcbState
, FCB_STATE_ORPHANED
))
5799 RxReferenceSrvOpen(SrvOpen
);
5805 /* We didn't manage to find a SRV_OPEN */
5806 if (Entry
== &SrvCall
->BufferingManager
.SrvOpenLists
[0])
5810 /* The coming open might help, mark as pending for later retry */
5811 if (SrvCall
->BufferingManager
.NumberOfOutstandingOpens
!= 0)
5813 Status
= STATUS_PENDING
;
5815 /* Else, it's a complete failure */
5818 Status
= STATUS_NOT_FOUND
;
5822 /* Return the (not) found SRV_OPEN */
5823 Request
->SrvOpen
= SrvOpen
;
5832 RxpMarkInstanceForScavengedFinalization(
5835 NODE_TYPE_CODE NodeType
;
5836 PNODE_TYPE_AND_SIZE Node
;
5837 PRDBSS_SCAVENGER Scavenger
;
5838 PRDBSS_DEVICE_OBJECT DeviceObject
;
5839 PLIST_ENTRY ScavengerHead
, InstEntry
;
5843 /* If still referenced, don't mark it (broken caller) */
5844 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
5845 if (Node
->NodeReferenceCount
> 1)
5850 DeviceObject
= RxGetDeviceObjectOfInstance(Instance
);
5851 Scavenger
= DeviceObject
->pRdbssScavenger
;
5854 NodeType
= NodeType(Instance
);
5855 SetFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
5856 DPRINT("Node %p has now the scavenger mark!\n", Instance
);
5858 /* Increase the count in the scavenger, and queue it */
5859 ScavengerHead
= NULL
;
5862 case RDBSS_NTC_FOBX
:
5863 ++Scavenger
->FobxsToBeFinalized
;
5864 ScavengerHead
= &Scavenger
->FobxFinalizationList
;
5865 InstEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
5868 case RDBSS_NTC_SRVCALL
:
5869 ++Scavenger
->SrvCallsToBeFinalized
;
5870 ScavengerHead
= &Scavenger
->SrvCallFinalizationList
;
5871 InstEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
5874 case RDBSS_NTC_NETROOT
:
5875 ++Scavenger
->NetRootsToBeFinalized
;
5876 ScavengerHead
= &Scavenger
->NetRootFinalizationList
;
5877 InstEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
5880 case RDBSS_NTC_V_NETROOT
:
5881 ++Scavenger
->VNetRootsToBeFinalized
;
5882 ScavengerHead
= &Scavenger
->VNetRootFinalizationList
;
5883 InstEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
5886 case RDBSS_NTC_SRVOPEN
:
5887 ++Scavenger
->SrvOpensToBeFinalized
;
5888 ScavengerHead
= &Scavenger
->SrvOpenFinalizationList
;
5889 InstEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
5893 /* Extra ref for scavenger */
5894 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
5896 /* If matching type */
5897 if (ScavengerHead
!= NULL
)
5899 /* Insert in the scavenger list */
5900 InsertTailList(ScavengerHead
, InstEntry
);
5902 /* And if it wasn't started, start it */
5903 if (Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
5905 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
5906 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
5907 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
5917 RxPostOneShotTimerRequest(
5918 IN PRDBSS_DEVICE_OBJECT pDeviceObject
,
5919 IN PRX_WORK_ITEM pWorkItem
,
5920 IN PRX_WORKERTHREAD_ROUTINE Routine
,
5922 IN LARGE_INTEGER TimeInterval
)
5926 ASSERT(pWorkItem
!= NULL
);
5928 /* Prepare the work item */
5929 ExInitializeWorkItem(&pWorkItem
->WorkQueueItem
, Routine
, pContext
);
5930 pWorkItem
->WorkQueueItem
.pDeviceObject
= pDeviceObject
;
5932 /* Last tick can be computed with the number of times it was caller (timertickcount)
5933 * and the interval between calls
5935 KeAcquireSpinLock(&RxTimerLock
, &OldIrql
);
5936 pWorkItem
->LastTick
= (TimeInterval
.QuadPart
/ 550000) + RxTimerTickCount
+ 1;
5937 /* Insert in work queue */
5938 InsertTailList(&RxTimerQueueHead
, &pWorkItem
->WorkQueueItem
.List
);
5939 KeReleaseSpinLock(&RxTimerLock
, OldIrql
);
5941 /* If there are queued events, queue an execution */
5942 if (IsListEmpty(&RxTimerQueueHead
))
5944 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
5947 return STATUS_SUCCESS
;
5955 RxPostToWorkerThread(
5956 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
5957 _In_ WORK_QUEUE_TYPE WorkQueueType
,
5958 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem
,
5959 _In_ PRX_WORKERTHREAD_ROUTINE Routine
,
5960 _In_ PVOID pContext
)
5962 /* Initialize work queue item */
5963 pWorkQueueItem
->List
.Flink
= NULL
;
5964 pWorkQueueItem
->WorkerRoutine
= Routine
;
5965 pWorkQueueItem
->Parameter
= pContext
;
5967 /* And insert it in the work queue */
5968 return RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, pWorkQueueItem
);
5972 RxpProcessChangeBufferingStateRequests(
5974 BOOLEAN UpdateHandlerState
)
5983 RxPrefixTableInsertName(
5984 IN OUT PRX_PREFIX_TABLE ThisTable
,
5985 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
5987 IN PULONG ContainerRefCount
,
5988 IN USHORT CaseInsensitiveLength
,
5989 IN PRX_CONNECTION_ID ConnectionId
5994 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
5996 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
5997 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
5999 /* Copy parameters and compute hash */
6000 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
6001 ThisEntry
->ContainingRecord
= Container
;
6002 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
6003 InterlockedIncrement((volatile long *)ContainerRefCount
);
6004 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
6005 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
6007 /* If no path length: this is entry for null path */
6008 if (ThisEntry
->Prefix
.Length
== 0)
6010 ThisTable
->TableEntryForNull
= ThisEntry
;
6012 /* Otherwise, insert in the appropriate bucket */
6015 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
6018 /* If we had a connection ID, keep track of it */
6019 if (ConnectionId
!= NULL
)
6021 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
6025 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
6026 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
6029 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
6030 /* Reflect the changes */
6031 ++ThisTable
->Version
;
6033 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
6042 RxPrefixTableLookupName(
6043 IN PRX_PREFIX_TABLE ThisTable
,
6044 IN PUNICODE_STRING CanonicalName
,
6045 OUT PUNICODE_STRING RemainingName
,
6046 IN PRX_CONNECTION_ID ConnectionId
)
6052 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
6053 ASSERT(CanonicalName
->Length
> 0);
6055 /* Call the internal helper */
6056 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
6057 if (Container
== NULL
)
6062 /* Reference our container before returning it */
6063 if (RdbssReferenceTracingValue
!= 0)
6065 NODE_TYPE_CODE Type
;
6067 Type
= NodeType(Container
);
6070 case RDBSS_NTC_SRVCALL
:
6071 RxReferenceSrvCall(Container
);
6074 case RDBSS_NTC_NETROOT
:
6075 RxReferenceNetRoot(Container
);
6078 case RDBSS_NTC_V_NETROOT
:
6079 RxReferenceVNetRoot(Container
);
6089 RxReference(Container
);
6106 ASSERT(NodeTypeIsFcb(Fcb
));
6108 NewCount
= InterlockedIncrement((volatile long *)&Fcb
->NodeReferenceCount
);
6110 PRINT_REF_COUNT(NETFCB
, Fcb
->NodeReferenceCount
);
6119 RxpReleasePrefixTableLock(
6120 PRX_PREFIX_TABLE pTable
,
6121 BOOLEAN ProcessBufferingStateChangeRequests
)
6125 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
6126 pTable
->TableLock
.ActiveEntries
);
6128 ExReleaseResourceLite(&pTable
->TableLock
);
6136 RxPrepareContextForReuse(
6137 IN OUT PRX_CONTEXT RxContext
)
6141 /* When we reach that point, make sure mandatory parts are null-ed */
6142 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
6144 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
6145 RxContext
->Create
.RdrFlags
= 0;
6147 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
6149 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
6150 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
6153 RxContext
->ReferenceCount
= 0;
6160 RxPrepareRequestForReuse(
6161 PCHANGE_BUFFERING_STATE_REQUEST Request
)
6167 SrvOpen
= Request
->SrvOpen
;
6169 /* If the request was already prepared for service */
6170 if (BooleanFlagOn(Request
->Flags
, RX_REQUEST_PREPARED_FOR_HANDLING
))
6172 /* We have to dereference the associated SRV_OPEN depending on the lock */
6173 if (RxIsFcbAcquiredExclusive(SrvOpen
->pFcb
))
6175 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
6179 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6182 /* Otherwise, just dereference */
6183 else if (SrvOpen
!= NULL
)
6185 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6188 Request
->SrvOpen
= NULL
;
6196 RxProcessChangeBufferingStateRequests(
6199 /* Call internal routine */
6200 RxUndoScavengerFinalizationMarking(SrvCall
);
6201 RxpProcessChangeBufferingStateRequests(SrvCall
, TRUE
);
6208 RxProcessChangeBufferingStateRequestsForSrvOpen(
6211 LONG NumberOfBufferingChangeRequests
, LockedOldBufferingToken
, OldBufferingToken
;
6213 /* Get the current number of change requests */
6214 NumberOfBufferingChangeRequests
= ((PSRV_CALL
)SrvOpen
->pVNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
.CumulativeNumberOfBufferingChangeRequests
;
6215 /* Get our old token */
6216 OldBufferingToken
= SrvOpen
->BufferingToken
;
6217 LockedOldBufferingToken
= InterlockedCompareExchange(&SrvOpen
->BufferingToken
,
6218 NumberOfBufferingChangeRequests
,
6219 NumberOfBufferingChangeRequests
);
6220 /* If buffering state changed in between, process changes */
6221 if (OldBufferingToken
!= LockedOldBufferingToken
)
6226 /* Acquire the FCB and start processing */
6227 Fcb
= (PFCB
)SrvOpen
->pFcb
;
6228 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
6229 if (Status
== STATUS_SUCCESS
)
6231 RxProcessFcbChangeBufferingStateRequest(Fcb
);
6232 RxReleaseFcb(NULL
, Fcb
);
6238 RxProcessFcbChangeBufferingStateRequest(
6245 RxpTrackDereference(
6246 _In_ ULONG TraceType
,
6247 _In_ PCSTR FileName
,
6249 _In_ PVOID Instance
)
6253 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6264 _In_ ULONG TraceType
,
6265 _In_ PCSTR FileName
,
6267 _In_ PVOID Instance
)
6269 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6281 RxpUndoScavengerFinalizationMarking(
6284 PLIST_ENTRY ListEntry
;
6285 PNODE_TYPE_AND_SIZE Node
;
6286 PRDBSS_SCAVENGER Scavenger
;
6290 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6291 /* There's no marking - nothing to do */
6292 if (!BooleanFlagOn(NodeType(Node
), RX_SCAVENGER_MASK
))
6297 /* First of all, remove the mark */
6298 ClearFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6299 DPRINT("Node %p no longer has the scavenger mark\n");
6301 /* And now, remove from the scavenger */
6302 Scavenger
= RxGetDeviceObjectOfInstance(Instance
)->pRdbssScavenger
;
6303 switch (NodeType(Node
))
6305 case RDBSS_NTC_FOBX
:
6306 --Scavenger
->FobxsToBeFinalized
;
6307 ListEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6310 case RDBSS_NTC_SRVCALL
:
6311 --Scavenger
->SrvCallsToBeFinalized
;
6312 ListEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6315 case RDBSS_NTC_NETROOT
:
6316 --Scavenger
->NetRootsToBeFinalized
;
6317 ListEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6320 case RDBSS_NTC_V_NETROOT
:
6321 --Scavenger
->VNetRootsToBeFinalized
;
6322 ListEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6325 case RDBSS_NTC_SRVOPEN
:
6326 --Scavenger
->SrvOpensToBeFinalized
;
6327 ListEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6331 /* Also, remove the extra ref from the scavenger */
6332 RemoveEntryList(ListEntry
);
6333 InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
6340 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6344 LIST_ENTRY Discarded
;
6348 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
6350 /* Initialize our discarded list */
6351 InitializeListHead(&Discarded
);
6353 SrvCall
= (PSRV_CALL
)SrvOpen
->Fcb
->VNetRoot
->pNetRoot
->pSrvCall
;
6354 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
6356 /* Set the flag, and get the requests */
6357 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
6358 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED
);
6359 RxGatherRequestsForSrvOpen(SrvCall
, SrvOpen
, &Discarded
);
6361 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
6363 /* If there were discarded requests */
6364 if (!IsListEmpty(&Discarded
))
6366 /* And a pending buffering state change */
6367 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
6369 /* Clear the flag, and set the associated event - job done */
6370 RxAcquireSerializationMutex();
6371 ClearFlag(SrvOpen
->Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
6372 if (SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
6374 KeSetEvent(SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
, IO_NETWORK_INCREMENT
, FALSE
);
6376 RxReleaseSerializationMutex();
6379 /* Drop the discarded requests */
6380 RxpDiscardChangeBufferingStateRequests(&Discarded
);
6393 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6395 /* Reference our FCB so that it doesn't disappear */
6396 RxReferenceNetFcb(Fcb
);
6397 /* Purge Cc if required */
6398 if (Fcb
->OpenCount
!= 0)
6400 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
6403 /* If it wasn't freed, release the lock */
6404 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6406 RxReleaseFcb(NULL
, Fcb
);
6414 RxPurgeFcbInSystemCache(
6416 IN PLARGE_INTEGER FileOffset OPTIONAL
,
6418 IN BOOLEAN UninitializeCacheMaps
,
6419 IN BOOLEAN FlushFile
)
6426 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6428 /* Try to flush first, if asked */
6431 /* If flushing failed, just make some noise */
6432 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
6433 if (!NT_SUCCESS(Status
))
6435 PVOID CallersAddress
, CallersCaller
;
6437 RtlGetCallersAddress(&CallersAddress
, &CallersCaller
);
6438 DPRINT1("Flush failed with status %lx for FCB %p\n", Status
, Fcb
);
6439 DPRINT1("Caller was %p %p\n", CallersAddress
, CallersCaller
);
6443 /* Deal with Cc for purge */
6444 Purged
= CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, FileOffset
,
6445 Length
, UninitializeCacheMaps
);
6446 /* If purge failed, force section closing */
6449 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
6451 RxReleaseFcb(NULL
, Fcb
);
6452 Purged
= MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
6453 RxAcquireExclusiveFcb(NULL
, Fcb
);
6456 /* Return appropriate status */
6457 Status
= (Purged
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
6458 DPRINT("Purge for FCB %p returns %lx\n", Fcb
, Status
);
6467 RxPurgeFobxFromCache(
6468 PFOBX FobxToBePurged
)
6475 FcbToBePurged
= (PFCB
)FobxToBePurged
->pSrvOpen
->pFcb
;
6476 ASSERT(FcbToBePurged
!= NULL
);
6478 /* If we cannot have our FCB exclusively, give up */
6479 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
6480 if (Status
!= STATUS_SUCCESS
)
6482 RxDereferenceNetFobx(FobxToBePurged
, LHS_LockNotHeld
);
6486 /* Don't let the FCB disappear */
6487 RxReferenceNetFcb(FcbToBePurged
);
6489 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
6490 if (BooleanFlagOn(FobxToBePurged
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
) || FobxToBePurged
->pSrvOpen
->UncleanFobxCount
!= 0)
6492 DPRINT("FCB purge skipped\n");
6496 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
6499 RxDereferenceNetFobx(FobxToBePurged
, LHS_ExclusiveLockHeld
);
6500 /* Drop our extra reference */
6501 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged
, NULL
, FALSE
, FALSE
))
6503 RxReleaseFcb(NULL
, FcbToBePurged
);
6513 RxpWorkerThreadDispatcher(
6514 IN PRX_WORK_QUEUE WorkQueue
,
6515 IN PLARGE_INTEGER WaitInterval
)
6519 PETHREAD CurrentThread
;
6520 BOOLEAN KillThread
, Dereference
;
6521 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
6522 PWORKER_THREAD_ROUTINE WorkerRoutine
;
6524 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6526 /* Reference ourselves */
6527 CurrentThread
= PsGetCurrentThread();
6528 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
6529 ASSERT(NT_SUCCESS(Status
));
6531 /* Infinite loop for worker */
6533 Dereference
= FALSE
;
6537 PLIST_ENTRY ListEntry
;
6539 /* Remove an entry from the work queue */
6540 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
6541 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
6543 PRDBSS_DEVICE_OBJECT DeviceObject
;
6545 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
6547 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
6548 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
6549 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6551 /* Get the parameters, and null-them in the struct */
6552 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
6553 Parameter
= WorkQueueItem
->Parameter
;
6554 DeviceObject
= WorkQueueItem
->pDeviceObject
;
6556 WorkQueueItem
->List
.Flink
= NULL
;
6557 WorkQueueItem
->WorkerRoutine
= NULL
;
6558 WorkQueueItem
->Parameter
= NULL
;
6559 WorkQueueItem
->pDeviceObject
= NULL
;
6561 /* Call the routine */
6562 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
6563 WorkerRoutine(Parameter
);
6565 /* Are we going down now? */
6566 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
6568 PKEVENT TearDownEvent
;
6570 TearDownEvent
= InterlockedExchangePointer((void * volatile*)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
6571 if (TearDownEvent
!= NULL
)
6573 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
6577 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6580 /* Shall we shutdown... */
6581 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
6582 switch (WorkQueue
->State
)
6584 /* Our queue is active, kill it if we have no more items to dispatch
6585 * and more threads than the required minimum
6587 case RxWorkQueueActive
:
6588 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
6590 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
6591 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
6595 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
6600 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6605 /* The queue is inactive: kill it we have more threads than the required minimum */
6606 case RxWorkQueueInactive
:
6607 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
6608 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
6612 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
6617 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6621 /* Rundown in progress..., kill it for sure! */
6622 case RxWorkQueueRundownInProgress
:
6624 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
6626 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
6628 RundownContext
= WorkQueue
->pRundownContext
;
6629 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
6631 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
6633 Dereference
= FALSE
;
6635 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
6637 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
6640 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
6647 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
6648 } while (!KillThread
);
6650 DPRINT("Killed worker thread\n");
6652 /* Do we have to dereference ourselves? */
6655 ObDereferenceObject(CurrentThread
);
6658 /* Dump last executed routine */
6659 if (DumpDispatchRoutine
)
6661 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
6664 PsTerminateSystemThread(STATUS_SUCCESS
);
6669 IN OUT PVOID Instance
)
6671 NODE_TYPE_CODE NodeType
;
6672 PNODE_TYPE_AND_SIZE Node
;
6676 RxAcquireScavengerMutex();
6678 /* We can only reference a few structs */
6679 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
6680 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
6681 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
6682 (NodeType
== RDBSS_NTC_FOBX
));
6684 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6685 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
6687 /* Trace refcount if asked */
6690 case RDBSS_NTC_SRVCALL
:
6691 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
6694 case RDBSS_NTC_NETROOT
:
6695 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
6698 case RDBSS_NTC_V_NETROOT
:
6699 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
6702 case RDBSS_NTC_SRVOPEN
:
6703 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
6706 case RDBSS_NTC_FOBX
:
6707 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
6715 RxpUndoScavengerFinalizationMarking(Instance
);
6716 RxReleaseScavengerMutex();
6730 ASSERT(NodeTypeIsFcb(ThisFcb
));
6732 /* Just remove the entry from the FCB_TABLE */
6733 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
6734 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
6735 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
6737 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
6738 DPRINT("FCB (%p) %wZ removed\n", ThisFcb
, &ThisFcb
->FcbTableEntry
.Path
);
6739 /* Mark, so that we don't try to do it twice */
6740 SetFlag(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
);
6747 RxRemovePrefixTableEntry(
6748 IN OUT PRX_PREFIX_TABLE ThisTable
,
6749 IN OUT PRX_PREFIX_ENTRY Entry
)
6753 ASSERT(NodeType(Entry
) == RDBSS_NTC_PREFIX_ENTRY
);
6754 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
6756 /* Check whether we're asked to remove null entry */
6757 if (Entry
->Prefix
.Length
== 0)
6759 ThisTable
->TableEntryForNull
= NULL
;
6763 RemoveEntryList(&Entry
->HashLinks
);
6766 Entry
->ContainingRecord
= NULL
;
6768 /* Also remove it from global list */
6769 RemoveEntryList(&Entry
->MemberQLinks
);
6771 ++ThisTable
->Version
;
6778 RxRemoveVirtualNetRootFromNetRoot(
6780 PV_NET_ROOT VNetRoot
)
6782 PRX_PREFIX_TABLE PrefixTable
;
6786 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
6787 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
6789 /* Remove the VNetRoot from the list in the NetRoot */
6790 --NetRoot
->NumberOfVirtualNetRoots
;
6791 RemoveEntryList(&VNetRoot
->NetRootListEntry
);
6793 /* Fix the NetRoot if we were the default VNetRoot */
6794 if (NetRoot
->DefaultVNetRoot
== VNetRoot
)
6796 /* Put the first one available */
6797 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
6799 NetRoot
->DefaultVNetRoot
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
6801 /* Otherwise, none */
6804 NetRoot
->DefaultVNetRoot
= NULL
;
6808 /* If there are still other VNetRoot available, we're done */
6809 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
6814 /* Otherwise, initiate NetRoot finalization */
6815 if (!BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
6817 RxRemovePrefixTableEntry(PrefixTable
, &NetRoot
->PrefixEntry
);
6818 SetFlag(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
);
6821 /* Notify mini-rdr */
6822 if (NetRoot
->pSrvCall
!= NULL
&& NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
6826 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
6827 MRxFinalizeNetRoot
, ((PMRX_NET_ROOT
)NetRoot
, FALSE
));
6833 RxResumeBlockedOperations_ALL(
6834 IN OUT PRX_CONTEXT RxContext
)
6836 LIST_ENTRY BlockedOps
;
6840 /* Get the blocked operations */
6841 RxTransferListWithMutex(&BlockedOps
, &RxContext
->BlockedOperations
, RxContext
->BlockedOpsMutex
);
6843 if (!IsListEmpty(&BlockedOps
))
6851 RxResumeBlockedOperations_Serially(
6852 IN OUT PRX_CONTEXT RxContext
,
6853 IN OUT PLIST_ENTRY BlockingIoQ
)
6857 RxAcquireSerializationMutex();
6859 /* This can only happen on pipes */
6860 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
6862 RxReleaseSerializationMutex();
6868 RxReleaseSerializationMutex();
6875 RxScavengeRelatedFobxs(
6879 LIST_ENTRY LocalList
;
6880 PLIST_ENTRY NextEntry
;
6881 PRDBSS_SCAVENGER Scavenger
;
6885 /* First of all, check whether there are FOBX to scavenge */
6886 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
6887 RxAcquireScavengerMutex();
6888 if (Scavenger
->FobxsToBeFinalized
<= 0)
6890 RxReleaseScavengerMutex();
6894 /* Initialize our local list which will hold all the FOBX to scavenge so
6895 * that we don't acquire the scavenger mutex too long
6897 InitializeListHead(&LocalList
);
6899 /* Technically, that condition should all be true... */
6900 if (!IsListEmpty(&Scavenger
->FobxFinalizationList
))
6902 PLIST_ENTRY NextEntry
, LastEntry
;
6904 /* Browse all the FCBs to find the matching ones */
6905 NextEntry
= Scavenger
->FobxFinalizationList
.Flink
;
6906 LastEntry
= &Scavenger
->FobxFinalizationList
;
6907 while (NextEntry
!= LastEntry
)
6909 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
6910 NextEntry
= NextEntry
->Flink
;
6911 /* Matching our FCB? Let's finalize it */
6912 if (Fobx
->pSrvOpen
!= NULL
&& Fobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
6914 RxpUndoScavengerFinalizationMarking(Fobx
);
6915 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
6916 InsertTailList(&LocalList
, &Fobx
->ScavengerFinalizationList
);
6921 RxReleaseScavengerMutex();
6923 /* Nothing to scavenge? Quit */
6924 if (IsListEmpty(&LocalList
))
6929 /* Now, finalize all the extracted FOBX */
6930 while (!IsListEmpty(&LocalList
))
6932 NextEntry
= RemoveHeadList(&LocalList
);
6933 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
6934 RxFinalizeNetFobx(Fobx
, TRUE
, TRUE
);
6941 RxScavengerFinalizeEntries(
6942 PRDBSS_DEVICE_OBJECT DeviceObject
)
6952 RxScavengerTimerRoutine(
6956 PRDBSS_DEVICE_OBJECT DeviceObject
;
6957 PRDBSS_SCAVENGER Scavenger
;
6961 DeviceObject
= Context
;
6962 Scavenger
= DeviceObject
->pRdbssScavenger
;
6965 RxAcquireScavengerMutex();
6966 /* If the scavenger was dormant, wake it up! */
6967 if (Scavenger
->State
== RDBSS_SCAVENGER_DORMANT
)
6970 Scavenger
->State
= RDBSS_SCAVENGER_ACTIVE
;
6971 KeResetEvent(&Scavenger
->ScavengeEvent
);
6973 /* Scavenger the entries */
6974 RxReleaseScavengerMutex();
6975 RxScavengerFinalizeEntries(DeviceObject
);
6976 RxAcquireScavengerMutex();
6978 /* If we're still active (race) */
6979 if (Scavenger
->State
== RDBSS_SCAVENGER_ACTIVE
)
6981 /* If there are new entries to scavenge, stay dormant and requeue a run */
6982 if (Scavenger
->NumberOfDormantFiles
+ Scavenger
->SrvCallsToBeFinalized
+
6983 Scavenger
->NetRootsToBeFinalized
+ Scavenger
->VNetRootsToBeFinalized
+
6984 Scavenger
->FcbsToBeFinalized
+ Scavenger
->SrvOpensToBeFinalized
+
6985 Scavenger
->FobxsToBeFinalized
!= 0)
6988 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
6990 /* Otherwise, we're inactive again */
6993 Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
;
6997 RxReleaseScavengerMutex();
6999 /* Requeue an execution */
7002 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
7003 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
7008 RxReleaseScavengerMutex();
7011 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
7015 RxScavengeVNetRoots(
7016 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
7027 RxSpinUpRequestsDispatcher(
7031 PRX_DISPATCHER RxDispatcher
;
7033 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7034 if (!NT_SUCCESS(Status
))
7036 PsTerminateSystemThread(STATUS_SUCCESS
);
7039 RxDispatcher
= Dispatcher
;
7044 PLIST_ENTRY ListEntry
;
7046 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
7047 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
7048 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
7050 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
7051 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
7053 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
7057 ListEntry
= &RxDispatcher
->SpinUpRequests
;
7059 KeResetEvent(&RxDispatcher
->SpinUpRequestsEvent
);
7060 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
7062 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
7064 PWORK_QUEUE_ITEM WorkItem
;
7065 PRX_WORK_QUEUE WorkQueue
;
7067 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
7068 WorkQueue
= WorkItem
->Parameter
;
7070 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
7072 DPRINT("Workqueue: calling %p(%p)\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
7073 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
7075 } while (RxDispatcher
->State
== RxDispatcherActive
);
7077 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
7078 PsTerminateSystemThread(STATUS_SUCCESS
);
7085 RxSpinUpWorkerThread(
7086 PRX_WORK_QUEUE WorkQueue
,
7087 PRX_WORKERTHREAD_ROUTINE Routine
,
7092 HANDLE ThreadHandle
;
7096 /* If work queue is inactive, that cannot work */
7097 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7098 if (WorkQueue
->State
!= RxWorkQueueActive
)
7100 Status
= STATUS_UNSUCCESSFUL
;
7101 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
7105 ++WorkQueue
->NumberOfActiveWorkerThreads
;
7106 Status
= STATUS_SUCCESS
;
7108 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
7110 /* Quit on failure */
7111 if (!NT_SUCCESS(Status
))
7116 /* Spin up the worker thread */
7117 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
7118 if (NT_SUCCESS(Status
))
7120 ZwClose(ThreadHandle
);
7123 /* Read well: we reached that point because it failed! */
7124 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
7126 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7127 --WorkQueue
->NumberOfActiveWorkerThreads
;
7128 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
7130 /* Rundown, no more active threads, set the event! */
7131 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
7132 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
7134 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
7137 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
7139 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
7145 RxSpinUpWorkerThreads(
7146 PRX_WORK_QUEUE WorkQueue
)
7152 RxSynchronizeWithScavenger(
7153 IN PRX_CONTEXT RxContext
)
7162 RxTableComputeHashValue(
7163 IN PUNICODE_STRING Name
)
7171 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
7174 Loops
[1] = MaxChar
- 1;
7175 Loops
[2] = MaxChar
- 2;
7176 Loops
[3] = MaxChar
- 3;
7177 Loops
[4] = MaxChar
- 4;
7178 Loops
[5] = MaxChar
/ 4;
7179 Loops
[6] = 2 * MaxChar
/ 4;
7180 Loops
[7] = 3 * MaxChar
/ 4;
7183 for (i
= 0; i
< 8; ++i
)
7188 if (Idx
>= 0 && Idx
< MaxChar
)
7190 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
7201 RxTableComputePathHashValue(
7202 IN PUNICODE_STRING Name
)
7210 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
7213 Loops
[1] = MaxChar
- 1;
7214 Loops
[2] = MaxChar
- 2;
7215 Loops
[3] = MaxChar
- 3;
7216 Loops
[4] = MaxChar
- 4;
7217 Loops
[5] = MaxChar
/ 4;
7218 Loops
[6] = 2 * MaxChar
/ 4;
7219 Loops
[7] = 3 * MaxChar
/ 4;
7222 for (i
= 0; i
< 8; ++i
)
7227 if (Idx
>= 0 && Idx
< MaxChar
)
7229 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
7241 IN PRX_PREFIX_TABLE ThisTable
,
7242 IN PUNICODE_STRING Name
,
7243 OUT PUNICODE_STRING RemainingName
,
7244 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
7248 PRX_PREFIX_ENTRY Entry
;
7249 RX_CONNECTION_ID NullId
;
7250 UNICODE_STRING LookupString
;
7254 /* If caller didn't provide a connection ID, setup one */
7255 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
7257 NullId
.Luid
.LowPart
= 0;
7258 NullId
.Luid
.HighPart
= 0;
7259 RxConnectionId
= &NullId
;
7263 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
7267 LookupString
.Buffer
= Name
->Buffer
;
7268 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
7269 /* We'll perform the lookup, path component after another */
7270 for (i
= 1; i
< MaxChar
; ++i
)
7273 PRX_PREFIX_ENTRY CurEntry
;
7275 /* Don't cut in the middle of a path element */
7276 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
7281 /* Perform lookup in the table */
7282 LookupString
.Length
= i
* sizeof(WCHAR
);
7283 Hash
= RxTableComputeHashValue(&LookupString
);
7284 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
7286 ++ThisTable
->Lookups
;
7288 /* Entry not found, move to the next component */
7289 if (CurEntry
== NULL
)
7292 ++ThisTable
->FailedLookups
;
7298 ASSERT(Entry
->ContainingRecord
!= NULL
);
7299 Container
= Entry
->ContainingRecord
;
7301 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
7302 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
7306 NetRoot
= (PNET_ROOT
)Entry
->ContainingRecord
;
7307 /* If there's a default one, perfect, that's a match */
7308 if (NetRoot
->DefaultVNetRoot
!= NULL
)
7310 Container
= NetRoot
->DefaultVNetRoot
;
7312 /* If none (that shouldn't happen!), try to find one */
7315 /* Use the first one in the list */
7316 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7318 Container
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
7320 /* Really, really, shouldn't happen */
7331 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
7337 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
7341 /* Entry was found */
7346 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
7348 /* Setup remaining name */
7349 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
7350 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
7351 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
7355 /* Otherwise, that's the whole name */
7356 RemainingName
= Name
;
7366 RxTableLookupName_ExactLengthMatch(
7367 IN PRX_PREFIX_TABLE ThisTable
,
7368 IN PUNICODE_STRING Name
,
7370 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
7372 PLIST_ENTRY ListEntry
, HashBucket
;
7376 ASSERT(RxConnectionId
!= NULL
);
7378 /* Select the right bucket */
7379 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
7380 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
7381 /* If bucket is empty, no match */
7382 if (IsListEmpty(HashBucket
))
7387 /* Browse all the entries in the bucket */
7388 for (ListEntry
= HashBucket
->Flink
;
7389 ListEntry
!= HashBucket
;
7390 ListEntry
= ListEntry
->Flink
)
7393 PRX_PREFIX_ENTRY Entry
;
7394 BOOLEAN CaseInsensitive
;
7395 PUNICODE_STRING CmpName
, CmpPrefix
;
7396 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
7398 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
7399 ++ThisTable
->Considers
;
7400 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
7402 Container
= Entry
->ContainingRecord
;
7403 ASSERT(Container
!= NULL
);
7405 /* Not the same hash, not the same length, move on */
7406 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
7411 ++ThisTable
->Compares
;
7412 /* If we have to perform a case insensitive compare on a portion... */
7413 if (Entry
->CaseInsensitiveLength
!= 0)
7415 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
7417 /* Perform the case insensitive check on the asked length */
7418 InsensitiveName
.Buffer
= Name
->Buffer
;
7419 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
7420 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
7421 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
7422 /* No match, move to the next entry */
7423 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
7428 /* Was the case insensitive covering the whole name? */
7429 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
7431 /* If connection ID also matches, that a complete match! */
7432 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
7438 /* Otherwise, we have to continue with the sensitive match.... */
7439 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
7440 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
7441 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
7442 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
7444 CmpName
= &InsensitiveName
;
7445 CmpPrefix
= &InsensitivePrefix
;
7446 CaseInsensitive
= FALSE
;
7451 CmpPrefix
= &Entry
->Prefix
;
7452 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
7455 /* Perform the compare, if there's a match, also check for connection ID */
7456 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
7458 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
7472 RxTearDownBufferingManager(
7478 return STATUS_SUCCESS
;
7487 _In_
struct _KDPC
*Dpc
,
7488 _In_opt_ PVOID DeferredContext
,
7489 _In_opt_ PVOID SystemArgument1
,
7490 _In_opt_ PVOID SystemArgument2
)
7493 LIST_ENTRY LocalList
;
7494 PLIST_ENTRY ListEntry
;
7495 PRX_WORK_ITEM WorkItem
;
7497 InitializeListHead(&LocalList
);
7499 KeAcquireSpinLockAtDpcLevel(&RxTimerLock
);
7502 /* Find any entry matching */
7503 if (!IsListEmpty(&RxTimerQueueHead
))
7505 ListEntry
= RxTimerQueueHead
.Flink
;
7508 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
7509 if (WorkItem
->LastTick
== RxTimerTickCount
)
7511 ListEntry
= ListEntry
->Flink
;
7513 RemoveEntryList(&WorkItem
->WorkQueueItem
.List
);
7514 InsertTailList(&LocalList
, &WorkItem
->WorkQueueItem
.List
);
7518 ListEntry
= ListEntry
->Flink
;
7520 } while (ListEntry
!= &RxTimerQueueHead
);
7522 /* Do we have to requeue a later execution? */
7523 Set
= !IsListEmpty(&RxTimerQueueHead
);
7525 KeReleaseSpinLockFromDpcLevel(&RxTimerLock
);
7527 /* Requeue if list wasn't empty */
7530 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
7533 /* If we had matching entries */
7534 if (!IsListEmpty(&LocalList
))
7536 /* Post them, one after another */
7537 ListEntry
= LocalList
.Flink
;
7540 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
7541 ListEntry
= ListEntry
->Flink
;
7543 WorkItem
->WorkQueueItem
.List
.Flink
= NULL
;
7544 WorkItem
->WorkQueueItem
.List
.Blink
= NULL
;
7545 RxPostToWorkerThread(WorkItem
->WorkQueueItem
.pDeviceObject
, CriticalWorkQueue
,
7546 &WorkItem
->WorkQueueItem
, WorkItem
->WorkQueueItem
.WorkerRoutine
,
7547 WorkItem
->WorkQueueItem
.Parameter
);
7549 while (ListEntry
!= &LocalList
);
7557 RxTrackerUpdateHistory(
7558 _Inout_opt_ PRX_CONTEXT RxContext
,
7559 _Inout_ PMRX_FCB MrxFcb
,
7560 _In_ ULONG Operation
,
7561 _In_ ULONG LineNumber
,
7562 _In_ PCSTR FileName
,
7563 _In_ ULONG SerialNumber
)
7566 RX_FCBTRACKER_CASES Case
;
7568 /* Check for null or special context */
7569 if (RxContext
== NULL
)
7571 Case
= RX_FCBTRACKER_CASE_NULLCONTEXT
;
7573 else if ((ULONG_PTR
)RxContext
== -1)
7575 Case
= RX_FCBTRACKER_CASE_CBS_CONTEXT
;
7577 else if ((ULONG_PTR
)RxContext
== -2)
7579 Case
= RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT
;
7583 ASSERT(NodeType(RxContext
) == RDBSS_NTC_RX_CONTEXT
);
7584 Case
= RX_FCBTRACKER_CASE_NORMAL
;
7587 /* If caller provided a FCB, update its history */
7591 ASSERT(NodeTypeIsFcb(Fcb
));
7593 /* Only one acquire operation, so many release operations... */
7594 if (Operation
== TRACKER_ACQUIRE_FCB
)
7596 ++Fcb
->FcbAcquires
[Case
];
7600 ++Fcb
->FcbReleases
[Case
];
7604 /* If we have a normal context, update its history about this function calls */
7605 if (Case
== RX_FCBTRACKER_CASE_NORMAL
)
7607 ULONG TrackerHistoryPointer
;
7609 /* Only one acquire operation, so many release operations... */
7610 if (Operation
== TRACKER_ACQUIRE_FCB
)
7612 InterlockedIncrement(&RxContext
->AcquireReleaseFcbTrackerX
);
7616 InterlockedDecrement(&RxContext
->AcquireReleaseFcbTrackerX
);
7619 /* We only keep track of the 32 first calls */
7620 TrackerHistoryPointer
= InterlockedExchangeAdd((volatile long *)&RxContext
->TrackerHistoryPointer
, 1);
7621 if (TrackerHistoryPointer
< RDBSS_TRACKER_HISTORY_SIZE
)
7623 RxContext
->TrackerHistory
[TrackerHistoryPointer
].AcquireRelease
= Operation
;
7624 RxContext
->TrackerHistory
[TrackerHistoryPointer
].LineNumber
= LineNumber
;
7625 RxContext
->TrackerHistory
[TrackerHistoryPointer
].FileName
= (PSZ
)FileName
;
7626 RxContext
->TrackerHistory
[TrackerHistoryPointer
].SavedTrackerValue
= RxContext
->AcquireReleaseFcbTrackerX
;
7627 RxContext
->TrackerHistory
[TrackerHistoryPointer
].Flags
= RxContext
->Flags
;
7630 /* If it's negative, then we released once more than we acquired it?! */
7631 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
>= 0);
7636 RxTrackPagingIoResource(
7637 _Inout_ PVOID Instance
,
7649 RxUndoScavengerFinalizationMarking(
7652 /* Just call internal routine with mutex held */
7653 RxAcquireScavengerMutex();
7654 RxpUndoScavengerFinalizationMarking(Instance
);
7655 RxReleaseScavengerMutex();
7662 RxUninitializeVNetRootParameters(
7663 IN PUNICODE_STRING UserName
,
7664 IN PUNICODE_STRING UserDomainName
,
7665 IN PUNICODE_STRING Password
,
7670 /* Only free what could have been allocated */
7671 if (UserName
!= NULL
)
7673 RxFreePool(UserName
);
7676 if (UserDomainName
!= NULL
)
7678 RxFreePool(UserDomainName
);
7681 if (Password
!= NULL
)
7683 RxFreePool(Password
);
7686 /* And remove the possibly set CSC agent flag */
7689 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
7698 IN RX_BLOCK_CONDITION NewConditionValue
,
7699 OUT PRX_BLOCK_CONDITION Condition
,
7700 IN OUT PLIST_ENTRY TransitionWaitList
)
7702 PRX_CONTEXT Context
;
7703 LIST_ENTRY SerializationQueue
;
7707 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
7709 /* Set the new condition */
7710 RxAcquireSerializationMutex();
7711 ASSERT(NewConditionValue
!= Condition_InTransition
);
7712 *Condition
= NewConditionValue
;
7713 /* And get the serialization queue for treatment */
7714 RxTransferList(&SerializationQueue
, TransitionWaitList
);
7715 RxReleaseSerializationMutex();
7717 /* Handle the serialization queue */
7718 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
7719 while (Context
!= NULL
)
7721 /* If the caller asked for post, post the request */
7722 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
7724 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
7725 RxFsdPostRequest(Context
);
7727 /* Otherwise, wake up sleeping waiters */
7730 RxSignalSynchronousWaiter(Context
);
7733 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
7741 RxVerifyOperationIsLegal(
7742 IN PRX_CONTEXT RxContext
)
7747 PFILE_OBJECT FileObject
;
7748 PIO_STACK_LOCATION Stack
;
7752 Irp
= RxContext
->CurrentIrp
;
7753 Stack
= RxContext
->CurrentIrpSp
;
7754 FileObject
= Stack
->FileObject
;
7756 /* We'll only check stuff on opened files, this requires an IRP and a FO */
7757 if (Irp
== NULL
|| FileObject
== NULL
)
7762 /* Set no exception for breakpoint - remember whether is was already set */
7763 FlagSet
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
7764 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
7766 /* If we have a CCB, perform a few checks on opened file */
7767 Fobx
= RxContext
->pFobx
;
7770 PMRX_SRV_OPEN SrvOpen
;
7772 SrvOpen
= Fobx
->pSrvOpen
;
7773 if (SrvOpen
!= NULL
)
7775 UCHAR MajorFunction
;
7777 MajorFunction
= RxContext
->MajorFunction
;
7778 /* Only allow closing/cleanup operations on renamed files */
7779 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
7780 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
7782 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_RENAMED
;
7783 ExRaiseStatus(STATUS_FILE_RENAMED
);
7786 /* Only allow closing/cleanup operations on deleted files */
7787 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
7788 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
))
7790 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_DELETED
;
7791 ExRaiseStatus(STATUS_FILE_DELETED
);
7796 /* If that's an open operation */
7797 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
7799 PFILE_OBJECT RelatedFileObject
;
7801 /* We won't allow an open operation relative to a file to be deleted */
7802 RelatedFileObject
= FileObject
->RelatedFileObject
;
7803 if (RelatedFileObject
!= NULL
)
7807 Fcb
= RelatedFileObject
->FsContext
;
7808 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
7810 RxContext
->IoStatusBlock
.Status
= STATUS_DELETE_PENDING
;
7811 ExRaiseStatus(STATUS_DELETE_PENDING
);
7816 /* If cleanup was completed */
7817 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
7819 if (!BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
))
7821 UCHAR MajorFunction
;
7823 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
7824 MajorFunction
= Stack
->MajorFunction
;
7825 if (MajorFunction
!= IRP_MJ_CLOSE
&& MajorFunction
!= IRP_MJ_QUERY_INFORMATION
&&
7826 MajorFunction
!= IRP_MJ_SET_INFORMATION
)
7828 if ((MajorFunction
!= IRP_MJ_READ
&& MajorFunction
!= IRP_MJ_WRITE
) ||
7829 !BooleanFlagOn(Stack
->MinorFunction
, IRP_MN_COMPLETE
))
7831 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_CLOSED
;
7832 ExRaiseStatus(STATUS_FILE_CLOSED
);
7838 /* If flag was already set, don't clear it */
7841 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
7849 RxWaitForStableCondition(
7850 IN PRX_BLOCK_CONDITION Condition
,
7851 IN OUT PLIST_ENTRY TransitionWaitList
,
7852 IN OUT PRX_CONTEXT RxContext
,
7853 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
7856 NTSTATUS LocalStatus
;
7860 /* Make sure to always get status */
7861 if (AsyncStatus
== NULL
)
7863 AsyncStatus
= &LocalStatus
;
7866 /* By default, it's a success */
7867 *AsyncStatus
= STATUS_SUCCESS
;
7870 /* If it's not stable, we've to wait */
7871 if (!StableCondition(*Condition
))
7873 /* Lock the mutex */
7874 RxAcquireSerializationMutex();
7875 /* Still not stable? */
7876 if (!StableCondition(*Condition
))
7878 /* Insert us in the wait list for processing on stable condition */
7879 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
7881 /* If we're asked to post on stable, don't wait, and just return pending */
7882 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
7884 *AsyncStatus
= STATUS_PENDING
;
7891 RxReleaseSerializationMutex();
7893 /* We don't post on stable, so, just wait... */
7896 RxWaitSync(RxContext
);
7906 RxWorkItemDispatcher(
7909 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
7911 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
7913 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
7915 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
7923 _RxAllocatePoolWithTag(
7924 _In_ POOL_TYPE PoolType
,
7925 _In_ SIZE_T NumberOfBytes
,
7928 return ExAllocatePoolWithTagPriority(PoolType
, NumberOfBytes
, Tag
, LowPoolPriority
);
7939 ExFreePoolWithTag(Buffer
, 0);
7951 ExFreePoolWithTag(Buffer
, Tag
);
7957 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
7959 #ifdef RDBSS_TRACKER
7961 _In_ ULONG LineNumber
,
7962 _In_ PCSTR FileName
,
7963 _In_ ULONG SerialNumber
7968 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
7972 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
7974 SpecialContext
= FALSE
;
7975 ContextIsPresent
= FALSE
;
7976 /* Check for special context */
7977 if ((ULONG_PTR
)RxContext
== -1 || (ULONG_PTR
)RxContext
== -2)
7979 SpecialContext
= TRUE
;
7982 /* We don't handle buffering state change yet... */
7983 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
7984 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
7989 /* Nor special contexts */
7995 /* If we don't have a context, assume we can wait! */
7996 if (RxContext
== NULL
)
8002 /* That said: we have a real context! */
8003 ContextIsPresent
= TRUE
;
8005 /* If we've been cancelled in between, give up */
8006 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
8007 if (!NT_SUCCESS(Status
))
8013 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
8018 /* Assume we cannot lock */
8019 Status
= STATUS_LOCK_NOT_GRANTED
;
8021 /* Lock according to what the caller asked */
8024 case FCB_MODE_EXCLUSIVE
:
8025 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
8028 case FCB_MODE_SHARED
:
8029 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
8032 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
8033 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
8037 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
8038 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
8045 Status
= STATUS_SUCCESS
;
8046 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
8048 /* Handle paging write - not implemented */
8049 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
8055 /* And break, that cool! */
8061 /* If it failed, return immediately */
8062 if (!NT_SUCCESS(Status
))
8068 /* If we don't have to check for valid operation, job done, nothing more to do */
8069 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
8071 if (NT_SUCCESS(Status
))
8073 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
8079 /* Verify operation */
8082 RxVerifyOperationIsLegal(RxContext
);
8086 /* If it failed, release lock and fail */
8087 if (_SEH2_AbnormalTermination())
8089 ExReleaseResourceLite(Fcb
->Header
.Resource
);
8090 Status
= STATUS_LOCK_NOT_GRANTED
;
8095 if (NT_SUCCESS(Status
))
8097 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
8100 DPRINT("Status: %x\n", Status
);
8108 __RxItsTheSameContext(
8109 _In_ PRX_CONTEXT RxContext
,
8110 _In_ ULONG CapturedRxContextSerialNumber
,
8114 /* Check we have a context with the same serial number */
8115 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
8116 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
8119 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
8125 _Inout_opt_ PRX_CONTEXT RxContext
,
8126 _Inout_ PMRX_FCB MrxFcb
8127 #ifdef RDBSS_TRACKER
8129 _In_ ULONG LineNumber
,
8130 _In_ PCSTR FileName
,
8131 _In_ ULONG SerialNumber
8135 BOOLEAN IsExclusive
, BufferingPending
;
8137 RxAcquireSerializationMutex();
8139 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
8140 IsExclusive
= BooleanFlagOn(MrxFcb
->Header
.Resource
->Flag
, ResourceOwnedExclusive
);
8142 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
8143 * then just release the FCB
8145 if (!BufferingPending
|| !IsExclusive
)
8147 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
8148 LineNumber
, FileName
, SerialNumber
);
8149 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
8152 RxReleaseSerializationMutex();
8154 /* And finally leave */
8155 if (!BufferingPending
|| !IsExclusive
)
8160 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
8162 /* Otherwise, handle buffering state and release */
8163 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
8165 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
8166 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
8170 __RxReleaseFcbForThread(
8171 _Inout_opt_ PRX_CONTEXT RxContext
,
8172 _Inout_ PMRX_FCB MrxFcb
,
8173 _In_ ERESOURCE_THREAD ResourceThreadId
8174 #ifdef RDBSS_TRACKER
8176 _In_ ULONG LineNumber
,
8177 _In_ PCSTR FileName
,
8178 _In_ ULONG SerialNumber
8182 BOOLEAN IsExclusive
, BufferingPending
;
8184 RxAcquireSerializationMutex();
8186 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
8187 IsExclusive
= BooleanFlagOn(MrxFcb
->Header
.Resource
->Flag
, ResourceOwnedExclusive
);
8189 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
8190 * then just release the FCB
8192 if (!BufferingPending
|| !IsExclusive
)
8194 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
8195 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
8196 LineNumber
, FileName
, SerialNumber
);
8197 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
8200 RxReleaseSerializationMutex();
8202 /* And finally leave */
8203 if (!BufferingPending
|| !IsExclusive
)
8208 /* Otherwise, handle buffering state and release */
8209 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
8210 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
8211 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);