3 * Copyright (C) 2017 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: sdk/lib/drivers/rxce/rxce.c
23 * PURPOSE: RXCE library
24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org)
27 /* INCLUDES *****************************************************************/
30 #include <pseh/pseh2.h>
45 RxCreateSrvCallCallBack(
46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
);
49 RxFinishSrvCallConstruction(
50 PMRX_SRVCALLDOWN_STRUCTURE Calldown
);
54 RxFinishSrvCallConstructionDispatcher(
58 RxInsertWorkQueueItem(
59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
60 WORK_QUEUE_TYPE WorkQueueType
,
61 PRX_WORK_QUEUE_ITEM WorkQueueItem
);
65 PRX_CONTEXT RxContext
);
73 RxpDispatchChangeBufferingStateRequests(
76 PLIST_ENTRY DiscardedRequests
);
80 RxScavengerTimerRoutine(
86 _In_
struct _KDPC
*Dpc
,
87 _In_opt_ PVOID DeferredContext
,
88 _In_opt_ PVOID SystemArgument1
,
89 _In_opt_ PVOID SystemArgument2
);
98 _RxAllocatePoolWithTag(
99 _In_ POOL_TYPE PoolType
,
100 _In_ SIZE_T NumberOfBytes
,
114 extern ULONG ReadAheadGranularity
;
116 volatile LONG RxNumberOfActiveFcbs
= 0;
117 ULONG SerialNumber
= 1;
119 volatile ULONG RxContextSerialNumberCounter
;
120 BOOLEAN RxStopOnLoudCompletion
= TRUE
;
121 BOOLEAN RxSrvCallConstructionDispatcherActive
= FALSE
;
122 LIST_ENTRY RxSrvCalldownList
;
123 RX_SPIN_LOCK RxStrucSupSpinLock
;
125 ULONG RdbssReferenceTracingValue
= (RDBSS_REF_TRACK_SRVCALL
| RDBSS_REF_TRACK_NETROOT
|
126 RDBSS_REF_TRACK_VNETROOT
| RDBSS_REF_TRACK_NETFOBX
|
127 RDBSS_REF_TRACK_NETFCB
| RDBSS_REF_TRACK_SRVOPEN
|
128 RX_PRINT_REF_TRACKING
);
130 ULONG RdbssReferenceTracingValue
= 0;
132 LARGE_INTEGER RxWorkQueueWaitInterval
[RxMaximumWorkQueue
];
133 LARGE_INTEGER RxSpinUpDispatcherWaitInterval
;
134 RX_DISPATCHER RxDispatcher
;
135 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues
;
136 FAST_MUTEX RxLowIoPagingIoSyncMutex
;
137 BOOLEAN RxContinueFromAssert
= TRUE
;
138 ULONG RxExplodePoolTags
= 1;
139 LARGE_INTEGER RxTimerInterval
;
140 RX_SPIN_LOCK RxTimerLock
;
141 LIST_ENTRY RxTimerQueueHead
;
142 LIST_ENTRY RxRecurrentWorkItemsList
;
145 ULONG RxTimerTickCount
;
146 FAST_MUTEX RxContextPerFileSerializationMutex
;
148 BOOLEAN DumpDispatchRoutine
= TRUE
;
150 BOOLEAN DumpDispatchRoutine
= FALSE
;
158 #define ASSERT(exp) \
161 RxAssert(#exp, __FILE__, __LINE__, NULL); \
166 #undef RxAllocatePool
167 #undef RxAllocatePoolWithTag
170 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
171 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag
172 #define RxFreePool _RxFreePool
173 #define RxFreePoolWithTag _RxFreePoolWithTag
176 /* FUNCTIONS ****************************************************************/
183 RxAcquireExclusiveFcbResourceInMRx(
184 _Inout_ PMRX_FCB Fcb
)
186 return RxAcquireExclusiveFcb(NULL
, (PFCB
)Fcb
);
194 RxAcquireFcbForLazyWrite(
204 /* The received context is a FCB */
205 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
206 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
207 ASSERT(Fcb
->Specific
.Fcb
.LazyWriteThread
== NULL
);
209 /* Acquire the paging resource (shared) */
210 Ret
= ExAcquireResourceSharedLite(Fcb
->Header
.PagingIoResource
, Wait
);
213 /* Update tracker information */
214 Fcb
->PagingIoResourceFile
= __FILE__
;
215 Fcb
->PagingIoResourceLine
= __LINE__
;
216 /* Lazy writer thread is the current one */
217 Fcb
->Specific
.Fcb
.LazyWriteThread
= PsGetCurrentThread();
219 /* There is no top level IRP */
220 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
221 /* Now, there will be! */
222 Ret
= RxTryToBecomeTheTopLevelIrp(NULL
, (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
,
223 Fcb
->RxDeviceObject
, TRUE
);
224 /* In case of failure, release the lock and reset everything */
227 Fcb
->PagingIoResourceFile
= NULL
;
228 Fcb
->PagingIoResourceLine
= 0;
229 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
230 Fcb
->Specific
.Fcb
.LazyWriteThread
= NULL
;
242 RxAcquireFcbForReadAhead(
252 /* The received context is a FCB */
253 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
254 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
256 Ret
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, Wait
);
259 /* There is no top level IRP */
260 ASSERT(RxIsThisTheTopLevelIrp(NULL
));
261 /* Now, there will be! */
262 Ret
= RxTryToBecomeTheTopLevelIrp(NULL
, (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
,
263 Fcb
->RxDeviceObject
, TRUE
);
264 /* In case of failure, release the lock and reset everything */
267 ExReleaseResourceLite(Fcb
->Header
.Resource
);
276 RxAcquireFileForNtCreateSection(
277 PFILE_OBJECT FileObject
)
285 PFILE_OBJECT FileObject
,
286 PDEVICE_OBJECT DeviceObject
)
289 return STATUS_NOT_IMPLEMENTED
;
296 RxAddVirtualNetRootToNetRoot(
298 PV_NET_ROOT VNetRoot
)
302 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot
, VNetRoot
);
304 /* Insert in the VNetRoot list - make sure lock is held */
305 ASSERT(RxIsPrefixTableLockExclusive(NetRoot
->SrvCall
->RxDeviceObject
->pRxNetNameTable
));
307 VNetRoot
->pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
308 ++NetRoot
->NumberOfVirtualNetRoots
;
309 InsertTailList(&NetRoot
->VirtualNetRoots
, &VNetRoot
->NetRootListEntry
);
317 PRDBSS_DEVICE_OBJECT RxDeviceObject
,
318 NODE_TYPE_CODE NodeType
,
321 PVOID AlreadyAllocatedObject
)
326 PVOID Buffer
, PAPNBuffer
;
327 PNON_PAGED_FCB NonPagedFcb
;
328 PMINIRDR_DISPATCH Dispatch
;
329 ULONG NonPagedSize
, FobxSize
, SrvOpenSize
, FcbSize
;
333 Dispatch
= RxDeviceObject
->Dispatch
;
346 /* If we ask for FOBX, just allocate FOBX and its extension if asked */
347 if (NodeType
== RDBSS_NTC_FOBX
)
349 FobxSize
= sizeof(FOBX
);
350 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
352 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
355 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */
356 else if (NodeType
== RDBSS_NTC_SRVOPEN
|| NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
358 SrvOpenSize
= sizeof(SRV_OPEN
);
359 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
361 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
364 FobxSize
= sizeof(FOBX
);
365 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
367 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
370 /* Otherwise, we're asked to allocate a FCB */
373 /* So, allocate the FCB and its extension if asked */
374 FcbSize
= sizeof(FCB
);
375 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
377 FcbSize
+= QuadAlign(Dispatch
->MRxFcbSize
);
380 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB
381 * Otherwise, it will be allocated later on, specifically
383 if (PoolType
== NonPagedPool
)
385 NonPagedSize
= sizeof(NON_PAGED_FCB
);
388 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */
389 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
391 SrvOpenSize
= sizeof(SRV_OPEN
);
392 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
394 SrvOpenSize
+= QuadAlign(Dispatch
->MRxSrvOpenSize
);
397 FobxSize
= sizeof(FOBX
);
398 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
400 FobxSize
+= QuadAlign(Dispatch
->MRxFobxSize
);
405 /* If we already have a buffer, go ahead */
406 if (AlreadyAllocatedObject
!= NULL
)
408 Buffer
= AlreadyAllocatedObject
;
410 /* Otherwise, allocate it */
413 Buffer
= RxAllocatePoolWithTag(PoolType
, NameSize
+ FcbSize
+ SrvOpenSize
+ FobxSize
+ NonPagedSize
, RX_FCB_POOLTAG
);
420 /* Now, get the pointers - FOBX is easy */
421 if (NodeType
== RDBSS_NTC_FOBX
)
425 /* SRV_OPEN first, FOBX next */
426 else if (NodeType
== RDBSS_NTC_SRVOPEN
)
429 Fobx
= Add2Ptr(Buffer
, SrvOpenSize
);
431 else if (NodeType
== RDBSS_NTC_INTERNAL_SRVOPEN
)
437 /* FCB first, and if needed, SRV_OPEN next, FOBX last */
439 if (NodeType
!= RDBSS_NTC_OPENTARGETDIR_FCB
)
441 SrvOpen
= Add2Ptr(Buffer
, FcbSize
);
442 Fobx
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
);
445 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */
446 if (PoolType
!= NonPagedPool
)
448 NonPagedFcb
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(NON_PAGED_FCB
), RX_NONPAGEDFCB_POOLTAG
);
449 if (NonPagedFcb
== NULL
)
451 RxFreePoolWithTag(Buffer
, RX_FCB_POOLTAG
);
455 PAPNBuffer
= Add2Ptr(Buffer
, FcbSize
+ SrvOpenSize
+ FobxSize
);
457 /* Otherwise, just point at the right place in what has been allocated previously */
460 NonPagedFcb
= Add2Ptr(Fobx
, FobxSize
);
461 PAPNBuffer
= Add2Ptr(Fobx
, FobxSize
+ NonPagedSize
);
465 /* If we have allocated a SRV_OPEN, initialize it */
468 ZeroAndInitializeNodeType(SrvOpen
, RDBSS_NTC_SRVOPEN
, SrvOpenSize
);
470 if (NodeType
== RDBSS_NTC_SRVOPEN
)
472 SrvOpen
->InternalFobx
= Fobx
;
476 SrvOpen
->InternalFobx
= NULL
;
477 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
480 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_OPEN_EXTENSION
))
482 SrvOpen
->Context
= Add2Ptr(SrvOpen
, sizeof(SRV_OPEN
));
485 InitializeListHead(&SrvOpen
->SrvOpenQLinks
);
488 /* If we have allocated a FOBX, initialize it */
491 ZeroAndInitializeNodeType(Fobx
, RDBSS_NTC_FOBX
, FobxSize
);
493 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FOBX_EXTENSION
))
495 Fobx
->Context
= Add2Ptr(Fobx
, sizeof(FOBX
));
499 /* If we have allocated a FCB, initialize it */
502 ZeroAndInitializeNodeType(Fcb
, RDBSS_STORAGE_NTC(FileTypeNotYetKnown
), FcbSize
);
504 Fcb
->NonPaged
= NonPagedFcb
;
505 ZeroAndInitializeNodeType(Fcb
->NonPaged
, RDBSS_NTC_NONPAGED_FCB
, sizeof(NON_PAGED_FCB
));
507 Fcb
->CopyOfNonPaged
= NonPagedFcb
;
508 NonPagedFcb
->FcbBackPointer
= Fcb
;
511 Fcb
->InternalSrvOpen
= SrvOpen
;
512 Fcb
->InternalFobx
= Fobx
;
514 Fcb
->PrivateAlreadyPrefixedName
.Length
= NameSize
;
515 Fcb
->PrivateAlreadyPrefixedName
.MaximumLength
= NameSize
;
516 Fcb
->PrivateAlreadyPrefixedName
.Buffer
= PAPNBuffer
;
518 if (BooleanFlagOn(Dispatch
->MRxFlags
, RDBSS_MANAGE_FCB_EXTENSION
))
520 Fcb
->Context
= Add2Ptr(Fcb
, sizeof(FCB
));
523 ZeroAndInitializeNodeType(&Fcb
->FcbTableEntry
, RDBSS_NTC_FCB_TABLE_ENTRY
, sizeof(RX_FCB_TABLE_ENTRY
));
525 InterlockedIncrement(&RxNumberOfActiveFcbs
);
526 InterlockedIncrement((volatile long *)&RxDeviceObject
->NumberOfActiveFcbs
);
528 ExInitializeFastMutex(&NonPagedFcb
->AdvancedFcbHeaderMutex
);
529 FsRtlSetupAdvancedHeader(Fcb
, &NonPagedFcb
->AdvancedFcbHeaderMutex
);
532 DPRINT("Allocated %p\n", Buffer
);
542 NODE_TYPE_CODE NodeType
,
543 PMINIRDR_DISPATCH MRxDispatch
,
546 ULONG Tag
, ObjectSize
;
547 PVOID Object
, *Extension
;
548 PRX_PREFIX_ENTRY PrefixEntry
;
549 USHORT StructSize
, ExtensionSize
;
553 /* Select the node to allocate and always deal with the fact we may have to manage its extension */
557 case RDBSS_NTC_SRVCALL
:
558 Tag
= RX_SRVCALL_POOLTAG
;
559 StructSize
= sizeof(SRV_CALL
);
560 if (MRxDispatch
!= NULL
&& BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
562 ExtensionSize
= QuadAlign(MRxDispatch
->MRxSrvCallSize
);
566 case RDBSS_NTC_NETROOT
:
567 Tag
= RX_NETROOT_POOLTAG
;
568 StructSize
= sizeof(NET_ROOT
);
569 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_NET_ROOT_EXTENSION
))
571 ExtensionSize
= QuadAlign(MRxDispatch
->MRxNetRootSize
);
575 case RDBSS_NTC_V_NETROOT
:
576 Tag
= RX_V_NETROOT_POOLTAG
;
577 StructSize
= sizeof(V_NET_ROOT
);
578 if (BooleanFlagOn(MRxDispatch
->MRxFlags
, RDBSS_MANAGE_V_NET_ROOT_EXTENSION
))
580 ExtensionSize
= QuadAlign(MRxDispatch
->MRxVNetRootSize
);
589 /* Now, allocate the object */
590 ObjectSize
= ExtensionSize
+ StructSize
+ NameLength
;
591 Object
= RxAllocatePoolWithTag(NonPagedPool
, ObjectSize
, Tag
);
597 ZeroAndInitializeNodeType(Object
, NodeType
, ObjectSize
);
599 /* For SRV_CALL and NETROOT, the name points to the prefix table name */
602 case RDBSS_NTC_SRVCALL
:
603 PrefixEntry
= &((PSRV_CALL
)Object
)->PrefixEntry
;
604 Extension
= &((PSRV_CALL
)Object
)->Context
;
605 ((PSRV_CALL
)Object
)->pSrvCallName
= &PrefixEntry
->Prefix
;
608 case RDBSS_NTC_NETROOT
:
609 PrefixEntry
= &((PNET_ROOT
)Object
)->PrefixEntry
;
610 Extension
= &((PNET_ROOT
)Object
)->Context
;
611 ((PNET_ROOT
)Object
)->pNetRootName
= &PrefixEntry
->Prefix
;
614 case RDBSS_NTC_V_NETROOT
:
615 PrefixEntry
= &((PV_NET_ROOT
)Object
)->PrefixEntry
;
616 Extension
= &((PV_NET_ROOT
)Object
)->Context
;
624 /* Set the prefix table unicode string */
625 RtlZeroMemory(PrefixEntry
, sizeof(RX_PREFIX_ENTRY
));
626 PrefixEntry
->NodeTypeCode
= RDBSS_NTC_PREFIX_ENTRY
;
627 PrefixEntry
->NodeByteSize
= sizeof(RX_PREFIX_ENTRY
);
628 PrefixEntry
->Prefix
.Length
= NameLength
;
629 PrefixEntry
->Prefix
.MaximumLength
= NameLength
;
630 PrefixEntry
->Prefix
.Buffer
= Add2Ptr(Object
, ExtensionSize
+ StructSize
);
632 /* Return the extension if we are asked to manage it */
633 if (ExtensionSize
!= 0)
635 *Extension
= Add2Ptr(Object
, StructSize
);
654 /* If we're not asked to continue, just stop the system */
655 if (!RxContinueFromAssert
)
657 KeBugCheckEx(RDBSS_FILE_SYSTEM
, RDBSS_BUG_CHECK_ASSERT
| Line
, 0, 0, 0);
660 /* Otherwise, capture context to offer the user to dump it */
661 RtlCaptureContext(&Context
);
663 /* Loop until the user hits 'i' */
666 /* If no file provided, use empty name */
672 /* If no message provided, use empty one */
678 /* Display the message */
679 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message
, Assert
, File
, Line
);
680 /* And ask the user */
681 DbgPrompt("Break, Ignore (bi)? ", Response
, sizeof(Response
));
682 /* If he asks for ignore, quit
683 * In case of invalid input, ask again
685 if (Response
[0] != 'B' && Response
[0] != 'b')
687 if (Response
[0] == 'I' || Response
[0] == 'i')
695 /* Break: offer the user to dump the context and break */
696 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context
);
699 /* Continue looping, so that after dump, execution can continue (with ignore) */
708 RxBootstrapWorkerThreadDispatcher(
711 PRX_WORK_QUEUE RxWorkQueue
;
715 RxWorkQueue
= WorkQueue
;
716 RxpWorkerThreadDispatcher(RxWorkQueue
, NULL
);
723 RxCancelBlockingOperation(
724 IN OUT PRX_CONTEXT RxContext
)
730 C_ASSERT(FIELD_OFFSET(RX_CONTEXT
, IoStatusBlock
.Status
) == 0x0B0);
732 C_ASSERT(FIELD_OFFSET(RX_CONTEXT
, IoStatusBlock
.Status
) == 0x064);
737 Fobx
= (PFOBX
)RxContext
->pFobx
;
740 /* Acquire the pipe mutex */
741 ExAcquireFastMutex(&RxContextPerFileSerializationMutex
);
743 /* If that's a blocking pipe operation which is not the CCB one, then handle it */
744 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
) &&
745 RxContext
->RxContextSerializationQLinks
.Flink
!= NULL
&&
746 RxContext
!= CONTAINING_RECORD(&Fobx
->Specific
.NamedPipe
.ReadSerializationQueue
, RX_CONTEXT
, RxContextSerializationQLinks
) &&
747 RxContext
!= CONTAINING_RECORD(&Fobx
->Specific
.NamedPipe
.WriteSerializationQueue
, RX_CONTEXT
, RxContextSerializationQLinks
))
750 ClearFlag(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
);
752 /* Drop it off the list */
753 RemoveEntryList(&RxContext
->RxContextSerializationQLinks
);
754 RxContext
->RxContextSerializationQLinks
.Flink
= NULL
;
755 RxContext
->RxContextSerializationQLinks
.Blink
= NULL
;
757 /* Set we've been cancelled */
758 RxContext
->IoStatusBlock
.Status
= STATUS_CANCELLED
;
761 * If it's async, we'll post completion, otherwise, we signal to waiters
762 * it's being cancelled
764 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
770 RxSignalSynchronousWaiter(RxContext
);
775 ExReleaseFastMutex(&RxContextPerFileSerializationMutex
);
780 RxFsdPostRequest(RxContext
);
789 RxChangeBufferingState(
792 BOOLEAN ComputeNewState
)
795 NTSTATUS Status
, MiniStatus
;
796 ULONG NewBufferingState
, OldBufferingState
;
800 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen
, Context
, ComputeNewState
);
802 Fcb
= (PFCB
)SrvOpen
->pFcb
;
803 ASSERT(NodeTypeIsFcb(Fcb
));
804 /* First of all, mark that buffering state is changing */
805 SetFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
808 Status
= STATUS_SUCCESS
;
811 /* If we're asked to compute a new state, ask the mini-rdr for it */
814 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxComputeNewBufferingState
,
815 ((PMRX_SRV_OPEN
)SrvOpen
, Context
, &NewBufferingState
));
816 if (MiniStatus
!= STATUS_SUCCESS
)
818 NewBufferingState
= 0;
823 /* If not, use SRV_OPEN state */
824 NewBufferingState
= SrvOpen
->BufferingFlags
;
827 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */
828 if ((Fcb
->ShareAccess
.SharedRead
+ Fcb
->ShareAccess
.SharedWrite
+ Fcb
->ShareAccess
.SharedDelete
) == 0 && !ComputeNewState
)
830 SetFlag(NewBufferingState
, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES
);
833 /* If there's a lock operation to complete, clear that flag */
834 if (Fcb
->OutstandingLockOperationsCount
!= 0)
836 ClearFlag(NewBufferingState
, FCB_STATE_LOCK_BUFFERING_ENABLED
);
839 /* Get the old state */
840 OldBufferingState
= Fcb
->FcbState
& FCB_STATE_BUFFERING_STATE_MASK
;
841 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState
, NewBufferingState
, SrvOpen
->BufferingFlags
);
843 /* If we're dropping write cache, then flush the FCB */
844 if (BooleanFlagOn(OldBufferingState
, FCB_STATE_WRITECACHING_ENABLED
) &&
845 !BooleanFlagOn(NewBufferingState
, FCB_STATE_WRITECACHING_ENABLED
))
847 DPRINT("Flushing\n");
849 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
852 /* If we're dropping read cache, then purge */
853 if (Fcb
->UncleanCount
== 0 ||
854 (BooleanFlagOn(OldBufferingState
, FCB_STATE_READCACHING_ENABLED
) &&
855 !BooleanFlagOn(NewBufferingState
, FCB_STATE_READCACHING_ENABLED
)) ||
856 BooleanFlagOn(NewBufferingState
, FCB_STATE_DELETE_ON_CLOSE
))
860 if (!NT_SUCCESS(Status
))
862 DPRINT("Previous flush failed with status: %lx\n", Status
);
865 CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, TRUE
);
868 /* If there's already a change pending in SRV_OPEN */
869 if (ComputeNewState
&& BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
871 /* If there's a FOBX at least */
872 if (!IsListEmpty(&SrvOpen
->FobxList
))
874 PRX_CONTEXT RxContext
;
876 /* Create a fake context to pass to the mini-rdr */
877 RxContext
= RxCreateRxContext(NULL
, Fcb
->RxDeviceObject
, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING
| RX_CONTEXT_FLAG_WAIT
);
878 if (RxContext
!= NULL
)
882 RxContext
->pFcb
= RX_GET_MRX_FCB(Fcb
);
884 /* Give the first FOBX */
885 Fobx
= CONTAINING_RECORD(SrvOpen
->FobxList
.Flink
, FOBX
, FobxQLinks
);
886 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
887 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
889 /* If there was a delayed close, perform it */
890 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_CLOSE_DELAYED
))
892 DPRINT("Oplock break close for %p\n", SrvOpen
);
894 RxCloseAssociatedSrvOpen(Fobx
, RxContext
);
896 /* Otherwise, inform the mini-rdr about completion */
899 MINIRDR_CALL_THROUGH(MiniStatus
, Fcb
->MRxDispatch
, MRxCompleteBufferingStateChangeRequest
,
900 (RxContext
, (PMRX_SRV_OPEN
)SrvOpen
, Context
));
904 RxDereferenceAndDeleteRxContext(RxContext
);
909 /* Set the new state */
910 Fcb
->FcbState
^= (NewBufferingState
^ Fcb
->FcbState
) & FCB_STATE_BUFFERING_STATE_MASK
;
914 /* Job done, clear the flag */
915 ClearFlag(Fcb
->FcbState
, FCB_STATE_BUFFERSTATE_CHANGING
);
917 if (!BooleanFlagOn(NewBufferingState
, FCB_STATE_FILETIMECACHEING_ENABLED
))
919 ClearFlag(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
);
928 RxCheckVNetRootCredentials(
929 PRX_CONTEXT RxContext
,
930 PV_NET_ROOT VNetRoot
,
932 PUNICODE_STRING UserName
,
933 PUNICODE_STRING UserDomain
,
934 PUNICODE_STRING Password
,
939 /* If that's a UNC name, there's nothing to process */
940 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
) &&
941 (BooleanFlagOn(VNetRoot
->Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
) ||
944 return STATUS_MORE_PROCESSING_REQUIRED
;
947 /* Compare the logon ID in the VNetRoot with the one provided */
948 if (RtlCompareMemory(&VNetRoot
->LogonId
, LogonId
, sizeof(LUID
)) != sizeof(LUID
))
950 return STATUS_MORE_PROCESSING_REQUIRED
;
953 /* No credential provided? That's OK */
954 if (UserName
== NULL
&& UserDomain
== NULL
&& Password
== NULL
)
956 return STATUS_SUCCESS
;
961 return STATUS_NOT_IMPLEMENTED
;
973 DPRINT("RxCompleteRequest(%p, %lx)\n", Context
, Status
);
975 ASSERT(Context
!= NULL
);
976 ASSERT(Context
->CurrentIrp
!= NULL
);
977 Irp
= Context
->CurrentIrp
;
979 /* Debug what the caller asks for */
980 if (Context
->LoudCompletionString
!= NULL
)
982 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
983 /* Does the user asks to stop on failed completion */
984 if (!NT_SUCCESS(Status
) && RxStopOnLoudCompletion
)
986 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status
, Irp
->IoStatus
.Information
, Context
->LoudCompletionString
);
990 /* Complete for real */
991 Context
->CurrentIrp
= NULL
;
992 RxCompleteRequest_Real(Context
, Irp
, Status
);
994 DPRINT("Status: %lx\n", Status
);
1002 RxCompleteRequest_Real(
1003 IN PRX_CONTEXT RxContext
,
1009 PIO_STACK_LOCATION Stack
;
1011 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext
, Irp
, Status
);
1013 /* Nothing to complete, just free context */
1016 DPRINT("NULL IRP for %p\n", RxContext
);
1017 if (RxContext
!= NULL
)
1019 RxDereferenceAndDeleteRxContext_Real(RxContext
);
1025 /* Remove cancel routine */
1026 IoAcquireCancelSpinLock(&OldIrql
);
1027 IoSetCancelRoutine(Irp
, NULL
);
1028 IoReleaseCancelSpinLock(OldIrql
);
1030 /* Select the boost, given the success/paging operation */
1031 if (NT_SUCCESS(Status
) || !BooleanFlagOn(Irp
->Flags
, IRP_SYNCHRONOUS_PAGING_IO
))
1033 Boost
= IO_DISK_INCREMENT
;
1037 Irp
->IoStatus
.Information
= 0;
1038 Boost
= IO_NO_INCREMENT
;
1040 Irp
->IoStatus
.Status
= Status
;
1042 if (RxContext
!= NULL
)
1044 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
1045 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
1047 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n",
1048 RxContext
->MinorFunction
, RxContext
, Irp
,
1049 Status
, Irp
->IoStatus
.Information
, RxContext
->SerialNumber
);
1053 /* If that's an opening, there might be a canonical name allocated,
1054 * if completion isn't pending, release it
1056 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1057 if (Stack
->MajorFunction
== IRP_MJ_CREATE
&& Status
!= STATUS_PENDING
&&
1060 if (BooleanFlagOn(RxContext
->Create
.Flags
, 2))
1062 Stack
->FileObject
->FileName
.Length
+= sizeof(WCHAR
);
1065 RxpPrepareCreateContextForReuse(RxContext
);
1066 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
1069 /* If it's a write, validate the correct behavior of the operation */
1070 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
1072 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
1074 ASSERT(Irp
->IoStatus
.Information
<= Stack
->Parameters
.Write
.Length
);
1078 /* If it's pending, make sure IRP is marked as such */
1079 if (RxContext
!= NULL
)
1081 if (RxContext
->PendingReturned
)
1083 ASSERT(BooleanFlagOn(Stack
->Control
, SL_PENDING_RETURNED
));
1088 DPRINT("Completing IRP with %x/%x\n", Irp
->IoStatus
.Status
, Irp
->IoStatus
.Information
);
1089 IoCompleteRequest(Irp
, Boost
);
1091 /* If there's a context, dereference it */
1092 if (RxContext
!= NULL
)
1094 RxDereferenceAndDeleteRxContext_Real(RxContext
);
1102 RxCompleteSrvOpenKeyAssociation(
1103 IN OUT PSRV_OPEN SrvOpen
)
1107 SrvCall
= (PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
;
1108 /* Only handle requests if opening was a success */
1109 if (SrvOpen
->Condition
== Condition_Good
)
1112 BOOLEAN ProcessChange
;
1113 LIST_ENTRY DiscardedRequests
;
1115 /* Initialize our discarded requests list */
1116 InitializeListHead(&DiscardedRequests
);
1118 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
1120 /* Transfer our requests in the SRV_CALL */
1121 RxTransferList(&SrvCall
->BufferingManager
.SrvOpenLists
[0], &SrvOpen
->SrvOpenKeyList
);
1123 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */
1124 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
1126 /* Dispatch requests and get the discarded ones */
1127 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &DiscardedRequests
);
1129 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
1131 /* Is there still anything to process? */
1132 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
1133 if (IsListEmpty(&SrvCall
->BufferingManager
.HandlerList
))
1135 ProcessChange
= FALSE
;
1139 ProcessChange
= (SrvCall
->BufferingManager
.HandlerInactive
== FALSE
);
1142 SrvCall
->BufferingManager
.HandlerInactive
= TRUE
;
1145 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
1147 /* Yes? Go ahead! */
1150 RxReferenceSrvCall(SrvCall
);
1151 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
1152 &SrvCall
->BufferingManager
.HandlerWorkItem
,
1153 RxProcessChangeBufferingStateRequests
, SrvCall
);
1156 /* And discard left requests */
1157 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests
);
1161 InterlockedDecrement(&SrvCall
->BufferingManager
.NumberOfOutstandingOpens
);
1170 IN PRX_CONTEXT RxContext
,
1171 IN PSRV_CALL SrvCall
,
1172 IN PNET_ROOT NetRoot
,
1173 IN PV_NET_ROOT VirtualNetRoot
,
1174 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1177 PRX_PREFIX_TABLE PrefixTable
;
1178 PMRX_CREATENETROOT_CONTEXT Context
;
1179 RX_BLOCK_CONDITION RootCondition
, VRootCondition
;
1183 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext
, SrvCall
, NetRoot
,
1184 VirtualNetRoot
, LockHoldingState
);
1186 /* Validate the lock is exclusively held */
1187 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
1188 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1190 /* Allocate the context */
1191 Context
= RxAllocatePoolWithTag(PagedPool
, sizeof(MRX_CREATENETROOT_CONTEXT
), RX_SRVCALL_POOLTAG
);
1192 if (Context
== NULL
)
1194 return STATUS_INSUFFICIENT_RESOURCES
;
1197 /* We can release lock now */
1198 RxReleasePrefixTableLock(PrefixTable
);
1199 *LockHoldingState
= LHS_LockNotHeld
;
1201 RootCondition
= Condition_Bad
;
1202 VRootCondition
= Condition_Bad
;
1204 /* Initialize the context */
1205 RtlZeroMemory(Context
, sizeof(MRX_CREATENETROOT_CONTEXT
));
1206 KeInitializeEvent(&Context
->FinishEvent
, SynchronizationEvent
, FALSE
);
1207 Context
->RxContext
= RxContext
;
1208 Context
->pVNetRoot
= VirtualNetRoot
;
1209 Context
->Callback
= RxCreateNetRootCallBack
;
1211 /* And call the mini-rdr */
1212 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
, MRxCreateVNetRoot
, (Context
));
1213 if (Status
== STATUS_PENDING
)
1215 /* Wait for the mini-rdr to be done */
1216 KeWaitForSingleObject(&Context
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1217 /* Update the structures condition according to mini-rdr return */
1218 if (NT_SUCCESS(Context
->NetRootStatus
))
1220 if (NT_SUCCESS(Context
->VirtualNetRootStatus
))
1222 RootCondition
= Condition_Good
;
1223 VRootCondition
= Condition_Good
;
1224 Status
= STATUS_SUCCESS
;
1228 RootCondition
= Condition_Good
;
1229 Status
= Context
->VirtualNetRootStatus
;
1234 Status
= Context
->VirtualNetRootStatus
;
1235 if (NT_SUCCESS(Status
))
1237 Status
= Context
->NetRootStatus
;
1243 /* It has to return STATUS_PENDING! */
1247 /* Acquire lock again - for caller lock status will remain unchanged */
1248 ASSERT(*LockHoldingState
== LHS_LockNotHeld
);
1249 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
1250 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1252 /* Do the transition to the condition got from mini-rdr */
1253 RxTransitionNetRoot(NetRoot
, RootCondition
);
1254 RxTransitionVNetRoot(VirtualNetRoot
, VRootCondition
);
1256 /* Context is not longer needed */
1257 RxFreePoolWithTag(Context
, RX_SRVCALL_POOLTAG
);
1259 DPRINT("Status: %x\n", Status
);
1269 IN PRX_CONTEXT RxContext
,
1270 IN PSRV_CALL SrvCall
,
1271 OUT PLOCK_HOLDING_STATE LockHoldingState
)
1274 PRX_PREFIX_TABLE PrefixTable
;
1275 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1276 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1277 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext
;
1281 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext
, SrvCall
, LockHoldingState
);
1283 /* Validate the lock is exclusively held */
1284 RxDeviceObject
= RxContext
->RxDeviceObject
;
1285 PrefixTable
= RxDeviceObject
->pRxNetNameTable
;
1286 ASSERT(*LockHoldingState
== LHS_ExclusiveLockHeld
);
1288 /* Allocate the context for mini-rdr */
1289 Calldown
= RxAllocatePoolWithTag(NonPagedPool
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
), RX_SRVCALL_POOLTAG
);
1290 if (Calldown
== NULL
)
1292 SrvCall
->Context
= NULL
;
1293 SrvCall
->Condition
= Condition_Bad
;
1294 RxReleasePrefixTableLock(PrefixTable
);
1295 *LockHoldingState
= LHS_LockNotHeld
;
1296 return STATUS_INSUFFICIENT_RESOURCES
;
1300 RtlZeroMemory(Calldown
, sizeof(MRX_SRVCALLDOWN_STRUCTURE
));
1302 SrvCall
->Context
= NULL
;
1303 SrvCall
->Condition
= Condition_InTransition
;
1305 RxReleasePrefixTableLock(PrefixTable
);
1306 *LockHoldingState
= LHS_LockNotHeld
;
1308 CallbackContext
= &Calldown
->CallbackContexts
[0];
1309 DPRINT("CalldownContext %p for %wZ\n", CallbackContext
, &RxDeviceObject
->DeviceName
);
1310 DPRINT("With calldown %p and SrvCall %p\n", Calldown
, SrvCall
);
1311 CallbackContext
->SrvCalldownStructure
= Calldown
;
1312 CallbackContext
->CallbackContextOrdinal
= 0;
1313 CallbackContext
->RxDeviceObject
= RxDeviceObject
;
1315 RxReferenceSrvCall(SrvCall
);
1317 /* If we're async, we'll post, otherwise, we'll have to wait for completion */
1318 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1320 RxPrePostIrp(RxContext
, RxContext
->CurrentIrp
);
1324 KeInitializeEvent(&Calldown
->FinishEvent
, SynchronizationEvent
, FALSE
);
1327 Calldown
->NumberToWait
= 1;
1328 Calldown
->NumberRemaining
= 1;
1329 Calldown
->RxContext
= RxContext
;
1330 Calldown
->SrvCall
= (PMRX_SRV_CALL
)SrvCall
;
1331 Calldown
->CallBack
= RxCreateSrvCallCallBack
;
1332 Calldown
->BestFinisher
= NULL
;
1333 CallbackContext
->Status
= STATUS_BAD_NETWORK_PATH
;
1334 InitializeListHead(&Calldown
->SrvCalldownList
);
1336 /* Call the mini-rdr */
1337 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
1338 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
1339 ASSERT(RxDeviceObject
->Dispatch
->MRxCreateSrvCall
!= NULL
);
1340 Status
= RxDeviceObject
->Dispatch
->MRxCreateSrvCall((PMRX_SRV_CALL
)SrvCall
, CallbackContext
);
1341 /* It has to return STATUS_PENDING! */
1342 ASSERT(Status
== STATUS_PENDING
);
1344 /* No async, start completion */
1345 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1347 KeWaitForSingleObject(&Calldown
->FinishEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1349 /* Finish construction - we'll notify mini-rdr it's the winner */
1350 Status
= RxFinishSrvCallConstruction(Calldown
);
1351 if (!NT_SUCCESS(Status
))
1353 RxReleasePrefixTableLock(PrefixTable
);
1354 *LockHoldingState
= LHS_LockNotHeld
;
1358 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
1359 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1363 DPRINT("RxConstructSrvCall() = Status: %x\n", Status
);
1371 RxConstructVirtualNetRoot(
1372 IN PRX_CONTEXT RxContext
,
1373 IN PUNICODE_STRING CanonicalName
,
1374 IN NET_ROOT_TYPE NetRootType
,
1375 OUT PV_NET_ROOT
*VirtualNetRootPointer
,
1376 OUT PLOCK_HOLDING_STATE LockHoldingState
,
1377 OUT PRX_CONNECTION_ID RxConnectionId
)
1380 PV_NET_ROOT VNetRoot
;
1381 RX_BLOCK_CONDITION Condition
;
1382 UNICODE_STRING LocalNetRootName
, FilePathName
;
1386 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1389 Condition
= Condition_Bad
;
1390 /* Before creating the VNetRoot, try to find the appropriate connection */
1391 Status
= RxFindOrCreateConnections(RxContext
, CanonicalName
, NetRootType
,
1392 &LocalNetRootName
, &FilePathName
,
1393 LockHoldingState
, RxConnectionId
);
1394 /* Found and active */
1395 if (Status
== STATUS_CONNECTION_ACTIVE
)
1397 /* We need a new VNetRoot */
1398 VNetRoot
= RxCreateVNetRoot(RxContext
, (PNET_ROOT
)RxContext
->Create
.pVNetRoot
->pNetRoot
,
1399 CanonicalName
, &LocalNetRootName
, &FilePathName
, RxConnectionId
);
1400 if (VNetRoot
!= NULL
)
1402 RxReferenceVNetRoot(VNetRoot
);
1405 /* Dereference previous VNetRoot */
1406 RxDereferenceVNetRoot(RxContext
->Create
.pVNetRoot
->pNetRoot
, *LockHoldingState
);
1407 /* Reset and start construct (new structures will replace old ones) */
1408 RxContext
->Create
.pSrvCall
= NULL
;
1409 RxContext
->Create
.pNetRoot
= NULL
;
1410 RxContext
->Create
.pVNetRoot
= NULL
;
1412 /* Construct new NetRoot */
1413 if (VNetRoot
!= NULL
)
1415 Status
= RxConstructNetRoot(RxContext
, (PSRV_CALL
)VNetRoot
->pNetRoot
->pSrvCall
,
1416 (PNET_ROOT
)VNetRoot
->pNetRoot
, VNetRoot
, LockHoldingState
);
1417 if (NT_SUCCESS(Status
))
1419 Condition
= Condition_Good
;
1424 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1429 /* If it failed creating the connection, leave */
1430 if (Status
!= STATUS_SUCCESS
)
1432 if (*LockHoldingState
!= LHS_LockNotHeld
)
1434 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1435 *LockHoldingState
= LHS_LockNotHeld
;
1438 *VirtualNetRootPointer
= VNetRoot
;
1439 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status
);
1443 *LockHoldingState
= LHS_ExclusiveLockHeld
;
1445 VNetRoot
= (PV_NET_ROOT
)RxContext
->Create
.pVNetRoot
;
1446 Condition
= Condition_Good
;
1449 /* We have a non stable VNetRoot - transition it */
1450 if (VNetRoot
!= NULL
&& !StableCondition(VNetRoot
->Condition
))
1452 RxTransitionVNetRoot(VNetRoot
, Condition
);
1455 /* If recreation failed */
1456 if (Status
!= STATUS_SUCCESS
)
1458 /* Dereference potential VNetRoot */
1459 if (VNetRoot
!= NULL
)
1461 ASSERT(*LockHoldingState
!= LHS_LockNotHeld
);
1462 RxDereferenceVNetRoot(VNetRoot
, *LockHoldingState
);
1467 if (*LockHoldingState
!= LHS_LockNotHeld
)
1469 RxReleasePrefixTableLock(RxContext
->RxDeviceObject
->pRxNetNameTable
);
1470 *LockHoldingState
= LHS_LockNotHeld
;
1474 *VirtualNetRootPointer
= VNetRoot
;
1478 /* Return the allocated VNetRoot */
1479 *VirtualNetRootPointer
= VNetRoot
;
1488 IN PRX_CONTEXT RxContext
,
1489 IN PV_NET_ROOT VNetRoot
,
1490 IN PUNICODE_STRING Name
)
1496 NODE_TYPE_CODE NodeType
;
1497 PIO_STACK_LOCATION Stack
;
1498 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
1502 /* We need a decent VNetRoot */
1503 ASSERT(VNetRoot
!= NULL
&& NodeType(VNetRoot
) == RDBSS_NTC_V_NETROOT
);
1505 NetRoot
= (PNET_ROOT
)VNetRoot
->pNetRoot
;
1506 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
1507 ASSERT((PMRX_NET_ROOT
)NetRoot
== RxContext
->Create
.pNetRoot
);
1509 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
1510 ASSERT(RxDeviceObject
== RxContext
->RxDeviceObject
);
1512 Stack
= RxContext
->CurrentIrpSp
;
1514 /* Do we need to create a fake FCB? Like for renaming */
1515 FakeFcb
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
) &&
1516 !BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS
);
1517 ASSERT(FakeFcb
|| RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
1519 PoolType
= (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1520 NodeType
= (FakeFcb
) ? RDBSS_NTC_OPENTARGETDIR_FCB
: RDBSS_STORAGE_NTC(FileTypeNotYetKnown
);
1522 /* Allocate the FCB */
1523 Fcb
= RxAllocateFcbObject(RxDeviceObject
, NodeType
, PoolType
,
1524 NetRoot
->InnerNamePrefix
.Length
+ Name
->Length
, NULL
);
1530 /* Initialize the FCB */
1531 Fcb
->CachedNetRootType
= NetRoot
->Type
;
1532 Fcb
->RxDeviceObject
= RxDeviceObject
;
1533 Fcb
->MRxDispatch
= RxDeviceObject
->Dispatch
;
1534 Fcb
->VNetRoot
= VNetRoot
;
1535 Fcb
->pNetRoot
= VNetRoot
->pNetRoot
;
1537 InitializeListHead(&Fcb
->SrvOpenList
);
1538 Fcb
->SrvOpenListVersion
= 0;
1540 Fcb
->FcbTableEntry
.Path
.Length
= Name
->Length
;
1541 Fcb
->FcbTableEntry
.Path
.MaximumLength
= Name
->Length
;
1542 Fcb
->FcbTableEntry
.Path
.Buffer
= Add2Ptr(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Length
);
1543 RtlMoveMemory(Fcb
->PrivateAlreadyPrefixedName
.Buffer
, NetRoot
->InnerNamePrefix
.Buffer
,
1544 NetRoot
->InnerNamePrefix
.Length
);
1545 RtlMoveMemory(Fcb
->FcbTableEntry
.Path
.Buffer
, Name
->Buffer
, Name
->Length
);
1547 /* Copy back parameters from RxContext */
1548 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH
))
1550 Fcb
->FcbState
|= FCB_STATE_ADDEDBACKSLASH
;
1553 InitializeListHead(&Fcb
->NonPaged
->TransitionWaitList
);
1555 if (BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
))
1557 Fcb
->FcbState
|= FCB_STATE_PAGING_FILE
;
1560 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
&& BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH
))
1562 Fcb
->FcbState
|= FCB_STATE_SPECIAL_PATH
;
1565 Fcb
->Header
.Resource
= &Fcb
->NonPaged
->HeaderResource
;
1566 ExInitializeResourceLite(Fcb
->Header
.Resource
);
1568 Fcb
->Header
.PagingIoResource
= &Fcb
->NonPaged
->PagingIoResource
;
1569 ExInitializeResourceLite(Fcb
->Header
.PagingIoResource
);
1571 Fcb
->BufferedLocks
.Resource
= &Fcb
->NonPaged
->BufferedLocksResource
;
1572 ExInitializeResourceLite(Fcb
->BufferedLocks
.Resource
);
1574 /* Fake FCB doesn't go in prefix table */
1577 Fcb
->FcbState
|= (FCB_STATE_FAKEFCB
| FCB_STATE_NAME_ALREADY_REMOVED
);
1578 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
1579 DPRINT("Fake FCB: %p\n", Fcb
);
1583 RxFcbTableInsertFcb(&NetRoot
->FcbTable
, Fcb
);
1586 RxReferenceVNetRoot(VNetRoot
);
1587 InterlockedIncrement((volatile long *)&Fcb
->pNetRoot
->NumberOfFcbs
);
1589 Fcb
->ulFileSizeVersion
= 0;
1591 DPRINT("FCB %p for %wZ\n", Fcb
, &Fcb
->FcbTableEntry
.Path
);
1592 RxReferenceNetFcb(Fcb
);
1603 OUT PRX_CONTEXT RxContext
,
1604 IN PMRX_SRV_OPEN MrxSrvOpen
)
1615 SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1616 ASSERT(NodeType(SrvOpen
) == RDBSS_NTC_SRVOPEN
);
1617 ASSERT(NodeTypeIsFcb(SrvOpen
->Fcb
));
1618 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
1621 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1622 /* Can we use pre-allocated FOBX? */
1623 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_FOBX_USED
) && Fcb
->InternalSrvOpen
== (PSRV_OPEN
)MrxSrvOpen
)
1625 Fobx
= Fcb
->InternalFobx
;
1626 /* Call allocate to initialize the FOBX */
1627 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1628 /* Mark it used now */
1629 Fcb
->FcbState
|= FCB_STATE_FOBX_USED
;
1630 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1632 else if (!BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
))
1634 Fobx
= SrvOpen
->InternalFobx
;
1635 /* Call allocate to initialize the FOBX */
1636 RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, Fobx
);
1637 /* Mark it used now */
1638 SrvOpen
->Flags
|= SRVOPEN_FLAG_FOBX_USED
;
1639 Flags
= FOBX_FLAG_ENCLOSED_ALLOCATED
;
1643 /* Last case, we cannot, allocate a FOBX */
1644 Fobx
= RxAllocateFcbObject(Fcb
->RxDeviceObject
, RDBSS_NTC_FOBX
, PoolType
, 0, NULL
);
1648 /* Allocation failed! */
1655 Fobx
->Flags
= Flags
;
1657 /* Initialize throttling */
1658 NetRoot
= (PNET_ROOT
)RxContext
->Create
.pNetRoot
;
1659 if (NetRoot
!= NULL
)
1661 if (NetRoot
->DeviceType
== FILE_DEVICE_DISK
)
1663 RxInitializeThrottlingState(&Fobx
->Specific
.DiskFile
.LockThrottlingState
,
1664 NetRoot
->DiskParameters
.LockThrottlingParameters
.Increment
,
1665 NetRoot
->DiskParameters
.LockThrottlingParameters
.MaximumDelay
);
1667 else if (NetRoot
->DeviceType
== FILE_DEVICE_NAMED_PIPE
)
1669 RxInitializeThrottlingState(&Fobx
->Specific
.NamedPipe
.ThrottlingState
,
1670 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.Increment
,
1671 NetRoot
->NamedPipeParameters
.PipeReadThrottlingParameters
.MaximumDelay
);
1675 /* Propagate flags fron RxContext */
1676 if (BooleanFlagOn(RxContext
->Create
.Flags
, RX_CONTEXT_CREATE_FLAG_UNC_NAME
))
1678 Fobx
->Flags
|= FOBX_FLAG_UNC_NAME
;
1681 if (BooleanFlagOn(RxContext
->Create
.NtCreateParameters
.CreateOptions
, FILE_OPEN_FOR_BACKUP_INTENT
))
1683 Fobx
->Flags
|= FOBX_FLAG_BACKUP_INTENT
;
1687 Fobx
->FobxSerialNumber
= 0;
1688 Fobx
->SrvOpen
= (PSRV_OPEN
)MrxSrvOpen
;
1689 Fobx
->NodeReferenceCount
= 1;
1690 Fobx
->RxDeviceObject
= Fcb
->RxDeviceObject
;
1692 RxReferenceSrvOpen(SrvOpen
);
1693 InterlockedIncrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
1695 InsertTailList(&SrvOpen
->FobxList
, &Fobx
->FobxQLinks
);
1696 InitializeListHead(&Fobx
->ScavengerFinalizationList
);
1697 InitializeListHead(&Fobx
->ClosePendingList
);
1699 Fobx
->CloseTime
.QuadPart
= 0;
1700 Fobx
->fOpenCountDecremented
= FALSE
;
1702 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx
, Fobx
->SrvOpen
, Fobx
->SrvOpen
->pFcb
);
1704 return (PMRX_FOBX
)Fobx
;
1712 IN PSRV_CALL SrvCall
,
1713 IN PUNICODE_STRING Name
,
1714 IN ULONG NetRootFlags
,
1715 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
1718 USHORT CaseInsensitiveLength
;
1719 PRX_PREFIX_TABLE PrefixTable
;
1721 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall
, Name
, NetRootFlags
, RxConnectionId
);
1725 /* We need a SRV_CALL */
1726 ASSERT(SrvCall
!= NULL
);
1728 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
1729 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
1731 /* Get name length */
1732 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.Prefix
.Length
+ Name
->Length
;
1733 if (CaseInsensitiveLength
> MAXUSHORT
)
1738 /* Allocate the NetRoot */
1739 NetRoot
= RxAllocateObject(RDBSS_NTC_NETROOT
, SrvCall
->RxDeviceObject
->Dispatch
,
1740 CaseInsensitiveLength
);
1741 if (NetRoot
== NULL
)
1746 /* Construct name */
1747 RtlMoveMemory(Add2Ptr(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Length
),
1748 Name
->Buffer
, Name
->Length
);
1749 if (SrvCall
->PrefixEntry
.Prefix
.Length
!= 0)
1751 RtlMoveMemory(NetRoot
->PrefixEntry
.Prefix
.Buffer
, SrvCall
->PrefixEntry
.Prefix
.Buffer
,
1752 SrvCall
->PrefixEntry
.Prefix
.Length
);
1755 if (!BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
1757 CaseInsensitiveLength
= SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
1759 /* Inisert in prefix table */
1760 RxPrefixTableInsertName(PrefixTable
, &NetRoot
->PrefixEntry
, NetRoot
,
1761 (PULONG
)&NetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
1764 /* Prepare the FCB table */
1765 RxInitializeFcbTable(&NetRoot
->FcbTable
, TRUE
);
1767 InitializeListHead(&NetRoot
->TransitionWaitList
);
1768 InitializeListHead(&NetRoot
->ScavengerFinalizationList
);
1769 InitializeListHead(&NetRoot
->VirtualNetRoots
);
1771 RxInitializePurgeSyncronizationContext(&NetRoot
->PurgeSyncronizationContext
);
1773 NetRoot
->SerialNumberForEnum
= SerialNumber
++;
1774 NetRoot
->Flags
|= NetRootFlags
;
1775 NetRoot
->DiskParameters
.ClusterSize
= 1;
1776 NetRoot
->DiskParameters
.ReadAheadGranularity
= ReadAheadGranularity
;
1777 NetRoot
->SrvCall
= SrvCall
;
1779 RxReferenceSrvCall(SrvCall
);
1781 DPRINT("NetRootName: %wZ (%p)\n", NetRoot
->pNetRootName
, NetRoot
);
1790 RxCreateNetRootCallBack(
1791 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext
)
1795 KeSetEvent(&CreateNetRootContext
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1805 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
1806 IN ULONG InitialContextFlags
)
1809 PRX_CONTEXT Context
;
1811 ASSERT(RxDeviceObject
!= NULL
);
1813 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp
, RxDeviceObject
, InitialContextFlags
);
1816 InterlockedIncrement((volatile LONG
*)&RxFsdEntryCount
);
1818 InterlockedIncrement((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
);
1820 /* Allocate the context from our lookaside list */
1821 Context
= ExAllocateFromNPagedLookasideList(&RxContextLookasideList
);
1822 if (Context
== NULL
)
1828 RtlZeroMemory(Context
, sizeof(RX_CONTEXT
));
1830 /* It was allocated on NP pool, keep track of it! */
1831 SetFlag(Context
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
1832 /* And initialize it */
1833 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, Context
);
1834 ASSERT((Context
->MajorFunction
!= IRP_MJ_CREATE
) || !BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED
));
1836 /* Add it to our global list */
1837 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1838 InsertTailList(&RxActiveContexts
, &Context
->ContextListEntry
);
1839 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1841 DPRINT("Context: %p\n", Context
);
1850 IN PRX_CONTEXT RxContext
,
1851 IN PUNICODE_STRING Name
,
1852 IN PUNICODE_STRING InnerNamePrefix OPTIONAL
,
1853 IN PRX_CONNECTION_ID RxConnectionId
)
1860 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext
, Name
, InnerNamePrefix
, RxConnectionId
);
1862 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
1864 /* Get the name length */
1865 NameLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1866 if (InnerNamePrefix
!= NULL
)
1868 NameLength
+= InnerNamePrefix
->Length
;
1871 /* Allocate the object */
1872 SrvCall
= RxAllocateObject(RDBSS_NTC_SRVCALL
, NULL
, NameLength
);
1873 if (SrvCall
== NULL
)
1879 SrvCall
->SerialNumberForEnum
= SerialNumber
++;
1880 SrvCall
->RxDeviceObject
= RxContext
->RxDeviceObject
;
1881 RxInitializeBufferingManager(SrvCall
);
1882 InitializeListHead(&SrvCall
->TransitionWaitList
);
1883 InitializeListHead(&SrvCall
->ScavengerFinalizationList
);
1884 RxInitializePurgeSyncronizationContext(&SrvCall
->PurgeSyncronizationContext
);
1885 RxInitializeSrvCallParameters(RxContext
, SrvCall
);
1886 RtlMoveMemory(SrvCall
->PrefixEntry
.Prefix
.Buffer
, Name
->Buffer
, Name
->Length
);
1887 SrvCall
->PrefixEntry
.Prefix
.MaximumLength
= Name
->Length
+ 2 * sizeof(WCHAR
);
1888 SrvCall
->PrefixEntry
.Prefix
.Length
= Name
->Length
;
1889 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &SrvCall
->PrefixEntry
,
1890 SrvCall
, (PULONG
)&SrvCall
->NodeReferenceCount
, Name
->Length
, RxConnectionId
);
1892 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall
->pSrvCallName
, SrvCall
);
1901 RxCreateSrvCallCallBack(
1902 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context
)
1906 PRX_CONTEXT RxContext
;
1907 ULONG NumberRemaining
;
1908 BOOLEAN StartDispatcher
;
1909 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
1911 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context
);
1913 /* Get our context structures */
1914 Calldown
= Context
->SrvCalldownStructure
;
1915 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
1917 /* If it is a success, that's the winner */
1918 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1919 if (Context
->Status
== STATUS_SUCCESS
)
1921 Calldown
->BestFinisherOrdinal
= Context
->CallbackContextOrdinal
;
1922 Calldown
->BestFinisher
= Context
->RxDeviceObject
;
1924 NumberRemaining
= --Calldown
->NumberRemaining
;
1925 SrvCall
->Status
= Context
->Status
;
1926 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1928 /* Still some to ask, keep going */
1929 if (NumberRemaining
!= 0)
1934 /* If that's not async, signal we're done */
1935 RxContext
= Calldown
->RxContext
;
1936 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
1938 KeSetEvent(&Calldown
->FinishEvent
, IO_NETWORK_INCREMENT
, FALSE
);
1941 /* If that's a mailslot, finish construction, no more to do */
1942 else if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CREATE_MAILSLOT
))
1944 RxFinishSrvCallConstruction(Calldown
);
1948 /* Queue our finish call for delayed completion */
1949 DPRINT("Queuing RxFinishSrvCallConstruction() call\n");
1950 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
1951 InsertTailList(&RxSrvCalldownList
, &Calldown
->SrvCalldownList
);
1952 StartDispatcher
= !RxSrvCallConstructionDispatcherActive
;
1953 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
1955 /* If we have to start dispatcher, go ahead */
1956 if (StartDispatcher
)
1960 Status
= RxDispatchToWorkerThread(RxFileSystemDeviceObject
, CriticalWorkQueue
,
1961 RxFinishSrvCallConstructionDispatcher
, &RxSrvCalldownList
);
1962 if (!NT_SUCCESS(Status
))
1964 /* It failed - run it manually.... */
1965 RxFinishSrvCallConstructionDispatcher(NULL
);
1975 IN PV_NET_ROOT VNetRoot
,
1984 ASSERT(NodeTypeIsFcb(Fcb
));
1985 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
1987 PoolType
= (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
) ? NonPagedPool
: PagedPool
);
1991 SrvOpen
= Fcb
->InternalSrvOpen
;
1992 /* Check whethet we have to allocate a new SRV_OPEN */
1993 if (Fcb
->InternalSrvOpen
== NULL
|| BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
) ||
1994 BooleanFlagOn(Fcb
->InternalSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
) ||
1995 !IsListEmpty(&Fcb
->InternalSrvOpen
->SrvOpenQLinks
))
1998 SrvOpen
= RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
1999 RDBSS_NTC_SRVOPEN
, PoolType
, 0, NULL
);
2004 /* Otherwise, just use internal one and initialize it */
2005 RxAllocateFcbObject(Fcb
->VNetRoot
->NetRoot
->pSrvCall
->RxDeviceObject
,
2006 RDBSS_NTC_INTERNAL_SRVOPEN
, PoolType
, 0,
2007 Fcb
->InternalSrvOpen
);
2008 Fcb
->FcbState
|= FCB_STATE_SRVOPEN_USED
;
2009 Flags
= SRVOPEN_FLAG_ENCLOSED_ALLOCATED
| SRVOPEN_FLAG_FOBX_USED
;
2012 /* If SrvOpen was properly allocated, initialize it */
2013 if (SrvOpen
!= NULL
)
2015 SrvOpen
->Flags
= Flags
;
2016 SrvOpen
->pFcb
= RX_GET_MRX_FCB(Fcb
);
2017 SrvOpen
->pAlreadyPrefixedName
= &Fcb
->PrivateAlreadyPrefixedName
;
2018 SrvOpen
->pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
2019 SrvOpen
->ulFileSizeVersion
= Fcb
->ulFileSizeVersion
;
2020 SrvOpen
->NodeReferenceCount
= 1;
2022 RxReferenceVNetRoot(VNetRoot
);
2023 RxReferenceNetFcb(Fcb
);
2025 InsertTailList(&Fcb
->SrvOpenList
, &SrvOpen
->SrvOpenQLinks
);
2026 ++Fcb
->SrvOpenListVersion
;
2028 InitializeListHead(&SrvOpen
->ScavengerFinalizationList
);
2029 InitializeListHead(&SrvOpen
->TransitionWaitList
);
2030 InitializeListHead(&SrvOpen
->FobxList
);
2031 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
2036 if (_SEH2_AbnormalTermination())
2038 if (SrvOpen
!= NULL
)
2040 RxFinalizeSrvOpen(SrvOpen
, TRUE
, TRUE
);
2046 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen
, SrvOpen
->pFcb
);
2059 IN PRX_CONTEXT RxContext
,
2060 IN PNET_ROOT NetRoot
,
2061 IN PUNICODE_STRING CanonicalName
,
2062 IN PUNICODE_STRING LocalNetRootName
,
2063 IN PUNICODE_STRING FilePath
,
2064 IN PRX_CONNECTION_ID RxConnectionId
)
2067 PV_NET_ROOT VNetRoot
;
2068 USHORT CaseInsensitiveLength
;
2072 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext
, NetRoot
, CanonicalName
,
2073 LocalNetRootName
, FilePath
, RxConnectionId
);
2075 /* Lock must be held exclusively */
2076 ASSERT(RxIsPrefixTableLockExclusive(RxContext
->RxDeviceObject
->pRxNetNameTable
));
2078 /* Check for overflow */
2079 if (LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
> MAXUSHORT
)
2084 /* Get name length and allocate VNetRoot */
2085 CaseInsensitiveLength
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
2086 VNetRoot
= RxAllocateObject(RDBSS_NTC_V_NETROOT
, NetRoot
->SrvCall
->RxDeviceObject
->Dispatch
,
2087 CaseInsensitiveLength
);
2088 if (VNetRoot
== NULL
)
2093 /* Initialize its connection parameters */
2094 Status
= RxInitializeVNetRootParameters(RxContext
, &VNetRoot
->LogonId
, &VNetRoot
->SessionId
,
2095 &VNetRoot
->pUserName
, &VNetRoot
->pUserDomainName
,
2096 &VNetRoot
->pPassword
, &VNetRoot
->Flags
);
2097 if (!NT_SUCCESS(Status
))
2099 RxUninitializeVNetRootParameters(VNetRoot
->pUserName
, VNetRoot
->pUserDomainName
,
2100 VNetRoot
->pPassword
, &VNetRoot
->Flags
);
2101 RxFreeObject(VNetRoot
);
2107 RtlMoveMemory(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
2109 VNetRoot
->PrefixOffsetInBytes
= LocalNetRootName
->Length
+ NetRoot
->PrefixEntry
.Prefix
.Length
;
2110 VNetRoot
->NamePrefix
.Buffer
= Add2Ptr(VNetRoot
->PrefixEntry
.Prefix
.Buffer
, VNetRoot
->PrefixOffsetInBytes
);
2111 VNetRoot
->NamePrefix
.Length
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
2112 VNetRoot
->NamePrefix
.MaximumLength
= VNetRoot
->PrefixEntry
.Prefix
.Length
- VNetRoot
->PrefixOffsetInBytes
;
2114 InitializeListHead(&VNetRoot
->TransitionWaitList
);
2115 InitializeListHead(&VNetRoot
->ScavengerFinalizationList
);
2117 if (!BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES
))
2121 if (BooleanFlagOn(NetRoot
->SrvCall
->Flags
, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS
))
2123 CaseInsensitiveLength
= NetRoot
->PrefixEntry
.CaseInsensitiveLength
;
2127 CaseInsensitiveLength
= NetRoot
->SrvCall
->PrefixEntry
.CaseInsensitiveLength
;
2130 for (i
= 1; i
< CanonicalName
->Length
/ sizeof(WCHAR
); ++i
)
2132 if (CanonicalName
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
)
2138 CaseInsensitiveLength
+= (i
* sizeof(WCHAR
));
2141 /* Insert in prefix table */
2142 RxPrefixTableInsertName(RxContext
->RxDeviceObject
->pRxNetNameTable
, &VNetRoot
->PrefixEntry
,
2143 VNetRoot
, (PULONG
)&VNetRoot
->NodeReferenceCount
, CaseInsensitiveLength
,
2146 RxReferenceNetRoot(NetRoot
);
2147 RxAddVirtualNetRootToNetRoot(NetRoot
, VNetRoot
);
2150 VNetRoot
->SerialNumberForEnum
= SerialNumber
++;
2151 VNetRoot
->UpperFinalizationDone
= FALSE
;
2152 VNetRoot
->ConnectionFinalizationDone
= FALSE
;
2153 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2155 DPRINT("NamePrefix: %wZ\n", &VNetRoot
->NamePrefix
);
2156 DPRINT("PrefixEntry: %wZ\n", &VNetRoot
->PrefixEntry
.Prefix
);
2166 IN OUT PVOID Instance
,
2167 IN LOCK_HOLDING_STATE LockHoldingState
)
2170 NODE_TYPE_CODE NodeType
;
2171 PNODE_TYPE_AND_SIZE Node
;
2175 RxAcquireScavengerMutex();
2177 /* Check we have a node we can handle */
2178 NodeType
= NodeType(Instance
);
2179 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
2180 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
2181 (NodeType
== RDBSS_NTC_FOBX
));
2183 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
2184 RefCount
= InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
2185 ASSERT(RefCount
>= 0);
2187 /* Trace refcount */
2190 case RDBSS_NTC_SRVCALL
:
2191 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
2194 case RDBSS_NTC_NETROOT
:
2195 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
2198 case RDBSS_NTC_V_NETROOT
:
2199 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
2202 case RDBSS_NTC_SRVOPEN
:
2203 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
2206 case RDBSS_NTC_FOBX
:
2207 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
2215 /* No need to free - still in use */
2218 RxReleaseScavengerMutex();
2222 /* We have to be locked exclusively */
2223 if (LockHoldingState
!= LHS_ExclusiveLockHeld
)
2225 if ((NodeType
== RDBSS_NTC_FOBX
&& RefCount
== 0) ||
2226 (NodeType
>= RDBSS_NTC_SRVCALL
&& NodeType
<= RDBSS_NTC_V_NETROOT
))
2228 RxpMarkInstanceForScavengedFinalization(Instance
);
2231 RxReleaseScavengerMutex();
2236 if (BooleanFlagOn(NodeType
, RX_SCAVENGER_MASK
))
2238 RxpUndoScavengerFinalizationMarking(Instance
);
2242 RxReleaseScavengerMutex();
2244 /* Now, deallocate the memory */
2247 case RDBSS_NTC_SRVCALL
:
2251 SrvCall
= (PSRV_CALL
)Instance
;
2253 ASSERT(SrvCall
->RxDeviceObject
!= NULL
);
2254 ASSERT(RxIsPrefixTableLockAcquired(SrvCall
->RxDeviceObject
->pRxNetNameTable
));
2255 RxFinalizeSrvCall(SrvCall
, TRUE
, TRUE
);
2259 case RDBSS_NTC_NETROOT
:
2263 NetRoot
= (PNET_ROOT
)Instance
;
2265 ASSERT(NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2266 ASSERT(RxIsPrefixTableLockAcquired(NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2267 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
2271 case RDBSS_NTC_V_NETROOT
:
2273 PV_NET_ROOT VNetRoot
;
2275 VNetRoot
= (PV_NET_ROOT
)Instance
;
2277 ASSERT(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
!= NULL
);
2278 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
));
2279 RxFinalizeVNetRoot(VNetRoot
, TRUE
, TRUE
);
2283 case RDBSS_NTC_SRVOPEN
:
2287 SrvOpen
= (PSRV_OPEN
)Instance
;
2289 ASSERT(RxIsFcbAcquired(SrvOpen
->Fcb
));
2290 if (SrvOpen
->OpenCount
== 0)
2292 RxFinalizeSrvOpen(SrvOpen
, FALSE
, FALSE
);
2297 case RDBSS_NTC_FOBX
:
2301 Fobx
= (PFOBX
)Instance
;
2303 ASSERT(RxIsFcbAcquired(Fobx
->SrvOpen
->Fcb
));
2304 RxFinalizeNetFobx(Fobx
, TRUE
, FALSE
);
2315 RxDereferenceAndDeleteRxContext_Real(
2316 IN PRX_CONTEXT RxContext
)
2321 PRX_CONTEXT StopContext
= NULL
;
2323 /* Make sure we really have a context */
2324 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
2325 ASSERT(RxContext
->NodeTypeCode
== RDBSS_NTC_RX_CONTEXT
);
2326 RefCount
= InterlockedDecrement((volatile LONG
*)&RxContext
->ReferenceCount
);
2327 /* If refcount is 0, start releasing stuff that needs spinlock held */
2330 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
2332 Allocated
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_FROM_POOL
);
2334 /* If that's stop context from DO, remove it */
2335 RxDeviceObject
= RxContext
->RxDeviceObject
;
2336 if (RxDeviceObject
->StartStopContext
.pStopContext
== RxContext
)
2338 RxDeviceObject
->StartStopContext
.pStopContext
= NULL
;
2342 /* Remove it from the list */
2343 ASSERT((RxContext
->ContextListEntry
.Flink
->Blink
== &RxContext
->ContextListEntry
) &&
2344 (RxContext
->ContextListEntry
.Blink
->Flink
== &RxContext
->ContextListEntry
));
2345 RemoveEntryList(&RxContext
->ContextListEntry
);
2347 /* If that was the last active context, save the stop context */
2348 if (InterlockedExchangeAdd((volatile LONG
*)&RxDeviceObject
->NumberOfActiveContexts
, -1) == 0)
2350 if (RxDeviceObject
->StartStopContext
.pStopContext
!= NULL
)
2352 StopContext
= RxDeviceObject
->StartStopContext
.pStopContext
;
2357 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
2359 /* Now, deal with what can be done without spinlock held */
2362 /* Refcount shouldn't have changed */
2363 ASSERT(RxContext
->ReferenceCount
== 0);
2364 /* Reset everything that can be */
2365 RxPrepareContextForReuse(RxContext
);
2367 #ifdef RDBSS_TRACKER
2368 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
== 0);
2370 /* If that was the last active, set the event */
2371 if (StopContext
!= NULL
)
2373 StopContext
->Flags
&= ~RX_CONTEXT_FLAG_RECURSIVE_CALL
;
2374 KeSetEvent(&StopContext
->SyncEvent
, IO_NO_INCREMENT
, FALSE
);
2378 /* Is ShadowCrit still owned? Shouldn't happen! */
2379 if (RxContext
->ShadowCritOwner
!= 0)
2381 DPRINT1("ShadowCritOwner not null! %lx\n", RxContext
->ShadowCritOwner
);
2386 /* If it was allocated, free it */
2389 ExFreeToNPagedLookasideList(&RxContextLookasideList
, RxContext
);
2396 RxDispatchChangeBufferingStateRequests(
2407 RxDispatchToWorkerThread(
2408 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
2409 IN WORK_QUEUE_TYPE WorkQueueType
,
2410 IN PRX_WORKERTHREAD_ROUTINE Routine
,
2414 PRX_WORK_DISPATCH_ITEM DispatchItem
;
2416 /* Allocate a bit of context */
2417 DispatchItem
= RxAllocatePoolWithTag(PagedPool
, sizeof(RX_WORK_DISPATCH_ITEM
), RX_WORKQ_POOLTAG
);
2418 if (DispatchItem
== NULL
)
2420 return STATUS_INSUFFICIENT_RESOURCES
;
2423 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */
2424 DispatchItem
->DispatchRoutine
= Routine
;
2425 DispatchItem
->DispatchRoutineParameter
= pContext
;
2426 DispatchItem
->WorkQueueItem
.WorkerRoutine
= RxWorkItemDispatcher
;
2427 DispatchItem
->WorkQueueItem
.Parameter
= DispatchItem
;
2430 Status
= RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, &DispatchItem
->WorkQueueItem
);
2431 if (!NT_SUCCESS(Status
))
2433 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
2434 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType
, Routine
, pContext
, Status
);
2437 DPRINT("Dispatching: %p, %p\n", Routine
, pContext
);
2446 RxExclusivePrefixTableLockToShared(
2447 PRX_PREFIX_TABLE Table
)
2451 ExConvertExclusiveToSharedLite(&Table
->TableLock
);
2458 RxExtractServerName(
2459 IN PUNICODE_STRING FilePathName
,
2460 OUT PUNICODE_STRING SrvCallName
,
2461 OUT PUNICODE_STRING RestOfName
)
2467 ASSERT(SrvCallName
!= NULL
);
2469 /* SrvCall name will start from the begin up to the first separator */
2470 SrvCallName
->Buffer
= FilePathName
->Buffer
;
2471 for (i
= 1; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
2473 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
2479 /* Compute length */
2480 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[i
] - (ULONG_PTR
)FilePathName
->Buffer
);
2481 SrvCallName
->MaximumLength
= Length
;
2482 SrvCallName
->Length
= Length
;
2484 /* Return the rest if asked */
2485 if (RestOfName
!= NULL
)
2487 Length
= (USHORT
)((ULONG_PTR
)&FilePathName
->Buffer
[FilePathName
->Length
/ sizeof(WCHAR
)] - (ULONG_PTR
)FilePathName
->Buffer
[i
]);
2488 RestOfName
->Buffer
= &FilePathName
->Buffer
[i
];
2489 RestOfName
->MaximumLength
= Length
;
2490 RestOfName
->Length
= Length
;
2498 RxFcbTableInsertFcb(
2499 IN OUT PRX_FCB_TABLE FcbTable
,
2504 /* We deal with the table, make sure it's locked */
2505 ASSERT(RxIsFcbTableLockExclusive(FcbTable
));
2507 /* Compute the hash */
2508 Fcb
->FcbTableEntry
.HashValue
= RxTableComputePathHashValue(&Fcb
->FcbTableEntry
.Path
);
2510 RxReferenceNetFcb(Fcb
);
2512 /* If no length, it will be our null entry */
2513 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2515 FcbTable
->TableEntryForNull
= &Fcb
->FcbTableEntry
;
2517 /* Otherwise, insert in the appropriate bucket */
2520 InsertTailList(FCB_HASH_BUCKET(FcbTable
, Fcb
->FcbTableEntry
.HashValue
),
2521 &Fcb
->FcbTableEntry
.HashLinks
);
2524 /* Propagate the change by incrementing the version number */
2525 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2527 return STATUS_SUCCESS
;
2534 RxFcbTableLookupFcb(
2535 IN PRX_FCB_TABLE FcbTable
,
2536 IN PUNICODE_STRING Path
)
2539 PRX_FCB_TABLE_ENTRY TableEntry
;
2543 /* No path - easy, that's null entry */
2546 TableEntry
= FcbTable
->TableEntryForNull
;
2551 PLIST_ENTRY HashBucket
, ListEntry
;
2553 /* Otherwise, compute the hash value and find the associated bucket */
2554 Hash
= RxTableComputePathHashValue(Path
);
2555 HashBucket
= FCB_HASH_BUCKET(FcbTable
, Hash
);
2556 /* If the bucket is empty, it means there's no entry yet */
2557 if (IsListEmpty(HashBucket
))
2563 /* Otherwise, browse all the entry */
2564 for (ListEntry
= HashBucket
->Flink
;
2565 ListEntry
!= HashBucket
;
2566 ListEntry
= ListEntry
->Flink
)
2568 TableEntry
= CONTAINING_RECORD(ListEntry
, RX_FCB_TABLE_ENTRY
, HashLinks
);
2569 InterlockedIncrement(&FcbTable
->Compares
);
2571 /* If entry hash and string are equal, thatt's the one! */
2572 if (TableEntry
->HashValue
== Hash
&&
2573 TableEntry
->Path
.Length
== Path
->Length
&&
2574 RtlEqualUnicodeString(Path
, &TableEntry
->Path
, FcbTable
->CaseInsensitiveMatch
))
2580 /* We reached the end? Not found */
2581 if (ListEntry
== HashBucket
)
2588 InterlockedIncrement(&FcbTable
->Lookups
);
2590 /* If table entry isn't null, return the FCB */
2591 if (TableEntry
!= NULL
)
2593 Fcb
= CONTAINING_RECORD(TableEntry
, FCB
, FcbTableEntry
);
2594 RxReferenceNetFcb(Fcb
);
2599 InterlockedIncrement(&FcbTable
->FailedLookups
);
2609 RxFcbTableRemoveFcb(
2610 IN OUT PRX_FCB_TABLE FcbTable
,
2615 ASSERT(RxIsPrefixTableLockExclusive(FcbTable
));
2617 /* If no path, then remove entry for null */
2618 if (Fcb
->FcbTableEntry
.Path
.Length
== 0)
2620 FcbTable
->TableEntryForNull
= NULL
;
2622 /* Otherwise, remove from the bucket */
2625 RemoveEntryList(&Fcb
->FcbTableEntry
.HashLinks
);
2628 /* Reset its list entry */
2629 InitializeListHead(&Fcb
->FcbTableEntry
.HashLinks
);
2631 /* Propagate the change by incrementing the version number */
2632 InterlockedIncrement((volatile long *)&FcbTable
->Version
);
2634 return STATUS_SUCCESS
;
2642 RxFinalizeConnection(
2643 IN OUT PNET_ROOT NetRoot
,
2644 IN OUT PV_NET_ROOT VNetRoot OPTIONAL
,
2645 IN LOGICAL ForceFilesClosed
)
2648 PRX_PREFIX_TABLE PrefixTable
;
2649 ULONG UncleanAny
, UncleanDir
;
2650 LONG FilesOpen
, AdditionalRef
;
2651 BOOLEAN PrefixLocked
, FcbTableLocked
, ForceClose
;
2655 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
2657 /* Get a BOOLEAN out of LOGICAL
2658 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure
2660 ForceClose
= (ForceFilesClosed
== TRUE
? TRUE
: FALSE
);
2662 /* First, delete any notification change */
2663 Status
= RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot
, ForceClose
);
2664 /* If it failed, continue if forced */
2665 if (Status
!= STATUS_SUCCESS
&& !ForceFilesClosed
)
2669 /* Reset status, in case notification deletion failed */
2670 Status
= STATUS_SUCCESS
;
2672 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
2674 PrefixLocked
= FALSE
;
2675 FcbTableLocked
= FALSE
;
2682 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
2683 PrefixLocked
= TRUE
;
2685 RxReferenceNetRoot(NetRoot
);
2687 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
2688 FcbTableLocked
= TRUE
;
2690 /* If our V_NET_ROOT wasn't finalized yet, proceed! */
2691 if (!VNetRoot
->ConnectionFinalizationDone
)
2694 PRX_FCB_TABLE FcbTable
;
2696 DPRINT("Finalizing connection %p: %wZ\n", NetRoot
, &NetRoot
->PrefixEntry
.Prefix
);
2698 /* We'll browse all its associated FCB to check whether they're open/orphaned */
2699 FcbTable
= &NetRoot
->FcbTable
;
2700 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2702 PLIST_ENTRY BucketList
, Entry
;
2704 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
2705 Entry
= BucketList
->Flink
;
2706 while (Entry
!= BucketList
)
2710 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
2711 Entry
= Entry
->Flink
;
2713 /* FCB for this connection, go ahead */
2714 if (Fcb
->VNetRoot
== VNetRoot
)
2716 /* It's still open, and no force? Fail and keep track */
2717 if (Fcb
->UncleanCount
> 0 && !ForceClose
)
2719 Status
= STATUS_CONNECTION_IN_USE
;
2720 if (NodeType(Fcb
) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
2731 /* Else, force purge */
2732 ASSERT(NodeTypeIsFcb(Fcb
));
2734 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
2735 ASSERT(Status
== STATUS_SUCCESS
);
2737 ClearFlag(Fcb
->FcbState
, FCB_STATE_COLLAPSING_ENABLED
);
2739 RxScavengeRelatedFobxs(Fcb
);
2742 /* We don't need to release FCB lock, FCB finalize will take care of it */
2748 /* No files left, our V_NET_ROOT is finalized */
2749 if (VNetRoot
->NumberOfFobxs
== 0)
2751 VNetRoot
->ConnectionFinalizationDone
= TRUE
;
2755 /* Keep Number of open files and track of the extra reference */
2756 FilesOpen
= VNetRoot
->NumberOfFobxs
;
2757 AdditionalRef
= VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
;
2758 /* If force close, caller doesn't want to keep connection alive
2759 * and wants it totally close, so drop the V_NET_ROOT too
2763 RxFinalizeVNetRoot(VNetRoot
, FALSE
, TRUE
);
2768 /* Release what was acquired */
2771 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
2774 /* If close is forced, only fix status if there are open files */
2777 if (Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0)
2779 Status
= STATUS_FILES_OPEN
;
2782 /* Else, fix status and fail closing if there are open files */
2785 if ((Status
!= STATUS_SUCCESS
&& UncleanAny
!= 0) || FilesOpen
> 0)
2787 Status
= STATUS_FILES_OPEN
;
2791 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny
, UncleanDir
, FilesOpen
);
2793 /* If we're are asked to remove the extra ref, or if closing was a success, do it;
2794 * only if it was still referenced!
2796 if ((ForceFilesClosed
== 0xFF || Status
== STATUS_SUCCESS
) && AdditionalRef
!= 0)
2798 VNetRoot
->AdditionalReferenceForDeleteFsctlTaken
= 0;
2799 RxDereferenceVNetRoot(VNetRoot
, LHS_ExclusiveLockHeld
);
2804 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
2805 RxReleasePrefixTableLock(PrefixTable
);
2818 IN OUT PRX_FCB_TABLE FcbTable
)
2824 /* Just delete the lock */
2825 ExDeleteResourceLite(&FcbTable
->TableLock
);
2827 /* And make sure (checked) that the table is really empty... */
2828 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
2830 ASSERT(IsListEmpty(&FcbTable
->HashBuckets
[Bucket
]));
2840 IN BOOLEAN RecursiveFinalize
,
2841 IN BOOLEAN ForceFinalize
,
2842 IN LONG ReferenceCount
)
2846 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb
, RecursiveFinalize
, ForceFinalize
, ReferenceCount
);
2847 DPRINT("Finalize: %wZ\n", &ThisFcb
->FcbTableEntry
.Path
);
2849 /* Make sure we have an exclusively acquired FCB */
2850 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb
);
2851 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
2853 /* We shouldn't force finalization... */
2854 ASSERT(!ForceFinalize
);
2856 /* If recurisve, finalize all the associated SRV_OPEN */
2857 if (RecursiveFinalize
)
2859 PLIST_ENTRY ListEntry
;
2861 for (ListEntry
= ThisFcb
->SrvOpenList
.Flink
;
2862 ListEntry
!= &ThisFcb
->SrvOpenList
;
2863 ListEntry
= ListEntry
->Flink
)
2867 SrvOpen
= CONTAINING_RECORD(ListEntry
, SRV_OPEN
, SrvOpenQLinks
);
2868 RxFinalizeSrvOpen(SrvOpen
, TRUE
, ForceFinalize
);
2871 /* If FCB is still in use, that's over */
2874 if (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0)
2876 ASSERT(ReferenceCount
> 0);
2882 ASSERT(ReferenceCount
>= 1);
2884 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */
2885 if (ReferenceCount
!= 1 && !ForceFinalize
)
2890 ASSERT(ForceFinalize
|| ((ThisFcb
->OpenCount
== 0) && (ThisFcb
->UncleanCount
== 0)));
2892 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb
->OpenCount
, ForceFinalize
);
2894 /* If finalization was not already initiated, go ahead */
2895 if (!ThisFcb
->UpperFinalizationDone
)
2897 /* Free any FCB_LOCK */
2898 if (NodeType(ThisFcb
) == RDBSS_NTC_STORAGE_TYPE_FILE
)
2900 FsRtlUninitializeFileLock(&ThisFcb
->Specific
.Fcb
.FileLock
);
2902 while (ThisFcb
->BufferedLocks
.List
!= NULL
)
2906 Entry
= ThisFcb
->BufferedLocks
.List
;
2907 ThisFcb
->BufferedLocks
.List
= Entry
->Next
;
2913 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */
2914 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
2918 NetRoot
= (PNET_ROOT
)ThisFcb
->pNetRoot
;
2920 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
2922 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
2924 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
2928 ThisFcb
->UpperFinalizationDone
= TRUE
;
2931 ASSERT(ReferenceCount
>= 1);
2933 /* Even if forced, don't allow broken free */
2934 if (ReferenceCount
!= 1)
2939 /* Now, release everything */
2940 if (ThisFcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
2942 RxFreePool(ThisFcb
->pBufferingStateChangeCompletedEvent
);
2945 if (ThisFcb
->MRxDispatch
!= NULL
)
2947 ThisFcb
->MRxDispatch
->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb
));
2950 ExDeleteResourceLite(ThisFcb
->BufferedLocks
.Resource
);
2951 ExDeleteResourceLite(ThisFcb
->Header
.Resource
);
2952 ExDeleteResourceLite(ThisFcb
->Header
.PagingIoResource
);
2954 InterlockedDecrement((volatile long *)&ThisFcb
->pNetRoot
->NumberOfFcbs
);
2955 RxDereferenceVNetRoot(ThisFcb
->VNetRoot
, LHS_LockNotHeld
);
2957 ASSERT(IsListEmpty(&ThisFcb
->FcbTableEntry
.HashLinks
));
2958 ASSERT(!ThisFcb
->fMiniInited
);
2960 /* And free the object */
2961 RxFreeFcbObject(ThisFcb
);
2971 _Out_ PFOBX ThisFobx
,
2972 _In_ BOOLEAN RecursiveFinalize
,
2973 _In_ BOOLEAN ForceFinalize
)
2980 ASSERT(NodeType(ThisFobx
) == RDBSS_NTC_FOBX
);
2982 /* Only finalize if forced or if there's no ref left */
2983 if (ThisFobx
->NodeReferenceCount
!= 0 &&
2989 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx
, ThisFobx
->NodeReferenceCount
, ForceFinalize
);
2991 SrvOpen
= ThisFobx
->SrvOpen
;
2993 /* If it wasn't finalized yet, do it */
2994 if (!ThisFobx
->UpperFinalizationDone
)
2996 ASSERT(NodeType(SrvOpen
->Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
2997 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
2999 /* Remove it from the SRV_OPEN */
3000 RemoveEntryList(&ThisFobx
->FobxQLinks
);
3002 /* If we were used to browse a directory, free the query buffer */
3003 if (BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_FREE_UNICODE
))
3005 RxFreePoolWithTag(ThisFobx
->UnicodeQueryTemplate
.Buffer
, RX_DIRCTL_POOLTAG
);
3008 /* Notify the mini-rdr */
3009 if (Fcb
->MRxDispatch
!= NULL
&& Fcb
->MRxDispatch
->MRxDeallocateForFobx
!= NULL
)
3011 Fcb
->MRxDispatch
->MRxDeallocateForFobx((PMRX_FOBX
)ThisFobx
);
3014 /* If the SRV_OPEN wasn't closed yet, do it */
3015 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
))
3019 Status
= RxCloseAssociatedSrvOpen(ThisFobx
, FALSE
);
3020 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen
, ThisFobx
, Status
);
3023 /* Finalization done */
3024 ThisFobx
->UpperFinalizationDone
= TRUE
;
3027 /* If we're still referenced, don't go any further! */
3028 if (ThisFobx
->NodeReferenceCount
!= 0)
3033 /* At that point, everything should be closed */
3034 ASSERT(IsListEmpty(&ThisFobx
->ClosePendingList
));
3036 /* Was the FOBX allocated with another object?
3037 * If so, mark the buffer free in said object
3039 if (ThisFobx
== Fcb
->InternalFobx
)
3041 ClearFlag(Fcb
->FcbState
, FCB_STATE_FOBX_USED
);
3043 else if (ThisFobx
== SrvOpen
->InternalFobx
)
3045 ClearFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_FOBX_USED
);
3048 ThisFobx
->pSrvOpen
= NULL
;
3051 InterlockedDecrement((volatile long *)&SrvOpen
->pVNetRoot
->NumberOfFobxs
);
3053 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
3055 /* If it wasn't allocated with another object, free the FOBX */
3056 if (!BooleanFlagOn(ThisFobx
->Flags
, FOBX_FLAG_ENCLOSED_ALLOCATED
))
3058 RxFreeFcbObject(ThisFobx
);
3069 OUT PNET_ROOT ThisNetRoot
,
3070 IN BOOLEAN RecursiveFinalize
,
3071 IN BOOLEAN ForceFinalize
)
3074 PRX_FCB_TABLE FcbTable
;
3075 PRX_PREFIX_TABLE PrefixTable
;
3079 ASSERT(NodeType(ThisNetRoot
) == RDBSS_NTC_NETROOT
);
3081 PrefixTable
= ThisNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3082 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3084 /* If sme finalization is already ongoing, leave */
3085 if (BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
))
3090 /* Mark we're finalizing */
3091 SetFlag(ThisNetRoot
->Flags
, NETROOT_FLAG_FINALIZATION_IN_PROGRESS
);
3093 FcbTable
= &ThisNetRoot
->FcbTable
;
3094 /* Did caller asked us to finalize any associated FCB? */
3095 if (RecursiveFinalize
)
3099 /* Browse all the FCBs in our FCB table */
3100 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
3101 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
3103 PLIST_ENTRY HashBucket
, ListEntry
;
3105 HashBucket
= &FcbTable
->HashBuckets
[Bucket
];
3106 ListEntry
= HashBucket
->Flink
;
3107 while (ListEntry
!= HashBucket
)
3111 Fcb
= CONTAINING_RECORD(ListEntry
, FCB
, FcbTableEntry
.HashLinks
);
3112 ASSERT(NodeTypeIsFcb(Fcb
));
3114 ListEntry
= ListEntry
->Flink
;
3116 /* If the FCB isn't orphaned, then, it's time to purge it */
3117 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3121 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
3122 ASSERT(Status
== STATUS_SUCCESS
);
3127 RxReleaseFcbTableLock(FcbTable
);
3130 /* Only finalize if forced or if there's a single ref left */
3131 if (ThisNetRoot
->NodeReferenceCount
!= 1 && !ForceFinalize
)
3136 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot
, &ThisNetRoot
->PrefixEntry
.Prefix
);
3138 /* If we're still referenced, don't go any further! */
3139 if (ThisNetRoot
->NodeReferenceCount
!= 1)
3144 /* Finalize the FCB table (and make sure it's empty!) */
3145 RxFinalizeFcbTable(FcbTable
);
3147 /* If name wasn't remove already, do it now */
3148 if (!BooleanFlagOn(ThisNetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
3150 RxRemovePrefixTableEntry(PrefixTable
, &ThisNetRoot
->PrefixEntry
);
3153 /* Delete the object */
3154 SrvCall
= (PSRV_CALL
)ThisNetRoot
->pSrvCall
;
3155 RxFreeObject(ThisNetRoot
);
3157 /* And dereference the associated SRV_CALL */
3158 if (SrvCall
!= NULL
)
3160 RxDereferenceSrvCall(SrvCall
, LHS_ExclusiveLockHeld
);
3171 OUT PSRV_CALL ThisSrvCall
,
3172 IN BOOLEAN RecursiveFinalize
,
3173 IN BOOLEAN ForceFinalize
)
3175 PRX_PREFIX_TABLE PrefixTable
;
3179 ASSERT(NodeType(ThisSrvCall
) == RDBSS_NTC_SRVCALL
);
3181 PrefixTable
= ThisSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3182 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3184 /* Only finalize if forced or if there's a single ref left */
3185 if (ThisSrvCall
->NodeReferenceCount
!= 1 &&
3191 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall
, &ThisSrvCall
->PrefixEntry
.Prefix
);
3193 /* If it wasn't finalized yet, do it */
3194 if (!ThisSrvCall
->UpperFinalizationDone
)
3198 /* Remove ourselves from prefix table */
3199 RxRemovePrefixTableEntry(PrefixTable
, &ThisSrvCall
->PrefixEntry
);
3201 /* Remember our third arg, in case we get queued for later execution */
3204 SetFlag(ThisSrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
3208 ThisSrvCall
->UpperFinalizationDone
= TRUE
;
3210 /* Would defered execution free the object? */
3211 WillFree
= (ThisSrvCall
->NodeReferenceCount
== 1);
3213 /* If we have a device object */
3214 if (ThisSrvCall
->RxDeviceObject
!= NULL
)
3218 /* If we're not executing in the RDBSS thread, queue for execution within the thread */
3219 if (RxGetRDBSSProcess() != IoGetCurrentProcess())
3221 /* Extra ref, as usual */
3222 InterlockedIncrement((volatile long *)&ThisSrvCall
->NodeReferenceCount
);
3224 RxDispatchToWorkerThread(ThisSrvCall
->RxDeviceObject
, DelayedWorkQueue
, RxpDestroySrvCall
, ThisSrvCall
);
3226 /* Return to the caller, in advance, whether we're freeing the object or not */
3230 /* If in the right thread already, call the mini-rdr */
3231 MINIRDR_CALL_THROUGH(Status
, ThisSrvCall
->RxDeviceObject
->Dispatch
,
3232 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)ThisSrvCall
, ForceFinalize
));
3237 /* If we're still referenced, don't go any further! */
3238 if (ThisSrvCall
->NodeReferenceCount
!= 1)
3244 if (ThisSrvCall
->pDomainName
!= NULL
)
3246 RxFreePool(ThisSrvCall
->pDomainName
);
3250 RxTearDownBufferingManager(ThisSrvCall
);
3251 RxFreeObject(ThisSrvCall
);
3261 OUT PSRV_OPEN ThisSrvOpen
,
3262 IN BOOLEAN RecursiveFinalize
,
3263 IN BOOLEAN ForceFinalize
)
3269 /* We have to have a SRV_OPEN */
3270 ASSERT(NodeType(ThisSrvOpen
) == RDBSS_NTC_SRVOPEN
);
3272 /* If that's a recursive finalization, finalize any related FOBX */
3273 if (RecursiveFinalize
)
3275 PLIST_ENTRY ListEntry
;
3277 ListEntry
= ThisSrvOpen
->FobxList
.Flink
;
3278 while (ListEntry
!= &ThisSrvOpen
->FobxList
)
3282 Fobx
= CONTAINING_RECORD(ListEntry
, FOBX
, FobxQLinks
);
3283 ListEntry
= ListEntry
->Flink
;
3284 RxFinalizeNetFobx(Fobx
, TRUE
, ForceFinalize
);
3288 /* If we have still references, don't finalize unless forced */
3289 if (ThisSrvOpen
->NodeReferenceCount
!= 0 &&
3295 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen
, ThisSrvOpen
->NodeReferenceCount
, ForceFinalize
);
3297 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */
3298 Fcb
= (PFCB
)ThisSrvOpen
->pFcb
;
3299 if ((!ThisSrvOpen
->UpperFinalizationDone
&& ThisSrvOpen
->Condition
!= Condition_Good
) ||
3300 BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_CLOSED
))
3302 PV_NET_ROOT VNetRoot
;
3304 /* Associated FCB can't be fake one */
3305 ASSERT(NodeType(Fcb
) != RDBSS_NTC_OPENTARGETDIR_FCB
);
3306 ASSERT(RxIsFcbAcquiredExclusive (Fcb
));
3308 /* Purge any pending operation */
3309 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen
);
3311 /* If the FCB wasn't orphaned, inform the mini-rdr about close */
3312 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_ORPHANED
))
3316 MINIRDR_CALL_THROUGH(Status
, Fcb
->MRxDispatch
, MRxForceClosed
, ((PMRX_SRV_OPEN
)ThisSrvOpen
));
3320 /* Remove ourselves from the FCB */
3321 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3322 InitializeListHead(&ThisSrvOpen
->SrvOpenQLinks
);
3323 ++Fcb
->SrvOpenListVersion
;
3325 /* If we have a V_NET_ROOT, dereference it */
3326 VNetRoot
= (PV_NET_ROOT
)ThisSrvOpen
->pVNetRoot
;
3327 if (VNetRoot
!= NULL
)
3329 InterlockedDecrement((volatile long *)&VNetRoot
->pNetRoot
->NumberOfSrvOpens
);
3330 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3331 ThisSrvOpen
->pVNetRoot
= NULL
;
3334 /* Finalization done */
3335 ThisSrvOpen
->UpperFinalizationDone
= TRUE
;
3338 /* Don't free memory if still referenced */
3339 if (ThisSrvOpen
->NodeReferenceCount
!= 0)
3344 /* No key association left */
3345 ASSERT(IsListEmpty(&ThisSrvOpen
->SrvOpenKeyList
));
3347 /* If we're still in some FCB, remove us */
3348 if (!IsListEmpty(&ThisSrvOpen
->SrvOpenQLinks
))
3350 RemoveEntryList(&ThisSrvOpen
->SrvOpenQLinks
);
3353 /* If enclosed allocation, mark the memory zone free */
3354 if (BooleanFlagOn(ThisSrvOpen
->Flags
, SRVOPEN_FLAG_ENCLOSED_ALLOCATED
))
3356 ClearFlag(Fcb
->FcbState
, FCB_STATE_SRVOPEN_USED
);
3358 /* Otherwise, free the memory */
3361 RxFreeFcbObject(ThisSrvOpen
);
3364 RxDereferenceNetFcb(Fcb
);
3374 OUT PV_NET_ROOT ThisVNetRoot
,
3375 IN BOOLEAN RecursiveFinalize
,
3376 IN BOOLEAN ForceFinalize
)
3379 PRX_PREFIX_TABLE PrefixTable
;
3383 ASSERT(NodeType(ThisVNetRoot
) == RDBSS_NTC_V_NETROOT
);
3385 PrefixTable
= ThisVNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
3386 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
3388 /* Only finalize if forced or if there's a single ref left */
3389 if (ThisVNetRoot
->NodeReferenceCount
!= 1 &&
3395 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot
, &ThisVNetRoot
->PrefixEntry
.Prefix
);
3397 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
3398 /* If it wasn't finalized yet, do it */
3399 if (!ThisVNetRoot
->UpperFinalizationDone
)
3401 ASSERT(NodeType(NetRoot
) == RDBSS_NTC_NETROOT
);
3403 /* Reference the NetRoot so that it doesn't disappear */
3404 RxReferenceNetRoot(NetRoot
);
3405 RxOrphanSrvOpens(ThisVNetRoot
);
3406 /* Remove us from the available VNetRoot for NetRoot */
3407 RxRemoveVirtualNetRootFromNetRoot(NetRoot
, ThisVNetRoot
);
3408 /* Remove extra ref */
3409 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3411 /* Remove ourselves from prefix table */
3412 RxRemovePrefixTableEntry(PrefixTable
, &ThisVNetRoot
->PrefixEntry
);
3414 /* Finalization done */
3415 ThisVNetRoot
->UpperFinalizationDone
= TRUE
;
3418 /* If we're still referenced, don't go any further! */
3419 if (ThisVNetRoot
->NodeReferenceCount
!= 1)
3424 /* If there's an associated device, notify mini-rdr */
3425 if (NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
3429 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
3430 MRxFinalizeVNetRoot
, ((PMRX_V_NET_ROOT
)ThisVNetRoot
, FALSE
));
3434 /* Free parameters */
3435 RxUninitializeVNetRootParameters(ThisVNetRoot
->pUserName
, ThisVNetRoot
->pUserDomainName
,
3436 ThisVNetRoot
->pPassword
, &ThisVNetRoot
->Flags
);
3437 /* Dereference our NetRoot, we won't reference it anymore */
3438 RxDereferenceNetRoot(NetRoot
, LHS_ExclusiveLockHeld
);
3440 /* And free the object! */
3441 RxFreePoolWithTag(ThisVNetRoot
, RX_V_NETROOT_POOLTAG
);
3447 RxFindOrConstructVirtualNetRoot(
3448 IN PRX_CONTEXT RxContext
,
3449 IN PUNICODE_STRING CanonicalName
,
3450 IN NET_ROOT_TYPE NetRootType
,
3451 IN PUNICODE_STRING RemainingName
)
3457 PV_NET_ROOT VNetRoot
;
3458 RX_CONNECTION_ID ConnectionID
;
3459 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
3460 LOCK_HOLDING_STATE LockHoldingState
;
3464 RxDeviceObject
= RxContext
->RxDeviceObject
;
3465 ASSERT(RxDeviceObject
->Dispatch
!= NULL
);
3466 ASSERT(NodeType(RxDeviceObject
->Dispatch
) == RDBSS_NTC_MINIRDR_DISPATCH
);
3468 /* Ask the mini-rdr for connection ID */
3469 ConnectionID
.SessionID
= 0;
3470 if (RxDeviceObject
->Dispatch
->MRxGetConnectionId
!= NULL
)
3472 Status
= RxDeviceObject
->Dispatch
->MRxGetConnectionId(RxContext
, &ConnectionID
);
3473 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_IMPLEMENTED
)
3475 /* mini-rdr is expected not to fail - unless it's not implemented */
3476 DPRINT1("Failed to initialize connection ID\n");
3481 RxContext
->Create
.NetNamePrefixEntry
= NULL
;
3483 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
3484 RxAcquirePrefixTableLockShared(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3485 LockHoldingState
= LHS_SharedLockHeld
;
3489 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */
3493 PV_NET_ROOT SavedVNetRoot
;
3495 /* Look in prefix table */
3496 Container
= RxPrefixTableLookupName(RxDeviceObject
->pRxNetNameTable
, CanonicalName
, RemainingName
, &ConnectionID
);
3497 if (Container
!= NULL
)
3499 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */
3500 if (NodeType(Container
) != RDBSS_NTC_V_NETROOT
)
3502 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3503 RxDereferenceSrvCall(Container
, LockHoldingState
);
3507 VNetRoot
= Container
;
3508 NetRoot
= VNetRoot
->NetRoot
;
3510 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */
3511 if ((NetRoot
->Condition
!= Condition_InTransition
&& NetRoot
->Condition
!= Condition_Good
) ||
3512 NetRoot
->SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3514 Status
= STATUS_BAD_NETWORK_PATH
;
3515 SavedVNetRoot
= NULL
;
3521 PUNICODE_STRING UserName
, UserDomain
, Password
;
3523 /* We can reuse if we use same credentials */
3524 Status
= RxInitializeVNetRootParameters(RxContext
, &LogonId
,
3525 &SessionId
, &UserName
,
3526 &UserDomain
, &Password
,
3528 if (NT_SUCCESS(Status
))
3530 SavedVNetRoot
= VNetRoot
;
3531 Status
= RxCheckVNetRootCredentials(RxContext
, VNetRoot
,
3533 UserDomain
, Password
,
3535 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
3537 PLIST_ENTRY ListEntry
;
3539 for (ListEntry
= NetRoot
->VirtualNetRoots
.Flink
;
3540 ListEntry
!= &NetRoot
->VirtualNetRoots
;
3541 ListEntry
= ListEntry
->Flink
)
3543 SavedVNetRoot
= CONTAINING_RECORD(ListEntry
, V_NET_ROOT
, NetRootListEntry
);
3544 Status
= RxCheckVNetRootCredentials(RxContext
, SavedVNetRoot
,
3546 UserDomain
, Password
,
3548 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3554 if (ListEntry
== &NetRoot
->VirtualNetRoots
)
3556 SavedVNetRoot
= NULL
;
3560 if (!NT_SUCCESS(Status
))
3562 SavedVNetRoot
= NULL
;
3565 RxUninitializeVNetRootParameters(UserName
, UserDomain
, Password
, &Flags
);
3569 /* We'll fail, if we had referenced a VNetRoot, dereference it */
3570 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
3572 if (SavedVNetRoot
== NULL
)
3574 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3577 /* Reference VNetRoot we'll keep, and dereference current */
3578 else if (SavedVNetRoot
!= VNetRoot
)
3580 RxDereferenceVNetRoot(VNetRoot
, LockHoldingState
);
3581 if (SavedVNetRoot
!= NULL
)
3583 RxReferenceVNetRoot(SavedVNetRoot
);
3588 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */
3589 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
)
3596 /* If we're locked exclusive, we won't loop again, it was the second pass */
3597 if (LockHoldingState
!= LHS_SharedLockHeld
)
3602 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */
3603 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, FALSE
))
3605 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3606 LockHoldingState
= LHS_ExclusiveLockHeld
;
3610 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3611 RxAcquirePrefixTableLockExclusive(RxDeviceObject
->pRxNetNameTable
, TRUE
);
3612 LockHoldingState
= LHS_ExclusiveLockHeld
;
3615 /* We didn't fail, and didn't find any VNetRoot, construct one */
3618 ASSERT(LockHoldingState
== LHS_ExclusiveLockHeld
);
3620 Status
= RxConstructVirtualNetRoot(RxContext
, CanonicalName
, NetRootType
, &VNetRoot
, &LockHoldingState
, &ConnectionID
);
3621 ASSERT(Status
!= STATUS_SUCCESS
|| LockHoldingState
!= LHS_LockNotHeld
);
3623 if (Status
== STATUS_SUCCESS
)
3625 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName
, CanonicalName
->Length
);
3626 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot
->PrefixEntry
.Prefix
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3627 ASSERT(CanonicalName
->Length
>= VNetRoot
->PrefixEntry
.Prefix
.Length
);
3629 RemainingName
->Buffer
= Add2Ptr(CanonicalName
->Buffer
, VNetRoot
->PrefixEntry
.Prefix
.Length
);
3630 RemainingName
->Length
= CanonicalName
->Length
- VNetRoot
->PrefixEntry
.Prefix
.Length
;
3631 RemainingName
->MaximumLength
= RemainingName
->Length
;
3633 if (BooleanFlagOn(Flags
, VNETROOT_FLAG_CSCAGENT_INSTANCE
))
3635 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot
);
3637 VNetRoot
->Flags
|= Flags
;
3641 /* Release the prefix table - caller expects it to be released */
3642 if (LockHoldingState
!= LHS_LockNotHeld
)
3644 RxReleasePrefixTableLock(RxDeviceObject
->pRxNetNameTable
);
3647 /* If we failed creating, quit */
3648 if (Status
!= STATUS_SUCCESS
)
3650 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status
);
3654 /* Otherwise, wait until the VNetRoot is stable */
3655 DPRINT("Waiting for stable condition for: %p\n", VNetRoot
);
3656 RxWaitForStableVNetRoot(VNetRoot
, RxContext
);
3657 /* It's all good, update the RX_CONTEXT with all our structs */
3658 if (VNetRoot
->Condition
== Condition_Good
)
3662 NetRoot
= VNetRoot
->NetRoot
;
3663 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3664 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3665 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)NetRoot
->SrvCall
;
3669 RxDereferenceVNetRoot(VNetRoot
, LHS_LockNotHeld
);
3670 RxContext
->Create
.pVNetRoot
= NULL
;
3671 Status
= STATUS_BAD_NETWORK_PATH
;
3681 RxFindOrCreateConnections(
3682 _In_ PRX_CONTEXT RxContext
,
3683 _In_ PUNICODE_STRING CanonicalName
,
3684 _In_ NET_ROOT_TYPE NetRootType
,
3685 _Out_ PUNICODE_STRING LocalNetRootName
,
3686 _Out_ PUNICODE_STRING FilePathName
,
3687 _Inout_ PLOCK_HOLDING_STATE LockState
,
3688 _In_ PRX_CONNECTION_ID RxConnectionId
)
3693 PV_NET_ROOT VNetRoot
;
3694 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
3695 PRX_PREFIX_TABLE PrefixTable
;
3696 UNICODE_STRING RemainingName
, NetRootName
;
3700 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n",
3701 RxContext
, CanonicalName
, NetRootType
, LocalNetRootName
,
3702 FilePathName
, LockState
, RxConnectionId
);
3704 *FilePathName
= *CanonicalName
;
3705 LocalNetRootName
->Length
= 0;
3706 LocalNetRootName
->MaximumLength
= 0;
3707 LocalNetRootName
->Buffer
= CanonicalName
->Buffer
;
3709 /* UNC path, split it */
3710 if (FilePathName
->Buffer
[1] == ';')
3716 for (i
= 2; i
< FilePathName
->Length
/ sizeof(WCHAR
); ++i
)
3718 if (FilePathName
->Buffer
[i
] == OBJ_NAME_PATH_SEPARATOR
)
3727 return STATUS_OBJECT_NAME_INVALID
;
3730 FilePathName
->Buffer
= &FilePathName
->Buffer
[i
];
3731 Length
= (USHORT
)((ULONG_PTR
)FilePathName
->Buffer
- (ULONG_PTR
)LocalNetRootName
->Buffer
);
3732 LocalNetRootName
->Length
= Length
;
3733 LocalNetRootName
->MaximumLength
= Length
;
3734 FilePathName
->Length
-= Length
;
3736 DPRINT("CanonicalName: %wZ\n", CanonicalName
);
3737 DPRINT(" -> FilePathName: %wZ\n", FilePathName
);
3738 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName
);
3742 PrefixTable
= RxContext
->RxDeviceObject
->pRxNetNameTable
;
3747 ASSERT(*LockState
!= LHS_LockNotHeld
);
3749 /* If previous lookup left something, dereference it */
3750 if (Container
!= NULL
)
3752 switch (NodeType(Container
))
3754 case RDBSS_NTC_SRVCALL
:
3755 RxDereferenceSrvCall(Container
, *LockState
);
3758 case RDBSS_NTC_NETROOT
:
3759 RxDereferenceNetRoot(Container
, *LockState
);
3762 case RDBSS_NTC_V_NETROOT
:
3763 RxDereferenceVNetRoot(Container
, *LockState
);
3767 /* Should never happen */
3773 /* Look for our NetRoot in prefix table */
3774 Container
= RxPrefixTableLookupName(PrefixTable
, FilePathName
, &RemainingName
, RxConnectionId
);
3775 DPRINT("Container %p for path %wZ\n", Container
, FilePathName
);
3779 UNICODE_STRING SrvCallName
;
3785 /* Assume we didn't succeed */
3786 RxContext
->Create
.pVNetRoot
= NULL
;
3787 RxContext
->Create
.pNetRoot
= NULL
;
3788 RxContext
->Create
.pSrvCall
= NULL
;
3789 RxContext
->Create
.Type
= NetRootType
;
3791 /* If we found something */
3792 if (Container
!= NULL
)
3795 if (NodeType(Container
) == RDBSS_NTC_V_NETROOT
)
3797 VNetRoot
= Container
;
3798 /* Use its NetRoot */
3799 NetRoot
= VNetRoot
->NetRoot
;
3801 /* If it's not stable, wait for it to be stable */
3802 if (NetRoot
->Condition
== Condition_InTransition
)
3804 RxReleasePrefixTableLock(PrefixTable
);
3805 DPRINT("Waiting for stable condition for: %p\n", NetRoot
);
3806 RxWaitForStableNetRoot(NetRoot
, RxContext
);
3807 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3808 *LockState
= LHS_ExclusiveLockHeld
;
3810 /* Now that's it's ok, retry lookup to find what we want */
3811 if (NetRoot
->Condition
== Condition_Good
)
3817 /* Is the associated netroot good? */
3818 if (NetRoot
->Condition
== Condition_Good
)
3820 SrvCall
= (PSRV_CALL
)NetRoot
->pSrvCall
;
3822 /* If it is, and SrvCall as well, then, we have our active connection */
3823 if (SrvCall
->Condition
== Condition_Good
&&
3824 SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
)
3826 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3827 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3828 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3830 Status
= STATUS_CONNECTION_ACTIVE
;
3835 /* If VNetRoot was well constructed, it means the connection is active */
3836 if (VNetRoot
->ConstructionStatus
== STATUS_SUCCESS
)
3838 Status
= STATUS_CONNECTION_ACTIVE
;
3842 Status
= VNetRoot
->ConstructionStatus
;
3845 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3848 /* Can only be a SrvCall */
3851 ASSERT(NodeType(Container
) == RDBSS_NTC_SRVCALL
);
3852 SrvCall
= Container
;
3854 /* Wait for the SRV_CALL to be stable */
3855 if (SrvCall
->Condition
== Condition_InTransition
)
3857 RxReleasePrefixTableLock(PrefixTable
);
3858 DPRINT("Waiting for stable condition for: %p\n", SrvCall
);
3859 RxWaitForStableSrvCall(SrvCall
, RxContext
);
3860 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3861 *LockState
= LHS_ExclusiveLockHeld
;
3863 /* It went good, loop again to find what we look for */
3864 if (SrvCall
->Condition
== Condition_Good
)
3870 /* If it's not good... */
3871 if (SrvCall
->Condition
!= Condition_Good
)
3873 /* But SRV_CALL was well constructed, assume a connection was active */
3874 if (SrvCall
->Status
== STATUS_SUCCESS
)
3876 Status
= STATUS_CONNECTION_ACTIVE
;
3880 Status
= SrvCall
->Status
;
3883 RxDereferenceSrvCall(SrvCall
, *LockState
);
3889 /* If we found a SRV_CALL not matching our DO, quit */
3890 if (SrvCall
!= NULL
&& SrvCall
->Condition
== Condition_Good
&&
3891 SrvCall
->RxDeviceObject
!= RxContext
->RxDeviceObject
)
3893 RxDereferenceSrvCall(SrvCall
, *LockState
);
3894 Status
= STATUS_BAD_NETWORK_NAME
;
3898 /* Now, we want exclusive lock */
3899 if (*LockState
== LHS_SharedLockHeld
)
3901 if (!RxAcquirePrefixTableLockExclusive(PrefixTable
, FALSE
))
3903 RxReleasePrefixTableLock(PrefixTable
);
3904 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3905 *LockState
= LHS_ExclusiveLockHeld
;
3909 RxReleasePrefixTableLock(PrefixTable
);
3910 *LockState
= LHS_ExclusiveLockHeld
;
3913 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
3915 /* If we reach that point, we found something, no need to create something */
3916 if (Container
!= NULL
)
3921 /* Get the name for the SRV_CALL */
3922 RxExtractServerName(FilePathName
, &SrvCallName
, NULL
);
3923 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName
);
3924 /* And create the SRV_CALL */
3925 SrvCall
= RxCreateSrvCall(RxContext
, &SrvCallName
, NULL
, RxConnectionId
);
3926 if (SrvCall
== NULL
)
3928 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3932 /* Reset RX_CONTEXT, so far, connection creation isn't a success */
3933 RxReferenceSrvCall(SrvCall
);
3934 RxContext
->Create
.pVNetRoot
= NULL
;
3935 RxContext
->Create
.pNetRoot
= NULL
;
3936 RxContext
->Create
.pSrvCall
= NULL
;
3937 RxContext
->Create
.Type
= NetRootType
;
3938 Container
= SrvCall
;
3940 /* Construct SRV_CALL, ie, use mini-rdr */
3941 Status
= RxConstructSrvCall(RxContext
, SrvCall
, LockState
);
3942 ASSERT(Status
!= STATUS_SUCCESS
|| RxIsPrefixTableLockAcquired(PrefixTable
));
3943 if (Status
!= STATUS_SUCCESS
)
3945 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status
);
3946 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
3947 RxDereferenceSrvCall(SrvCall
, *LockState
);
3948 RxReleasePrefixTableLock(PrefixTable
);
3952 /* Loop again to make use of SRV_CALL stable condition wait */
3955 /* At that point, we have a stable SRV_CALL (either found or constructed) */
3956 ASSERT((NodeType(SrvCall
) == RDBSS_NTC_SRVCALL
) && (SrvCall
->Condition
== Condition_Good
));
3957 ASSERT(NetRoot
== NULL
&& VNetRoot
== NULL
);
3958 ASSERT(SrvCall
->RxDeviceObject
== RxContext
->RxDeviceObject
);
3960 /* Call mini-rdr to get NetRoot name */
3961 SrvCall
->RxDeviceObject
->Dispatch
->MRxExtractNetRootName(FilePathName
, (PMRX_SRV_CALL
)SrvCall
, &NetRootName
, NULL
);
3962 /* And create the NetRoot with that name */
3963 NetRoot
= RxCreateNetRoot(SrvCall
, &NetRootName
, 0, RxConnectionId
);
3964 if (NetRoot
== NULL
)
3966 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3969 NetRoot
->Type
= NetRootType
;
3971 RxDereferenceSrvCall(SrvCall
, *LockState
);
3973 /* Finally, create the associated VNetRoot */
3974 VNetRoot
= RxCreateVNetRoot(RxContext
, NetRoot
, CanonicalName
, LocalNetRootName
, FilePathName
, RxConnectionId
);
3975 if (VNetRoot
== NULL
)
3977 RxFinalizeNetRoot(NetRoot
, TRUE
, TRUE
);
3978 Status
= STATUS_INSUFFICIENT_RESOURCES
;
3981 RxReferenceVNetRoot(VNetRoot
);
3983 /* We're get closer! */
3984 NetRoot
->Condition
= Condition_InTransition
;
3985 RxContext
->Create
.pSrvCall
= (PMRX_SRV_CALL
)SrvCall
;
3986 RxContext
->Create
.pNetRoot
= (PMRX_NET_ROOT
)NetRoot
;
3987 RxContext
->Create
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
3989 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */
3990 Status
= RxConstructNetRoot(RxContext
, SrvCall
, NetRoot
, VNetRoot
, LockState
);
3991 if (!NT_SUCCESS(Status
))
3993 RxTransitionVNetRoot(VNetRoot
, Condition_Bad
);
3994 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext
, VNetRoot
, Status
, VNetRoot
->Condition
);
3995 RxDereferenceVNetRoot(VNetRoot
, *LockState
);
3997 RxContext
->Create
.pNetRoot
= NULL
;
3998 RxContext
->Create
.pVNetRoot
= NULL
;
4002 PIO_STACK_LOCATION Stack
;
4004 ASSERT(*LockState
== LHS_ExclusiveLockHeld
);
4006 Stack
= RxContext
->CurrentIrpSp
;
4007 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_CREATE_TREE_CONNECTION
))
4009 RxExclusivePrefixTableLockToShared(PrefixTable
);
4010 *LockState
= LHS_SharedLockHeld
;
4016 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_CONNECTION_ACTIVE
)
4018 if (*LockState
!= LHS_LockNotHeld
)
4020 RxReleasePrefixTableLock(PrefixTable
);
4021 *LockState
= LHS_LockNotHeld
;
4027 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status
);
4036 RxFinishFcbInitialization(
4037 IN OUT PMRX_FCB Fcb
,
4038 IN RX_FILE_TYPE FileType
,
4039 IN PFCB_INIT_PACKET InitPacket OPTIONAL
)
4041 RX_FILE_TYPE OldType
;
4045 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb
, FileType
, InitPacket
);
4047 OldType
= NodeType(Fcb
);
4048 NodeType(Fcb
) = FileType
;
4049 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */
4050 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_TIME_AND_SIZE_ALREADY_SET
) && FileType
== RDBSS_NTC_MAILSLOT
)
4052 FILL_IN_FCB((PFCB
)Fcb
, 0, 0, 0, 0, 0, 0, 0, 0, 0);
4054 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */
4055 else if (InitPacket
!= NULL
)
4057 FILL_IN_FCB((PFCB
)Fcb
, *InitPacket
->pAttributes
, *InitPacket
->pNumLinks
,
4058 InitPacket
->pCreationTime
->QuadPart
, InitPacket
->pLastAccessTime
->QuadPart
,
4059 InitPacket
->pLastWriteTime
->QuadPart
, InitPacket
->pLastChangeTime
->QuadPart
,
4060 InitPacket
->pAllocationSize
->QuadPart
, InitPacket
->pFileSize
->QuadPart
,
4061 InitPacket
->pValidDataLength
->QuadPart
);
4064 if (FileType
!= RDBSS_NTC_STORAGE_TYPE_UNKNOWN
&&
4065 FileType
!= RDBSS_NTC_STORAGE_TYPE_DIRECTORY
)
4067 /* If our FCB newly points to a file, initiliaze everything related */
4068 if (FileType
== RDBSS_NTC_STORAGE_TYPE_FILE
)
4071 if (OldType
!= RDBSS_NTC_STORAGE_TYPE_FILE
)
4073 RxInitializeLowIoPerFcbInfo(&((PFCB
)Fcb
)->Specific
.Fcb
.LowIoPerFcbInfo
);
4074 FsRtlInitializeFileLock(&((PFCB
)Fcb
)->Specific
.Fcb
.FileLock
, RxLockOperationCompletion
,
4077 ((PFCB
)Fcb
)->BufferedLocks
.List
= NULL
;
4078 ((PFCB
)Fcb
)->BufferedLocks
.PendingLockOps
= 0;
4080 Fcb
->Header
.IsFastIoPossible
= FastIoIsQuestionable
;
4083 /* If not a file, validate type */
4086 ASSERT(FileType
>= RDBSS_NTC_SPOOLFILE
&& FileType
<= RDBSS_NTC_MAILSLOT
);
4095 RxFinishSrvCallConstruction(
4096 PMRX_SRVCALLDOWN_STRUCTURE Calldown
)
4100 PRX_CONTEXT Context
;
4101 RX_BLOCK_CONDITION Condition
;
4102 PRX_PREFIX_TABLE PrefixTable
;
4104 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown
);
4106 SrvCall
= (PSRV_CALL
)Calldown
->SrvCall
;
4107 Context
= Calldown
->RxContext
;
4108 PrefixTable
= Context
->RxDeviceObject
->pRxNetNameTable
;
4110 /* We have a winner, notify him */
4111 if (Calldown
->BestFinisher
!= NULL
)
4113 DPRINT("Notify the winner: %p (%wZ)\n", Calldown
->BestFinisher
, &Calldown
->BestFinisher
->DeviceName
);
4115 ASSERT(SrvCall
->RxDeviceObject
== Calldown
->BestFinisher
);
4117 MINIRDR_CALL_THROUGH(Status
, Calldown
->BestFinisher
->Dispatch
,
4118 MRxSrvCallWinnerNotify
,
4119 ((PMRX_SRV_CALL
)SrvCall
, TRUE
,
4120 Calldown
->CallbackContexts
[Calldown
->BestFinisherOrdinal
].RecommunicateContext
));
4121 if (Status
!= STATUS_SUCCESS
)
4123 Condition
= Condition_Bad
;
4127 Condition
= Condition_Good
;
4130 /* Otherwise, just fail our SRV_CALL */
4133 Status
= Calldown
->CallbackContexts
[0].Status
;
4134 Condition
= Condition_Bad
;
4137 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
4138 RxTransitionSrvCall(SrvCall
, Condition
);
4139 RxFreePoolWithTag(Calldown
, RX_SRVCALL_POOLTAG
);
4141 /* If async, finish it here, otherwise, caller has already finished the stuff */
4142 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
))
4144 DPRINT("Finishing async call\n");
4146 RxReleasePrefixTableLock(PrefixTable
);
4148 /* Make sure we weren't cancelled in-between */
4149 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_CANCELLED
))
4151 Status
= STATUS_CANCELLED
;
4154 /* In case that was a create, context can be reused */
4155 if (Context
->MajorFunction
== IRP_MJ_CREATE
)
4157 RxpPrepareCreateContextForReuse(Context
);
4160 /* If that's a failure, reset everything and return failure */
4161 if (Status
!= STATUS_SUCCESS
)
4163 Context
->MajorFunction
= Context
->CurrentIrpSp
->MajorFunction
;
4164 if (Context
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4166 if (Context
->Info
.Buffer
!= NULL
)
4168 RxFreePool(Context
->Info
.Buffer
);
4169 Context
->Info
.Buffer
= NULL
;
4172 Context
->CurrentIrp
->IoStatus
.Information
= 0;
4173 Context
->CurrentIrp
->IoStatus
.Status
= Status
;
4174 RxCompleteRequest(Context
, Status
);
4176 /* Otherwise, call resume routine and done! */
4179 Status
= Context
->ResumeRoutine(Context
);
4180 if (Status
!= STATUS_PENDING
)
4182 RxCompleteRequest(Context
, Status
);
4185 DPRINT("Not completing, pending\n");
4189 RxDereferenceSrvCall(SrvCall
, LHS_LockNotHeld
);
4198 RxFinishSrvCallConstructionDispatcher(
4202 BOOLEAN Direct
, KeepLoop
;
4204 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context
);
4206 /* In case of failure of starting dispatcher, context is not set
4207 * We keep track of it to fail associated SRV_CALL
4209 Direct
= (Context
== NULL
);
4211 /* Separated thread, loop forever */
4214 PLIST_ENTRY ListEntry
;
4215 PMRX_SRVCALLDOWN_STRUCTURE Calldown
;
4217 /* If there are no SRV_CALL to finalize left, just finish thread */
4218 KeAcquireSpinLock(&RxStrucSupSpinLock
, &OldIrql
);
4219 if (IsListEmpty(&RxSrvCalldownList
))
4222 RxSrvCallConstructionDispatcherActive
= FALSE
;
4224 /* Otherwise, get the SRV_CALL to finish construction */
4227 ListEntry
= RemoveHeadList(&RxSrvCalldownList
);
4230 KeReleaseSpinLock(&RxStrucSupSpinLock
, OldIrql
);
4238 /* If direct is set, reset the finisher to avoid electing a winner
4239 * and fail SRV_CALL (see upper comment)
4241 Calldown
= CONTAINING_RECORD(ListEntry
, MRX_SRVCALLDOWN_STRUCTURE
, SrvCalldownList
);
4244 Calldown
->BestFinisher
= NULL
;
4246 /* Finish SRV_CALL construction */
4247 RxFinishSrvCallConstruction(Calldown
);
4255 RxFlushFcbInSystemCache(
4257 IN BOOLEAN SynchronizeWithLazyWriter
)
4259 IO_STATUS_BLOCK IoStatus
;
4264 CcFlushCache(&Fcb
->NonPaged
->SectionObjectPointers
, NULL
, 0, &IoStatus
);
4265 /* If we're asked to sync with LW, do it in case of success */
4266 if (SynchronizeWithLazyWriter
&& NT_SUCCESS(IoStatus
.Status
))
4268 RxAcquirePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4269 RxReleasePagingIoResource((PRX_CONTEXT
)NULL
, Fcb
);
4272 DPRINT("Flushing for FCB %p returns %lx\n", Fcb
, IoStatus
.Status
);
4273 return IoStatus
.Status
;
4285 DPRINT("Freeing %p\n", Object
);
4287 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */
4288 if (NodeType(Object
) == RDBSS_NTC_FOBX
|| NodeType(Object
) == RDBSS_NTC_SRVOPEN
)
4290 RxFreePoolWithTag(Object
, RX_FCB_POOLTAG
);
4292 /* If that's a FCB... */
4293 else if (NodeTypeIsFcb(Object
))
4296 PRDBSS_DEVICE_OBJECT DeviceObject
;
4299 DeviceObject
= Fcb
->RxDeviceObject
;
4301 /* Delete per stream contexts */
4302 FsRtlTeardownPerStreamContexts(&Fcb
->Header
);
4304 SetFlag(Fcb
->Header
.Flags
, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH
);
4306 /* If there was a non-paged FCB allocated, free it */
4307 if (!BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_PAGING_FILE
))
4309 RxFreePoolWithTag(Fcb
->NonPaged
, RX_NONPAGEDFCB_POOLTAG
);
4315 /* Update statistics */
4316 InterlockedDecrement(&RxNumberOfActiveFcbs
);
4317 InterlockedDecrement((volatile long *)&DeviceObject
->NumberOfActiveFcbs
);
4330 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */
4331 if (NodeType(pObject
) == RDBSS_NTC_SRVCALL
)
4334 PRDBSS_DEVICE_OBJECT DeviceObject
;
4336 SrvCall
= (PSRV_CALL
)pObject
;
4337 DeviceObject
= SrvCall
->RxDeviceObject
;
4338 if (DeviceObject
!= NULL
)
4340 if (!BooleanFlagOn(DeviceObject
->Dispatch
->MRxFlags
, RDBSS_MANAGE_SRV_CALL_EXTENSION
))
4342 ASSERT(SrvCall
->Context
== NULL
);
4345 ASSERT(SrvCall
->Context2
== NULL
);
4347 SrvCall
->RxDeviceObject
= NULL
;
4350 else if (NodeType(pObject
) == RDBSS_NTC_NETROOT
)
4354 NetRoot
= (PNET_ROOT
)pObject
;
4355 NetRoot
->pSrvCall
= NULL
;
4356 NetRoot
->NodeTypeCode
= NodeType(pObject
) | 0xF000;
4359 /* And just free the object */
4360 RxFreePool(pObject
);
4367 RxGatherRequestsForSrvOpen(
4368 IN OUT PSRV_CALL SrvCall
,
4369 IN PSRV_OPEN SrvOpen
,
4370 IN OUT PLIST_ENTRY RequestsListHead
)
4373 LIST_ENTRY Discarded
, *Entry
;
4374 PCHANGE_BUFFERING_STATE_REQUEST Request
;
4376 /* Dispatch any pending operation first */
4377 RxpDispatchChangeBufferingStateRequests(SrvCall
, SrvOpen
, &Discarded
);
4379 /* Then, get any entry related to our key and SRV_OPEN */
4380 KeAcquireSpinLock(&SrvCall
->BufferingManager
.SpinLock
, &OldIrql
);
4381 Entry
= SrvCall
->BufferingManager
.HandlerList
.Flink
;
4382 while (Entry
!= &SrvCall
->BufferingManager
.HandlerList
)
4384 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4385 Entry
= Entry
->Flink
;
4386 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4388 RemoveEntryList(&Request
->ListEntry
);
4389 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4392 KeReleaseSpinLock(&SrvCall
->BufferingManager
.SpinLock
, OldIrql
);
4394 /* Perform the same search in the last change list */
4395 Entry
= SrvCall
->BufferingManager
.LastChanceHandlerList
.Flink
;
4396 while (Entry
!= &SrvCall
->BufferingManager
.LastChanceHandlerList
)
4398 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
4399 Entry
= Entry
->Flink
;
4400 if (Request
->SrvOpenKey
== SrvOpen
->Key
&& Request
->SrvOpen
== SrvOpen
)
4402 RemoveEntryList(&Request
->ListEntry
);
4403 InsertTailList(RequestsListHead
, &Request
->ListEntry
);
4407 /* Discard the discarded requests */
4408 RxpDiscardChangeBufferingStateRequests(&Discarded
);
4414 PRDBSS_DEVICE_OBJECT
4415 RxGetDeviceObjectOfInstance(
4418 NODE_TYPE_CODE NodeType
;
4419 PRDBSS_DEVICE_OBJECT DeviceObject
;
4423 /* We only handle a few object types */
4424 NodeType
= NodeType(Instance
);
4425 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
4426 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) || (NodeType
== RDBSS_NTC_FOBX
));
4428 /* Get the device object depending on the object */
4431 case RDBSS_NTC_FOBX
:
4435 Fobx
= (PFOBX
)Instance
;
4436 DeviceObject
= Fobx
->RxDeviceObject
;
4440 case RDBSS_NTC_SRVCALL
:
4444 SrvCall
= (PSRV_CALL
)Instance
;
4445 DeviceObject
= SrvCall
->RxDeviceObject
;
4449 case RDBSS_NTC_NETROOT
:
4453 NetRoot
= (PNET_ROOT
)Instance
;
4454 DeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
4458 case RDBSS_NTC_V_NETROOT
:
4460 PV_NET_ROOT VNetRoot
;
4462 VNetRoot
= (PV_NET_ROOT
)Instance
;
4463 DeviceObject
= VNetRoot
->pNetRoot
->pSrvCall
->RxDeviceObject
;
4467 case RDBSS_NTC_SRVOPEN
:
4471 SrvOpen
= (PSRV_OPEN
)Instance
;
4472 DeviceObject
= ((PFCB
)SrvOpen
->pFcb
)->RxDeviceObject
;
4477 DeviceObject
= NULL
;
4482 return DeviceObject
;
4489 RxGetFileSizeWithLock(
4491 OUT PLONGLONG FileSize
)
4495 *FileSize
= Fcb
->Header
.FileSize
.QuadPart
;
4506 return RxData
.OurProcess
;
4513 RxInitializeBufferingManager(
4516 KeInitializeSpinLock(&SrvCall
->BufferingManager
.SpinLock
);
4517 InitializeListHead(&SrvCall
->BufferingManager
.DispatcherList
);
4518 InitializeListHead(&SrvCall
->BufferingManager
.HandlerList
);
4519 InitializeListHead(&SrvCall
->BufferingManager
.LastChanceHandlerList
);
4520 SrvCall
->BufferingManager
.DispatcherActive
= FALSE
;
4521 SrvCall
->BufferingManager
.HandlerInactive
= FALSE
;
4522 SrvCall
->BufferingManager
.LastChanceHandlerActive
= FALSE
;
4523 SrvCall
->BufferingManager
.NumberOfOutstandingOpens
= 0;
4524 InitializeListHead(&SrvCall
->BufferingManager
.SrvOpenLists
[0]);
4525 ExInitializeFastMutex(&SrvCall
->BufferingManager
.Mutex
);
4527 return STATUS_SUCCESS
;
4535 RxInitializeContext(
4537 IN PRDBSS_DEVICE_OBJECT RxDeviceObject
,
4538 IN ULONG InitialContextFlags
,
4539 IN OUT PRX_CONTEXT RxContext
)
4541 PIO_STACK_LOCATION Stack
;
4543 /* Initialize our various fields */
4544 RxContext
->NodeTypeCode
= RDBSS_NTC_RX_CONTEXT
;
4545 RxContext
->NodeByteSize
= sizeof(RX_CONTEXT
);
4546 RxContext
->ReferenceCount
= 1;
4547 RxContext
->SerialNumber
= InterlockedExchangeAdd((volatile LONG
*)&RxContextSerialNumberCounter
, 1);
4548 RxContext
->RxDeviceObject
= RxDeviceObject
;
4549 KeInitializeEvent(&RxContext
->SyncEvent
, SynchronizationEvent
, FALSE
);
4550 RxInitializeScavengerEntry(&RxContext
->ScavengerEntry
);
4551 InitializeListHead(&RxContext
->BlockedOperations
);
4552 RxContext
->MRxCancelRoutine
= NULL
;
4553 RxContext
->ResumeRoutine
= NULL
;
4554 RxContext
->Flags
|= InitialContextFlags
;
4555 RxContext
->CurrentIrp
= Irp
;
4556 RxContext
->LastExecutionThread
= PsGetCurrentThread();
4557 RxContext
->OriginalThread
= RxContext
->LastExecutionThread
;
4559 /* If've got no IRP, mark RX_CONTEXT */
4562 RxContext
->CurrentIrpSp
= NULL
;
4563 RxContext
->MajorFunction
= IRP_MJ_MAXIMUM_FUNCTION
+ 1;
4564 RxContext
->MinorFunction
= 0;
4568 /* Otherwise, first determine whether we are performing async operation */
4569 Stack
= IoGetCurrentIrpStackLocation(Irp
);
4570 if (Stack
->FileObject
!= NULL
)
4574 Fcb
= Stack
->FileObject
->FsContext
;
4575 if (!IoIsOperationSynchronous(Irp
) ||
4576 ((Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
)) &&
4577 (Stack
->MajorFunction
== IRP_MJ_READ
|| Stack
->MajorFunction
== IRP_MJ_WRITE
|| Stack
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
4578 (Fcb
->pNetRoot
!= NULL
&& (Fcb
->pNetRoot
->Type
== NET_ROOT_PIPE
))))
4580 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4584 if (Stack
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& Stack
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
)
4586 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4588 if (Stack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
)
4590 RxContext
->Flags
|= RX_CONTEXT_FLAG_ASYNC_OPERATION
;
4593 /* Set proper flags if TopLevl IRP/Device */
4594 if (!RxIsThisTheTopLevelIrp(Irp
))
4596 RxContext
->Flags
|= RX_CONTEXT_FLAG_RECURSIVE_CALL
;
4598 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject
)
4600 RxContext
->Flags
|= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL
;
4603 /* Copy stack information */
4604 RxContext
->MajorFunction
= Stack
->MajorFunction
;
4605 RxContext
->MinorFunction
= Stack
->MinorFunction
;
4606 ASSERT(RxContext
->MajorFunction
<= IRP_MJ_MAXIMUM_FUNCTION
);
4607 RxContext
->CurrentIrpSp
= Stack
;
4609 /* If we have a FO associated, learn for more */
4610 if (Stack
->FileObject
!= NULL
)
4615 /* Get the FCB and CCB (FOBX) */
4616 Fcb
= Stack
->FileObject
->FsContext
;
4617 Fobx
= Stack
->FileObject
->FsContext2
;
4618 RxContext
->pFcb
= (PMRX_FCB
)Fcb
;
4619 if (Fcb
!= NULL
&& NodeTypeIsFcb(Fcb
))
4621 RxContext
->NonPagedFcb
= Fcb
->NonPaged
;
4624 /* We have a FOBX, this not a DFS opening, keep track of it */
4625 if (Fobx
!= NULL
&& Fobx
!= UIntToPtr(DFS_OPEN_CONTEXT
) && Fobx
!= UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT
))
4627 RxContext
->pFobx
= (PMRX_FOBX
)Fobx
;
4628 RxContext
->pRelevantSrvOpen
= Fobx
->pSrvOpen
;
4629 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4631 RxContext
->FobxSerialNumber
= InterlockedIncrement((volatile LONG
*)&Fobx
->FobxSerialNumber
);
4636 RxContext
->pFobx
= NULL
;
4639 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */
4640 if (RxContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
&& RxContext
->MinorFunction
== IRP_MN_NOTIFY_CHANGE_DIRECTORY
&&
4643 PV_NET_ROOT VNetRoot
= NULL
;
4645 if (Fobx
->NodeTypeCode
== RDBSS_NTC_FOBX
)
4647 VNetRoot
= Fcb
->VNetRoot
;
4649 else if (Fobx
->NodeTypeCode
== RDBSS_NTC_V_NETROOT
)
4651 VNetRoot
= (PV_NET_ROOT
)Fobx
;
4654 if (VNetRoot
!= NULL
)
4656 RxContext
->NotifyChangeDirectory
.pVNetRoot
= (PMRX_V_NET_ROOT
)VNetRoot
;
4660 /* Remember if that's a write through file */
4661 RxContext
->RealDevice
= Stack
->FileObject
->DeviceObject
;
4662 if (BooleanFlagOn(Stack
->FileObject
->Flags
, FO_WRITE_THROUGH
))
4664 RxContext
->Flags
|= RX_CONTEXT_FLAG_WRITE_THROUGH
;
4669 if (RxContext
->MajorFunction
!= IRP_MJ_DEVICE_CONTROL
)
4671 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n",
4672 RxContext
, RxContext
->MinorFunction
, Irp
,
4673 PsGetCurrentThread(), RxContext
->pFcb
, RxContext
->pFobx
,
4674 RxContext
->SerialNumber
);
4683 RxInitializeDebugSupport(
4694 RxInitializeDispatcher(
4698 HANDLE ThreadHandle
;
4702 RxFileSystemDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4703 RxFileSystemDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4705 /* Set appropriate timeouts: 10s & 60s */
4706 RxWorkQueueWaitInterval
[CriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4707 RxWorkQueueWaitInterval
[DelayedWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4708 RxWorkQueueWaitInterval
[HyperCriticalWorkQueue
].QuadPart
= -10 * 1000 * 1000 * 10;
4709 RxSpinUpDispatcherWaitInterval
.QuadPart
= -60 * 1000 * 1000 * 10;
4711 RxDispatcher
.NumberOfProcessors
= 1;
4712 RxDispatcher
.OwnerProcess
= IoGetCurrentProcess();
4713 RxDispatcher
.pWorkQueueDispatcher
= &RxDispatcherWorkQueues
;
4715 /* Initialize our dispatchers */
4716 Status
= RxInitializeWorkQueueDispatcher(RxDispatcher
.pWorkQueueDispatcher
);
4717 if (!NT_SUCCESS(Status
))
4722 Status
= RxInitializeMRxDispatcher(RxFileSystemDeviceObject
);
4723 if (!NT_SUCCESS(Status
))
4728 /* And start them */
4729 RxDispatcher
.State
= RxDispatcherActive
;
4730 InitializeListHead(&RxDispatcher
.SpinUpRequests
);
4731 KeInitializeSpinLock(&RxDispatcher
.SpinUpRequestsLock
);
4732 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsEvent
, 0, 0);
4733 KeInitializeEvent(&RxDispatcher
.SpinUpRequestsTearDownEvent
, 0, 0);
4734 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
,
4735 NULL
, NULL
, RxSpinUpRequestsDispatcher
, &RxDispatcher
);
4736 if (NT_SUCCESS(Status
))
4738 ZwClose(ThreadHandle
);
4748 RxInitializeFcbTable(
4749 IN OUT PRX_FCB_TABLE FcbTable
,
4750 IN BOOLEAN CaseInsensitiveMatch
)
4756 FcbTable
->NodeTypeCode
= RDBSS_NTC_FCB_TABLE
;
4757 FcbTable
->NodeByteSize
= sizeof(RX_FCB_TABLE
);
4759 ExInitializeResourceLite(&FcbTable
->TableLock
);
4760 FcbTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4761 FcbTable
->Version
= 0;
4762 FcbTable
->TableEntryForNull
= NULL
;
4764 FcbTable
->NumberOfBuckets
= RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS
;
4765 for (i
= 0; i
< FcbTable
->NumberOfBuckets
; ++i
)
4767 InitializeListHead(&FcbTable
->HashBuckets
[i
]);
4770 FcbTable
->Lookups
= 0;
4771 FcbTable
->FailedLookups
= 0;
4772 FcbTable
->Compares
= 0;
4780 RxInitializeLowIoContext(
4781 OUT PLOWIO_CONTEXT LowIoContext
,
4784 PRX_CONTEXT RxContext
;
4785 PIO_STACK_LOCATION Stack
;
4789 RxContext
= CONTAINING_RECORD(LowIoContext
, RX_CONTEXT
, LowIoContext
);
4790 ASSERT(LowIoContext
== &RxContext
->LowIoContext
);
4792 Stack
= RxContext
->CurrentIrpSp
;
4794 KeInitializeEvent(&RxContext
->SyncEvent
, NotificationEvent
, FALSE
);
4795 RxContext
->LowIoContext
.ResourceThreadId
= (ERESOURCE_THREAD
)PsGetCurrentThread();
4796 RxContext
->LowIoContext
.Operation
= Operation
;
4801 case LOWIO_OP_WRITE
:
4802 /* In case of RW, set a canary, to make sure these fields are properly set
4803 * they will be asserted when lowio request will be submit to mini-rdr
4806 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteOffset
= 0xFFFFFFEE;
4807 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.ByteCount
= 0xEEEEEEEE;
4808 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Key
= Stack
->Parameters
.Read
.Key
;
4810 /* Keep track of paging IOs */
4811 if (BooleanFlagOn(RxContext
->CurrentIrp
->Flags
, IRP_PAGING_IO
))
4813 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= LOWIO_READWRITEFLAG_PAGING_IO
;
4817 RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
= 0;
4822 case LOWIO_OP_FSCTL
:
4823 case LOWIO_OP_IOCTL
:
4824 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */
4825 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.Flags
= 0;
4826 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= 0;
4827 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= NULL
;
4828 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= 0;
4829 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
4830 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= 0;
4833 /* Nothing to do for these */
4834 case LOWIO_OP_SHAREDLOCK
:
4835 case LOWIO_OP_EXCLUSIVELOCK
:
4836 case LOWIO_OP_UNLOCK
:
4837 case LOWIO_OP_UNLOCK_MULTIPLE
:
4838 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
4839 case LOWIO_OP_CLEAROUT
:
4843 /* Should never happen */
4853 RxInitializeLowIoPerFcbInfo(
4854 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo
)
4858 InitializeListHead(&LowIoPerFcbInfo
->PagingIoReadsOutstanding
);
4859 InitializeListHead(&LowIoPerFcbInfo
->PagingIoWritesOutstanding
);
4866 RxInitializeMRxDispatcher(
4867 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject
)
4871 pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
= 0;
4872 pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
= NULL
;
4874 return STATUS_SUCCESS
;
4881 RxInitializePrefixTable(
4882 IN OUT PRX_PREFIX_TABLE ThisTable
,
4883 IN ULONG TableSize OPTIONAL
,
4884 IN BOOLEAN CaseInsensitiveMatch
)
4890 TableSize
= RX_PREFIX_TABLE_DEFAULT_LENGTH
;
4893 ThisTable
->NodeTypeCode
= RDBSS_NTC_PREFIX_TABLE
;
4894 ThisTable
->NodeByteSize
= sizeof(RX_PREFIX_TABLE
);
4895 InitializeListHead(&ThisTable
->MemberQueue
);
4896 ThisTable
->Version
= 0;
4897 ThisTable
->TableEntryForNull
= NULL
;
4898 ThisTable
->IsNetNameTable
= FALSE
;
4899 ThisTable
->CaseInsensitiveMatch
= CaseInsensitiveMatch
;
4900 ThisTable
->TableSize
= TableSize
;
4906 for (i
= 0; i
< RX_PREFIX_TABLE_DEFAULT_LENGTH
; ++i
)
4908 InitializeListHead(&ThisTable
->HashBuckets
[i
]);
4917 RxInitializePurgeSyncronizationContext(
4918 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext
)
4922 InitializeListHead(&PurgeSyncronizationContext
->ContextsAwaitingPurgeCompletion
);
4923 PurgeSyncronizationContext
->PurgeInProgress
= FALSE
;
4927 RxInitializeSrvCallParameters(
4928 IN PRX_CONTEXT RxContext
,
4929 IN OUT PSRV_CALL SrvCall
)
4933 SrvCall
->pPrincipalName
= NULL
;
4935 /* We only have stuff to initialize for file opening from DFS */
4936 if (RxContext
->MajorFunction
!= IRP_MJ_CREATE
|| RxContext
->Create
.EaLength
== 0)
4938 return STATUS_SUCCESS
;
4941 ASSERT(RxContext
->Create
.EaBuffer
!= NULL
);
4944 return STATUS_NOT_IMPLEMENTED
;
4952 RxInitializeRxTimer(
4957 RxTimerInterval
.QuadPart
= -550000;
4958 KeInitializeSpinLock(&RxTimerLock
);
4959 InitializeListHead(&RxTimerQueueHead
);
4960 InitializeListHead(&RxRecurrentWorkItemsList
);
4961 KeInitializeDpc(&RxTimerDpc
, RxTimerDispatch
, NULL
);
4962 KeInitializeTimer(&RxTimer
);
4963 RxTimerTickCount
= 0;
4965 return STATUS_SUCCESS
;
4969 RxInitializeVNetRootParameters(
4970 PRX_CONTEXT RxContext
,
4972 OUT PULONG SessionId
,
4973 OUT PUNICODE_STRING
*UserNamePtr
,
4974 OUT PUNICODE_STRING
*UserDomainNamePtr
,
4975 OUT PUNICODE_STRING
*PasswordPtr
,
4979 PACCESS_TOKEN Token
;
4983 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext
,
4984 LogonId
, SessionId
, UserNamePtr
, UserDomainNamePtr
, PasswordPtr
, Flags
);
4986 *UserNamePtr
= NULL
;
4987 *UserDomainNamePtr
= NULL
;
4988 *PasswordPtr
= NULL
;
4989 /* By default, that's not CSC instance */
4990 *Flags
&= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
4992 Token
= SeQuerySubjectContextToken(&RxContext
->Create
.NtCreateParameters
.SecurityContext
->AccessState
->SubjectSecurityContext
);
4993 if (SeTokenIsRestricted(Token
))
4995 return STATUS_ACCESS_DENIED
;
4999 Status
= SeQueryAuthenticationIdToken(Token
, LogonId
);
5000 if (!NT_SUCCESS(Status
))
5006 Status
= SeQuerySessionIdToken(Token
, SessionId
);
5007 if (!NT_SUCCESS(Status
))
5012 if (RxContext
->Create
.UserName
.Buffer
!= NULL
)
5015 Status
= STATUS_NOT_IMPLEMENTED
;
5019 /* Deal with connection credentials */
5020 if (RxContext
->Create
.UserDomainName
.Buffer
!= NULL
)
5023 Status
= STATUS_NOT_IMPLEMENTED
;
5027 if (RxContext
->Create
.Password
.Buffer
!= NULL
)
5030 Status
= STATUS_NOT_IMPLEMENTED
;
5035 if (NT_SUCCESS(Status
))
5037 /* If that's a CSC instance, mark it as such */
5038 if (RxIsThisACscAgentOpen(RxContext
))
5040 *Flags
|= VNETROOT_FLAG_CSCAGENT_INSTANCE
;
5052 RxInitializeWorkQueue(
5053 PRX_WORK_QUEUE WorkQueue
,
5054 WORK_QUEUE_TYPE WorkQueueType
,
5055 ULONG MaximumNumberOfWorkerThreads
,
5056 ULONG MinimumNumberOfWorkerThreads
)
5060 WorkQueue
->Type
= WorkQueueType
;
5061 WorkQueue
->MaximumNumberOfWorkerThreads
= MaximumNumberOfWorkerThreads
;
5062 WorkQueue
->MinimumNumberOfWorkerThreads
= MinimumNumberOfWorkerThreads
;
5064 WorkQueue
->State
= RxWorkQueueActive
;
5065 WorkQueue
->SpinUpRequestPending
= FALSE
;
5066 WorkQueue
->pRundownContext
= NULL
;
5067 WorkQueue
->NumberOfWorkItemsDispatched
= 0;
5068 WorkQueue
->NumberOfWorkItemsToBeDispatched
= 0;
5069 WorkQueue
->CumulativeQueueLength
= 0;
5070 WorkQueue
->NumberOfSpinUpRequests
= 0;
5071 WorkQueue
->NumberOfActiveWorkerThreads
= 0;
5072 WorkQueue
->NumberOfIdleWorkerThreads
= 0;
5073 WorkQueue
->NumberOfFailedSpinUpRequests
= 0;
5074 WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
= 0;
5075 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.List
.Flink
= NULL
;
5076 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.WorkerRoutine
= NULL
;
5077 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.Parameter
= NULL
;
5078 WorkQueue
->WorkQueueItemForTearDownWorkQueue
.pDeviceObject
= NULL
;
5079 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.List
.Flink
= NULL
;
5080 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.WorkerRoutine
= NULL
;
5081 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.Parameter
= NULL
;
5082 WorkQueue
->WorkQueueItemForSpinUpWorkerThread
.pDeviceObject
= NULL
;
5083 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.List
.Flink
= NULL
;
5084 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.WorkerRoutine
= NULL
;
5085 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.Parameter
= NULL
;
5086 WorkQueue
->WorkQueueItemForSpinDownWorkerThread
.pDeviceObject
= NULL
;
5088 KeInitializeQueue(&WorkQueue
->Queue
, MaximumNumberOfWorkerThreads
);
5089 KeInitializeSpinLock(&WorkQueue
->SpinLock
);
5096 RxInitializeWorkQueueDispatcher(
5097 PRX_WORK_QUEUE_DISPATCHER Dispatcher
)
5100 ULONG MaximumNumberOfWorkerThreads
;
5104 /* Number of threads will depend on system capacity */
5105 if (MmQuerySystemSize() != MmLargeSystem
)
5107 MaximumNumberOfWorkerThreads
= 5;
5111 MaximumNumberOfWorkerThreads
= 10;
5114 /* Initialize the work queues */
5115 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[CriticalWorkQueue
], CriticalWorkQueue
,
5116 MaximumNumberOfWorkerThreads
, 1);
5117 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[DelayedWorkQueue
], DelayedWorkQueue
, 2, 1);
5118 RxInitializeWorkQueue(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
], HyperCriticalWorkQueue
, 5, 1);
5120 /* And start the worker threads */
5121 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
],
5122 RxBootstrapWorkerThreadDispatcher
,
5123 &Dispatcher
->WorkQueue
[HyperCriticalWorkQueue
]);
5124 if (!NT_SUCCESS(Status
))
5129 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[CriticalWorkQueue
],
5130 RxBootstrapWorkerThreadDispatcher
,
5131 &Dispatcher
->WorkQueue
[CriticalWorkQueue
]);
5132 if (!NT_SUCCESS(Status
))
5137 Status
= RxSpinUpWorkerThread(&Dispatcher
->WorkQueue
[DelayedWorkQueue
],
5138 RxBootstrapWorkerThreadDispatcher
,
5139 &Dispatcher
->WorkQueue
[DelayedWorkQueue
]);
5147 RxInitiateSrvOpenKeyAssociation(
5148 IN OUT PSRV_OPEN SrvOpen
)
5150 PRX_BUFFERING_MANAGER BufferingManager
;
5154 SrvOpen
->Key
= NULL
;
5156 /* Just keep track of the opening request */
5157 BufferingManager
= &((PSRV_CALL
)((PFCB
)SrvOpen
->pFcb
)->VNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
;
5158 InterlockedIncrement(&BufferingManager
->NumberOfOutstandingOpens
);
5160 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
5167 RxInsertWorkQueueItem(
5168 PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
5169 WORK_QUEUE_TYPE WorkQueueType
,
5170 PRX_WORK_QUEUE_ITEM WorkQueueItem
)
5174 BOOLEAN SpinUpThreads
;
5175 PRX_WORK_QUEUE WorkQueue
;
5177 /* No dispatcher, nothing to insert */
5178 if (RxDispatcher
.State
!= RxDispatcherActive
)
5180 return STATUS_UNSUCCESSFUL
;
5183 /* Get the work queue */
5184 WorkQueue
= &RxDispatcher
.pWorkQueueDispatcher
->WorkQueue
[WorkQueueType
];
5186 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
5187 /* Only insert if the work queue is in decent state */
5188 if (WorkQueue
->State
!= RxWorkQueueActive
|| pMRxDeviceObject
->DispatcherContext
.pTearDownEvent
!= NULL
)
5190 Status
= STATUS_UNSUCCESSFUL
;
5194 SpinUpThreads
= FALSE
;
5195 WorkQueueItem
->pDeviceObject
= pMRxDeviceObject
;
5196 InterlockedIncrement(&pMRxDeviceObject
->DispatcherContext
.NumberOfWorkerThreads
);
5197 WorkQueue
->CumulativeQueueLength
+= WorkQueue
->NumberOfWorkItemsToBeDispatched
;
5198 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
5200 /* If required (and possible!), spin up a new worker thread */
5201 if (WorkQueue
->NumberOfIdleWorkerThreads
< WorkQueue
->NumberOfWorkItemsToBeDispatched
&&
5202 WorkQueue
->NumberOfActiveWorkerThreads
< WorkQueue
->MaximumNumberOfWorkerThreads
&&
5203 !WorkQueue
->SpinUpRequestPending
)
5205 WorkQueue
->SpinUpRequestPending
= TRUE
;
5206 SpinUpThreads
= TRUE
;
5209 Status
= STATUS_SUCCESS
;
5211 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
5213 /* If we failed, return and still not insert item */
5214 if (!NT_SUCCESS(Status
))
5219 /* All fine, insert the item */
5220 KeInsertQueue(&WorkQueue
->Queue
, &WorkQueueItem
->List
);
5222 /* And start a new worker thread if needed */
5225 RxSpinUpWorkerThreads(WorkQueue
);
5232 RxIsThisACscAgentOpen(
5233 IN PRX_CONTEXT RxContext
)
5239 /* Client Side Caching is DFS stuff - we don't support it */
5240 if (RxContext
->Create
.EaLength
!= 0)
5245 if (RxContext
->Create
.NtCreateParameters
.DfsNameContext
!= NULL
&&
5246 ((PDFS_NAME_CONTEXT
)RxContext
->Create
.NtCreateParameters
.DfsNameContext
)->NameContextType
== 0xAAAAAAAA)
5256 IN PRX_CONTEXT RxContext
,
5257 IN LOCK_OPERATION Operation
,
5258 IN ULONG BufferLength
)
5267 Irp
= RxContext
->CurrentIrp
;
5268 /* If we already have a MDL, make sure it's locked */
5269 if (Irp
->MdlAddress
!= NULL
)
5271 ASSERT(RxLowIoIsMdlLocked(Irp
->MdlAddress
));
5275 /* That likely means the driver asks for buffered IOs - we don't support it! */
5276 ASSERT(!BooleanFlagOn(Irp
->Flags
, IRP_INPUT_OPERATION
));
5278 /* If we have a real length */
5279 if (BufferLength
> 0)
5281 /* Allocate a MDL and lock it */
5282 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, BufferLength
, FALSE
, FALSE
, Irp
);
5285 RxContext
->StoredStatus
= STATUS_INSUFFICIENT_RESOURCES
;
5286 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
5289 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, Operation
);
5293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
5297 Status
= _SEH2_GetExceptionCode();
5299 /* Free the possible MDL we have allocated */
5301 Irp
->MdlAddress
= NULL
;
5303 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
;
5306 if (!FsRtlIsNtstatusExpected(Status
))
5308 Status
= STATUS_INVALID_USER_BUFFER
;
5311 RxContext
->IoStatusBlock
.Status
= Status
;
5312 ExRaiseStatus(Status
);
5321 RxLowIoCompletionTail(
5322 IN PRX_CONTEXT RxContext
)
5329 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext
);
5331 /* Only continue if we're at APC_LEVEL or lower */
5332 if (RxShouldPostCompletion() &&
5333 !BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL
))
5335 return STATUS_MORE_PROCESSING_REQUIRED
;
5338 /* Call the completion routine */
5339 DPRINT("Calling completion routine: %p\n", RxContext
->LowIoContext
.CompletionRoutine
);
5340 Status
= RxContext
->LowIoContext
.CompletionRoutine(RxContext
);
5341 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
|| Status
== STATUS_RETRY
)
5346 /* If it was a RW operation, for a paging file ... */
5347 Operation
= RxContext
->LowIoContext
.Operation
;
5348 if (Operation
== LOWIO_OP_READ
|| Operation
== LOWIO_OP_WRITE
)
5350 /* Remove ourselves from the list and resume operations */
5351 if (BooleanFlagOn(RxContext
->LowIoContext
.ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5353 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5354 RemoveEntryList(&RxContext
->RxContextSerializationQLinks
);
5355 RxContext
->RxContextSerializationQLinks
.Flink
= NULL
;
5356 RxContext
->RxContextSerializationQLinks
.Blink
= NULL
;
5357 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5358 RxResumeBlockedOperations_ALL(RxContext
);
5363 /* Sanity check: we had known operation */
5364 ASSERT(Operation
< LOWIO_OP_MAXIMUM
);
5367 /* If not sync operation, complete now. Otherwise, caller has already completed */
5368 if (!BooleanFlagOn(RxContext
->LowIoContext
.Flags
, LOWIO_CONTEXT_FLAG_SYNCCALL
))
5370 RxCompleteRequest(RxContext
, Status
);
5373 DPRINT("Status: %x\n", Status
);
5382 RxLowIoPopulateFsctlInfo(
5383 IN PRX_CONTEXT RxContext
)
5388 PIO_STACK_LOCATION Stack
;
5392 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext
);
5394 Irp
= RxContext
->CurrentIrp
;
5395 Stack
= RxContext
->CurrentIrpSp
;
5397 /* Copy stack parameters */
5398 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
= Stack
->Parameters
.FileSystemControl
.FsControlCode
;
5399 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.InputBufferLength
= Stack
->Parameters
.FileSystemControl
.InputBufferLength
;
5400 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.OutputBufferLength
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
;
5401 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.MinorFunction
= Stack
->MinorFunction
;
5402 Method
= METHOD_FROM_CTL_CODE(RxContext
->LowIoContext
.ParamsFor
.FsCtl
.FsControlCode
);
5404 /* Same buffer in case of buffered */
5405 if (Method
== METHOD_BUFFERED
)
5407 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5408 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5410 return STATUS_SUCCESS
;
5413 /* Two buffers for neither */
5414 if (Method
== METHOD_NEITHER
)
5416 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
5417 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= Irp
->UserBuffer
;
5419 return STATUS_SUCCESS
;
5422 /* Only IN/OUT remain */
5423 ASSERT(Method
== METHOD_IN_DIRECT
|| Method
== METHOD_OUT_DIRECT
);
5425 /* Use system buffer for input */
5426 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pInputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
5427 /* And MDL for output */
5428 Mdl
= Irp
->MdlAddress
;
5431 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= MmGetSystemAddressForMdlSafe(Mdl
, NormalPagePriority
);
5432 if (RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
== NULL
)
5434 return STATUS_INSUFFICIENT_RESOURCES
;
5439 RxContext
->LowIoContext
.ParamsFor
.FsCtl
.pOutputBuffer
= NULL
;
5442 return STATUS_SUCCESS
;
5448 IN PRX_CONTEXT RxContext
,
5449 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine
)
5453 BOOLEAN Synchronous
;
5454 PLOWIO_CONTEXT LowIoContext
;
5456 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext
, CompletionRoutine
);
5460 LowIoContext
= &RxContext
->LowIoContext
;
5461 Synchronous
= !BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_ASYNC_OPERATION
);
5463 LowIoContext
->CompletionRoutine
= CompletionRoutine
;
5465 Status
= STATUS_SUCCESS
;
5466 Operation
= LowIoContext
->Operation
;
5470 case LOWIO_OP_WRITE
:
5471 /* Check that the parameters were properly set by caller
5472 * See comment in RxInitializeLowIoContext()
5474 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteOffset
!= 0xFFFFFFEE);
5475 ASSERT(LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
!= 0xEEEEEEEE);
5477 /* Lock the buffer */
5478 RxLockUserBuffer(RxContext
,
5479 (Operation
== LOWIO_OP_READ
? IoWriteAccess
: IoReadAccess
),
5480 LowIoContext
->ParamsFor
.ReadWrite
.ByteCount
);
5481 if (RxNewMapUserBuffer(RxContext
) == NULL
)
5483 return STATUS_INSUFFICIENT_RESOURCES
;
5485 LowIoContext
->ParamsFor
.ReadWrite
.Buffer
= RxContext
->CurrentIrp
->MdlAddress
;
5487 /* If that's a paging IO, initialize serial operation */
5488 if (BooleanFlagOn(LowIoContext
->ParamsFor
.ReadWrite
.Flags
, LOWIO_READWRITEFLAG_PAGING_IO
))
5492 Fcb
= (PFCB
)RxContext
->pFcb
;
5494 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5495 RxContext
->BlockedOpsMutex
= &RxLowIoPagingIoSyncMutex
;
5496 if (Operation
== LOWIO_OP_READ
)
5498 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoReadsOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5502 InsertTailList(&Fcb
->Specific
.Fcb
.PagingIoWritesOutstanding
, &RxContext
->RxContextSerializationQLinks
);
5505 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex
);
5510 case LOWIO_OP_FSCTL
:
5511 case LOWIO_OP_IOCTL
:
5512 /* Set FSCTL/IOCTL parameters */
5513 Status
= RxLowIoPopulateFsctlInfo(RxContext
);
5514 /* Check whether we're consistent: a length means a buffer */
5515 if (NT_SUCCESS(Status
))
5517 if ((LowIoContext
->ParamsFor
.FsCtl
.InputBufferLength
> 0 &&
5518 LowIoContext
->ParamsFor
.FsCtl
.pInputBuffer
== NULL
) ||
5519 (LowIoContext
->ParamsFor
.FsCtl
.OutputBufferLength
> 0 &&
5520 LowIoContext
->ParamsFor
.FsCtl
.pOutputBuffer
== NULL
))
5522 Status
= STATUS_INVALID_PARAMETER
;
5528 case LOWIO_OP_SHAREDLOCK
:
5529 case LOWIO_OP_EXCLUSIVELOCK
:
5530 case LOWIO_OP_UNLOCK
:
5531 case LOWIO_OP_UNLOCK_MULTIPLE
:
5532 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY
:
5533 case LOWIO_OP_CLEAROUT
:
5538 Status
= STATUS_INVALID_PARAMETER
;
5542 /* No need to perform extra init in case of posting */
5543 RxContext
->Flags
|= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED
;
5545 /* Preflight checks were OK, time to submit */
5546 if (NT_SUCCESS(Status
))
5548 PMINIRDR_DISPATCH Dispatch
;
5552 InterlockedIncrement((volatile long *)&RxContext
->ReferenceCount
);
5553 /* If not synchronous, we're likely to return before the operation is finished */
5554 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5556 IoMarkIrpPending(RxContext
->CurrentIrp
);
5560 Dispatch
= RxContext
->RxDeviceObject
->Dispatch
;
5561 if (Dispatch
!= NULL
)
5563 /* We'll try to execute until the mini-rdr doesn't return pending */
5566 RxContext
->IoStatusBlock
.Information
= 0;
5568 MINIRDR_CALL(Status
, RxContext
, Dispatch
, MRxLowIOSubmit
[Operation
], (RxContext
));
5569 if (Status
== STATUS_PENDING
)
5571 /* Unless it's not synchronous, caller will be happy with pending op */
5577 RxWaitSync(RxContext
);
5578 Status
= RxContext
->IoStatusBlock
.Status
;
5584 /* We had marked the IRP pending, whereas the operation finished, drop that */
5585 if (Status
!= STATUS_RETRY
)
5587 if (!BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_IN_FSP
))
5589 RxContext
->CurrentIrpSp
->Flags
&= ~SL_PENDING_RETURNED
;
5592 InterlockedDecrement((volatile long *)&RxContext
->ReferenceCount
);
5596 } while (Status
== STATUS_PENDING
);
5600 Status
= STATUS_INVALID_PARAMETER
;
5604 /* Call completion and return */
5605 RxContext
->IoStatusBlock
.Status
= Status
;
5606 LowIoContext
->Flags
|= LOWIO_CONTEXT_FLAG_SYNCCALL
;
5607 return RxLowIoCompletionTail(RxContext
);
5615 IN PRX_CONTEXT RxContext
)
5621 Irp
= RxContext
->CurrentIrp
;
5622 /* We should have a MDL (buffered IOs are not supported!) */
5623 if (Irp
->MdlAddress
!= NULL
)
5626 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5629 /* Just return system buffer */
5630 return Irp
->AssociatedIrp
.SystemBuffer
;
5637 RxMarkFobxOnCleanup(
5642 PFOBX ScavengerFobx
;
5643 LARGE_INTEGER TickCount
;
5644 PRDBSS_SCAVENGER Scavenger
;
5648 /* No FOBX, nothing to mark */
5654 /* Query time for close */
5655 KeQueryTickCount(&TickCount
);
5657 Fcb
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
5658 ASSERT(NodeTypeIsFcb(Fcb
));
5660 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5661 RxAcquireScavengerMutex();
5663 ScavengerFobx
= NULL
;
5664 /* If that's not a file, or even not a disk resource, just mark as dormant */
5665 if (NodeType(Fcb
) != RDBSS_NTC_STORAGE_TYPE_FILE
|| Fcb
->VNetRoot
->pNetRoot
->DeviceType
!= FILE_DEVICE_DISK
)
5667 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5668 InitializeListHead(&pFobx
->ClosePendingList
);
5669 ++Scavenger
->NumberOfDormantFiles
;
5673 ASSERT(Scavenger
->NumberOfDormantFiles
>= 0);
5674 /* If we're about to reach the maximum dormant of FOBX */
5675 if (Scavenger
->NumberOfDormantFiles
>= Scavenger
->MaximumNumberOfDormantFiles
)
5677 /* This should never be wrong... */
5678 if (!IsListEmpty(&Scavenger
->ClosePendingFobxsList
))
5680 /* Then, take the first from the list (oldest) and save it for later purge */
5681 ScavengerFobx
= CONTAINING_RECORD(Scavenger
->ClosePendingFobxsList
.Flink
, FOBX
, ClosePendingList
);
5682 if (ScavengerFobx
->pSrvOpen
!= NULL
&& ScavengerFobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
5685 ScavengerFobx
= NULL
;
5689 RxReferenceNetFobx(ScavengerFobx
);
5694 /* Mark ourselves as dormant */
5695 SetFlag(pFobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5696 pFobx
->CloseTime
.QuadPart
= TickCount
.QuadPart
;
5698 /* And insert us in the list of dormant files */
5699 InsertTailList(&Scavenger
->ClosePendingFobxsList
, &pFobx
->ClosePendingList
);
5700 /* If scavenger was inactive, start it */
5701 if (Scavenger
->NumberOfDormantFiles
++ == 0 && Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
5703 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
5704 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
, RxScavengerTimerRoutine
,
5705 Fcb
->RxDeviceObject
, Scavenger
->TimeLimit
);
5709 RxReleaseScavengerMutex();
5711 /* If we had reached max */
5712 if (ScavengerFobx
!= NULL
)
5716 /* Purge the oldest FOBX */
5717 Status
= RxPurgeFobxFromCache(ScavengerFobx
);
5718 if (Status
!= STATUS_SUCCESS
)
5733 PRDBSS_SCAVENGER Scavenger
;
5737 /* No FOBX, nothing to mark */
5743 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5744 ASSERT(NodeTypeIsFcb(Fcb
));
5746 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
5748 RxAcquireScavengerMutex();
5749 /* Only mark it if it was already marked as dormant */
5750 if (BooleanFlagOn(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
))
5752 /* If FCB wasn't already decrement, do it now */
5753 if (!Fobx
->fOpenCountDecremented
)
5755 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
5756 ASSERT(NodeTypeIsFcb(Fcb
));
5757 InterlockedDecrement((volatile long *)&Fcb
->OpenCount
);
5759 Fobx
->fOpenCountDecremented
= TRUE
;
5762 /* We're no longer dormant */
5763 InterlockedDecrement(&Scavenger
->NumberOfDormantFiles
);
5764 ClearFlag(Fobx
->Flags
, FOBX_FLAG_MARKED_AS_DORMANT
);
5767 /* If we were inserted in the scavenger, drop ourselves out */
5768 if (!IsListEmpty(&Fobx
->ClosePendingList
))
5770 RemoveEntryList(&Fobx
->ClosePendingList
);
5771 InitializeListHead(&Fobx
->ClosePendingList
);
5774 RxReleaseScavengerMutex();
5782 PRX_CONTEXT RxContext
)
5788 Irp
= RxContext
->CurrentIrp
;
5789 if (Irp
->MdlAddress
!= NULL
)
5791 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
5794 return Irp
->UserBuffer
;
5824 IN PV_NET_ROOT ThisVNetRoot
)
5829 PRX_FCB_TABLE FcbTable
;
5830 PRX_PREFIX_TABLE PrefixTable
;
5834 /* Mailslot won't have any SRV_OPEN (to orphan) */
5835 NetRoot
= (PNET_ROOT
)ThisVNetRoot
->pNetRoot
;
5836 if (NetRoot
->Type
== NET_ROOT_MAILSLOT
)
5841 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
5842 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable
));
5844 FcbTable
= &NetRoot
->FcbTable
;
5845 RxAcquireFcbTableLockExclusive(FcbTable
, TRUE
);
5849 /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */
5850 for (Bucket
= 0; Bucket
< FcbTable
->NumberOfBuckets
; ++Bucket
)
5852 PLIST_ENTRY BucketList
, Entry
;
5854 BucketList
= &FcbTable
->HashBuckets
[Bucket
];
5855 Entry
= BucketList
->Flink
;
5856 while (Entry
!= BucketList
)
5858 Fcb
= CONTAINING_RECORD(Entry
, FCB
, FcbTableEntry
.HashLinks
);
5859 Entry
= Entry
->Flink
;
5861 ASSERT(NodeTypeIsFcb(Fcb
));
5862 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5866 /* Of course, don't forget about NULL-entry */
5867 if (FcbTable
->TableEntryForNull
!= NULL
)
5869 Fcb
= CONTAINING_RECORD(FcbTable
->TableEntryForNull
, FCB
, FcbTableEntry
.HashLinks
);
5870 ASSERT(NodeTypeIsFcb(Fcb
));
5871 RxOrphanSrvOpensForThisFcb(Fcb
, ThisVNetRoot
, FALSE
);
5876 RxReleaseFcbTableLock(FcbTable
);
5882 RxOrphanSrvOpensForThisFcb(
5884 IN PV_NET_ROOT ThisVNetRoot
,
5885 IN BOOLEAN OrphanAll
)
5894 RxpAcquirePrefixTableLockShared(
5895 PRX_PREFIX_TABLE pTable
,
5897 BOOLEAN ProcessBufferingStateChangeRequests
)
5901 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5902 pTable
->TableLock
.ActiveEntries
);
5904 return ExAcquireResourceSharedLite(&pTable
->TableLock
, Wait
);
5911 RxpAcquirePrefixTableLockExclusive(
5912 PRX_PREFIX_TABLE pTable
,
5914 BOOLEAN ProcessBufferingStateChangeRequests
)
5918 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable
, Wait
, ProcessBufferingStateChangeRequests
,
5919 pTable
->TableLock
.ActiveEntries
);
5921 return ExAcquireResourceExclusiveLite(&pTable
->TableLock
, Wait
);
5928 RxpDereferenceAndFinalizeNetFcb(
5930 IN PRX_CONTEXT RxContext
,
5931 IN BOOLEAN RecursiveFinalize
,
5932 IN BOOLEAN ForceFinalize
)
5937 BOOLEAN ResourceAcquired
, NetRootReferenced
, Freed
;
5941 ASSERT(!ForceFinalize
);
5942 ASSERT(NodeTypeIsFcb(ThisFcb
));
5943 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
5945 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */
5946 References
= InterlockedDecrement((volatile long *)&ThisFcb
->NodeReferenceCount
);
5947 if (!ForceFinalize
&& !RecursiveFinalize
&& (ThisFcb
->OpenCount
!= 0 || ThisFcb
->UncleanCount
!= 0 || References
> 1))
5953 Status
= STATUS_SUCCESS
;
5954 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
5955 ResourceAcquired
= FALSE
;
5956 NetRootReferenced
= FALSE
;
5957 /* If FCB isn't orphaned, it still have context attached */
5958 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_ORPHANED
))
5960 /* Don't let NetRoot go away before we're done */
5961 RxReferenceNetRoot(NetRoot
);
5962 NetRootReferenced
= TRUE
;
5964 /* Try to acquire the table lock exclusively */
5965 if (!RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
))
5967 RxReferenceNetFcb(ThisFcb
);
5969 if (!RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, FALSE
))
5971 if (RxContext
!= NULL
&& RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT
&&
5972 RxContext
!= CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
5974 RxContext
->Flags
|= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
;
5977 RxReleaseFcb(RxContext
, ThisFcb
);
5979 RxAcquireFcbTableLockExclusive(&NetRoot
->FcbTable
, TRUE
);
5981 Status
= RxAcquireExclusiveFcb(RxContext
, ThisFcb
);
5984 References
= RxDereferenceNetFcb(ThisFcb
);
5986 ResourceAcquired
= TRUE
;
5990 /* If locking was OK (or not needed!), attempt finalization */
5991 if (Status
== STATUS_SUCCESS
)
5993 Freed
= RxFinalizeNetFcb(ThisFcb
, RecursiveFinalize
, ForceFinalize
, References
);
5996 /* Release table lock if acquired */
5997 if (ResourceAcquired
)
5999 RxReleaseFcbTableLock(&NetRoot
->FcbTable
);
6002 /* We don't need the NetRoot anylonger */
6003 if (NetRootReferenced
)
6005 RxDereferenceNetRoot(NetRoot
, LHS_LockNotHeld
);
6015 RxpDereferenceNetFcb(
6022 ASSERT(NodeTypeIsFcb(Fcb
));
6024 NewCount
= InterlockedDecrement((volatile long *)&Fcb
->NodeReferenceCount
);
6025 ASSERT(NewCount
>= 0);
6027 PRINT_REF_COUNT(NETFCB
, NewCount
);
6042 BOOLEAN ForceFinalize
;
6043 PRX_PREFIX_TABLE PrefixTable
;
6045 SrvCall
= (PSRV_CALL
)Context
;
6046 /* At this step, RxFinalizeSrvCall already cleaned some fields */
6047 ASSERT(SrvCall
->UpperFinalizationDone
);
6049 PrefixTable
= SrvCall
->RxDeviceObject
->pRxNetNameTable
;
6050 /* Were we called with ForceFinalize? */
6051 ForceFinalize
= BooleanFlagOn(SrvCall
->Flags
, SRVCALL_FLAG_FORCE_FINALIZED
);
6053 /* Notify mini-rdr */
6054 MINIRDR_CALL_THROUGH(Status
, SrvCall
->RxDeviceObject
->Dispatch
,
6055 MRxFinalizeSrvCall
, ((PMRX_SRV_CALL
)SrvCall
,
6059 /* Dereference our extra reference (set before queueing) */
6060 RxAcquirePrefixTableLockExclusive(PrefixTable
, TRUE
);
6061 InterlockedDecrement((volatile long *)&SrvCall
->NodeReferenceCount
);
6062 /* And finalize for real, with the right context */
6063 RxFinalizeSrvCall(SrvCall
, FALSE
, ForceFinalize
);
6064 RxReleasePrefixTableLock(PrefixTable
);
6071 RxpDiscardChangeBufferingStateRequests(
6072 _Inout_ PLIST_ENTRY DiscardedRequests
)
6078 /* No requests to discard */
6079 if (IsListEmpty(DiscardedRequests
))
6084 /* Free all the discarded requests */
6085 Entry
= DiscardedRequests
->Flink
;
6086 while (Entry
!= DiscardedRequests
)
6088 PCHANGE_BUFFERING_STATE_REQUEST Request
;
6090 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
6091 Entry
= Entry
->Flink
;
6093 DPRINT("Req %p for %p (%p) discarded\n", Request
, Request
->SrvOpenKey
, Request
->SrvOpen
);
6095 RxPrepareRequestForReuse(Request
);
6096 RxFreePool(Request
);
6104 RxpDispatchChangeBufferingStateRequests(
6107 PLIST_ENTRY DiscardedRequests
)
6111 BOOLEAN StartDispatcher
;
6112 LIST_ENTRY AcceptedReqs
;
6113 LIST_ENTRY DispatcherList
;
6114 PRX_BUFFERING_MANAGER BufferingManager
;
6116 /* Initialize our lists */
6117 InitializeListHead(&AcceptedReqs
);
6118 InitializeListHead(DiscardedRequests
);
6120 /* Transfer the requests to dispatch locally */
6121 BufferingManager
= &SrvCall
->BufferingManager
;
6122 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
6123 RxTransferList(&DispatcherList
, &BufferingManager
->DispatcherList
);
6124 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6126 /* If there were requests */
6127 if (!IsListEmpty(&DispatcherList
))
6131 /* For each of the entries... */
6132 Entry
= DispatcherList
.Flink
;
6133 while (Entry
!= &DispatcherList
)
6135 PCHANGE_BUFFERING_STATE_REQUEST Request
;
6137 Request
= CONTAINING_RECORD(Entry
, CHANGE_BUFFERING_STATE_REQUEST
, ListEntry
);
6138 Entry
= Entry
->Flink
;
6140 /* If we have been provided a SRV_OPEN, see whether it matches */
6141 if (SrvOpen
!= NULL
)
6143 /* Match, the request is accepted */
6144 if (Request
->SrvOpenKey
== SrvOpen
->Key
)
6146 Request
->SrvOpen
= SrvOpen
;
6147 RxReferenceSrvOpen(SrvOpen
);
6149 RemoveEntryList(&Request
->ListEntry
);
6150 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
6152 /* Move to the next entry */
6157 Status
= STATUS_PENDING
;
6162 /* No SRV_OPEN provided, try to find one */
6163 Status
= RxpLookupSrvOpenForRequestLite(SrvCall
, Request
);
6166 /* We found a matching SRV_OPEN, accept the request */
6167 if (Status
== STATUS_SUCCESS
)
6169 RemoveEntryList(&Request
->ListEntry
);
6170 InsertTailList(&AcceptedReqs
, &Request
->ListEntry
);
6172 /* Another run might help handling it, don't discard it */
6173 else if (Status
== STATUS_PENDING
)
6177 /* Otherwise, discard the request */
6180 ASSERT(Status
== STATUS_NOT_FOUND
);
6182 RemoveEntryList(&Request
->ListEntry
);
6183 InsertTailList(DiscardedRequests
, &Request
->ListEntry
);
6188 KeAcquireSpinLock(&BufferingManager
->SpinLock
, &OldIrql
);
6189 /* Nothing to dispatch, no need to start dispatcher */
6190 if (IsListEmpty(&DispatcherList
))
6192 StartDispatcher
= FALSE
;
6196 /* Transfer back the list of the not treated entries to the buffering manager */
6197 RxTransferList(&BufferingManager
->DispatcherList
, &DispatcherList
);
6198 StartDispatcher
= (BufferingManager
->DispatcherActive
== FALSE
);
6199 /* If the dispatcher isn't active, start it */
6200 if (StartDispatcher
)
6202 BufferingManager
->DispatcherActive
= TRUE
;
6206 /* If there were accepted requests, move them to the buffering manager */
6207 if (!IsListEmpty(&AcceptedReqs
))
6209 RxTransferList(&BufferingManager
->HandlerList
, &AcceptedReqs
);
6211 KeReleaseSpinLock(&BufferingManager
->SpinLock
, OldIrql
);
6213 /* If we're to start the dispatcher, do it */
6214 if (StartDispatcher
)
6216 RxReferenceSrvCall(SrvCall
);
6217 DPRINT("Starting dispatcher\n");
6218 RxPostToWorkerThread(RxFileSystemDeviceObject
, HyperCriticalWorkQueue
,
6219 &BufferingManager
->DispatcherWorkItem
,
6220 RxDispatchChangeBufferingStateRequests
, SrvCall
);
6228 RxpLookupSrvOpenForRequestLite(
6229 IN PSRV_CALL SrvCall
,
6230 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request
)
6238 Status
= STATUS_SUCCESS
;
6239 /* Browse all our associated SRV_OPENs to find the one! */
6240 for (Entry
= SrvCall
->BufferingManager
.SrvOpenLists
[0].Flink
;
6241 Entry
!= &SrvCall
->BufferingManager
.SrvOpenLists
[0];
6242 Entry
= Entry
->Flink
)
6244 /* Same key, not orphaned, this is ours */
6245 SrvOpen
= CONTAINING_RECORD(Entry
, SRV_OPEN
, SrvOpenKeyList
);
6246 if (SrvOpen
->Key
== Request
->SrvOpenKey
)
6248 if (!BooleanFlagOn(SrvOpen
->pFcb
->FcbState
, FCB_STATE_ORPHANED
))
6250 RxReferenceSrvOpen(SrvOpen
);
6256 /* We didn't manage to find a SRV_OPEN */
6257 if (Entry
== &SrvCall
->BufferingManager
.SrvOpenLists
[0])
6261 /* The coming open might help, mark as pending for later retry */
6262 if (SrvCall
->BufferingManager
.NumberOfOutstandingOpens
!= 0)
6264 Status
= STATUS_PENDING
;
6266 /* Else, it's a complete failure */
6269 Status
= STATUS_NOT_FOUND
;
6273 /* Return the (not) found SRV_OPEN */
6274 Request
->SrvOpen
= SrvOpen
;
6283 RxpMarkInstanceForScavengedFinalization(
6286 NODE_TYPE_CODE NodeType
;
6287 PNODE_TYPE_AND_SIZE Node
;
6288 PRDBSS_SCAVENGER Scavenger
;
6289 PRDBSS_DEVICE_OBJECT DeviceObject
;
6290 PLIST_ENTRY ScavengerHead
, InstEntry
;
6294 /* If still referenced, don't mark it (broken caller) */
6295 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6296 if (Node
->NodeReferenceCount
> 1)
6301 DeviceObject
= RxGetDeviceObjectOfInstance(Instance
);
6302 Scavenger
= DeviceObject
->pRdbssScavenger
;
6305 NodeType
= NodeType(Instance
);
6306 SetFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6307 DPRINT("Node %p has now the scavenger mark!\n", Instance
);
6309 /* Increase the count in the scavenger, and queue it */
6310 ScavengerHead
= NULL
;
6313 case RDBSS_NTC_FOBX
:
6314 ++Scavenger
->FobxsToBeFinalized
;
6315 ScavengerHead
= &Scavenger
->FobxFinalizationList
;
6316 InstEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6319 case RDBSS_NTC_SRVCALL
:
6320 ++Scavenger
->SrvCallsToBeFinalized
;
6321 ScavengerHead
= &Scavenger
->SrvCallFinalizationList
;
6322 InstEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6325 case RDBSS_NTC_NETROOT
:
6326 ++Scavenger
->NetRootsToBeFinalized
;
6327 ScavengerHead
= &Scavenger
->NetRootFinalizationList
;
6328 InstEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6331 case RDBSS_NTC_V_NETROOT
:
6332 ++Scavenger
->VNetRootsToBeFinalized
;
6333 ScavengerHead
= &Scavenger
->VNetRootFinalizationList
;
6334 InstEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6337 case RDBSS_NTC_SRVOPEN
:
6338 ++Scavenger
->SrvOpensToBeFinalized
;
6339 ScavengerHead
= &Scavenger
->SrvOpenFinalizationList
;
6340 InstEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6344 /* Extra ref for scavenger */
6345 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
6347 /* If matching type */
6348 if (ScavengerHead
!= NULL
)
6350 /* Insert in the scavenger list */
6351 InsertTailList(ScavengerHead
, InstEntry
);
6353 /* And if it wasn't started, start it */
6354 if (Scavenger
->State
== RDBSS_SCAVENGER_INACTIVE
)
6356 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
6357 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
6358 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
6368 RxPostOneShotTimerRequest(
6369 IN PRDBSS_DEVICE_OBJECT pDeviceObject
,
6370 IN PRX_WORK_ITEM pWorkItem
,
6371 IN PRX_WORKERTHREAD_ROUTINE Routine
,
6373 IN LARGE_INTEGER TimeInterval
)
6377 ASSERT(pWorkItem
!= NULL
);
6379 /* Prepare the work item */
6380 ExInitializeWorkItem(&pWorkItem
->WorkQueueItem
, Routine
, pContext
);
6381 pWorkItem
->WorkQueueItem
.pDeviceObject
= pDeviceObject
;
6383 /* Last tick can be computed with the number of times it was caller (timertickcount)
6384 * and the interval between calls
6386 KeAcquireSpinLock(&RxTimerLock
, &OldIrql
);
6387 pWorkItem
->LastTick
= (TimeInterval
.QuadPart
/ 550000) + RxTimerTickCount
+ 1;
6388 /* Insert in work queue */
6389 InsertTailList(&RxTimerQueueHead
, &pWorkItem
->WorkQueueItem
.List
);
6390 KeReleaseSpinLock(&RxTimerLock
, OldIrql
);
6392 /* If there are queued events, queue an execution */
6393 if (IsListEmpty(&RxTimerQueueHead
))
6395 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
6398 return STATUS_SUCCESS
;
6406 RxPostToWorkerThread(
6407 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject
,
6408 _In_ WORK_QUEUE_TYPE WorkQueueType
,
6409 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem
,
6410 _In_ PRX_WORKERTHREAD_ROUTINE Routine
,
6411 _In_ PVOID pContext
)
6413 /* Initialize work queue item */
6414 pWorkQueueItem
->List
.Flink
= NULL
;
6415 pWorkQueueItem
->WorkerRoutine
= Routine
;
6416 pWorkQueueItem
->Parameter
= pContext
;
6418 /* And insert it in the work queue */
6419 return RxInsertWorkQueueItem(pMRxDeviceObject
, WorkQueueType
, pWorkQueueItem
);
6423 RxpProcessChangeBufferingStateRequests(
6425 BOOLEAN UpdateHandlerState
)
6434 RxPrefixTableInsertName(
6435 IN OUT PRX_PREFIX_TABLE ThisTable
,
6436 IN OUT PRX_PREFIX_ENTRY ThisEntry
,
6438 IN PULONG ContainerRefCount
,
6439 IN USHORT CaseInsensitiveLength
,
6440 IN PRX_CONNECTION_ID ConnectionId
6445 DPRINT("Insert: %wZ\n", &ThisEntry
->Prefix
);
6447 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
6448 ASSERT(CaseInsensitiveLength
<= ThisEntry
->Prefix
.Length
);
6450 /* Copy parameters and compute hash */
6451 ThisEntry
->CaseInsensitiveLength
= CaseInsensitiveLength
;
6452 ThisEntry
->ContainingRecord
= Container
;
6453 ThisEntry
->ContainerRefCount
= ContainerRefCount
;
6454 InterlockedIncrement((volatile long *)ContainerRefCount
);
6455 ThisEntry
->SavedHashValue
= RxTableComputeHashValue(&ThisEntry
->Prefix
);
6456 DPRINT("Associated hash: %x\n", ThisEntry
->SavedHashValue
);
6458 /* If no path length: this is entry for null path */
6459 if (ThisEntry
->Prefix
.Length
== 0)
6461 ThisTable
->TableEntryForNull
= ThisEntry
;
6463 /* Otherwise, insert in the appropriate bucket */
6466 InsertTailList(HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
), &ThisEntry
->HashLinks
);
6469 /* If we had a connection ID, keep track of it */
6470 if (ConnectionId
!= NULL
)
6472 ThisEntry
->ConnectionId
.Luid
= ConnectionId
->Luid
;
6476 ThisEntry
->ConnectionId
.Luid
.LowPart
= 0;
6477 ThisEntry
->ConnectionId
.Luid
.HighPart
= 0;
6480 InsertTailList(&ThisTable
->MemberQueue
, &ThisEntry
->MemberQLinks
);
6481 /* Reflect the changes */
6482 ++ThisTable
->Version
;
6484 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable
, ThisEntry
->SavedHashValue
));
6493 RxPrefixTableLookupName(
6494 IN PRX_PREFIX_TABLE ThisTable
,
6495 IN PUNICODE_STRING CanonicalName
,
6496 OUT PUNICODE_STRING RemainingName
,
6497 IN PRX_CONNECTION_ID ConnectionId
)
6503 ASSERT(RxIsPrefixTableLockAcquired(ThisTable
));
6504 ASSERT(CanonicalName
->Length
> 0);
6506 /* Call the internal helper */
6507 Container
= RxTableLookupName(ThisTable
, CanonicalName
, RemainingName
, ConnectionId
);
6508 if (Container
== NULL
)
6513 /* Reference our container before returning it */
6514 if (RdbssReferenceTracingValue
!= 0)
6516 NODE_TYPE_CODE Type
;
6518 Type
= (NodeType(Container
) & ~RX_SCAVENGER_MASK
);
6521 case RDBSS_NTC_SRVCALL
:
6522 RxReferenceSrvCall(Container
);
6525 case RDBSS_NTC_NETROOT
:
6526 RxReferenceNetRoot(Container
);
6529 case RDBSS_NTC_V_NETROOT
:
6530 RxReferenceVNetRoot(Container
);
6534 DPRINT1("Invalid node type: %x\n", Type
);
6536 RxReference(Container
);
6542 RxReference(Container
);
6559 ASSERT(NodeTypeIsFcb(Fcb
));
6561 NewCount
= InterlockedIncrement((volatile long *)&Fcb
->NodeReferenceCount
);
6563 PRINT_REF_COUNT(NETFCB
, Fcb
->NodeReferenceCount
);
6572 RxpReleasePrefixTableLock(
6573 PRX_PREFIX_TABLE pTable
,
6574 BOOLEAN ProcessBufferingStateChangeRequests
)
6578 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable
, ProcessBufferingStateChangeRequests
,
6579 pTable
->TableLock
.ActiveEntries
);
6581 ExReleaseResourceLite(&pTable
->TableLock
);
6589 RxPrepareContextForReuse(
6590 IN OUT PRX_CONTEXT RxContext
)
6594 /* When we reach that point, make sure mandatory parts are null-ed */
6595 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
6597 ASSERT(RxContext
->Create
.CanonicalNameBuffer
== NULL
);
6598 RxContext
->Create
.RdrFlags
= 0;
6600 else if (RxContext
->MajorFunction
== IRP_MJ_READ
|| RxContext
->MajorFunction
== IRP_MJ_WRITE
)
6602 ASSERT(RxContext
->RxContextSerializationQLinks
.Flink
== NULL
);
6603 ASSERT(RxContext
->RxContextSerializationQLinks
.Blink
== NULL
);
6606 RxContext
->ReferenceCount
= 0;
6613 RxPrepareRequestForReuse(
6614 PCHANGE_BUFFERING_STATE_REQUEST Request
)
6620 SrvOpen
= Request
->SrvOpen
;
6622 /* If the request was already prepared for service */
6623 if (BooleanFlagOn(Request
->Flags
, RX_REQUEST_PREPARED_FOR_HANDLING
))
6625 /* We have to dereference the associated SRV_OPEN depending on the lock */
6626 if (RxIsFcbAcquiredExclusive(SrvOpen
->pFcb
))
6628 RxDereferenceSrvOpen(SrvOpen
, LHS_ExclusiveLockHeld
);
6632 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6635 /* Otherwise, just dereference */
6636 else if (SrvOpen
!= NULL
)
6638 RxDereferenceSrvOpen(SrvOpen
, LHS_LockNotHeld
);
6641 Request
->SrvOpen
= NULL
;
6649 RxProcessChangeBufferingStateRequests(
6652 /* Call internal routine */
6653 RxUndoScavengerFinalizationMarking(SrvCall
);
6654 RxpProcessChangeBufferingStateRequests(SrvCall
, TRUE
);
6661 RxProcessChangeBufferingStateRequestsForSrvOpen(
6664 LONG NumberOfBufferingChangeRequests
, LockedOldBufferingToken
, OldBufferingToken
;
6666 /* Get the current number of change requests */
6667 NumberOfBufferingChangeRequests
= ((PSRV_CALL
)SrvOpen
->pVNetRoot
->pNetRoot
->pSrvCall
)->BufferingManager
.CumulativeNumberOfBufferingChangeRequests
;
6668 /* Get our old token */
6669 OldBufferingToken
= SrvOpen
->BufferingToken
;
6670 LockedOldBufferingToken
= InterlockedCompareExchange(&SrvOpen
->BufferingToken
,
6671 NumberOfBufferingChangeRequests
,
6672 NumberOfBufferingChangeRequests
);
6673 /* If buffering state changed in between, process changes */
6674 if (OldBufferingToken
!= LockedOldBufferingToken
)
6679 /* Acquire the FCB and start processing */
6680 Fcb
= (PFCB
)SrvOpen
->pFcb
;
6681 Status
= RxAcquireExclusiveFcb(NULL
, Fcb
);
6682 if (Status
== STATUS_SUCCESS
)
6684 RxProcessFcbChangeBufferingStateRequest(Fcb
);
6685 RxReleaseFcb(NULL
, Fcb
);
6691 RxProcessFcbChangeBufferingStateRequest(
6702 PRDBSS_SCAVENGER Scavenger
,
6703 PLIST_ENTRY FobxToScavenge
)
6705 /* Explore the whole list of FOBX to scavenge */
6706 while (!IsListEmpty(FobxToScavenge
))
6712 Entry
= RemoveHeadList(FobxToScavenge
);
6713 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ScavengerFinalizationList
);
6714 Fcb
= (PFCB
)Fobx
->SrvOpen
->pFcb
;
6716 /* Try to acquire the lock exclusively to perform finalization */
6717 if (RxAcquireExclusiveFcb(NULL
, Fcb
) != STATUS_SUCCESS
)
6719 RxDereferenceNetRoot(Fobx
, LHS_LockNotHeld
);
6723 RxReferenceNetFcb(Fcb
);
6724 RxDereferenceNetRoot(Fobx
, LHS_ExclusiveLockHeld
);
6726 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6728 RxReleaseFcb(NULL
, Fcb
);
6735 RxpTrackDereference(
6736 _In_ ULONG TraceType
,
6737 _In_ PCSTR FileName
,
6739 _In_ PVOID Instance
)
6742 ULONG ReferenceCount
;
6746 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6753 case RDBSS_REF_TRACK_SRVCALL
:
6754 InstanceType
= "SrvCall";
6755 ReferenceCount
= ((PSRV_CALL
)Instance
)->NodeReferenceCount
;
6758 case RDBSS_REF_TRACK_NETROOT
:
6759 InstanceType
= "NetRoot";
6760 ReferenceCount
= ((PNET_ROOT
)Instance
)->NodeReferenceCount
;
6763 case RDBSS_REF_TRACK_VNETROOT
:
6764 InstanceType
= "VNetRoot";
6765 ReferenceCount
= ((PV_NET_ROOT
)Instance
)->NodeReferenceCount
;
6768 case RDBSS_REF_TRACK_NETFOBX
:
6769 InstanceType
= "NetFobx";
6770 ReferenceCount
= ((PFOBX
)Instance
)->NodeReferenceCount
;
6773 case RDBSS_REF_TRACK_NETFCB
:
6774 InstanceType
= "NetFcb";
6775 ReferenceCount
= ((PFCB
)Instance
)->NodeReferenceCount
;
6778 case RDBSS_REF_TRACK_SRVOPEN
:
6779 InstanceType
= "SrvOpen";
6780 ReferenceCount
= ((PSRV_OPEN
)Instance
)->NodeReferenceCount
;
6784 DPRINT1("Invalid node type!\n");
6788 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_LOG_REF_TRACKING
))
6793 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_PRINT_REF_TRACKING
))
6795 DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName
, Line
, Instance
, InstanceType
, ReferenceCount
);
6803 _In_ ULONG TraceType
,
6804 _In_ PCSTR FileName
,
6806 _In_ PVOID Instance
)
6809 ULONG ReferenceCount
;
6811 if (!BooleanFlagOn(RdbssReferenceTracingValue
, TraceType
))
6818 case RDBSS_REF_TRACK_SRVCALL
:
6819 InstanceType
= "SrvCall";
6820 ReferenceCount
= ((PSRV_CALL
)Instance
)->NodeReferenceCount
;
6823 case RDBSS_REF_TRACK_NETROOT
:
6824 InstanceType
= "NetRoot";
6825 ReferenceCount
= ((PNET_ROOT
)Instance
)->NodeReferenceCount
;
6828 case RDBSS_REF_TRACK_VNETROOT
:
6829 InstanceType
= "VNetRoot";
6830 ReferenceCount
= ((PV_NET_ROOT
)Instance
)->NodeReferenceCount
;
6833 case RDBSS_REF_TRACK_NETFOBX
:
6834 InstanceType
= "NetFobx";
6835 ReferenceCount
= ((PFOBX
)Instance
)->NodeReferenceCount
;
6838 case RDBSS_REF_TRACK_NETFCB
:
6839 InstanceType
= "NetFcb";
6840 ReferenceCount
= ((PFCB
)Instance
)->NodeReferenceCount
;
6843 case RDBSS_REF_TRACK_SRVOPEN
:
6844 InstanceType
= "SrvOpen";
6845 ReferenceCount
= ((PSRV_OPEN
)Instance
)->NodeReferenceCount
;
6849 DPRINT1("Invalid node type!\n");
6853 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_LOG_REF_TRACKING
))
6858 if (BooleanFlagOn(RdbssReferenceTracingValue
, RX_PRINT_REF_TRACKING
))
6860 DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName
, Line
, Instance
, InstanceType
, ReferenceCount
);
6868 RxpUndoScavengerFinalizationMarking(
6871 PLIST_ENTRY ListEntry
;
6872 PNODE_TYPE_AND_SIZE Node
;
6873 PRDBSS_SCAVENGER Scavenger
;
6877 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
6878 /* There's no marking - nothing to do */
6879 if (!BooleanFlagOn(NodeType(Node
), RX_SCAVENGER_MASK
))
6884 /* First of all, remove the mark */
6885 ClearFlag(NodeType(Node
), RX_SCAVENGER_MASK
);
6886 DPRINT("Node %p no longer has the scavenger mark\n");
6888 /* And now, remove from the scavenger */
6889 Scavenger
= RxGetDeviceObjectOfInstance(Instance
)->pRdbssScavenger
;
6890 switch (NodeType(Node
))
6892 case RDBSS_NTC_FOBX
:
6893 --Scavenger
->FobxsToBeFinalized
;
6894 ListEntry
= &((PFOBX
)Instance
)->ScavengerFinalizationList
;
6897 case RDBSS_NTC_SRVCALL
:
6898 --Scavenger
->SrvCallsToBeFinalized
;
6899 ListEntry
= &((PSRV_CALL
)Instance
)->ScavengerFinalizationList
;
6902 case RDBSS_NTC_NETROOT
:
6903 --Scavenger
->NetRootsToBeFinalized
;
6904 ListEntry
= &((PNET_ROOT
)Instance
)->ScavengerFinalizationList
;
6907 case RDBSS_NTC_V_NETROOT
:
6908 --Scavenger
->VNetRootsToBeFinalized
;
6909 ListEntry
= &((PV_NET_ROOT
)Instance
)->ScavengerFinalizationList
;
6912 case RDBSS_NTC_SRVOPEN
:
6913 --Scavenger
->SrvOpensToBeFinalized
;
6914 ListEntry
= &((PSRV_OPEN
)Instance
)->ScavengerFinalizationList
;
6921 /* Also, remove the extra ref from the scavenger */
6922 RemoveEntryList(ListEntry
);
6923 InterlockedDecrement((volatile long *)&Node
->NodeReferenceCount
);
6930 RxPurgeChangeBufferingStateRequestsForSrvOpen(
6934 LIST_ENTRY Discarded
;
6938 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen
->Fcb
));
6940 /* Initialize our discarded list */
6941 InitializeListHead(&Discarded
);
6943 SrvCall
= (PSRV_CALL
)SrvOpen
->Fcb
->VNetRoot
->pNetRoot
->pSrvCall
;
6944 RxAcquireBufferingManagerMutex(&SrvCall
->BufferingManager
);
6946 /* Set the flag, and get the requests */
6947 InitializeListHead(&SrvOpen
->SrvOpenKeyList
);
6948 SetFlag(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED
);
6949 RxGatherRequestsForSrvOpen(SrvCall
, SrvOpen
, &Discarded
);
6951 RxReleaseBufferingManagerMutex(&SrvCall
->BufferingManager
);
6953 /* If there were discarded requests */
6954 if (!IsListEmpty(&Discarded
))
6956 /* And a pending buffering state change */
6957 if (BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING
))
6959 /* Clear the flag, and set the associated event - job done */
6960 RxAcquireSerializationMutex();
6961 ClearFlag(SrvOpen
->Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
6962 if (SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
!= NULL
)
6964 KeSetEvent(SrvOpen
->Fcb
->pBufferingStateChangeCompletedEvent
, IO_NETWORK_INCREMENT
, FALSE
);
6966 RxReleaseSerializationMutex();
6969 /* Drop the discarded requests */
6970 RxpDiscardChangeBufferingStateRequests(&Discarded
);
6983 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
6985 /* Reference our FCB so that it doesn't disappear */
6986 RxReferenceNetFcb(Fcb
);
6987 /* Purge Cc if required */
6988 if (Fcb
->OpenCount
!= 0)
6990 RxPurgeFcbInSystemCache(Fcb
, NULL
, 0, TRUE
, TRUE
);
6993 /* If it wasn't freed, release the lock */
6994 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
6996 RxReleaseFcb(NULL
, Fcb
);
7004 RxPurgeFcbInSystemCache(
7006 IN PLARGE_INTEGER FileOffset OPTIONAL
,
7008 IN BOOLEAN UninitializeCacheMaps
,
7009 IN BOOLEAN FlushFile
)
7016 ASSERT(RxIsFcbAcquiredExclusive(Fcb
));
7018 /* Try to flush first, if asked */
7021 /* If flushing failed, just make some noise */
7022 Status
= RxFlushFcbInSystemCache(Fcb
, TRUE
);
7023 if (!NT_SUCCESS(Status
))
7025 PVOID CallersAddress
, CallersCaller
;
7027 RtlGetCallersAddress(&CallersAddress
, &CallersCaller
);
7028 DPRINT1("Flush failed with status %lx for FCB %p\n", Status
, Fcb
);
7029 DPRINT1("Caller was %p %p\n", CallersAddress
, CallersCaller
);
7033 /* Deal with Cc for purge */
7034 Purged
= CcPurgeCacheSection(&Fcb
->NonPaged
->SectionObjectPointers
, FileOffset
,
7035 Length
, UninitializeCacheMaps
);
7036 /* If purge failed, force section closing */
7039 MmFlushImageSection(&Fcb
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
);
7041 RxReleaseFcb(NULL
, Fcb
);
7042 Purged
= MmForceSectionClosed(&Fcb
->NonPaged
->SectionObjectPointers
, TRUE
);
7043 RxAcquireExclusiveFcb(NULL
, Fcb
);
7046 /* Return appropriate status */
7047 Status
= (Purged
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
7048 DPRINT("Purge for FCB %p returns %lx\n", Fcb
, Status
);
7065 /* Get the associated FCB */
7066 FcbToBePurged
= (PFCB
)pFobx
->pSrvOpen
->pFcb
;
7067 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
7068 ASSERT(Status
== STATUS_SUCCESS
);
7071 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
7072 if (Status
!= STATUS_SUCCESS
)
7074 DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged
, pFobx
);
7079 if (!MmFlushImageSection(&FcbToBePurged
->NonPaged
->SectionObjectPointers
, MmFlushForWrite
))
7081 DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged
, pFobx
);
7085 DPRINT("Purge OK for %p (%p)\n", FcbToBePurged
, pFobx
);
7093 RxPurgeFobxFromCache(
7094 PFOBX FobxToBePurged
)
7101 FcbToBePurged
= (PFCB
)FobxToBePurged
->pSrvOpen
->pFcb
;
7102 ASSERT(FcbToBePurged
!= NULL
);
7104 /* If we cannot have our FCB exclusively, give up */
7105 Status
= RxAcquireExclusiveFcb(NULL
, FcbToBePurged
);
7106 if (Status
!= STATUS_SUCCESS
)
7108 RxDereferenceNetFobx(FobxToBePurged
, LHS_LockNotHeld
);
7112 /* Don't let the FCB disappear */
7113 RxReferenceNetFcb(FcbToBePurged
);
7115 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */
7116 if (BooleanFlagOn(FobxToBePurged
->Flags
, FOBX_FLAG_SRVOPEN_CLOSED
) || FobxToBePurged
->pSrvOpen
->UncleanFobxCount
!= 0)
7118 DPRINT("FCB purge skipped\n");
7122 Status
= RxPurgeFcbInSystemCache(FcbToBePurged
, NULL
, 0, FALSE
, TRUE
);
7125 RxDereferenceNetFobx(FobxToBePurged
, LHS_ExclusiveLockHeld
);
7126 /* Drop our extra reference */
7127 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged
, NULL
, FALSE
, FALSE
))
7129 RxReleaseFcb(NULL
, FcbToBePurged
);
7139 RxPurgeRelatedFobxs(
7141 PRX_CONTEXT RxContext
,
7142 BOOLEAN AttemptFinalization
,
7146 ULONG SuccessfullPurge
;
7147 PRDBSS_SCAVENGER Scavenger
;
7148 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7149 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx
;
7153 RxDeviceObject
= RxContext
->RxDeviceObject
;
7154 Scavenger
= RxDeviceObject
->pRdbssScavenger
;
7155 PurgeSyncCtx
= &NetRoot
->PurgeSyncronizationContext
;
7157 RxAcquireScavengerMutex();
7159 /* If there's already a purge in progress */
7160 if (PurgeSyncCtx
->PurgeInProgress
)
7162 /* Add our RX_CONTEXT to the current run */
7163 InsertTailList(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
,
7164 &RxContext
->RxContextSerializationQLinks
);
7166 /* And wait until it's done */
7167 RxReleaseScavengerMutex();
7168 RxWaitSync(RxContext
);
7169 RxAcquireScavengerMutex();
7172 /* Start the purge */
7173 PurgeSyncCtx
->PurgeInProgress
= TRUE
;
7175 /* While the purge is still handling our NET_ROOT, do nothing but wait */
7176 while (Scavenger
->CurrentNetRootForClosePendingProcessing
== NetRoot
)
7178 RxReleaseScavengerMutex();
7179 KeWaitForSingleObject(&Scavenger
->ClosePendingProcessingSyncEvent
, Executive
,
7180 KernelMode
, TRUE
, NULL
);
7181 RxAcquireScavengerMutex();
7184 /* Now, for all the entries */
7185 SuccessfullPurge
= 0;
7186 Entry
= Scavenger
->ClosePendingFobxsList
.Flink
;
7187 while (Entry
!= &Scavenger
->ClosePendingFobxsList
)
7193 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ClosePendingList
);
7194 DPRINT("Dealing with FOBX: %p\n", Fobx
);
7196 Entry
= Entry
->Flink
;
7198 /* If it's not matching our NET_ROOT, ignore */
7199 if (Fobx
->pSrvOpen
== NULL
||
7200 Fobx
->pSrvOpen
->pFcb
== NULL
||
7201 ((PFCB
)Fobx
->pSrvOpen
->pFcb
)->VNetRoot
== NULL
||
7202 (PNET_ROOT
)((PFCB
)Fobx
->pSrvOpen
->pFcb
)->VNetRoot
->pNetRoot
!= NetRoot
)
7207 /* Determine if it matches our FCB */
7208 Fcb
= (PFCB
)Fobx
->pSrvOpen
->pFcb
;
7209 if (PurgingFcb
!= NULL
&& NodeType(PurgingFcb
) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY
&&
7214 MINIRDR_CALL_THROUGH(Status
, RxDeviceObject
->Dispatch
, MRxAreFilesAliased
, (Fcb
, PurgingFcb
));
7215 if (Status
== STATUS_SUCCESS
)
7221 /* Matching, we'll purge it */
7222 RemoveEntryList(&Fobx
->ClosePendingList
);
7224 /* Reference it so that it doesn't disappear */
7225 RxReferenceNetFobx(Fobx
);
7227 RxReleaseScavengerMutex();
7230 Success
= RxPurgeFobx(Fobx
);
7236 /* If we don't have to finalize it (or if we cannot acquire lock exclusively
7237 * Just normally dereference
7239 if ((AttemptFinalization
== DONT_ATTEMPT_FINALIZE_ON_PURGE
) ||
7240 RxAcquireExclusiveFcb(NULL
, Fcb
) != STATUS_SUCCESS
)
7242 RxDereferenceNetFobx(Fobx
, LHS_LockNotHeld
);
7244 /* Otherwise, finalize */
7247 RxReferenceNetFcb(Fcb
);
7248 RxDereferenceNetFobx(Fobx
, LHS_ExclusiveLockHeld
);
7249 if (!RxDereferenceAndFinalizeNetFcb(Fcb
, NULL
, FALSE
, FALSE
))
7251 RxReleaseFcb(NULL
, Fcb
);
7257 DPRINT1("Failed purging %p (%p)\n", Fcb
, Fobx
);
7260 RxAcquireScavengerMutex();
7263 /* If no contexts left, purge is not running */
7264 if (IsListEmpty(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
))
7266 PurgeSyncCtx
->PurgeInProgress
= FALSE
;
7268 /* Otherwise, notify a waiter it can start */
7271 PRX_CONTEXT Context
;
7273 Entry
= RemoveHeadList(&PurgeSyncCtx
->ContextsAwaitingPurgeCompletion
);
7274 Context
= CONTAINING_RECORD(Entry
, RX_CONTEXT
, RxContextSerializationQLinks
);
7276 RxSignalSynchronousWaiter(Context
);
7279 RxReleaseScavengerMutex();
7281 return (SuccessfullPurge
> 0 ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
);
7288 RxpWorkerThreadDispatcher(
7289 IN PRX_WORK_QUEUE WorkQueue
,
7290 IN PLARGE_INTEGER WaitInterval
)
7294 PETHREAD CurrentThread
;
7295 BOOLEAN KillThread
, Dereference
;
7296 PRX_WORK_QUEUE_ITEM WorkQueueItem
;
7297 PWORKER_THREAD_ROUTINE WorkerRoutine
;
7299 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7301 /* Reference ourselves */
7302 CurrentThread
= PsGetCurrentThread();
7303 Status
= ObReferenceObjectByPointer(CurrentThread
, THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
7304 ASSERT(NT_SUCCESS(Status
));
7306 /* Infinite loop for worker */
7308 Dereference
= FALSE
;
7312 PLIST_ENTRY ListEntry
;
7314 /* Remove an entry from the work queue */
7315 ListEntry
= KeRemoveQueue(&WorkQueue
->Queue
, KernelMode
, WaitInterval
);
7316 if ((ULONG_PTR
)ListEntry
!= STATUS_TIMEOUT
)
7318 PRDBSS_DEVICE_OBJECT DeviceObject
;
7320 WorkQueueItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_QUEUE_ITEM
, List
);
7322 InterlockedIncrement(&WorkQueue
->NumberOfWorkItemsDispatched
);
7323 InterlockedDecrement(&WorkQueue
->NumberOfWorkItemsToBeDispatched
);
7324 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7326 /* Get the parameters, and null-them in the struct */
7327 WorkerRoutine
= WorkQueueItem
->WorkerRoutine
;
7328 Parameter
= WorkQueueItem
->Parameter
;
7329 DeviceObject
= WorkQueueItem
->pDeviceObject
;
7331 WorkQueueItem
->List
.Flink
= NULL
;
7332 WorkQueueItem
->WorkerRoutine
= NULL
;
7333 WorkQueueItem
->Parameter
= NULL
;
7334 WorkQueueItem
->pDeviceObject
= NULL
;
7336 /* Call the routine */
7337 DPRINT("Calling: %p(%p)\n", WorkerRoutine
, Parameter
);
7338 WorkerRoutine(Parameter
);
7340 /* Are we going down now? */
7341 if (InterlockedDecrement(&DeviceObject
->DispatcherContext
.NumberOfWorkerThreads
) == 0)
7343 PKEVENT TearDownEvent
;
7345 TearDownEvent
= InterlockedExchangePointer((void * volatile*)&DeviceObject
->DispatcherContext
.pTearDownEvent
, NULL
);
7346 if (TearDownEvent
!= NULL
)
7348 KeSetEvent(TearDownEvent
, IO_NO_INCREMENT
, FALSE
);
7352 InterlockedIncrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7355 /* Shall we shutdown... */
7356 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
7357 switch (WorkQueue
->State
)
7359 /* Our queue is active, kill it if we have no more items to dispatch
7360 * and more threads than the required minimum
7362 case RxWorkQueueActive
:
7363 if (WorkQueue
->NumberOfWorkItemsToBeDispatched
<= 0)
7365 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
7366 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
7370 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7375 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7380 /* The queue is inactive: kill it we have more threads than the required minimum */
7381 case RxWorkQueueInactive
:
7382 ASSERT(WorkQueue
->NumberOfActiveWorkerThreads
> 0);
7383 if (WorkQueue
->NumberOfActiveWorkerThreads
> WorkQueue
->MinimumNumberOfWorkerThreads
)
7387 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7392 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7396 /* Rundown in progress..., kill it for sure! */
7397 case RxWorkQueueRundownInProgress
:
7399 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext
;
7401 ASSERT(WorkQueue
->pRundownContext
!= NULL
);
7403 RundownContext
= WorkQueue
->pRundownContext
;
7404 RundownContext
->ThreadPointers
[RundownContext
->NumberOfThreadsSpunDown
++] = CurrentThread
;
7406 InterlockedDecrement(&WorkQueue
->NumberOfActiveWorkerThreads
);
7408 Dereference
= FALSE
;
7410 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0)
7412 KeSetEvent(&RundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
7415 InterlockedDecrement(&WorkQueue
->NumberOfIdleWorkerThreads
);
7422 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
7423 } while (!KillThread
);
7425 DPRINT("Killed worker thread\n");
7427 /* Do we have to dereference ourselves? */
7430 ObDereferenceObject(CurrentThread
);
7433 /* Dump last executed routine */
7434 if (DumpDispatchRoutine
)
7436 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine
, Parameter
, WorkQueueItem
);
7439 PsTerminateSystemThread(STATUS_SUCCESS
);
7444 IN OUT PVOID Instance
)
7446 NODE_TYPE_CODE NodeType
;
7447 PNODE_TYPE_AND_SIZE Node
;
7451 RxAcquireScavengerMutex();
7453 /* We can only reference a few structs */
7454 NodeType
= NodeType(Instance
) & ~RX_SCAVENGER_MASK
;
7455 ASSERT((NodeType
== RDBSS_NTC_SRVCALL
) || (NodeType
== RDBSS_NTC_NETROOT
) ||
7456 (NodeType
== RDBSS_NTC_V_NETROOT
) || (NodeType
== RDBSS_NTC_SRVOPEN
) ||
7457 (NodeType
== RDBSS_NTC_FOBX
));
7459 Node
= (PNODE_TYPE_AND_SIZE
)Instance
;
7460 InterlockedIncrement((volatile long *)&Node
->NodeReferenceCount
);
7462 /* Trace refcount if asked */
7465 case RDBSS_NTC_SRVCALL
:
7466 PRINT_REF_COUNT(SRVCALL
, Node
->NodeReferenceCount
);
7469 case RDBSS_NTC_NETROOT
:
7470 PRINT_REF_COUNT(NETROOT
, Node
->NodeReferenceCount
);
7473 case RDBSS_NTC_V_NETROOT
:
7474 PRINT_REF_COUNT(VNETROOT
, Node
->NodeReferenceCount
);
7477 case RDBSS_NTC_SRVOPEN
:
7478 PRINT_REF_COUNT(SRVOPEN
, Node
->NodeReferenceCount
);
7481 case RDBSS_NTC_FOBX
:
7482 PRINT_REF_COUNT(NETFOBX
, Node
->NodeReferenceCount
);
7490 RxpUndoScavengerFinalizationMarking(Instance
);
7491 RxReleaseScavengerMutex();
7499 RxReinitializeContext(
7500 IN OUT PRX_CONTEXT RxContext
)
7503 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7504 ULONG InitialContextFlags
, SavedFlags
;
7508 /* Backup a few flags */
7509 Irp
= RxContext
->CurrentIrp
;
7510 RxDeviceObject
= RxContext
->RxDeviceObject
;
7511 SavedFlags
= RxContext
->Flags
& RX_CONTEXT_PRESERVED_FLAGS
;
7512 InitialContextFlags
= RxContext
->Flags
& RX_CONTEXT_INITIALIZATION_FLAGS
;
7514 /* Reset our context */
7515 RxPrepareContextForReuse(RxContext
);
7517 /* Zero everything */
7518 RtlZeroMemory(&RxContext
->MajorFunction
, sizeof(RX_CONTEXT
) - FIELD_OFFSET(RX_CONTEXT
, MajorFunction
));
7520 /* Restore saved flags */
7521 RxContext
->Flags
= SavedFlags
;
7522 /* And reinit the context */
7523 RxInitializeContext(Irp
, RxDeviceObject
, InitialContextFlags
, RxContext
);
7531 RxReleaseFcbFromLazyWrite(
7539 /* The received context is a FCB */
7540 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
7541 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
7543 /* Lazy writer is releasing lock, so forget about it */
7544 Fcb
->Specific
.Fcb
.LazyWriteThread
= NULL
;
7546 /* If we were top level IRP, unwind */
7547 if (RxGetTopIrpIfRdbssIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
)
7549 RxUnwindTopLevelIrp(NULL
);
7552 /* And finally, release the lock */
7553 Fcb
->PagingIoResourceFile
= NULL
;
7554 Fcb
->PagingIoResourceLine
= 0;
7555 ExReleaseResourceLite(Fcb
->Header
.PagingIoResource
);
7563 RxReleaseFcbFromReadAhead(
7571 /* The received context is a FCB */
7572 ASSERT(NodeType(Fcb
) == RDBSS_NTC_FCB
);
7573 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
7575 /* Top Level IRP is CC */
7576 ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
);
7577 RxUnwindTopLevelIrp(NULL
);
7579 ExReleaseResourceLite(Fcb
->Header
.Resource
);
7584 RxReleaseFileForNtCreateSection(
7585 PFILE_OBJECT FileObject
)
7592 RxReleaseForCcFlush(
7593 PFILE_OBJECT FileObject
,
7594 PDEVICE_OBJECT DeviceObject
)
7597 return STATUS_NOT_IMPLEMENTED
;
7611 ASSERT(NodeTypeIsFcb(ThisFcb
));
7613 /* Just remove the entry from the FCB_TABLE */
7614 NetRoot
= (PNET_ROOT
)ThisFcb
->VNetRoot
->pNetRoot
;
7615 ASSERT(RxIsFcbTableLockExclusive(&NetRoot
->FcbTable
));
7616 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb
));
7619 if (!BooleanFlagOn(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
))
7622 RxFcbTableRemoveFcb(&NetRoot
->FcbTable
, ThisFcb
);
7623 DPRINT("FCB (%p) %wZ removed\n", ThisFcb
, &ThisFcb
->FcbTableEntry
.Path
);
7624 /* Mark, so that we don't try to do it twice */
7625 SetFlag(ThisFcb
->FcbState
, FCB_STATE_NAME_ALREADY_REMOVED
);
7635 RxRemoveOperationFromBlockingQueue(
7636 IN OUT PRX_CONTEXT RxContext
)
7638 /* Acquire the pipe mutex */
7639 ExAcquireFastMutex(&RxContextPerFileSerializationMutex
);
7641 /* Is that a blocking serial operation? */
7642 if (BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7645 ClearFlag(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
);
7647 /* Drop it off the list */
7648 RemoveEntryList(&RxContext
->RxContextSerializationQLinks
);
7649 RxContext
->RxContextSerializationQLinks
.Flink
= NULL
;
7650 RxContext
->RxContextSerializationQLinks
.Blink
= NULL
;
7654 ExReleaseFastMutex(&RxContextPerFileSerializationMutex
);
7661 RxRemovePrefixTableEntry(
7662 IN OUT PRX_PREFIX_TABLE ThisTable
,
7663 IN OUT PRX_PREFIX_ENTRY Entry
)
7667 ASSERT(NodeType(Entry
) == RDBSS_NTC_PREFIX_ENTRY
);
7668 ASSERT(RxIsPrefixTableLockExclusive(ThisTable
));
7670 /* Check whether we're asked to remove null entry */
7671 if (Entry
->Prefix
.Length
== 0)
7673 ThisTable
->TableEntryForNull
= NULL
;
7677 RemoveEntryList(&Entry
->HashLinks
);
7680 Entry
->ContainingRecord
= NULL
;
7682 /* Also remove it from global list */
7683 RemoveEntryList(&Entry
->MemberQLinks
);
7685 ++ThisTable
->Version
;
7692 RxRemoveVirtualNetRootFromNetRoot(
7694 PV_NET_ROOT VNetRoot
)
7696 PRX_PREFIX_TABLE PrefixTable
;
7700 PrefixTable
= NetRoot
->pSrvCall
->RxDeviceObject
->pRxNetNameTable
;
7701 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable
));
7703 /* Remove the VNetRoot from the list in the NetRoot */
7704 --NetRoot
->NumberOfVirtualNetRoots
;
7705 RemoveEntryList(&VNetRoot
->NetRootListEntry
);
7707 /* Fix the NetRoot if we were the default VNetRoot */
7708 if (NetRoot
->DefaultVNetRoot
== VNetRoot
)
7710 /* Put the first one available */
7711 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7713 NetRoot
->DefaultVNetRoot
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
7715 /* Otherwise, none */
7718 NetRoot
->DefaultVNetRoot
= NULL
;
7722 /* If there are still other VNetRoot available, we're done */
7723 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
7728 /* Otherwise, initiate NetRoot finalization */
7729 if (!BooleanFlagOn(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
))
7731 RxRemovePrefixTableEntry(PrefixTable
, &NetRoot
->PrefixEntry
);
7732 SetFlag(NetRoot
->Flags
, NETROOT_FLAG_NAME_ALREADY_REMOVED
);
7735 /* Notify mini-rdr */
7736 if (NetRoot
->pSrvCall
!= NULL
&& NetRoot
->pSrvCall
->RxDeviceObject
!= NULL
)
7740 MINIRDR_CALL_THROUGH(Status
, NetRoot
->pSrvCall
->RxDeviceObject
->Dispatch
,
7741 MRxFinalizeNetRoot
, ((PMRX_NET_ROOT
)NetRoot
, FALSE
));
7747 RxResumeBlockedOperations_ALL(
7748 IN OUT PRX_CONTEXT RxContext
)
7750 LIST_ENTRY BlockedOps
;
7754 /* Get the blocked operations */
7755 RxTransferListWithMutex(&BlockedOps
, &RxContext
->BlockedOperations
, RxContext
->BlockedOpsMutex
);
7757 if (!IsListEmpty(&BlockedOps
))
7765 RxResumeBlockedOperations_Serially(
7766 IN OUT PRX_CONTEXT RxContext
,
7767 IN OUT PLIST_ENTRY BlockingIoQ
)
7771 RxAcquireSerializationMutex();
7773 /* This can only happen on pipes */
7774 if (!BooleanFlagOn(RxContext
->FlagsForLowIo
, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION
))
7776 RxReleaseSerializationMutex();
7782 RxReleaseSerializationMutex();
7789 RxSetFileSizeWithLock(
7791 IN PLONGLONG FileSize
)
7795 /* Set attribute and increase version */
7796 Fcb
->Header
.FileSize
.QuadPart
= *FileSize
;
7797 ++Fcb
->ulFileSizeVersion
;
7804 RxScavengeFobxsForNetRoot(
7807 BOOLEAN SynchronizeWithScavenger
)
7809 PRDBSS_SCAVENGER Scavenger
;
7810 PRDBSS_DEVICE_OBJECT RxDeviceObject
;
7814 RxDeviceObject
= NetRoot
->pSrvCall
->RxDeviceObject
;
7815 Scavenger
= RxDeviceObject
->pRdbssScavenger
;
7817 /* Wait for the scavenger, if asked to */
7818 if (SynchronizeWithScavenger
)
7820 KeWaitForSingleObject(&Scavenger
->ScavengeEvent
, Executive
, KernelMode
, FALSE
, NULL
);
7823 RxAcquireScavengerMutex();
7825 /* If there's nothing left to do... */
7826 if (Scavenger
->FobxsToBeFinalized
<= 0)
7828 RxReleaseScavengerMutex();
7833 LIST_ENTRY FobxToScavenge
;
7835 InitializeListHead(&FobxToScavenge
);
7837 /* Browse all the FOBXs to finalize */
7838 Entry
= Scavenger
->FobxFinalizationList
.Flink
;
7839 while (Entry
!= &Scavenger
->FobxFinalizationList
)
7843 Fobx
= CONTAINING_RECORD(Entry
, FOBX
, ScavengerFinalizationList
);
7844 Entry
= Entry
->Flink
;
7846 if (Fobx
->SrvOpen
!= NULL
)
7850 Fcb
= (PFCB
)Fobx
->SrvOpen
->pFcb
;
7852 /* If it matches our NET_ROOT */
7853 if ((PNET_ROOT
)Fcb
->pNetRoot
== NetRoot
)
7857 /* Check whether it matches our FCB */
7858 Status
= STATUS_MORE_PROCESSING_REQUIRED
;
7859 if (PurgingFcb
!= NULL
&& PurgingFcb
!= Fcb
)
7861 MINIRDR_CALL_THROUGH(Status
, RxDeviceObject
->Dispatch
, MRxAreFilesAliased
, (Fcb
, PurgingFcb
));
7864 /* If so, add it to the list of the FOBXs to scavenge */
7865 if (Status
!= STATUS_SUCCESS
)
7867 RxReferenceNetFobx(Fobx
);
7868 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7870 RemoveEntryList(&Fobx
->ScavengerFinalizationList
);
7871 InsertTailList(&FobxToScavenge
, &Fobx
->ScavengerFinalizationList
);
7877 RxReleaseScavengerMutex();
7879 /* Now, scavenge all the extracted FOBX */
7880 RxpScavengeFobxs(Scavenger
, &FobxToScavenge
);
7883 if (SynchronizeWithScavenger
)
7885 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
7893 RxScavengeRelatedFobxs(
7897 LIST_ENTRY LocalList
;
7898 PLIST_ENTRY NextEntry
;
7899 PRDBSS_SCAVENGER Scavenger
;
7903 /* First of all, check whether there are FOBX to scavenge */
7904 Scavenger
= Fcb
->RxDeviceObject
->pRdbssScavenger
;
7905 RxAcquireScavengerMutex();
7906 if (Scavenger
->FobxsToBeFinalized
<= 0)
7908 RxReleaseScavengerMutex();
7912 /* Initialize our local list which will hold all the FOBX to scavenge so
7913 * that we don't acquire the scavenger mutex too long
7915 InitializeListHead(&LocalList
);
7917 /* Technically, that condition should all be true... */
7918 if (!IsListEmpty(&Scavenger
->FobxFinalizationList
))
7920 PLIST_ENTRY NextEntry
, LastEntry
;
7922 /* Browse all the FCBs to find the matching ones */
7923 NextEntry
= Scavenger
->FobxFinalizationList
.Flink
;
7924 LastEntry
= &Scavenger
->FobxFinalizationList
;
7925 while (NextEntry
!= LastEntry
)
7927 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7928 NextEntry
= NextEntry
->Flink
;
7929 /* Matching our FCB? Let's finalize it */
7930 if (Fobx
->pSrvOpen
!= NULL
&& Fobx
->pSrvOpen
->pFcb
== RX_GET_MRX_FCB(Fcb
))
7932 RxpUndoScavengerFinalizationMarking(Fobx
);
7933 ASSERT(NodeType(Fobx
) == RDBSS_NTC_FOBX
);
7934 InsertTailList(&LocalList
, &Fobx
->ScavengerFinalizationList
);
7939 RxReleaseScavengerMutex();
7941 /* Nothing to scavenge? Quit */
7942 if (IsListEmpty(&LocalList
))
7947 /* Now, finalize all the extracted FOBX */
7948 while (!IsListEmpty(&LocalList
))
7950 NextEntry
= RemoveHeadList(&LocalList
);
7951 Fobx
= CONTAINING_RECORD(NextEntry
, FOBX
, ScavengerFinalizationList
);
7952 RxFinalizeNetFobx(Fobx
, TRUE
, TRUE
);
7959 RxScavengerFinalizeEntries(
7960 PRDBSS_DEVICE_OBJECT DeviceObject
)
7970 RxScavengerTimerRoutine(
7974 PRDBSS_DEVICE_OBJECT DeviceObject
;
7975 PRDBSS_SCAVENGER Scavenger
;
7979 DeviceObject
= Context
;
7980 Scavenger
= DeviceObject
->pRdbssScavenger
;
7983 RxAcquireScavengerMutex();
7984 /* If the scavenger was dormant, wake it up! */
7985 if (Scavenger
->State
== RDBSS_SCAVENGER_DORMANT
)
7988 Scavenger
->State
= RDBSS_SCAVENGER_ACTIVE
;
7989 KeClearEvent(&Scavenger
->ScavengeEvent
);
7991 /* Scavenger the entries */
7992 RxReleaseScavengerMutex();
7993 RxScavengerFinalizeEntries(DeviceObject
);
7994 RxAcquireScavengerMutex();
7996 /* If we're still active (race) */
7997 if (Scavenger
->State
== RDBSS_SCAVENGER_ACTIVE
)
7999 /* If there are new entries to scavenge, stay dormant and requeue a run */
8000 if (Scavenger
->NumberOfDormantFiles
+ Scavenger
->SrvCallsToBeFinalized
+
8001 Scavenger
->NetRootsToBeFinalized
+ Scavenger
->VNetRootsToBeFinalized
+
8002 Scavenger
->FcbsToBeFinalized
+ Scavenger
->SrvOpensToBeFinalized
+
8003 Scavenger
->FobxsToBeFinalized
!= 0)
8006 Scavenger
->State
= RDBSS_SCAVENGER_DORMANT
;
8008 /* Otherwise, we're inactive again */
8011 Scavenger
->State
= RDBSS_SCAVENGER_INACTIVE
;
8015 RxReleaseScavengerMutex();
8017 /* Requeue an execution */
8020 RxPostOneShotTimerRequest(RxFileSystemDeviceObject
, &Scavenger
->WorkItem
,
8021 RxScavengerTimerRoutine
, DeviceObject
, Scavenger
->TimeLimit
);
8026 RxReleaseScavengerMutex();
8029 KeSetEvent(&Scavenger
->ScavengeEvent
, IO_NO_INCREMENT
, FALSE
);
8033 RxScavengeVNetRoots(
8034 PRDBSS_DEVICE_OBJECT RxDeviceObject
)
8045 RxSpinUpRequestsDispatcher(
8049 PRX_DISPATCHER RxDispatcher
;
8051 Status
= ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS
, *PsThreadType
, KernelMode
);
8052 if (!NT_SUCCESS(Status
))
8054 PsTerminateSystemThread(STATUS_SUCCESS
);
8057 RxDispatcher
= Dispatcher
;
8062 PLIST_ENTRY ListEntry
;
8064 Status
= KeWaitForSingleObject(&RxDispatcher
->SpinUpRequestsEvent
, Executive
,
8065 KernelMode
, FALSE
, &RxSpinUpDispatcherWaitInterval
);
8066 ASSERT((Status
== STATUS_SUCCESS
) || (Status
== STATUS_TIMEOUT
));
8068 KeAcquireSpinLock(&RxDispatcher
->SpinUpRequestsLock
, &OldIrql
);
8069 if (!IsListEmpty(&RxDispatcher
->SpinUpRequests
))
8071 ListEntry
= RemoveHeadList(&RxDispatcher
->SpinUpRequests
);
8075 ListEntry
= &RxDispatcher
->SpinUpRequests
;
8077 KeClearEvent(&RxDispatcher
->SpinUpRequestsEvent
);
8078 KeReleaseSpinLock(&RxDispatcher
->SpinUpRequestsLock
, OldIrql
);
8080 while (ListEntry
!= &RxDispatcher
->SpinUpRequests
)
8082 PWORK_QUEUE_ITEM WorkItem
;
8083 PRX_WORK_QUEUE WorkQueue
;
8085 WorkItem
= CONTAINING_RECORD(ListEntry
, WORK_QUEUE_ITEM
, List
);
8086 WorkQueue
= WorkItem
->Parameter
;
8088 InterlockedDecrement(&WorkQueue
->WorkQueueItemForSpinUpWorkerThreadInUse
);
8090 DPRINT("Workqueue: calling %p(%p)\n", WorkItem
->WorkerRoutine
, WorkItem
->Parameter
);
8091 WorkItem
->WorkerRoutine(WorkItem
->Parameter
);
8093 } while (RxDispatcher
->State
== RxDispatcherActive
);
8095 KeSetEvent(&RxDispatcher
->SpinUpRequestsTearDownEvent
, IO_NO_INCREMENT
, FALSE
);
8096 PsTerminateSystemThread(STATUS_SUCCESS
);
8103 RxSpinUpWorkerThread(
8104 PRX_WORK_QUEUE WorkQueue
,
8105 PRX_WORKERTHREAD_ROUTINE Routine
,
8110 HANDLE ThreadHandle
;
8114 /* If work queue is inactive, that cannot work */
8115 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
8116 if (WorkQueue
->State
!= RxWorkQueueActive
)
8118 Status
= STATUS_UNSUCCESSFUL
;
8119 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
8123 ++WorkQueue
->NumberOfActiveWorkerThreads
;
8124 Status
= STATUS_SUCCESS
;
8126 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
8128 /* Quit on failure */
8129 if (!NT_SUCCESS(Status
))
8134 /* Spin up the worker thread */
8135 Status
= PsCreateSystemThread(&ThreadHandle
, PROCESS_ALL_ACCESS
, NULL
, NULL
, NULL
, Routine
, Parameter
);
8136 if (NT_SUCCESS(Status
))
8138 ZwClose(ThreadHandle
);
8141 /* Read well: we reached that point because it failed! */
8142 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue
, Status
);
8144 KeAcquireSpinLock(&WorkQueue
->SpinLock
, &OldIrql
);
8145 --WorkQueue
->NumberOfActiveWorkerThreads
;
8146 ++WorkQueue
->NumberOfFailedSpinUpRequests
;
8148 /* Rundown, no more active threads, set the event! */
8149 if (WorkQueue
->NumberOfActiveWorkerThreads
== 0 &&
8150 WorkQueue
->State
== RxWorkQueueRundownInProgress
)
8152 KeSetEvent(&WorkQueue
->pRundownContext
->RundownCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
8155 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue
, WorkQueue
->State
, WorkQueue
->NumberOfActiveWorkerThreads
);
8157 KeReleaseSpinLock(&WorkQueue
->SpinLock
, OldIrql
);
8163 RxSpinUpWorkerThreads(
8164 PRX_WORK_QUEUE WorkQueue
)
8170 RxSynchronizeWithScavenger(
8171 IN PRX_CONTEXT RxContext
)
8180 RxTableComputeHashValue(
8181 IN PUNICODE_STRING Name
)
8189 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8192 Loops
[1] = MaxChar
- 1;
8193 Loops
[2] = MaxChar
- 2;
8194 Loops
[3] = MaxChar
- 3;
8195 Loops
[4] = MaxChar
- 4;
8196 Loops
[5] = MaxChar
/ 4;
8197 Loops
[6] = 2 * MaxChar
/ 4;
8198 Loops
[7] = 3 * MaxChar
/ 4;
8201 for (i
= 0; i
< 8; ++i
)
8206 if (Idx
>= 0 && Idx
< MaxChar
)
8208 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
8219 RxTableComputePathHashValue(
8220 IN PUNICODE_STRING Name
)
8228 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8231 Loops
[1] = MaxChar
- 1;
8232 Loops
[2] = MaxChar
- 2;
8233 Loops
[3] = MaxChar
- 3;
8234 Loops
[4] = MaxChar
- 4;
8235 Loops
[5] = MaxChar
/ 4;
8236 Loops
[6] = 2 * MaxChar
/ 4;
8237 Loops
[7] = 3 * MaxChar
/ 4;
8240 for (i
= 0; i
< 8; ++i
)
8245 if (Idx
>= 0 && Idx
< MaxChar
)
8247 Hash
= RtlUpcaseUnicodeChar(Name
->Buffer
[Idx
]) + 8 * Hash
;
8259 IN PRX_PREFIX_TABLE ThisTable
,
8260 IN PUNICODE_STRING Name
,
8261 OUT PUNICODE_STRING RemainingName
,
8262 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
8266 PRX_PREFIX_ENTRY Entry
;
8267 RX_CONNECTION_ID NullId
;
8268 UNICODE_STRING LookupString
;
8272 /* If caller didn't provide a connection ID, setup one */
8273 if (ThisTable
->IsNetNameTable
&& RxConnectionId
== NULL
)
8275 NullId
.Luid
.LowPart
= 0;
8276 NullId
.Luid
.HighPart
= 0;
8277 RxConnectionId
= &NullId
;
8281 ASSERT(Name
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
);
8285 LookupString
.Buffer
= Name
->Buffer
;
8286 MaxChar
= Name
->Length
/ sizeof(WCHAR
);
8287 /* We'll perform the lookup, path component after another */
8288 for (i
= 1; i
< MaxChar
; ++i
)
8291 PRX_PREFIX_ENTRY CurEntry
;
8293 /* Don't cut in the middle of a path element */
8294 if (Name
->Buffer
[i
] != OBJ_NAME_PATH_SEPARATOR
&& Name
->Buffer
[i
] != ':')
8299 /* Perform lookup in the table */
8300 LookupString
.Length
= i
* sizeof(WCHAR
);
8301 Hash
= RxTableComputeHashValue(&LookupString
);
8302 CurEntry
= RxTableLookupName_ExactLengthMatch(ThisTable
, &LookupString
, Hash
, RxConnectionId
);
8304 ++ThisTable
->Lookups
;
8306 /* Entry not found, move to the next component */
8307 if (CurEntry
== NULL
)
8310 ++ThisTable
->FailedLookups
;
8316 ASSERT(Entry
->ContainingRecord
!= NULL
);
8317 Container
= Entry
->ContainingRecord
;
8319 /* If we have a NET_ROOT, let's return a V_NET_ROOT */
8320 if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_NETROOT
)
8324 NetRoot
= (PNET_ROOT
)Entry
->ContainingRecord
;
8325 /* If there's a default one, perfect, that's a match */
8326 if (NetRoot
->DefaultVNetRoot
!= NULL
)
8328 Container
= NetRoot
->DefaultVNetRoot
;
8330 /* If none (that shouldn't happen!), try to find one */
8333 /* Use the first one in the list */
8334 if (!IsListEmpty(&NetRoot
->VirtualNetRoots
))
8336 Container
= CONTAINING_RECORD(NetRoot
->VirtualNetRoots
.Flink
, V_NET_ROOT
, NetRootListEntry
);
8338 /* Really, really, shouldn't happen */
8349 else if ((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_V_NETROOT
)
8355 ASSERT((NodeType(Entry
->ContainingRecord
) & ~RX_SCAVENGER_MASK
) == RDBSS_NTC_SRVCALL
);
8359 /* Entry was found */
8364 ASSERT(Name
->Length
>= Entry
->Prefix
.Length
);
8366 /* Setup remaining name */
8367 RemainingName
->Buffer
= Add2Ptr(Name
->Buffer
, Entry
->Prefix
.Length
);
8368 RemainingName
->Length
= Name
->Length
- Entry
->Prefix
.Length
;
8369 RemainingName
->MaximumLength
= Name
->Length
- Entry
->Prefix
.Length
;
8373 /* Otherwise, that's the whole name */
8374 RemainingName
= Name
;
8384 RxTableLookupName_ExactLengthMatch(
8385 IN PRX_PREFIX_TABLE ThisTable
,
8386 IN PUNICODE_STRING Name
,
8388 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId
)
8390 PLIST_ENTRY ListEntry
, HashBucket
;
8394 ASSERT(RxConnectionId
!= NULL
);
8396 /* Select the right bucket */
8397 HashBucket
= HASH_BUCKET(ThisTable
, HashValue
);
8398 DPRINT("Looking in bucket: %p for %x\n", HashBucket
, HashValue
);
8399 /* If bucket is empty, no match */
8400 if (IsListEmpty(HashBucket
))
8405 /* Browse all the entries in the bucket */
8406 for (ListEntry
= HashBucket
->Flink
;
8407 ListEntry
!= HashBucket
;
8408 ListEntry
= ListEntry
->Flink
)
8411 PRX_PREFIX_ENTRY Entry
;
8412 BOOLEAN CaseInsensitive
;
8413 PUNICODE_STRING CmpName
, CmpPrefix
;
8414 UNICODE_STRING InsensitiveName
, InsensitivePrefix
;
8416 Entry
= CONTAINING_RECORD(ListEntry
, RX_PREFIX_ENTRY
, HashLinks
);
8418 ++ThisTable
->Considers
;
8420 ASSERT(HashBucket
== HASH_BUCKET(ThisTable
, Entry
->SavedHashValue
));
8422 Container
= Entry
->ContainingRecord
;
8423 ASSERT(Container
!= NULL
);
8425 /* Not the same hash, not the same length, move on */
8426 if (Entry
->SavedHashValue
!= HashValue
|| Entry
->Prefix
.Length
!= Name
->Length
)
8432 ++ThisTable
->Compares
;
8434 /* If we have to perform a case insensitive compare on a portion... */
8435 if (Entry
->CaseInsensitiveLength
!= 0)
8437 ASSERT(Entry
->CaseInsensitiveLength
<= Name
->Length
);
8439 /* Perform the case insensitive check on the asked length */
8440 InsensitiveName
.Buffer
= Name
->Buffer
;
8441 InsensitivePrefix
.Buffer
= Entry
->Prefix
.Buffer
;
8442 InsensitiveName
.Length
= Entry
->CaseInsensitiveLength
;
8443 InsensitivePrefix
.Length
= Entry
->CaseInsensitiveLength
;
8444 /* No match, move to the next entry */
8445 if (!RtlEqualUnicodeString(&InsensitiveName
, &InsensitivePrefix
, TRUE
))
8450 /* Was the case insensitive covering the whole name? */
8451 if (Name
->Length
== Entry
->CaseInsensitiveLength
)
8453 /* If connection ID also matches, that a complete match! */
8454 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
8460 /* Otherwise, we have to continue with the sensitive match.... */
8461 InsensitiveName
.Buffer
= Add2Ptr(InsensitiveName
.Buffer
, Entry
->CaseInsensitiveLength
);
8462 InsensitivePrefix
.Buffer
= Add2Ptr(InsensitivePrefix
.Buffer
, Entry
->CaseInsensitiveLength
);
8463 InsensitiveName
.Length
= Name
->Length
- Entry
->CaseInsensitiveLength
;
8464 InsensitivePrefix
.Length
= Entry
->Prefix
.Length
- Entry
->CaseInsensitiveLength
;
8466 CmpName
= &InsensitiveName
;
8467 CmpPrefix
= &InsensitivePrefix
;
8468 CaseInsensitive
= FALSE
;
8473 CmpPrefix
= &Entry
->Prefix
;
8474 CaseInsensitive
= ThisTable
->CaseInsensitiveMatch
;
8477 /* Perform the compare, if there's a match, also check for connection ID */
8478 if (RtlEqualUnicodeString(CmpName
, CmpPrefix
, CaseInsensitive
))
8480 if (!ThisTable
->IsNetNameTable
|| RxEqualConnectionId(RxConnectionId
, &Entry
->ConnectionId
))
8494 RxTearDownBufferingManager(
8500 return STATUS_SUCCESS
;
8509 _In_
struct _KDPC
*Dpc
,
8510 _In_opt_ PVOID DeferredContext
,
8511 _In_opt_ PVOID SystemArgument1
,
8512 _In_opt_ PVOID SystemArgument2
)
8515 LIST_ENTRY LocalList
;
8516 PLIST_ENTRY ListEntry
;
8517 PRX_WORK_ITEM WorkItem
;
8519 InitializeListHead(&LocalList
);
8521 KeAcquireSpinLockAtDpcLevel(&RxTimerLock
);
8524 /* Find any entry matching */
8525 if (!IsListEmpty(&RxTimerQueueHead
))
8527 ListEntry
= RxTimerQueueHead
.Flink
;
8530 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
8531 if (WorkItem
->LastTick
== RxTimerTickCount
)
8533 ListEntry
= ListEntry
->Flink
;
8535 RemoveEntryList(&WorkItem
->WorkQueueItem
.List
);
8536 InsertTailList(&LocalList
, &WorkItem
->WorkQueueItem
.List
);
8540 ListEntry
= ListEntry
->Flink
;
8542 } while (ListEntry
!= &RxTimerQueueHead
);
8544 /* Do we have to requeue a later execution? */
8545 Set
= !IsListEmpty(&RxTimerQueueHead
);
8547 KeReleaseSpinLockFromDpcLevel(&RxTimerLock
);
8549 /* Requeue if list wasn't empty */
8552 KeSetTimer(&RxTimer
, RxTimerInterval
, &RxTimerDpc
);
8555 /* If we had matching entries */
8556 if (!IsListEmpty(&LocalList
))
8558 /* Post them, one after another */
8559 ListEntry
= LocalList
.Flink
;
8562 WorkItem
= CONTAINING_RECORD(ListEntry
, RX_WORK_ITEM
, WorkQueueItem
.List
);
8563 ListEntry
= ListEntry
->Flink
;
8565 WorkItem
->WorkQueueItem
.List
.Flink
= NULL
;
8566 WorkItem
->WorkQueueItem
.List
.Blink
= NULL
;
8567 RxPostToWorkerThread(WorkItem
->WorkQueueItem
.pDeviceObject
, CriticalWorkQueue
,
8568 &WorkItem
->WorkQueueItem
, WorkItem
->WorkQueueItem
.WorkerRoutine
,
8569 WorkItem
->WorkQueueItem
.Parameter
);
8571 while (ListEntry
!= &LocalList
);
8575 #ifdef RDBSS_TRACKER
8580 RxTrackerUpdateHistory(
8581 _Inout_opt_ PRX_CONTEXT RxContext
,
8582 _Inout_ PMRX_FCB MrxFcb
,
8583 _In_ ULONG Operation
,
8584 _In_ ULONG LineNumber
,
8585 _In_ PCSTR FileName
,
8586 _In_ ULONG SerialNumber
)
8589 RX_FCBTRACKER_CASES Case
;
8591 /* Check for null or special context */
8592 if (RxContext
== NULL
)
8594 Case
= RX_FCBTRACKER_CASE_NULLCONTEXT
;
8596 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
)
8598 Case
= RX_FCBTRACKER_CASE_CBS_CONTEXT
;
8600 else if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
8602 Case
= RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT
;
8606 ASSERT(NodeType(RxContext
) == RDBSS_NTC_RX_CONTEXT
);
8607 Case
= RX_FCBTRACKER_CASE_NORMAL
;
8610 /* If caller provided a FCB, update its history */
8614 ASSERT(NodeTypeIsFcb(Fcb
));
8616 /* Only one acquire operation, so many release operations... */
8617 if (Operation
== TRACKER_ACQUIRE_FCB
)
8619 ++Fcb
->FcbAcquires
[Case
];
8623 ++Fcb
->FcbReleases
[Case
];
8627 /* If we have a normal context, update its history about this function calls */
8628 if (Case
== RX_FCBTRACKER_CASE_NORMAL
)
8630 ULONG TrackerHistoryPointer
;
8632 /* Only one acquire operation, so many release operations... */
8633 if (Operation
== TRACKER_ACQUIRE_FCB
)
8635 InterlockedIncrement(&RxContext
->AcquireReleaseFcbTrackerX
);
8639 InterlockedDecrement(&RxContext
->AcquireReleaseFcbTrackerX
);
8642 /* We only keep track of the 32 first calls */
8643 TrackerHistoryPointer
= InterlockedExchangeAdd((volatile long *)&RxContext
->TrackerHistoryPointer
, 1);
8644 if (TrackerHistoryPointer
< RDBSS_TRACKER_HISTORY_SIZE
)
8646 RxContext
->TrackerHistory
[TrackerHistoryPointer
].AcquireRelease
= Operation
;
8647 RxContext
->TrackerHistory
[TrackerHistoryPointer
].LineNumber
= LineNumber
;
8648 RxContext
->TrackerHistory
[TrackerHistoryPointer
].FileName
= (PSZ
)FileName
;
8649 RxContext
->TrackerHistory
[TrackerHistoryPointer
].SavedTrackerValue
= RxContext
->AcquireReleaseFcbTrackerX
;
8650 RxContext
->TrackerHistory
[TrackerHistoryPointer
].Flags
= RxContext
->Flags
;
8653 /* If it's negative, then we released once more than we acquired it?! */
8654 ASSERT(RxContext
->AcquireReleaseFcbTrackerX
>= 0);
8660 RxTrackPagingIoResource(
8661 _Inout_ PVOID Instance
,
8673 RxUndoScavengerFinalizationMarking(
8676 /* Just call internal routine with mutex held */
8677 RxAcquireScavengerMutex();
8678 RxpUndoScavengerFinalizationMarking(Instance
);
8679 RxReleaseScavengerMutex();
8686 RxUninitializeVNetRootParameters(
8687 IN PUNICODE_STRING UserName
,
8688 IN PUNICODE_STRING UserDomainName
,
8689 IN PUNICODE_STRING Password
,
8694 /* Only free what could have been allocated */
8695 if (UserName
!= NULL
)
8697 RxFreePool(UserName
);
8700 if (UserDomainName
!= NULL
)
8702 RxFreePool(UserDomainName
);
8705 if (Password
!= NULL
)
8707 RxFreePool(Password
);
8710 /* And remove the possibly set CSC agent flag */
8713 (*Flags
) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE
;
8722 IN RX_BLOCK_CONDITION NewConditionValue
,
8723 OUT PRX_BLOCK_CONDITION Condition
,
8724 IN OUT PLIST_ENTRY TransitionWaitList
)
8726 PRX_CONTEXT Context
;
8727 LIST_ENTRY SerializationQueue
;
8731 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue
, Condition
, TransitionWaitList
);
8733 /* Set the new condition */
8734 RxAcquireSerializationMutex();
8735 ASSERT(NewConditionValue
!= Condition_InTransition
);
8736 *Condition
= NewConditionValue
;
8737 /* And get the serialization queue for treatment */
8738 RxTransferList(&SerializationQueue
, TransitionWaitList
);
8739 RxReleaseSerializationMutex();
8741 /* Handle the serialization queue */
8742 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
8743 while (Context
!= NULL
)
8745 /* If the caller asked for post, post the request */
8746 if (BooleanFlagOn(Context
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8748 Context
->Flags
&= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
;
8749 RxFsdPostRequest(Context
);
8751 /* Otherwise, wake up sleeping waiters */
8754 RxSignalSynchronousWaiter(Context
);
8757 Context
= RxRemoveFirstContextFromSerializationQueue(&SerializationQueue
);
8765 RxVerifyOperationIsLegal(
8766 IN PRX_CONTEXT RxContext
)
8771 PFILE_OBJECT FileObject
;
8772 PIO_STACK_LOCATION Stack
;
8776 Irp
= RxContext
->CurrentIrp
;
8777 Stack
= RxContext
->CurrentIrpSp
;
8778 FileObject
= Stack
->FileObject
;
8780 /* We'll only check stuff on opened files, this requires an IRP and a FO */
8781 if (Irp
== NULL
|| FileObject
== NULL
)
8786 /* Set no exception for breakpoint - remember whether is was already set */
8787 FlagSet
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8788 SetFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8790 /* If we have a CCB, perform a few checks on opened file */
8791 Fobx
= RxContext
->pFobx
;
8794 PMRX_SRV_OPEN SrvOpen
;
8796 SrvOpen
= Fobx
->pSrvOpen
;
8797 if (SrvOpen
!= NULL
)
8799 UCHAR MajorFunction
;
8801 MajorFunction
= RxContext
->MajorFunction
;
8802 /* Only allow closing/cleanup operations on renamed files */
8803 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8804 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_RENAMED
))
8806 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_RENAMED
;
8807 ExRaiseStatus(STATUS_FILE_RENAMED
);
8810 /* Only allow closing/cleanup operations on deleted files */
8811 if (MajorFunction
!= IRP_MJ_CLEANUP
&& MajorFunction
!= IRP_MJ_CLOSE
&&
8812 BooleanFlagOn(SrvOpen
->Flags
, SRVOPEN_FLAG_FILE_DELETED
))
8814 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_DELETED
;
8815 ExRaiseStatus(STATUS_FILE_DELETED
);
8820 /* If that's an open operation */
8821 if (RxContext
->MajorFunction
== IRP_MJ_CREATE
)
8823 PFILE_OBJECT RelatedFileObject
;
8825 /* We won't allow an open operation relative to a file to be deleted */
8826 RelatedFileObject
= FileObject
->RelatedFileObject
;
8827 if (RelatedFileObject
!= NULL
)
8831 Fcb
= RelatedFileObject
->FsContext
;
8832 if (BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_DELETE_ON_CLOSE
))
8834 RxContext
->IoStatusBlock
.Status
= STATUS_DELETE_PENDING
;
8835 ExRaiseStatus(STATUS_DELETE_PENDING
);
8840 /* If cleanup was completed */
8841 if (BooleanFlagOn(FileObject
->Flags
, FO_CLEANUP_COMPLETE
))
8843 if (!BooleanFlagOn(Irp
->Flags
, IRP_PAGING_IO
))
8845 UCHAR MajorFunction
;
8847 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */
8848 MajorFunction
= Stack
->MajorFunction
;
8849 if (MajorFunction
!= IRP_MJ_CLOSE
&& MajorFunction
!= IRP_MJ_QUERY_INFORMATION
&&
8850 MajorFunction
!= IRP_MJ_SET_INFORMATION
)
8852 if ((MajorFunction
!= IRP_MJ_READ
&& MajorFunction
!= IRP_MJ_WRITE
) ||
8853 !BooleanFlagOn(Stack
->MinorFunction
, IRP_MN_COMPLETE
))
8855 RxContext
->IoStatusBlock
.Status
= STATUS_FILE_CLOSED
;
8856 ExRaiseStatus(STATUS_FILE_CLOSED
);
8862 /* If flag was already set, don't clear it */
8865 ClearFlag(RxContext
->Flags
, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT
);
8873 RxWaitForStableCondition(
8874 IN PRX_BLOCK_CONDITION Condition
,
8875 IN OUT PLIST_ENTRY TransitionWaitList
,
8876 IN OUT PRX_CONTEXT RxContext
,
8877 OUT NTSTATUS
*AsyncStatus OPTIONAL
)
8880 NTSTATUS LocalStatus
;
8884 /* Make sure to always get status */
8885 if (AsyncStatus
== NULL
)
8887 AsyncStatus
= &LocalStatus
;
8890 /* By default, it's a success */
8891 *AsyncStatus
= STATUS_SUCCESS
;
8894 /* If it's not stable, we've to wait */
8895 if (!StableCondition(*Condition
))
8897 /* Lock the mutex */
8898 RxAcquireSerializationMutex();
8899 /* Still not stable? */
8900 if (!StableCondition(*Condition
))
8902 /* Insert us in the wait list for processing on stable condition */
8903 RxInsertContextInSerializationQueue(TransitionWaitList
, RxContext
);
8905 /* If we're asked to post on stable, don't wait, and just return pending */
8906 if (BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION
))
8908 *AsyncStatus
= STATUS_PENDING
;
8915 RxReleaseSerializationMutex();
8917 /* We don't post on stable, so, just wait... */
8920 RxWaitSync(RxContext
);
8930 RxWorkItemDispatcher(
8933 PRX_WORK_DISPATCH_ITEM DispatchItem
= Context
;
8935 DPRINT("Calling: %p, %p\n", DispatchItem
->DispatchRoutine
, DispatchItem
->DispatchRoutineParameter
);
8937 DispatchItem
->DispatchRoutine(DispatchItem
->DispatchRoutineParameter
);
8939 RxFreePoolWithTag(DispatchItem
, RX_WORKQ_POOLTAG
);
8947 _RxAllocatePoolWithTag(
8948 _In_ POOL_TYPE PoolType
,
8949 _In_ SIZE_T NumberOfBytes
,
8952 return ExAllocatePoolWithTagPriority(PoolType
, NumberOfBytes
, Tag
, LowPoolPriority
);
8963 ExFreePoolWithTag(Buffer
, 0);
8975 ExFreePoolWithTag(Buffer
, Tag
);
8981 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL
,
8983 #ifdef RDBSS_TRACKER
8985 _In_ ULONG LineNumber
,
8986 _In_ PCSTR FileName
,
8987 _In_ ULONG SerialNumber
8992 BOOLEAN SpecialContext
, CanWait
, Acquired
, ContextIsPresent
;
8996 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb
, RxContext
, Mode
, LineNumber
, FileName
, SerialNumber
);
8998 SpecialContext
= FALSE
;
8999 ContextIsPresent
= FALSE
;
9000 /* Check for special context */
9001 if (RxContext
== CHANGE_BUFFERING_STATE_CONTEXT
|| RxContext
== CHANGE_BUFFERING_STATE_CONTEXT_WAIT
)
9003 SpecialContext
= TRUE
;
9006 /* We don't handle buffering state change yet... */
9007 if (!RxIsFcbAcquired(Fcb
) && !SpecialContext
&&
9008 BooleanFlagOn(Fcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
))
9013 /* Nor special contexts */
9019 /* If we don't have a context, assume we can wait! */
9020 if (RxContext
== NULL
)
9026 /* That said: we have a real context! */
9027 ContextIsPresent
= TRUE
;
9029 /* If we've been cancelled in between, give up */
9030 Status
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_CANCELLED
) ? STATUS_CANCELLED
: STATUS_SUCCESS
;
9031 if (!NT_SUCCESS(Status
))
9037 CanWait
= BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_WAIT
);
9042 /* Assume we cannot lock */
9043 Status
= STATUS_LOCK_NOT_GRANTED
;
9045 /* Lock according to what the caller asked */
9048 case FCB_MODE_EXCLUSIVE
:
9049 Acquired
= ExAcquireResourceExclusiveLite(Fcb
->Header
.Resource
, CanWait
);
9052 case FCB_MODE_SHARED
:
9053 Acquired
= ExAcquireResourceSharedLite(Fcb
->Header
.Resource
, CanWait
);
9056 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE
:
9057 Acquired
= ExAcquireSharedWaitForExclusive(Fcb
->Header
.Resource
, CanWait
);
9061 ASSERT(Mode
== FCB_MODE_SHARED_STARVE_EXCLUSIVE
);
9062 Acquired
= ExAcquireSharedStarveExclusive(Fcb
->Header
.Resource
, CanWait
);
9069 Status
= STATUS_SUCCESS
;
9070 ASSERT_CORRECT_FCB_STRUCTURE(Fcb
);
9072 /* Handle paging write - not implemented */
9073 if (Fcb
->NonPaged
->OutstandingAsyncWrites
!= 0)
9079 /* And break, that cool! */
9085 /* If it failed, return immediately */
9086 if (!NT_SUCCESS(Status
))
9092 /* If we don't have to check for valid operation, job done, nothing more to do */
9093 if (!ContextIsPresent
|| BooleanFlagOn(RxContext
->Flags
, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK
))
9095 if (NT_SUCCESS(Status
))
9097 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
9103 /* Verify operation */
9106 RxVerifyOperationIsLegal(RxContext
);
9110 /* If it failed, release lock and fail */
9111 if (_SEH2_AbnormalTermination())
9113 ExReleaseResourceLite(Fcb
->Header
.Resource
);
9114 Status
= STATUS_LOCK_NOT_GRANTED
;
9119 if (NT_SUCCESS(Status
))
9121 RxTrackerUpdateHistory(RxContext
, RX_GET_MRX_FCB(Fcb
), TRACKER_ACQUIRE_FCB
, LineNumber
, FileName
, SerialNumber
);
9124 DPRINT("Status: %x\n", Status
);
9132 __RxItsTheSameContext(
9133 _In_ PRX_CONTEXT RxContext
,
9134 _In_ ULONG CapturedRxContextSerialNumber
,
9138 /* Check we have a context with the same serial number */
9139 if (NodeType(RxContext
) != RDBSS_NTC_RX_CONTEXT
||
9140 RxContext
->SerialNumber
!= CapturedRxContextSerialNumber
)
9143 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext
, Line
, File
);
9149 _Inout_opt_ PRX_CONTEXT RxContext
,
9150 _Inout_ PMRX_FCB MrxFcb
9151 #ifdef RDBSS_TRACKER
9153 _In_ ULONG LineNumber
,
9154 _In_ PCSTR FileName
,
9155 _In_ ULONG SerialNumber
9159 BOOLEAN IsExclusive
, BufferingPending
;
9161 RxAcquireSerializationMutex();
9163 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
9164 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
9166 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9167 * then just release the FCB
9169 if (!BufferingPending
|| !IsExclusive
)
9171 RxTrackerUpdateHistory(RxContext
, MrxFcb
, (!BufferingPending
? TRACKER_RELEASE_FCB_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING
),
9172 LineNumber
, FileName
, SerialNumber
);
9173 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
9176 RxReleaseSerializationMutex();
9178 /* And finally leave */
9179 if (!BufferingPending
|| !IsExclusive
)
9184 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb
));
9186 /* Otherwise, handle buffering state and release */
9187 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
9189 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
9190 ExReleaseResourceLite(MrxFcb
->Header
.Resource
);
9194 __RxReleaseFcbForThread(
9195 _Inout_opt_ PRX_CONTEXT RxContext
,
9196 _Inout_ PMRX_FCB MrxFcb
,
9197 _In_ ERESOURCE_THREAD ResourceThreadId
9198 #ifdef RDBSS_TRACKER
9200 _In_ ULONG LineNumber
,
9201 _In_ PCSTR FileName
,
9202 _In_ ULONG SerialNumber
9206 BOOLEAN IsExclusive
, BufferingPending
;
9208 RxAcquireSerializationMutex();
9210 BufferingPending
= BooleanFlagOn(MrxFcb
->FcbState
, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING
);
9211 IsExclusive
= !!RxIsResourceOwnershipStateExclusive(MrxFcb
->Header
.Resource
);
9213 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock),
9214 * then just release the FCB
9216 if (!BufferingPending
|| !IsExclusive
)
9218 RxTrackerUpdateHistory(RxContext
, MrxFcb
,
9219 (!BufferingPending
? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING
: TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING
),
9220 LineNumber
, FileName
, SerialNumber
);
9221 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);
9224 RxReleaseSerializationMutex();
9226 /* And finally leave */
9227 if (!BufferingPending
|| !IsExclusive
)
9232 /* Otherwise, handle buffering state and release */
9233 RxTrackerUpdateHistory(RxContext
, MrxFcb
, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING
, LineNumber
, FileName
, SerialNumber
);
9234 RxProcessFcbChangeBufferingStateRequest((PFCB
)MrxFcb
);
9235 ExReleaseResourceForThreadLite(MrxFcb
->Header
.Resource
, ResourceThreadId
);