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
));