xref: /reactos/drivers/filesystems/fastfat/close.c (revision 23b7c7b8)
1*23b7c7b8SHermès Bélusca-Maïto /*++
2*23b7c7b8SHermès Bélusca-Maïto 
3*23b7c7b8SHermès Bélusca-Maïto Copyright (c) 1989-2000 Microsoft Corporation
4*23b7c7b8SHermès Bélusca-Maïto 
5*23b7c7b8SHermès Bélusca-Maïto Module Name:
6*23b7c7b8SHermès Bélusca-Maïto 
7*23b7c7b8SHermès Bélusca-Maïto     Close.c
8*23b7c7b8SHermès Bélusca-Maïto 
9*23b7c7b8SHermès Bélusca-Maïto Abstract:
10*23b7c7b8SHermès Bélusca-Maïto 
11*23b7c7b8SHermès Bélusca-Maïto     This module implements the File Close routine for Fat called by the
12*23b7c7b8SHermès Bélusca-Maïto     dispatch driver.
13*23b7c7b8SHermès Bélusca-Maïto 
14*23b7c7b8SHermès Bélusca-Maïto 
15*23b7c7b8SHermès Bélusca-Maïto --*/
16*23b7c7b8SHermès Bélusca-Maïto 
17*23b7c7b8SHermès Bélusca-Maïto #include "fatprocs.h"
18*23b7c7b8SHermès Bélusca-Maïto 
19*23b7c7b8SHermès Bélusca-Maïto //
20*23b7c7b8SHermès Bélusca-Maïto //  The Bug check file id for this module
21*23b7c7b8SHermès Bélusca-Maïto //
22*23b7c7b8SHermès Bélusca-Maïto 
23*23b7c7b8SHermès Bélusca-Maïto #define BugCheckFileId                   (FAT_BUG_CHECK_CLOSE)
24*23b7c7b8SHermès Bélusca-Maïto 
25*23b7c7b8SHermès Bélusca-Maïto //
26*23b7c7b8SHermès Bélusca-Maïto //  The local debug trace level
27*23b7c7b8SHermès Bélusca-Maïto //
28*23b7c7b8SHermès Bélusca-Maïto 
29*23b7c7b8SHermès Bélusca-Maïto #define Dbg                              (DEBUG_TRACE_CLOSE)
30*23b7c7b8SHermès Bélusca-Maïto 
31*23b7c7b8SHermès Bélusca-Maïto ULONG FatMaxDelayedCloseCount;
32*23b7c7b8SHermès Bélusca-Maïto 
33*23b7c7b8SHermès Bélusca-Maïto 
34*23b7c7b8SHermès Bélusca-Maïto #define FatAcquireCloseMutex() {                        \
35*23b7c7b8SHermès Bélusca-Maïto     NT_ASSERT(KeAreApcsDisabled());                     \
36*23b7c7b8SHermès Bélusca-Maïto     ExAcquireFastMutexUnsafe( &FatCloseQueueMutex );    \
37*23b7c7b8SHermès Bélusca-Maïto }
38*23b7c7b8SHermès Bélusca-Maïto 
39*23b7c7b8SHermès Bélusca-Maïto #define FatReleaseCloseMutex() {                        \
40*23b7c7b8SHermès Bélusca-Maïto     NT_ASSERT(KeAreApcsDisabled());                     \
41*23b7c7b8SHermès Bélusca-Maïto     ExReleaseFastMutexUnsafe( &FatCloseQueueMutex );    \
42*23b7c7b8SHermès Bélusca-Maïto }
43*23b7c7b8SHermès Bélusca-Maïto 
44*23b7c7b8SHermès Bélusca-Maïto //
45*23b7c7b8SHermès Bélusca-Maïto //  Local procedure prototypes
46*23b7c7b8SHermès Bélusca-Maïto //
47*23b7c7b8SHermès Bélusca-Maïto 
48*23b7c7b8SHermès Bélusca-Maïto _Requires_lock_held_(_Global_critical_region_)
49*23b7c7b8SHermès Bélusca-Maïto VOID
50*23b7c7b8SHermès Bélusca-Maïto FatQueueClose (
51*23b7c7b8SHermès Bélusca-Maïto     IN PCLOSE_CONTEXT CloseContext,
52*23b7c7b8SHermès Bélusca-Maïto     IN BOOLEAN DelayClose
53*23b7c7b8SHermès Bélusca-Maïto     );
54*23b7c7b8SHermès Bélusca-Maïto 
55*23b7c7b8SHermès Bélusca-Maïto _Requires_lock_held_(_Global_critical_region_)
56*23b7c7b8SHermès Bélusca-Maïto PCLOSE_CONTEXT
57*23b7c7b8SHermès Bélusca-Maïto FatRemoveClose (
58*23b7c7b8SHermès Bélusca-Maïto     PVCB Vcb OPTIONAL,
59*23b7c7b8SHermès Bélusca-Maïto     PVCB LastVcbHint OPTIONAL
60*23b7c7b8SHermès Bélusca-Maïto     );
61*23b7c7b8SHermès Bélusca-Maïto 
62*23b7c7b8SHermès Bélusca-Maïto IO_WORKITEM_ROUTINE FatCloseWorker;
63*23b7c7b8SHermès Bélusca-Maïto 
64*23b7c7b8SHermès Bélusca-Maïto VOID
65*23b7c7b8SHermès Bélusca-Maïto NTAPI
66*23b7c7b8SHermès Bélusca-Maïto FatCloseWorker (
67*23b7c7b8SHermès Bélusca-Maïto     _In_        PDEVICE_OBJECT DeviceObject,
68*23b7c7b8SHermès Bélusca-Maïto     _In_opt_    PVOID Context
69*23b7c7b8SHermès Bélusca-Maïto     );
70*23b7c7b8SHermès Bélusca-Maïto 
71*23b7c7b8SHermès Bélusca-Maïto #ifdef ALLOC_PRAGMA
72*23b7c7b8SHermès Bélusca-Maïto #pragma alloc_text(PAGE, FatFsdClose)
73*23b7c7b8SHermès Bélusca-Maïto #pragma alloc_text(PAGE, FatFspClose)
74*23b7c7b8SHermès Bélusca-Maïto #pragma alloc_text(PAGE, FatRemoveClose)
75*23b7c7b8SHermès Bélusca-Maïto #pragma alloc_text(PAGE, FatCommonClose)
76*23b7c7b8SHermès Bélusca-Maïto #pragma alloc_text(PAGE, FatCloseWorker)
77*23b7c7b8SHermès Bélusca-Maïto #endif
78*23b7c7b8SHermès Bélusca-Maïto 
79*23b7c7b8SHermès Bélusca-Maïto 
80*23b7c7b8SHermès Bélusca-Maïto _Function_class_(IRP_MJ_CLOSE)
_Function_class_(DRIVER_DISPATCH)81*23b7c7b8SHermès Bélusca-Maïto _Function_class_(DRIVER_DISPATCH)
82*23b7c7b8SHermès Bélusca-Maïto NTSTATUS
83*23b7c7b8SHermès Bélusca-Maïto NTAPI
84*23b7c7b8SHermès Bélusca-Maïto FatFsdClose (
85*23b7c7b8SHermès Bélusca-Maïto     _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
86*23b7c7b8SHermès Bélusca-Maïto     _Inout_ PIRP Irp
87*23b7c7b8SHermès Bélusca-Maïto     )
88*23b7c7b8SHermès Bélusca-Maïto 
89*23b7c7b8SHermès Bélusca-Maïto /*++
90*23b7c7b8SHermès Bélusca-Maïto 
91*23b7c7b8SHermès Bélusca-Maïto Routine Description:
92*23b7c7b8SHermès Bélusca-Maïto 
93*23b7c7b8SHermès Bélusca-Maïto     This routine implements the FSD part of Close.
94*23b7c7b8SHermès Bélusca-Maïto 
95*23b7c7b8SHermès Bélusca-Maïto Arguments:
96*23b7c7b8SHermès Bélusca-Maïto 
97*23b7c7b8SHermès Bélusca-Maïto     VolumeDeviceObject - Supplies the volume device object where the
98*23b7c7b8SHermès Bélusca-Maïto         file exists
99*23b7c7b8SHermès Bélusca-Maïto 
100*23b7c7b8SHermès Bélusca-Maïto     Irp - Supplies the Irp being processed
101*23b7c7b8SHermès Bélusca-Maïto 
102*23b7c7b8SHermès Bélusca-Maïto Return Value:
103*23b7c7b8SHermès Bélusca-Maïto 
104*23b7c7b8SHermès Bélusca-Maïto     NTSTATUS - The FSD status for the IRP
105*23b7c7b8SHermès Bélusca-Maïto 
106*23b7c7b8SHermès Bélusca-Maïto --*/
107*23b7c7b8SHermès Bélusca-Maïto 
108*23b7c7b8SHermès Bélusca-Maïto {
109*23b7c7b8SHermès Bélusca-Maïto     NTSTATUS Status = STATUS_SUCCESS;
110*23b7c7b8SHermès Bélusca-Maïto     PIO_STACK_LOCATION IrpSp;
111*23b7c7b8SHermès Bélusca-Maïto     PFILE_OBJECT FileObject;
112*23b7c7b8SHermès Bélusca-Maïto 
113*23b7c7b8SHermès Bélusca-Maïto     PVCB Vcb;
114*23b7c7b8SHermès Bélusca-Maïto     PFCB Fcb;
115*23b7c7b8SHermès Bélusca-Maïto     PCCB Ccb;
116*23b7c7b8SHermès Bélusca-Maïto     TYPE_OF_OPEN TypeOfOpen;
117*23b7c7b8SHermès Bélusca-Maïto 
118*23b7c7b8SHermès Bélusca-Maïto     BOOLEAN TopLevel;
119*23b7c7b8SHermès Bélusca-Maïto     BOOLEAN VcbDeleted = FALSE;
120*23b7c7b8SHermès Bélusca-Maïto 
121*23b7c7b8SHermès Bélusca-Maïto     PAGED_CODE();
122*23b7c7b8SHermès Bélusca-Maïto 
123*23b7c7b8SHermès Bélusca-Maïto     //
124*23b7c7b8SHermès Bélusca-Maïto     //  If we were called with our file system device object instead of a
125*23b7c7b8SHermès Bélusca-Maïto     //  volume device object, just complete this request with STATUS_SUCCESS
126*23b7c7b8SHermès Bélusca-Maïto     //
127*23b7c7b8SHermès Bélusca-Maïto 
128*23b7c7b8SHermès Bélusca-Maïto     if (FatDeviceIsFatFsdo( VolumeDeviceObject))  {
129*23b7c7b8SHermès Bélusca-Maïto 
130*23b7c7b8SHermès Bélusca-Maïto         Irp->IoStatus.Status = STATUS_SUCCESS;
131*23b7c7b8SHermès Bélusca-Maïto         Irp->IoStatus.Information = FILE_OPENED;
132*23b7c7b8SHermès Bélusca-Maïto 
133*23b7c7b8SHermès Bélusca-Maïto         IoCompleteRequest( Irp, IO_DISK_INCREMENT );
134*23b7c7b8SHermès Bélusca-Maïto 
135*23b7c7b8SHermès Bélusca-Maïto         return STATUS_SUCCESS;
136*23b7c7b8SHermès Bélusca-Maïto     }
137*23b7c7b8SHermès Bélusca-Maïto 
138*23b7c7b8SHermès Bélusca-Maïto     DebugTrace(+1, Dbg, "FatFsdClose\n", 0);
139*23b7c7b8SHermès Bélusca-Maïto 
140*23b7c7b8SHermès Bélusca-Maïto     //
141*23b7c7b8SHermès Bélusca-Maïto     //  Call the common Close routine
142*23b7c7b8SHermès Bélusca-Maïto     //
143*23b7c7b8SHermès Bélusca-Maïto 
144*23b7c7b8SHermès Bélusca-Maïto     FsRtlEnterFileSystem();
145*23b7c7b8SHermès Bélusca-Maïto 
146*23b7c7b8SHermès Bélusca-Maïto     TopLevel = FatIsIrpTopLevel( Irp );
147*23b7c7b8SHermès Bélusca-Maïto 
148*23b7c7b8SHermès Bélusca-Maïto     //
149*23b7c7b8SHermès Bélusca-Maïto     //  Get a pointer to the current stack location and the file object
150*23b7c7b8SHermès Bélusca-Maïto     //
151*23b7c7b8SHermès Bélusca-Maïto 
152*23b7c7b8SHermès Bélusca-Maïto     IrpSp = IoGetCurrentIrpStackLocation( Irp );
153*23b7c7b8SHermès Bélusca-Maïto 
154*23b7c7b8SHermès Bélusca-Maïto     FileObject = IrpSp->FileObject;
155*23b7c7b8SHermès Bélusca-Maïto 
156*23b7c7b8SHermès Bélusca-Maïto     //
157*23b7c7b8SHermès Bélusca-Maïto     //  Decode the file object and set the read-only bit in the Ccb.
158*23b7c7b8SHermès Bélusca-Maïto     //
159*23b7c7b8SHermès Bélusca-Maïto 
160*23b7c7b8SHermès Bélusca-Maïto     TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
161*23b7c7b8SHermès Bélusca-Maïto 
162*23b7c7b8SHermès Bélusca-Maïto     if (Ccb && IsFileObjectReadOnly(FileObject)) {
163*23b7c7b8SHermès Bélusca-Maïto 
164*23b7c7b8SHermès Bélusca-Maïto         SetFlag( Ccb->Flags, CCB_FLAG_READ_ONLY );
165*23b7c7b8SHermès Bélusca-Maïto     }
166*23b7c7b8SHermès Bélusca-Maïto 
167*23b7c7b8SHermès Bélusca-Maïto     _SEH2_TRY {
168*23b7c7b8SHermès Bélusca-Maïto 
169*23b7c7b8SHermès Bélusca-Maïto         PCLOSE_CONTEXT CloseContext = NULL;
170*23b7c7b8SHermès Bélusca-Maïto 
171*23b7c7b8SHermès Bélusca-Maïto         //
172*23b7c7b8SHermès Bélusca-Maïto         //  If we are top level, WAIT can be TRUE, otherwise make it FALSE
173*23b7c7b8SHermès Bélusca-Maïto         //  to avoid deadlocks, unless this is a top
174*23b7c7b8SHermès Bélusca-Maïto         //  level request not originating from the system process.
175*23b7c7b8SHermès Bélusca-Maïto         //
176*23b7c7b8SHermès Bélusca-Maïto 
177*23b7c7b8SHermès Bélusca-Maïto         BOOLEAN Wait = TopLevel && (PsGetCurrentProcess() != FatData.OurProcess);
178*23b7c7b8SHermès Bélusca-Maïto 
179*23b7c7b8SHermès Bélusca-Maïto #if (NTDDI_VERSION >= NTDDI_WIN8)
180*23b7c7b8SHermès Bélusca-Maïto 
181*23b7c7b8SHermès Bélusca-Maïto         //
182*23b7c7b8SHermès Bélusca-Maïto         //  To catch the odd case where a close comes in without a preceding cleanup,
183*23b7c7b8SHermès Bélusca-Maïto         //  call the oplock package to get rid of any oplock state.  This can only
184*23b7c7b8SHermès Bélusca-Maïto         //  be safely done in the FSD path.
185*23b7c7b8SHermès Bélusca-Maïto         //
186*23b7c7b8SHermès Bélusca-Maïto 
187*23b7c7b8SHermès Bélusca-Maïto         if ((Fcb != NULL) &&
188*23b7c7b8SHermès Bélusca-Maïto             !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) &&
189*23b7c7b8SHermès Bélusca-Maïto             FatIsFileOplockable( Fcb )) {
190*23b7c7b8SHermès Bélusca-Maïto 
191*23b7c7b8SHermès Bélusca-Maïto             //
192*23b7c7b8SHermès Bélusca-Maïto             //  This is equivalent to handling cleanup, and it always cleans up any
193*23b7c7b8SHermès Bélusca-Maïto             //  oplock immediately.  Also, we don't need any locking of the FCB here;
194*23b7c7b8SHermès Bélusca-Maïto             //  the oplock's own lock will be sufficient for this purpose.
195*23b7c7b8SHermès Bélusca-Maïto             //
196*23b7c7b8SHermès Bélusca-Maïto 
197*23b7c7b8SHermès Bélusca-Maïto             FsRtlCheckOplockEx( FatGetFcbOplock(Fcb),
198*23b7c7b8SHermès Bélusca-Maïto                                 Irp,
199*23b7c7b8SHermès Bélusca-Maïto                                 0,
200*23b7c7b8SHermès Bélusca-Maïto                                 NULL,
201*23b7c7b8SHermès Bélusca-Maïto                                 NULL,
202*23b7c7b8SHermès Bélusca-Maïto                                 NULL );
203*23b7c7b8SHermès Bélusca-Maïto         }
204*23b7c7b8SHermès Bélusca-Maïto #endif
205*23b7c7b8SHermès Bélusca-Maïto 
206*23b7c7b8SHermès Bélusca-Maïto         //
207*23b7c7b8SHermès Bélusca-Maïto         //  Metadata streams have had close contexts preallocated. Pull one out now, while we're
208*23b7c7b8SHermès Bélusca-Maïto         //  guaranteed the VCB exists.
209*23b7c7b8SHermès Bélusca-Maïto         //
210*23b7c7b8SHermès Bélusca-Maïto 
211*23b7c7b8SHermès Bélusca-Maïto         if ( (TypeOfOpen == VirtualVolumeFile) || (TypeOfOpen == DirectoryFile) || (TypeOfOpen == EaFile)
212*23b7c7b8SHermès Bélusca-Maïto             ) {
213*23b7c7b8SHermès Bélusca-Maïto 
214*23b7c7b8SHermès Bélusca-Maïto             CloseContext = FatAllocateCloseContext( Vcb );
215*23b7c7b8SHermès Bélusca-Maïto             NT_ASSERT( CloseContext != NULL );
216*23b7c7b8SHermès Bélusca-Maïto             CloseContext->Free = TRUE;
217*23b7c7b8SHermès Bélusca-Maïto 
218*23b7c7b8SHermès Bélusca-Maïto         }
219*23b7c7b8SHermès Bélusca-Maïto 
220*23b7c7b8SHermès Bélusca-Maïto         //
221*23b7c7b8SHermès Bélusca-Maïto         //  Call the common Close routine if we are not delaying this close.
222*23b7c7b8SHermès Bélusca-Maïto         //
223*23b7c7b8SHermès Bélusca-Maïto 
224*23b7c7b8SHermès Bélusca-Maïto         if ((((TypeOfOpen == UserFileOpen) ||
225*23b7c7b8SHermès Bélusca-Maïto                 (TypeOfOpen == UserDirectoryOpen)) &&
226*23b7c7b8SHermès Bélusca-Maïto                  FlagOn(Fcb->FcbState, FCB_STATE_DELAY_CLOSE) &&
227*23b7c7b8SHermès Bélusca-Maïto                  !FatData.ShutdownStarted) ||
228*23b7c7b8SHermès Bélusca-Maïto                 (FatCommonClose( Vcb, Fcb, Ccb, TypeOfOpen, Wait, TopLevel, &VcbDeleted ) == STATUS_PENDING)) {
229*23b7c7b8SHermès Bélusca-Maïto 
230*23b7c7b8SHermès Bélusca-Maïto             //
231*23b7c7b8SHermès Bélusca-Maïto             //  Ship it off to the delayed close queue if we tried to close, and got STATUS_PENDING, or
232*23b7c7b8SHermès Bélusca-Maïto             //  if the user open told us to delay the close.
233*23b7c7b8SHermès Bélusca-Maïto             //
234*23b7c7b8SHermès Bélusca-Maïto 
235*23b7c7b8SHermès Bélusca-Maïto             //
236*23b7c7b8SHermès Bélusca-Maïto             //  Metadata streams have had close contexts preallocated. If we have a user open,
237*23b7c7b8SHermès Bélusca-Maïto             //  pull the close context out of the Ccb.
238*23b7c7b8SHermès Bélusca-Maïto             //
239*23b7c7b8SHermès Bélusca-Maïto 
240*23b7c7b8SHermès Bélusca-Maïto             if( CloseContext == NULL ) {
241*23b7c7b8SHermès Bélusca-Maïto 
242*23b7c7b8SHermès Bélusca-Maïto                 //
243*23b7c7b8SHermès Bélusca-Maïto                 //  Free up any query template strings before using the close context fields,
244*23b7c7b8SHermès Bélusca-Maïto                 //  which overlap (union)
245*23b7c7b8SHermès Bélusca-Maïto                 //
246*23b7c7b8SHermès Bélusca-Maïto 
247*23b7c7b8SHermès Bélusca-Maïto                 FatDeallocateCcbStrings( Ccb );
248*23b7c7b8SHermès Bélusca-Maïto 
249*23b7c7b8SHermès Bélusca-Maïto                 CloseContext = &Ccb->CloseContext;
250*23b7c7b8SHermès Bélusca-Maïto                 CloseContext->Free = FALSE;
251*23b7c7b8SHermès Bélusca-Maïto 
252*23b7c7b8SHermès Bélusca-Maïto                 SetFlag( Ccb->Flags, CCB_FLAG_CLOSE_CONTEXT );
253*23b7c7b8SHermès Bélusca-Maïto             }
254*23b7c7b8SHermès Bélusca-Maïto 
255*23b7c7b8SHermès Bélusca-Maïto             //
256*23b7c7b8SHermès Bélusca-Maïto             //  If the status is pending, then let's get the information we
257*23b7c7b8SHermès Bélusca-Maïto             //  need into the close context we already have bagged, complete
258*23b7c7b8SHermès Bélusca-Maïto             //  the request, and post it.  It is important we allocate nothing
259*23b7c7b8SHermès Bélusca-Maïto             //  in the close path.
260*23b7c7b8SHermès Bélusca-Maïto             //
261*23b7c7b8SHermès Bélusca-Maïto 
262*23b7c7b8SHermès Bélusca-Maïto             CloseContext->Vcb = Vcb;
263*23b7c7b8SHermès Bélusca-Maïto             CloseContext->Fcb = Fcb;
264*23b7c7b8SHermès Bélusca-Maïto             CloseContext->TypeOfOpen = TypeOfOpen;
265*23b7c7b8SHermès Bélusca-Maïto 
266*23b7c7b8SHermès Bélusca-Maïto             //
267*23b7c7b8SHermès Bélusca-Maïto             //  Send it off, either to an ExWorkerThread or to the async
268*23b7c7b8SHermès Bélusca-Maïto             //  close list.
269*23b7c7b8SHermès Bélusca-Maïto             //
270*23b7c7b8SHermès Bélusca-Maïto 
271*23b7c7b8SHermès Bélusca-Maïto             FatQueueClose( CloseContext,
272*23b7c7b8SHermès Bélusca-Maïto                            (BOOLEAN)(Fcb && FlagOn(Fcb->FcbState, FCB_STATE_DELAY_CLOSE)));
273*23b7c7b8SHermès Bélusca-Maïto 
274*23b7c7b8SHermès Bélusca-Maïto         } else {
275*23b7c7b8SHermès Bélusca-Maïto 
276*23b7c7b8SHermès Bélusca-Maïto             //
277*23b7c7b8SHermès Bélusca-Maïto             //  The close proceeded synchronously, so for the metadata objects we
278*23b7c7b8SHermès Bélusca-Maïto             //  can now drop the close context we preallocated.
279*23b7c7b8SHermès Bélusca-Maïto             //
280*23b7c7b8SHermès Bélusca-Maïto 
281*23b7c7b8SHermès Bélusca-Maïto             if ((TypeOfOpen == VirtualVolumeFile) ||
282*23b7c7b8SHermès Bélusca-Maïto                 (TypeOfOpen == DirectoryFile) ||
283*23b7c7b8SHermès Bélusca-Maïto                 (TypeOfOpen == EaFile)
284*23b7c7b8SHermès Bélusca-Maïto                 ) {
285*23b7c7b8SHermès Bélusca-Maïto 
286*23b7c7b8SHermès Bélusca-Maïto                 if (CloseContext != NULL) {
287*23b7c7b8SHermès Bélusca-Maïto 
288*23b7c7b8SHermès Bélusca-Maïto                     ExFreePool( CloseContext );
289*23b7c7b8SHermès Bélusca-Maïto 
290*23b7c7b8SHermès Bélusca-Maïto                 }
291*23b7c7b8SHermès Bélusca-Maïto             }
292*23b7c7b8SHermès Bélusca-Maïto         }
293*23b7c7b8SHermès Bélusca-Maïto 
294*23b7c7b8SHermès Bélusca-Maïto         FatCompleteRequest( FatNull, Irp, Status );
295*23b7c7b8SHermès Bélusca-Maïto 
296*23b7c7b8SHermès Bélusca-Maïto     }
297*23b7c7b8SHermès Bélusca-Maïto     _SEH2_EXCEPT(FatExceptionFilter( NULL, _SEH2_GetExceptionInformation() )) {
298*23b7c7b8SHermès Bélusca-Maïto 
299*23b7c7b8SHermès Bélusca-Maïto         //
300*23b7c7b8SHermès Bélusca-Maïto         //  We had some trouble trying to perform the requested
301*23b7c7b8SHermès Bélusca-Maïto         //  operation, so we'll abort the I/O request with the
302*23b7c7b8SHermès Bélusca-Maïto         //  error status that we get back from the exception code.
303*23b7c7b8SHermès Bélusca-Maïto         //
304*23b7c7b8SHermès Bélusca-Maïto 
305*23b7c7b8SHermès Bélusca-Maïto         Status = FatProcessException( NULL, Irp, _SEH2_GetExceptionCode() );
306*23b7c7b8SHermès Bélusca-Maïto     } _SEH2_END;
307*23b7c7b8SHermès Bélusca-Maïto 
308*23b7c7b8SHermès Bélusca-Maïto     if (TopLevel) { IoSetTopLevelIrp( NULL ); }
309*23b7c7b8SHermès Bélusca-Maïto 
310*23b7c7b8SHermès Bélusca-Maïto     FsRtlExitFileSystem();
311*23b7c7b8SHermès Bélusca-Maïto 
312*23b7c7b8SHermès Bélusca-Maïto     //
313*23b7c7b8SHermès Bélusca-Maïto     //  And return to our caller
314*23b7c7b8SHermès Bélusca-Maïto     //
315*23b7c7b8SHermès Bélusca-Maïto 
316*23b7c7b8SHermès Bélusca-Maïto     DebugTrace(-1, Dbg, "FatFsdClose -> %08lx\n", Status);
317*23b7c7b8SHermès Bélusca-Maïto 
318*23b7c7b8SHermès Bélusca-Maïto     UNREFERENCED_PARAMETER( VolumeDeviceObject );
319*23b7c7b8SHermès Bélusca-Maïto 
320*23b7c7b8SHermès Bélusca-Maïto     return Status;
321*23b7c7b8SHermès Bélusca-Maïto }
322*23b7c7b8SHermès Bélusca-Maïto 
323*23b7c7b8SHermès Bélusca-Maïto VOID
324*23b7c7b8SHermès Bélusca-Maïto NTAPI
FatCloseWorker(_In_ PDEVICE_OBJECT DeviceObject,_In_opt_ PVOID Context)325*23b7c7b8SHermès Bélusca-Maïto FatCloseWorker (
326*23b7c7b8SHermès Bélusca-Maïto     _In_        PDEVICE_OBJECT DeviceObject,
327*23b7c7b8SHermès Bélusca-Maïto     _In_opt_    PVOID Context
328*23b7c7b8SHermès Bélusca-Maïto     )
329*23b7c7b8SHermès Bélusca-Maïto /*++
330*23b7c7b8SHermès Bélusca-Maïto 
331*23b7c7b8SHermès Bélusca-Maïto Routine Description:
332*23b7c7b8SHermès Bélusca-Maïto 
333*23b7c7b8SHermès Bélusca-Maïto     This routine is a shim between the IO worker package and FatFspClose.
334*23b7c7b8SHermès Bélusca-Maïto 
335*23b7c7b8SHermès Bélusca-Maïto Arguments:
336*23b7c7b8SHermès Bélusca-Maïto 
337*23b7c7b8SHermès Bélusca-Maïto     DeviceObject - Registration device object, unused
338*23b7c7b8SHermès Bélusca-Maïto     Context - Context value, unused
339*23b7c7b8SHermès Bélusca-Maïto 
340*23b7c7b8SHermès Bélusca-Maïto Return Value:
341*23b7c7b8SHermès Bélusca-Maïto 
342*23b7c7b8SHermès Bélusca-Maïto     None.
343*23b7c7b8SHermès Bélusca-Maïto 
344*23b7c7b8SHermès Bélusca-Maïto --*/
345*23b7c7b8SHermès Bélusca-Maïto {
346*23b7c7b8SHermès Bélusca-Maïto     PAGED_CODE();
347*23b7c7b8SHermès Bélusca-Maïto 
348*23b7c7b8SHermès Bélusca-Maïto     UNREFERENCED_PARAMETER( DeviceObject );
349*23b7c7b8SHermès Bélusca-Maïto 
350*23b7c7b8SHermès Bélusca-Maïto     FsRtlEnterFileSystem();
351*23b7c7b8SHermès Bélusca-Maïto 
352*23b7c7b8SHermès Bélusca-Maïto     FatFspClose (Context);
353*23b7c7b8SHermès Bélusca-Maïto 
354*23b7c7b8SHermès Bélusca-Maïto     FsRtlExitFileSystem();
355*23b7c7b8SHermès Bélusca-Maïto }
356*23b7c7b8SHermès Bélusca-Maïto 
357*23b7c7b8SHermès Bélusca-Maïto 
_Requires_lock_held_(_Global_critical_region_)358*23b7c7b8SHermès Bélusca-Maïto _Requires_lock_held_(_Global_critical_region_)
359*23b7c7b8SHermès Bélusca-Maïto VOID
360*23b7c7b8SHermès Bélusca-Maïto FatFspClose (
361*23b7c7b8SHermès Bélusca-Maïto     IN PVCB Vcb OPTIONAL
362*23b7c7b8SHermès Bélusca-Maïto     )
363*23b7c7b8SHermès Bélusca-Maïto 
364*23b7c7b8SHermès Bélusca-Maïto /*++
365*23b7c7b8SHermès Bélusca-Maïto 
366*23b7c7b8SHermès Bélusca-Maïto Routine Description:
367*23b7c7b8SHermès Bélusca-Maïto 
368*23b7c7b8SHermès Bélusca-Maïto     This routine implements the FSP part of Close.
369*23b7c7b8SHermès Bélusca-Maïto 
370*23b7c7b8SHermès Bélusca-Maïto Arguments:
371*23b7c7b8SHermès Bélusca-Maïto 
372*23b7c7b8SHermès Bélusca-Maïto     Vcb - If present, tells us to only close file objects opened on the
373*23b7c7b8SHermès Bélusca-Maïto         specified volume.
374*23b7c7b8SHermès Bélusca-Maïto 
375*23b7c7b8SHermès Bélusca-Maïto Return Value:
376*23b7c7b8SHermès Bélusca-Maïto 
377*23b7c7b8SHermès Bélusca-Maïto     None.
378*23b7c7b8SHermès Bélusca-Maïto 
379*23b7c7b8SHermès Bélusca-Maïto --*/
380*23b7c7b8SHermès Bélusca-Maïto 
381*23b7c7b8SHermès Bélusca-Maïto {
382*23b7c7b8SHermès Bélusca-Maïto     PCLOSE_CONTEXT CloseContext;
383*23b7c7b8SHermès Bélusca-Maïto     PVCB CurrentVcb = NULL;
384*23b7c7b8SHermès Bélusca-Maïto     PVCB LastVcb = NULL;
385*23b7c7b8SHermès Bélusca-Maïto     BOOLEAN FreeContext = FALSE;
386*23b7c7b8SHermès Bélusca-Maïto     BOOLEAN TopLevel = FALSE;
387*23b7c7b8SHermès Bélusca-Maïto 
388*23b7c7b8SHermès Bélusca-Maïto     ULONG LoopsWithVcbHeld = 0;
389*23b7c7b8SHermès Bélusca-Maïto 
390*23b7c7b8SHermès Bélusca-Maïto     PAGED_CODE();
391*23b7c7b8SHermès Bélusca-Maïto 
392*23b7c7b8SHermès Bélusca-Maïto     DebugTrace(+1, Dbg, "FatFspClose\n", 0);
393*23b7c7b8SHermès Bélusca-Maïto 
394*23b7c7b8SHermès Bélusca-Maïto     //
395*23b7c7b8SHermès Bélusca-Maïto     //  Set the top level IRP for the true FSP operation.
396*23b7c7b8SHermès Bélusca-Maïto     //
397*23b7c7b8SHermès Bélusca-Maïto 
398*23b7c7b8SHermès Bélusca-Maïto     if (!ARGUMENT_PRESENT( Vcb )) {
399*23b7c7b8SHermès Bélusca-Maïto 
400*23b7c7b8SHermès Bélusca-Maïto         IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP );
401*23b7c7b8SHermès Bélusca-Maïto         TopLevel = TRUE;
402*23b7c7b8SHermès Bélusca-Maïto     }
403*23b7c7b8SHermès Bélusca-Maïto 
404*23b7c7b8SHermès Bélusca-Maïto     while ((CloseContext = FatRemoveClose(Vcb, LastVcb)) != NULL) {
405*23b7c7b8SHermès Bélusca-Maïto 
406*23b7c7b8SHermès Bélusca-Maïto         //
407*23b7c7b8SHermès Bélusca-Maïto         //  If we are in the FSP (i.e. Vcb == NULL), then try to keep ahead of
408*23b7c7b8SHermès Bélusca-Maïto         //  creates by doing several closes with one acquisition of the Vcb.
409*23b7c7b8SHermès Bélusca-Maïto         //
410*23b7c7b8SHermès Bélusca-Maïto         //  Note that we cannot be holding the Vcb on entry to FatCommonClose
411*23b7c7b8SHermès Bélusca-Maïto         //  if this is last close as we will try to acquire FatData, and
412*23b7c7b8SHermès Bélusca-Maïto         //  worse the volume (and therefore the Vcb) may go away.
413*23b7c7b8SHermès Bélusca-Maïto         //
414*23b7c7b8SHermès Bélusca-Maïto 
415*23b7c7b8SHermès Bélusca-Maïto         if (!ARGUMENT_PRESENT(Vcb)) {
416*23b7c7b8SHermès Bélusca-Maïto 
417*23b7c7b8SHermès Bélusca-Maïto             if (!FatData.ShutdownStarted) {
418*23b7c7b8SHermès Bélusca-Maïto 
419*23b7c7b8SHermès Bélusca-Maïto                 if (CloseContext->Vcb != CurrentVcb) {
420*23b7c7b8SHermès Bélusca-Maïto 
421*23b7c7b8SHermès Bélusca-Maïto                     LoopsWithVcbHeld = 0;
422*23b7c7b8SHermès Bélusca-Maïto 
423*23b7c7b8SHermès Bélusca-Maïto                     //
424*23b7c7b8SHermès Bélusca-Maïto                     //  Release a previously held Vcb, if any.
425*23b7c7b8SHermès Bélusca-Maïto                     //
426*23b7c7b8SHermès Bélusca-Maïto 
427*23b7c7b8SHermès Bélusca-Maïto                     if (CurrentVcb != NULL) {
428*23b7c7b8SHermès Bélusca-Maïto 
429*23b7c7b8SHermès Bélusca-Maïto                         ExReleaseResourceLite( &CurrentVcb->Resource);
430*23b7c7b8SHermès Bélusca-Maïto                     }
431*23b7c7b8SHermès Bélusca-Maïto 
432*23b7c7b8SHermès Bélusca-Maïto                     //
433*23b7c7b8SHermès Bélusca-Maïto                     //  Get the new Vcb.
434*23b7c7b8SHermès Bélusca-Maïto                     //
435*23b7c7b8SHermès Bélusca-Maïto 
436*23b7c7b8SHermès Bélusca-Maïto                     CurrentVcb = CloseContext->Vcb;
437*23b7c7b8SHermès Bélusca-Maïto                     (VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE );
438*23b7c7b8SHermès Bélusca-Maïto 
439*23b7c7b8SHermès Bélusca-Maïto                 } else {
440*23b7c7b8SHermès Bélusca-Maïto 
441*23b7c7b8SHermès Bélusca-Maïto                     //
442*23b7c7b8SHermès Bélusca-Maïto                     //  Share the resource occasionally if we seem to be finding a lot
443*23b7c7b8SHermès Bélusca-Maïto                     //  of closes for a single volume.
444*23b7c7b8SHermès Bélusca-Maïto                     //
445*23b7c7b8SHermès Bélusca-Maïto 
446*23b7c7b8SHermès Bélusca-Maïto                     if (++LoopsWithVcbHeld >= 20) {
447*23b7c7b8SHermès Bélusca-Maïto 
448*23b7c7b8SHermès Bélusca-Maïto                         if (ExGetSharedWaiterCount( &CurrentVcb->Resource ) +
449*23b7c7b8SHermès Bélusca-Maïto                             ExGetExclusiveWaiterCount( &CurrentVcb->Resource )) {
450*23b7c7b8SHermès Bélusca-Maïto 
451*23b7c7b8SHermès Bélusca-Maïto                             ExReleaseResourceLite( &CurrentVcb->Resource);
452*23b7c7b8SHermès Bélusca-Maïto                             (VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE );
453*23b7c7b8SHermès Bélusca-Maïto                         }
454*23b7c7b8SHermès Bélusca-Maïto 
455*23b7c7b8SHermès Bélusca-Maïto                         LoopsWithVcbHeld = 0;
456*23b7c7b8SHermès Bélusca-Maïto                     }
457*23b7c7b8SHermès Bélusca-Maïto                 }
458*23b7c7b8SHermès Bélusca-Maïto 
459*23b7c7b8SHermès Bélusca-Maïto                 //
460*23b7c7b8SHermès Bélusca-Maïto                 //  Now check the Open count.  We may be about to delete this volume!
461*23b7c7b8SHermès Bélusca-Maïto                 //
462*23b7c7b8SHermès Bélusca-Maïto                 //  The test below must be <= 1 because there could still be outstanding
463*23b7c7b8SHermès Bélusca-Maïto                 //  stream references on this VCB that are not counted in the OpenFileCount.
464*23b7c7b8SHermès Bélusca-Maïto                 //  For example if there are no open files OpenFileCount could be zero and we would
465*23b7c7b8SHermès Bélusca-Maïto                 //  not release the resource here.  The call to FatCommonClose() below may cause
466*23b7c7b8SHermès Bélusca-Maïto                 //  the VCB to be torn down and we will try to release memory we don't
467*23b7c7b8SHermès Bélusca-Maïto                 //  own later.
468*23b7c7b8SHermès Bélusca-Maïto                 //
469*23b7c7b8SHermès Bélusca-Maïto 
470*23b7c7b8SHermès Bélusca-Maïto                 if (CurrentVcb->OpenFileCount <= 1) {
471*23b7c7b8SHermès Bélusca-Maïto                     ExReleaseResourceLite( &CurrentVcb->Resource);
472*23b7c7b8SHermès Bélusca-Maïto                     CurrentVcb = NULL;
473*23b7c7b8SHermès Bélusca-Maïto                 }
474*23b7c7b8SHermès Bélusca-Maïto             //
475*23b7c7b8SHermès Bélusca-Maïto             //  If shutdown has started while processing our list, drop the
476*23b7c7b8SHermès Bélusca-Maïto             //  current Vcb resource.
477*23b7c7b8SHermès Bélusca-Maïto             //
478*23b7c7b8SHermès Bélusca-Maïto 
479*23b7c7b8SHermès Bélusca-Maïto             } else if (CurrentVcb != NULL) {
480*23b7c7b8SHermès Bélusca-Maïto 
481*23b7c7b8SHermès Bélusca-Maïto                 ExReleaseResourceLite( &CurrentVcb->Resource);
482*23b7c7b8SHermès Bélusca-Maïto                 CurrentVcb = NULL;
483*23b7c7b8SHermès Bélusca-Maïto             }
484*23b7c7b8SHermès Bélusca-Maïto         }
485*23b7c7b8SHermès Bélusca-Maïto 
486*23b7c7b8SHermès Bélusca-Maïto         LastVcb = CurrentVcb;
487*23b7c7b8SHermès Bélusca-Maïto 
488*23b7c7b8SHermès Bélusca-Maïto         //
489*23b7c7b8SHermès Bélusca-Maïto         //  Call the common Close routine.  Protected in a try {} except {}
490*23b7c7b8SHermès Bélusca-Maïto         //
491*23b7c7b8SHermès Bélusca-Maïto 
492*23b7c7b8SHermès Bélusca-Maïto         _SEH2_TRY {
493*23b7c7b8SHermès Bélusca-Maïto 
494*23b7c7b8SHermès Bélusca-Maïto             //
495*23b7c7b8SHermès Bélusca-Maïto             //  The close context either is in the CCB, automatically freed,
496*23b7c7b8SHermès Bélusca-Maïto             //  or was from pool for a metadata fileobject, CCB is NULL, and
497*23b7c7b8SHermès Bélusca-Maïto             //  we'll need to free it.
498*23b7c7b8SHermès Bélusca-Maïto             //
499*23b7c7b8SHermès Bélusca-Maïto 
500*23b7c7b8SHermès Bélusca-Maïto             FreeContext = CloseContext->Free;
501*23b7c7b8SHermès Bélusca-Maïto 
502*23b7c7b8SHermès Bélusca-Maïto             (VOID)FatCommonClose( CloseContext->Vcb,
503*23b7c7b8SHermès Bélusca-Maïto                                   CloseContext->Fcb,
504*23b7c7b8SHermès Bélusca-Maïto                                   (FreeContext ? NULL :
505*23b7c7b8SHermès Bélusca-Maïto                                                  CONTAINING_RECORD( CloseContext, CCB, CloseContext)),
506*23b7c7b8SHermès Bélusca-Maïto                                   CloseContext->TypeOfOpen,
507*23b7c7b8SHermès Bélusca-Maïto                                   TRUE,
508*23b7c7b8SHermès Bélusca-Maïto                                   TopLevel,
509*23b7c7b8SHermès Bélusca-Maïto                                   NULL );
510*23b7c7b8SHermès Bélusca-Maïto 
511*23b7c7b8SHermès Bélusca-Maïto         } _SEH2_EXCEPT(FatExceptionFilter( NULL, _SEH2_GetExceptionInformation() )) {
512*23b7c7b8SHermès Bélusca-Maïto 
513*23b7c7b8SHermès Bélusca-Maïto             //
514*23b7c7b8SHermès Bélusca-Maïto             //  Ignore anything we expect.
515*23b7c7b8SHermès Bélusca-Maïto             //
516*23b7c7b8SHermès Bélusca-Maïto 
517*23b7c7b8SHermès Bélusca-Maïto             NOTHING;
518*23b7c7b8SHermès Bélusca-Maïto         } _SEH2_END;
519*23b7c7b8SHermès Bélusca-Maïto 
520*23b7c7b8SHermès Bélusca-Maïto         //
521*23b7c7b8SHermès Bélusca-Maïto         //  Drop the context if it came from pool.
522*23b7c7b8SHermès Bélusca-Maïto         //
523*23b7c7b8SHermès Bélusca-Maïto 
524*23b7c7b8SHermès Bélusca-Maïto         if (FreeContext) {
525*23b7c7b8SHermès Bélusca-Maïto 
526*23b7c7b8SHermès Bélusca-Maïto             ExFreePool( CloseContext );
527*23b7c7b8SHermès Bélusca-Maïto         }
528*23b7c7b8SHermès Bélusca-Maïto     }
529*23b7c7b8SHermès Bélusca-Maïto 
530*23b7c7b8SHermès Bélusca-Maïto     //
531*23b7c7b8SHermès Bélusca-Maïto     //  Release a previously held Vcb, if any.
532*23b7c7b8SHermès Bélusca-Maïto     //
533*23b7c7b8SHermès Bélusca-Maïto 
534*23b7c7b8SHermès Bélusca-Maïto     if (CurrentVcb != NULL) {
535*23b7c7b8SHermès Bélusca-Maïto 
536*23b7c7b8SHermès Bélusca-Maïto         ExReleaseResourceLite( &CurrentVcb->Resource);
537*23b7c7b8SHermès Bélusca-Maïto     }
538*23b7c7b8SHermès Bélusca-Maïto 
539*23b7c7b8SHermès Bélusca-Maïto     //
540*23b7c7b8SHermès Bélusca-Maïto     //  Clean up the top level IRP hint if we owned it.
541*23b7c7b8SHermès Bélusca-Maïto     //
542*23b7c7b8SHermès Bélusca-Maïto 
543*23b7c7b8SHermès Bélusca-Maïto     if (!ARGUMENT_PRESENT( Vcb )) {
544*23b7c7b8SHermès Bélusca-Maïto 
545*23b7c7b8SHermès Bélusca-Maïto         IoSetTopLevelIrp( NULL );
546*23b7c7b8SHermès Bélusca-Maïto     }
547*23b7c7b8SHermès Bélusca-Maïto 
548*23b7c7b8SHermès Bélusca-Maïto     //
549*23b7c7b8SHermès Bélusca-Maïto     //  And return to our caller
550*23b7c7b8SHermès Bélusca-Maïto     //
551*23b7c7b8SHermès Bélusca-Maïto 
552*23b7c7b8SHermès Bélusca-Maïto     DebugTrace(-1, Dbg, "FatFspClose -> NULL\n", 0);
553*23b7c7b8SHermès Bélusca-Maïto }
554*23b7c7b8SHermès Bélusca-Maïto 
555*23b7c7b8SHermès Bélusca-Maïto 
_Requires_lock_held_(_Global_critical_region_)556*23b7c7b8SHermès Bélusca-Maïto _Requires_lock_held_(_Global_critical_region_)
557*23b7c7b8SHermès Bélusca-Maïto VOID
558*23b7c7b8SHermès Bélusca-Maïto FatQueueClose (
559*23b7c7b8SHermès Bélusca-Maïto     IN PCLOSE_CONTEXT CloseContext,
560*23b7c7b8SHermès Bélusca-Maïto     IN BOOLEAN DelayClose
561*23b7c7b8SHermès Bélusca-Maïto     )
562*23b7c7b8SHermès Bélusca-Maïto 
563*23b7c7b8SHermès Bélusca-Maïto /*++
564*23b7c7b8SHermès Bélusca-Maïto 
565*23b7c7b8SHermès Bélusca-Maïto Routine Description:
566*23b7c7b8SHermès Bélusca-Maïto 
567*23b7c7b8SHermès Bélusca-Maïto     Enqueue a deferred close to one of the two delayed close queues.
568*23b7c7b8SHermès Bélusca-Maïto 
569*23b7c7b8SHermès Bélusca-Maïto Arguments:
570*23b7c7b8SHermès Bélusca-Maïto 
571*23b7c7b8SHermès Bélusca-Maïto     CloseContext - a close context to enqueue for the delayed close thread.
572*23b7c7b8SHermès Bélusca-Maïto 
573*23b7c7b8SHermès Bélusca-Maïto     DelayClose - whether this should go on the delayed close queue (unreferenced
574*23b7c7b8SHermès Bélusca-Maïto         objects).
575*23b7c7b8SHermès Bélusca-Maïto 
576*23b7c7b8SHermès Bélusca-Maïto Return Value:
577*23b7c7b8SHermès Bélusca-Maïto 
578*23b7c7b8SHermès Bélusca-Maïto     None.
579*23b7c7b8SHermès Bélusca-Maïto 
580*23b7c7b8SHermès Bélusca-Maïto --*/
581*23b7c7b8SHermès Bélusca-Maïto 
582*23b7c7b8SHermès Bélusca-Maïto {
583*23b7c7b8SHermès Bélusca-Maïto     BOOLEAN StartWorker = FALSE;
584*23b7c7b8SHermès Bélusca-Maïto 
585*23b7c7b8SHermès Bélusca-Maïto     FatAcquireCloseMutex();
586*23b7c7b8SHermès Bélusca-Maïto 
587*23b7c7b8SHermès Bélusca-Maïto     if (DelayClose) {
588*23b7c7b8SHermès Bélusca-Maïto 
589*23b7c7b8SHermès Bélusca-Maïto         InsertTailList( &FatData.DelayedCloseList,
590*23b7c7b8SHermès Bélusca-Maïto                         &CloseContext->GlobalLinks );
591*23b7c7b8SHermès Bélusca-Maïto         InsertTailList( &CloseContext->Vcb->DelayedCloseList,
592*23b7c7b8SHermès Bélusca-Maïto                         &CloseContext->VcbLinks );
593*23b7c7b8SHermès Bélusca-Maïto 
594*23b7c7b8SHermès Bélusca-Maïto         FatData.DelayedCloseCount += 1;
595*23b7c7b8SHermès Bélusca-Maïto 
596*23b7c7b8SHermès Bélusca-Maïto         if ((FatData.DelayedCloseCount > FatMaxDelayedCloseCount) &&
597*23b7c7b8SHermès Bélusca-Maïto             !FatData.AsyncCloseActive) {
598*23b7c7b8SHermès Bélusca-Maïto 
599*23b7c7b8SHermès Bélusca-Maïto             FatData.AsyncCloseActive = TRUE;
600*23b7c7b8SHermès Bélusca-Maïto             StartWorker = TRUE;
601*23b7c7b8SHermès Bélusca-Maïto         }
602*23b7c7b8SHermès Bélusca-Maïto 
603*23b7c7b8SHermès Bélusca-Maïto     } else {
604*23b7c7b8SHermès Bélusca-Maïto 
605*23b7c7b8SHermès Bélusca-Maïto         InsertTailList( &FatData.AsyncCloseList,
606*23b7c7b8SHermès Bélusca-Maïto                         &CloseContext->GlobalLinks );
607*23b7c7b8SHermès Bélusca-Maïto         InsertTailList( &CloseContext->Vcb->AsyncCloseList,
608*23b7c7b8SHermès Bélusca-Maïto                         &CloseContext->VcbLinks );
609*23b7c7b8SHermès Bélusca-Maïto 
610*23b7c7b8SHermès Bélusca-Maïto         FatData.AsyncCloseCount += 1;
611*23b7c7b8SHermès Bélusca-Maïto 
612*23b7c7b8SHermès Bélusca-Maïto         if (!FatData.AsyncCloseActive) {
613*23b7c7b8SHermès Bélusca-Maïto 
614*23b7c7b8SHermès Bélusca-Maïto             FatData.AsyncCloseActive = TRUE;
615*23b7c7b8SHermès Bélusca-Maïto             StartWorker = TRUE;
616*23b7c7b8SHermès Bélusca-Maïto         }
617*23b7c7b8SHermès Bélusca-Maïto     }
618*23b7c7b8SHermès Bélusca-Maïto 
619*23b7c7b8SHermès Bélusca-Maïto     FatReleaseCloseMutex();
620*23b7c7b8SHermès Bélusca-Maïto 
621*23b7c7b8SHermès Bélusca-Maïto     if (StartWorker) {
622*23b7c7b8SHermès Bélusca-Maïto 
623*23b7c7b8SHermès Bélusca-Maïto         IoQueueWorkItem( FatData.FatCloseItem, FatCloseWorker, CriticalWorkQueue, NULL );
624*23b7c7b8SHermès Bélusca-Maïto     }
625*23b7c7b8SHermès Bélusca-Maïto }
626*23b7c7b8SHermès Bélusca-Maïto 
627*23b7c7b8SHermès Bélusca-Maïto 
_Requires_lock_held_(_Global_critical_region_)628*23b7c7b8SHermès Bélusca-Maïto _Requires_lock_held_(_Global_critical_region_)
629*23b7c7b8SHermès Bélusca-Maïto PCLOSE_CONTEXT
630*23b7c7b8SHermès Bélusca-Maïto FatRemoveClose (
631*23b7c7b8SHermès Bélusca-Maïto     PVCB Vcb OPTIONAL,
632*23b7c7b8SHermès Bélusca-Maïto     PVCB LastVcbHint OPTIONAL
633*23b7c7b8SHermès Bélusca-Maïto     )
634*23b7c7b8SHermès Bélusca-Maïto 
635*23b7c7b8SHermès Bélusca-Maïto /*++
636*23b7c7b8SHermès Bélusca-Maïto 
637*23b7c7b8SHermès Bélusca-Maïto Routine Description:
638*23b7c7b8SHermès Bélusca-Maïto 
639*23b7c7b8SHermès Bélusca-Maïto     Dequeue a deferred close from one of the two delayed close queues.
640*23b7c7b8SHermès Bélusca-Maïto 
641*23b7c7b8SHermès Bélusca-Maïto Arguments:
642*23b7c7b8SHermès Bélusca-Maïto 
643*23b7c7b8SHermès Bélusca-Maïto     Vcb - if specified, only returns close for this volume.
644*23b7c7b8SHermès Bélusca-Maïto 
645*23b7c7b8SHermès Bélusca-Maïto     LastVcbHint - if specified and other starvation avoidance is required by
646*23b7c7b8SHermès Bélusca-Maïto         the system condition, will attempt to return closes for this volume.
647*23b7c7b8SHermès Bélusca-Maïto 
648*23b7c7b8SHermès Bélusca-Maïto Return Value:
649*23b7c7b8SHermès Bélusca-Maïto 
650*23b7c7b8SHermès Bélusca-Maïto     A close to perform.
651*23b7c7b8SHermès Bélusca-Maïto 
652*23b7c7b8SHermès Bélusca-Maïto --*/
653*23b7c7b8SHermès Bélusca-Maïto 
654*23b7c7b8SHermès Bélusca-Maïto {
655*23b7c7b8SHermès Bélusca-Maïto     PLIST_ENTRY Entry;
656*23b7c7b8SHermès Bélusca-Maïto     PCLOSE_CONTEXT CloseContext;
657*23b7c7b8SHermès Bélusca-Maïto     BOOLEAN WorkerThread;
658*23b7c7b8SHermès Bélusca-Maïto 
659*23b7c7b8SHermès Bélusca-Maïto     PAGED_CODE();
660*23b7c7b8SHermès Bélusca-Maïto 
661*23b7c7b8SHermès Bélusca-Maïto     FatAcquireCloseMutex();
662*23b7c7b8SHermès Bélusca-Maïto 
663*23b7c7b8SHermès Bélusca-Maïto     //
664*23b7c7b8SHermès Bélusca-Maïto     //  Remember if this is the worker thread, so we can pull down the active
665*23b7c7b8SHermès Bélusca-Maïto     //  flag should we run everything out.
666*23b7c7b8SHermès Bélusca-Maïto     //
667*23b7c7b8SHermès Bélusca-Maïto 
668*23b7c7b8SHermès Bélusca-Maïto     WorkerThread = (Vcb == NULL);
669*23b7c7b8SHermès Bélusca-Maïto 
670*23b7c7b8SHermès Bélusca-Maïto     //
671*23b7c7b8SHermès Bélusca-Maïto     //  If the queues are above the limits by a significant amount, we have
672*23b7c7b8SHermès Bélusca-Maïto     //  to try hard to pull them down.  To do this, we will aggressively try
673*23b7c7b8SHermès Bélusca-Maïto     //  to find closes for the last volume the caller looked at.  This will
674*23b7c7b8SHermès Bélusca-Maïto     //  make sure we fully utilize the acquisition of the volume, which can
675*23b7c7b8SHermès Bélusca-Maïto     //  be a hugely expensive resource to get (create/close/cleanup use it
676*23b7c7b8SHermès Bélusca-Maïto     //  exclusively).
677*23b7c7b8SHermès Bélusca-Maïto     //
678*23b7c7b8SHermès Bélusca-Maïto     //  Only do this in the delayed close thread.  We will know this is the
679*23b7c7b8SHermès Bélusca-Maïto     //  case by seeing a NULL mandatory Vcb.
680*23b7c7b8SHermès Bélusca-Maïto     //
681*23b7c7b8SHermès Bélusca-Maïto 
682*23b7c7b8SHermès Bélusca-Maïto     if (Vcb == NULL && LastVcbHint != NULL) {
683*23b7c7b8SHermès Bélusca-Maïto 
684*23b7c7b8SHermès Bélusca-Maïto         //
685*23b7c7b8SHermès Bélusca-Maïto         //  Flip over to aggressive at twice the legal limit, and flip it
686*23b7c7b8SHermès Bélusca-Maïto         //  off at the legal limit.
687*23b7c7b8SHermès Bélusca-Maïto         //
688*23b7c7b8SHermès Bélusca-Maïto 
689*23b7c7b8SHermès Bélusca-Maïto         if (!FatData.HighAsync && FatData.AsyncCloseCount > FatMaxDelayedCloseCount*2) {
690*23b7c7b8SHermès Bélusca-Maïto 
691*23b7c7b8SHermès Bélusca-Maïto             FatData.HighAsync = TRUE;
692*23b7c7b8SHermès Bélusca-Maïto 
693*23b7c7b8SHermès Bélusca-Maïto         } else if (FatData.HighAsync && FatData.AsyncCloseCount < FatMaxDelayedCloseCount) {
694*23b7c7b8SHermès Bélusca-Maïto 
695*23b7c7b8SHermès Bélusca-Maïto             FatData.HighAsync = FALSE;
696*23b7c7b8SHermès Bélusca-Maïto         }
697*23b7c7b8SHermès Bélusca-Maïto 
698*23b7c7b8SHermès Bélusca-Maïto         if (!FatData.HighDelayed && FatData.DelayedCloseCount > FatMaxDelayedCloseCount*2) {
699*23b7c7b8SHermès Bélusca-Maïto 
700*23b7c7b8SHermès Bélusca-Maïto             FatData.HighDelayed = TRUE;
701*23b7c7b8SHermès Bélusca-Maïto 
702*23b7c7b8SHermès Bélusca-Maïto         } else if (FatData.HighDelayed && FatData.DelayedCloseCount < FatMaxDelayedCloseCount) {
703*23b7c7b8SHermès Bélusca-Maïto 
704*23b7c7b8SHermès Bélusca-Maïto             FatData.HighDelayed = FALSE;
705*23b7c7b8SHermès Bélusca-Maïto         }
706*23b7c7b8SHermès Bélusca-Maïto 
707*23b7c7b8SHermès Bélusca-Maïto         if (FatData.HighAsync || FatData.HighDelayed) {
708*23b7c7b8SHermès Bélusca-Maïto 
709*23b7c7b8SHermès Bélusca-Maïto             Vcb = LastVcbHint;
710*23b7c7b8SHermès Bélusca-Maïto         }
711*23b7c7b8SHermès Bélusca-Maïto     }
712*23b7c7b8SHermès Bélusca-Maïto 
713*23b7c7b8SHermès Bélusca-Maïto     //
714*23b7c7b8SHermès Bélusca-Maïto     //  Do the case when we don't care about which Vcb the close is on.
715*23b7c7b8SHermès Bélusca-Maïto     //  This is the case when we are in an ExWorkerThread and aren't
716*23b7c7b8SHermès Bélusca-Maïto     //  under pressure.
717*23b7c7b8SHermès Bélusca-Maïto     //
718*23b7c7b8SHermès Bélusca-Maïto 
719*23b7c7b8SHermès Bélusca-Maïto     if (Vcb == NULL) {
720*23b7c7b8SHermès Bélusca-Maïto 
721*23b7c7b8SHermès Bélusca-Maïto         AnyClose:
722*23b7c7b8SHermès Bélusca-Maïto 
723*23b7c7b8SHermès Bélusca-Maïto         //
724*23b7c7b8SHermès Bélusca-Maïto         //  First check the list of async closes.
725*23b7c7b8SHermès Bélusca-Maïto         //
726*23b7c7b8SHermès Bélusca-Maïto 
727*23b7c7b8SHermès Bélusca-Maïto         if (!IsListEmpty( &FatData.AsyncCloseList )) {
728*23b7c7b8SHermès Bélusca-Maïto 
729*23b7c7b8SHermès Bélusca-Maïto             Entry = RemoveHeadList( &FatData.AsyncCloseList );
730*23b7c7b8SHermès Bélusca-Maïto             FatData.AsyncCloseCount -= 1;
731*23b7c7b8SHermès Bélusca-Maïto 
732*23b7c7b8SHermès Bélusca-Maïto             CloseContext = CONTAINING_RECORD( Entry,
733*23b7c7b8SHermès Bélusca-Maïto                                               CLOSE_CONTEXT,
734*23b7c7b8SHermès Bélusca-Maïto                                               GlobalLinks );
735*23b7c7b8SHermès Bélusca-Maïto 
736*23b7c7b8SHermès Bélusca-Maïto             RemoveEntryList( &CloseContext->VcbLinks );
737*23b7c7b8SHermès Bélusca-Maïto 
738*23b7c7b8SHermès Bélusca-Maïto         //
739*23b7c7b8SHermès Bélusca-Maïto         //  Do any delayed closes over half the limit, unless shutdown has
740*23b7c7b8SHermès Bélusca-Maïto         //  started (then kill them all).
741*23b7c7b8SHermès Bélusca-Maïto         //
742*23b7c7b8SHermès Bélusca-Maïto 
743*23b7c7b8SHermès Bélusca-Maïto         } else if (!IsListEmpty( &FatData.DelayedCloseList ) &&
744*23b7c7b8SHermès Bélusca-Maïto                    (FatData.DelayedCloseCount > FatMaxDelayedCloseCount/2 ||
745*23b7c7b8SHermès Bélusca-Maïto                     FatData.ShutdownStarted)) {
746*23b7c7b8SHermès Bélusca-Maïto 
747*23b7c7b8SHermès Bélusca-Maïto             Entry = RemoveHeadList( &FatData.DelayedCloseList );
748*23b7c7b8SHermès Bélusca-Maïto             FatData.DelayedCloseCount -= 1;
749*23b7c7b8SHermès Bélusca-Maïto 
750*23b7c7b8SHermès Bélusca-Maïto             CloseContext = CONTAINING_RECORD( Entry,
751*23b7c7b8SHermès Bélusca-Maïto                                               CLOSE_CONTEXT,
752*23b7c7b8SHermès Bélusca-Maïto                                               GlobalLinks );
753*23b7c7b8SHermès Bélusca-Maïto 
754*23b7c7b8SHermès Bélusca-Maïto             RemoveEntryList( &CloseContext->VcbLinks );
755*23b7c7b8SHermès Bélusca-Maïto 
756*23b7c7b8SHermès Bélusca-Maïto         //
757*23b7c7b8SHermès Bélusca-Maïto         //  There are no more closes to perform; show that we are done.
758*23b7c7b8SHermès Bélusca-Maïto         //
759*23b7c7b8SHermès Bélusca-Maïto 
760*23b7c7b8SHermès Bélusca-Maïto         } else {
761*23b7c7b8SHermès Bélusca-Maïto 
762*23b7c7b8SHermès Bélusca-Maïto             CloseContext = NULL;
763*23b7c7b8SHermès Bélusca-Maïto 
764*23b7c7b8SHermès Bélusca-Maïto             if (WorkerThread) {
765*23b7c7b8SHermès Bélusca-Maïto 
766*23b7c7b8SHermès Bélusca-Maïto                 FatData.AsyncCloseActive = FALSE;
767*23b7c7b8SHermès Bélusca-Maïto             }
768*23b7c7b8SHermès Bélusca-Maïto         }
769*23b7c7b8SHermès Bélusca-Maïto 
770*23b7c7b8SHermès Bélusca-Maïto     //
771*23b7c7b8SHermès Bélusca-Maïto     //  We're running down a specific volume.
772*23b7c7b8SHermès Bélusca-Maïto     //
773*23b7c7b8SHermès Bélusca-Maïto 
774*23b7c7b8SHermès Bélusca-Maïto     } else {
775*23b7c7b8SHermès Bélusca-Maïto 
776*23b7c7b8SHermès Bélusca-Maïto 
777*23b7c7b8SHermès Bélusca-Maïto         //
778*23b7c7b8SHermès Bélusca-Maïto         //  First check the list of async closes.
779*23b7c7b8SHermès Bélusca-Maïto         //
780*23b7c7b8SHermès Bélusca-Maïto 
781*23b7c7b8SHermès Bélusca-Maïto         if (!IsListEmpty( &Vcb->AsyncCloseList )) {
782*23b7c7b8SHermès Bélusca-Maïto 
783*23b7c7b8SHermès Bélusca-Maïto             Entry = RemoveHeadList( &Vcb->AsyncCloseList );
784*23b7c7b8SHermès Bélusca-Maïto             FatData.AsyncCloseCount -= 1;
785*23b7c7b8SHermès Bélusca-Maïto 
786*23b7c7b8SHermès Bélusca-Maïto             CloseContext = CONTAINING_RECORD( Entry,
787*23b7c7b8SHermès Bélusca-Maïto                                               CLOSE_CONTEXT,
788*23b7c7b8SHermès Bélusca-Maïto                                               VcbLinks );
789*23b7c7b8SHermès Bélusca-Maïto 
790*23b7c7b8SHermès Bélusca-Maïto             RemoveEntryList( &CloseContext->GlobalLinks );
791*23b7c7b8SHermès Bélusca-Maïto 
792*23b7c7b8SHermès Bélusca-Maïto         //
793*23b7c7b8SHermès Bélusca-Maïto         //  Do any delayed closes.
794*23b7c7b8SHermès Bélusca-Maïto         //
795*23b7c7b8SHermès Bélusca-Maïto 
796*23b7c7b8SHermès Bélusca-Maïto         } else if (!IsListEmpty( &Vcb->DelayedCloseList )) {
797*23b7c7b8SHermès Bélusca-Maïto 
798*23b7c7b8SHermès Bélusca-Maïto             Entry = RemoveHeadList( &Vcb->DelayedCloseList );
799*23b7c7b8SHermès Bélusca-Maïto             FatData.DelayedCloseCount -= 1;
800*23b7c7b8SHermès Bélusca-Maïto 
801*23b7c7b8SHermès Bélusca-Maïto             CloseContext = CONTAINING_RECORD( Entry,
802*23b7c7b8SHermès Bélusca-Maïto                                               CLOSE_CONTEXT,
803*23b7c7b8SHermès Bélusca-Maïto                                               VcbLinks );
804*23b7c7b8SHermès Bélusca-Maïto 
805*23b7c7b8SHermès Bélusca-Maïto             RemoveEntryList( &CloseContext->GlobalLinks );
806*23b7c7b8SHermès Bélusca-Maïto 
807*23b7c7b8SHermès Bélusca-Maïto         //
808*23b7c7b8SHermès Bélusca-Maïto         //  If we were trying to run down the queues but didn't find anything for this
809*23b7c7b8SHermès Bélusca-Maïto         //  volume, flip over to accept anything and try again.
810*23b7c7b8SHermès Bélusca-Maïto         //
811*23b7c7b8SHermès Bélusca-Maïto 
812*23b7c7b8SHermès Bélusca-Maïto         } else if (LastVcbHint) {
813*23b7c7b8SHermès Bélusca-Maïto 
814*23b7c7b8SHermès Bélusca-Maïto             goto AnyClose;
815*23b7c7b8SHermès Bélusca-Maïto 
816*23b7c7b8SHermès Bélusca-Maïto         //
817*23b7c7b8SHermès Bélusca-Maïto         //  There are no more closes to perform; show that we are done.
818*23b7c7b8SHermès Bélusca-Maïto         //
819*23b7c7b8SHermès Bélusca-Maïto 
820*23b7c7b8SHermès Bélusca-Maïto         } else {
821*23b7c7b8SHermès Bélusca-Maïto 
822*23b7c7b8SHermès Bélusca-Maïto             CloseContext = NULL;
823*23b7c7b8SHermès Bélusca-Maïto         }
824*23b7c7b8SHermès Bélusca-Maïto     }
825*23b7c7b8SHermès Bélusca-Maïto 
826*23b7c7b8SHermès Bélusca-Maïto     FatReleaseCloseMutex();
827*23b7c7b8SHermès Bélusca-Maïto 
828*23b7c7b8SHermès Bélusca-Maïto     return CloseContext;
829*23b7c7b8SHermès Bélusca-Maïto }
830*23b7c7b8SHermès Bélusca-Maïto 
831*23b7c7b8SHermès Bélusca-Maïto 
_Requires_lock_held_(_Global_critical_region_)832*23b7c7b8SHermès Bélusca-Maïto _Requires_lock_held_(_Global_critical_region_)
833*23b7c7b8SHermès Bélusca-Maïto NTSTATUS
834*23b7c7b8SHermès Bélusca-Maïto FatCommonClose (
835*23b7c7b8SHermès Bélusca-Maïto     IN PVCB Vcb,
836*23b7c7b8SHermès Bélusca-Maïto     IN PFCB Fcb,
837*23b7c7b8SHermès Bélusca-Maïto     IN PCCB Ccb,
838*23b7c7b8SHermès Bélusca-Maïto     IN TYPE_OF_OPEN TypeOfOpen,
839*23b7c7b8SHermès Bélusca-Maïto     IN BOOLEAN Wait,
840*23b7c7b8SHermès Bélusca-Maïto     IN BOOLEAN TopLevel,
841*23b7c7b8SHermès Bélusca-Maïto     OUT PBOOLEAN VcbDeleted OPTIONAL
842*23b7c7b8SHermès Bélusca-Maïto     )
843*23b7c7b8SHermès Bélusca-Maïto 
844*23b7c7b8SHermès Bélusca-Maïto /*++
845*23b7c7b8SHermès Bélusca-Maïto 
846*23b7c7b8SHermès Bélusca-Maïto Routine Description:
847*23b7c7b8SHermès Bélusca-Maïto 
848*23b7c7b8SHermès Bélusca-Maïto     This is the common routine for closing a file/directory called by both
849*23b7c7b8SHermès Bélusca-Maïto     the fsd and fsp threads.
850*23b7c7b8SHermès Bélusca-Maïto 
851*23b7c7b8SHermès Bélusca-Maïto     Close is invoked whenever the last reference to a file object is deleted.
852*23b7c7b8SHermès Bélusca-Maïto     Cleanup is invoked when the last handle to a file object is closed, and
853*23b7c7b8SHermès Bélusca-Maïto     is called before close.
854*23b7c7b8SHermès Bélusca-Maïto 
855*23b7c7b8SHermès Bélusca-Maïto     The function of close is to completely tear down and remove the fcb/dcb/ccb
856*23b7c7b8SHermès Bélusca-Maïto     structures associated with the file object.
857*23b7c7b8SHermès Bélusca-Maïto 
858*23b7c7b8SHermès Bélusca-Maïto Arguments:
859*23b7c7b8SHermès Bélusca-Maïto 
860*23b7c7b8SHermès Bélusca-Maïto     Fcb - Supplies the file to process.
861*23b7c7b8SHermès Bélusca-Maïto 
862*23b7c7b8SHermès Bélusca-Maïto     Wait - If this is TRUE we are allowed to block for the Vcb, if FALSE
863*23b7c7b8SHermès Bélusca-Maïto         then we must try to acquire the Vcb anyway.
864*23b7c7b8SHermès Bélusca-Maïto 
865*23b7c7b8SHermès Bélusca-Maïto     TopLevel - If this is TRUE this is a top level request.
866*23b7c7b8SHermès Bélusca-Maïto 
867*23b7c7b8SHermès Bélusca-Maïto     VcbDeleted - Returns whether the VCB was deleted by this call.
868*23b7c7b8SHermès Bélusca-Maïto 
869*23b7c7b8SHermès Bélusca-Maïto Return Value:
870*23b7c7b8SHermès Bélusca-Maïto 
871*23b7c7b8SHermès Bélusca-Maïto     NTSTATUS - The return status for the operation
872*23b7c7b8SHermès Bélusca-Maïto 
873*23b7c7b8SHermès Bélusca-Maïto --*/
874*23b7c7b8SHermès Bélusca-Maïto 
875*23b7c7b8SHermès Bélusca-Maïto {
876*23b7c7b8SHermès Bélusca-Maïto     NTSTATUS Status = STATUS_SUCCESS;
877*23b7c7b8SHermès Bélusca-Maïto     PDCB ParentDcb;
878*23b7c7b8SHermès Bélusca-Maïto     BOOLEAN RecursiveClose;
879*23b7c7b8SHermès Bélusca-Maïto     BOOLEAN LocalVcbDeleted;
880*23b7c7b8SHermès Bélusca-Maïto     IRP_CONTEXT IrpContext;
881*23b7c7b8SHermès Bélusca-Maïto 
882*23b7c7b8SHermès Bélusca-Maïto     PAGED_CODE();
883*23b7c7b8SHermès Bélusca-Maïto 
884*23b7c7b8SHermès Bélusca-Maïto     DebugTrace(+1, Dbg, "FatCommonClose...\n", 0);
885*23b7c7b8SHermès Bélusca-Maïto 
886*23b7c7b8SHermès Bélusca-Maïto     //
887*23b7c7b8SHermès Bélusca-Maïto     //  Initialize the callers variable, if needed.
888*23b7c7b8SHermès Bélusca-Maïto     //
889*23b7c7b8SHermès Bélusca-Maïto 
890*23b7c7b8SHermès Bélusca-Maïto     LocalVcbDeleted = FALSE;
891*23b7c7b8SHermès Bélusca-Maïto 
892*23b7c7b8SHermès Bélusca-Maïto     if (ARGUMENT_PRESENT( VcbDeleted )) {
893*23b7c7b8SHermès Bélusca-Maïto 
894*23b7c7b8SHermès Bélusca-Maïto         *VcbDeleted = LocalVcbDeleted;
895*23b7c7b8SHermès Bélusca-Maïto     }
896*23b7c7b8SHermès Bélusca-Maïto 
897*23b7c7b8SHermès Bélusca-Maïto     //
898*23b7c7b8SHermès Bélusca-Maïto     //  Special case the unopened file object
899*23b7c7b8SHermès Bélusca-Maïto     //
900*23b7c7b8SHermès Bélusca-Maïto 
901*23b7c7b8SHermès Bélusca-Maïto     if (TypeOfOpen == UnopenedFileObject) {
902*23b7c7b8SHermès Bélusca-Maïto 
903*23b7c7b8SHermès Bélusca-Maïto         DebugTrace(0, Dbg, "Close unopened file object\n", 0);
904*23b7c7b8SHermès Bélusca-Maïto 
905*23b7c7b8SHermès Bélusca-Maïto         Status = STATUS_SUCCESS;
906*23b7c7b8SHermès Bélusca-Maïto 
907*23b7c7b8SHermès Bélusca-Maïto         DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status);
908*23b7c7b8SHermès Bélusca-Maïto         return Status;
909*23b7c7b8SHermès Bélusca-Maïto     }
910*23b7c7b8SHermès Bélusca-Maïto 
911*23b7c7b8SHermès Bélusca-Maïto     //
912*23b7c7b8SHermès Bélusca-Maïto     //  Set up our stack IrpContext.
913*23b7c7b8SHermès Bélusca-Maïto     //
914*23b7c7b8SHermès Bélusca-Maïto 
915*23b7c7b8SHermès Bélusca-Maïto     RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
916*23b7c7b8SHermès Bélusca-Maïto 
917*23b7c7b8SHermès Bélusca-Maïto     IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
918*23b7c7b8SHermès Bélusca-Maïto     IrpContext.NodeByteSize = sizeof( IrpContext );
919*23b7c7b8SHermès Bélusca-Maïto     IrpContext.MajorFunction = IRP_MJ_CLOSE;
920*23b7c7b8SHermès Bélusca-Maïto     IrpContext.Vcb = Vcb;
921*23b7c7b8SHermès Bélusca-Maïto 
922*23b7c7b8SHermès Bélusca-Maïto     if (Wait) {
923*23b7c7b8SHermès Bélusca-Maïto 
924*23b7c7b8SHermès Bélusca-Maïto         SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT );
925*23b7c7b8SHermès Bélusca-Maïto     }
926*23b7c7b8SHermès Bélusca-Maïto 
927*23b7c7b8SHermès Bélusca-Maïto     //
928*23b7c7b8SHermès Bélusca-Maïto     //  Acquire exclusive access to the Vcb and enqueue the irp if we didn't
929*23b7c7b8SHermès Bélusca-Maïto     //  get access.
930*23b7c7b8SHermès Bélusca-Maïto     //
931*23b7c7b8SHermès Bélusca-Maïto 
932*23b7c7b8SHermès Bélusca-Maïto #ifdef _MSC_VER
933*23b7c7b8SHermès Bélusca-Maïto #pragma prefast( suppress: 28137, "prefast wants Wait to be a constant, but that's not possible for fastfat" )
934*23b7c7b8SHermès Bélusca-Maïto #endif
935*23b7c7b8SHermès Bélusca-Maïto     if (!ExAcquireResourceExclusiveLite( &Vcb->Resource, Wait )) {
936*23b7c7b8SHermès Bélusca-Maïto 
937*23b7c7b8SHermès Bélusca-Maïto         return STATUS_PENDING;
938*23b7c7b8SHermès Bélusca-Maïto     }
939*23b7c7b8SHermès Bélusca-Maïto 
940*23b7c7b8SHermès Bélusca-Maïto     //
941*23b7c7b8SHermès Bélusca-Maïto     //  The following test makes sure that we don't blow away an Fcb if we
942*23b7c7b8SHermès Bélusca-Maïto     //  are trying to do a Supersede/Overwrite open above us.  This test
943*23b7c7b8SHermès Bélusca-Maïto     //  does not apply for the EA file.
944*23b7c7b8SHermès Bélusca-Maïto     //
945*23b7c7b8SHermès Bélusca-Maïto 
946*23b7c7b8SHermès Bélusca-Maïto     if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS) &&
947*23b7c7b8SHermès Bélusca-Maïto         Vcb->EaFcb != Fcb) {
948*23b7c7b8SHermès Bélusca-Maïto 
949*23b7c7b8SHermès Bélusca-Maïto         ExReleaseResourceLite( &Vcb->Resource );
950*23b7c7b8SHermès Bélusca-Maïto 
951*23b7c7b8SHermès Bélusca-Maïto         return STATUS_PENDING;
952*23b7c7b8SHermès Bélusca-Maïto     }
953*23b7c7b8SHermès Bélusca-Maïto 
954*23b7c7b8SHermès Bélusca-Maïto     //
955*23b7c7b8SHermès Bélusca-Maïto     //  Setting the following flag prevents recursive closes of directory file
956*23b7c7b8SHermès Bélusca-Maïto     //  objects, which are handled in a special case loop.
957*23b7c7b8SHermès Bélusca-Maïto     //
958*23b7c7b8SHermès Bélusca-Maïto 
959*23b7c7b8SHermès Bélusca-Maïto     if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS) ) {
960*23b7c7b8SHermès Bélusca-Maïto 
961*23b7c7b8SHermès Bélusca-Maïto         RecursiveClose = TRUE;
962*23b7c7b8SHermès Bélusca-Maïto 
963*23b7c7b8SHermès Bélusca-Maïto     } else {
964*23b7c7b8SHermès Bélusca-Maïto 
965*23b7c7b8SHermès Bélusca-Maïto 
966*23b7c7b8SHermès Bélusca-Maïto         SetFlag(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS);
967*23b7c7b8SHermès Bélusca-Maïto         RecursiveClose = FALSE;
968*23b7c7b8SHermès Bélusca-Maïto 
969*23b7c7b8SHermès Bélusca-Maïto         //
970*23b7c7b8SHermès Bélusca-Maïto         //  Since we are at the top of the close chain, we need to add
971*23b7c7b8SHermès Bélusca-Maïto         //  a reference to the VCB.  This will keep it from going away
972*23b7c7b8SHermès Bélusca-Maïto         //  on us until we are ready to check for a dismount below.
973*23b7c7b8SHermès Bélusca-Maïto         //
974*23b7c7b8SHermès Bélusca-Maïto 
975*23b7c7b8SHermès Bélusca-Maïto         Vcb->OpenFileCount += 1;
976*23b7c7b8SHermès Bélusca-Maïto     }
977*23b7c7b8SHermès Bélusca-Maïto 
978*23b7c7b8SHermès Bélusca-Maïto     _SEH2_TRY {
979*23b7c7b8SHermès Bélusca-Maïto 
980*23b7c7b8SHermès Bélusca-Maïto         //
981*23b7c7b8SHermès Bélusca-Maïto         //  Case on the type of open that we are trying to close.
982*23b7c7b8SHermès Bélusca-Maïto         //
983*23b7c7b8SHermès Bélusca-Maïto 
984*23b7c7b8SHermès Bélusca-Maïto         switch (TypeOfOpen) {
985*23b7c7b8SHermès Bélusca-Maïto 
986*23b7c7b8SHermès Bélusca-Maïto         case VirtualVolumeFile:
987*23b7c7b8SHermès Bélusca-Maïto 
988*23b7c7b8SHermès Bélusca-Maïto             DebugTrace(0, Dbg, "Close VirtualVolumeFile\n", 0);
989*23b7c7b8SHermès Bélusca-Maïto 
990*23b7c7b8SHermès Bélusca-Maïto             //
991*23b7c7b8SHermès Bélusca-Maïto             //  Remove this internal, residual open from the count.
992*23b7c7b8SHermès Bélusca-Maïto             //
993*23b7c7b8SHermès Bélusca-Maïto 
994*23b7c7b8SHermès Bélusca-Maïto             InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) );
995*23b7c7b8SHermès Bélusca-Maïto             InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) );
996*23b7c7b8SHermès Bélusca-Maïto 
997*23b7c7b8SHermès Bélusca-Maïto             try_return( Status = STATUS_SUCCESS );
998*23b7c7b8SHermès Bélusca-Maïto             break;
999*23b7c7b8SHermès Bélusca-Maïto 
1000*23b7c7b8SHermès Bélusca-Maïto         case UserVolumeOpen:
1001*23b7c7b8SHermès Bélusca-Maïto 
1002*23b7c7b8SHermès Bélusca-Maïto             DebugTrace(0, Dbg, "Close UserVolumeOpen\n", 0);
1003*23b7c7b8SHermès Bélusca-Maïto 
1004*23b7c7b8SHermès Bélusca-Maïto             Vcb->DirectAccessOpenCount -= 1;
1005*23b7c7b8SHermès Bélusca-Maïto             Vcb->OpenFileCount -= 1;
1006*23b7c7b8SHermès Bélusca-Maïto             if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; }
1007*23b7c7b8SHermès Bélusca-Maïto 
1008*23b7c7b8SHermès Bélusca-Maïto             FatDeleteCcb( &IrpContext, &Ccb );
1009*23b7c7b8SHermès Bélusca-Maïto 
1010*23b7c7b8SHermès Bélusca-Maïto             try_return( Status = STATUS_SUCCESS );
1011*23b7c7b8SHermès Bélusca-Maïto             break;
1012*23b7c7b8SHermès Bélusca-Maïto 
1013*23b7c7b8SHermès Bélusca-Maïto         case EaFile:
1014*23b7c7b8SHermès Bélusca-Maïto 
1015*23b7c7b8SHermès Bélusca-Maïto             DebugTrace(0, Dbg, "Close EaFile\n", 0);
1016*23b7c7b8SHermès Bélusca-Maïto 
1017*23b7c7b8SHermès Bélusca-Maïto             //
1018*23b7c7b8SHermès Bélusca-Maïto             //  Remove this internal, residual open from the count.
1019*23b7c7b8SHermès Bélusca-Maïto             //
1020*23b7c7b8SHermès Bélusca-Maïto 
1021*23b7c7b8SHermès Bélusca-Maïto             InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) );
1022*23b7c7b8SHermès Bélusca-Maïto             InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) );
1023*23b7c7b8SHermès Bélusca-Maïto 
1024*23b7c7b8SHermès Bélusca-Maïto             try_return( Status = STATUS_SUCCESS );
1025*23b7c7b8SHermès Bélusca-Maïto             break;
1026*23b7c7b8SHermès Bélusca-Maïto 
1027*23b7c7b8SHermès Bélusca-Maïto         case DirectoryFile:
1028*23b7c7b8SHermès Bélusca-Maïto 
1029*23b7c7b8SHermès Bélusca-Maïto             DebugTrace(0, Dbg, "Close DirectoryFile\n", 0);
1030*23b7c7b8SHermès Bélusca-Maïto 
1031*23b7c7b8SHermès Bélusca-Maïto             InterlockedDecrement( (LONG*)&Fcb->Specific.Dcb.DirectoryFileOpenCount );
1032*23b7c7b8SHermès Bélusca-Maïto 
1033*23b7c7b8SHermès Bélusca-Maïto             //
1034*23b7c7b8SHermès Bélusca-Maïto             //  Remove this internal open from the count.
1035*23b7c7b8SHermès Bélusca-Maïto             //
1036*23b7c7b8SHermès Bélusca-Maïto 
1037*23b7c7b8SHermès Bélusca-Maïto             InterlockedDecrement( (LONG*)&(Vcb->InternalOpenCount) );
1038*23b7c7b8SHermès Bélusca-Maïto 
1039*23b7c7b8SHermès Bélusca-Maïto             //
1040*23b7c7b8SHermès Bélusca-Maïto             //  If this is the root directory, it is a residual open
1041*23b7c7b8SHermès Bélusca-Maïto             //  as well.
1042*23b7c7b8SHermès Bélusca-Maïto             //
1043*23b7c7b8SHermès Bélusca-Maïto 
1044*23b7c7b8SHermès Bélusca-Maïto             if (NodeType( Fcb ) == FAT_NTC_ROOT_DCB) {
1045*23b7c7b8SHermès Bélusca-Maïto 
1046*23b7c7b8SHermès Bélusca-Maïto                 InterlockedDecrement( (LONG*)&(Vcb->ResidualOpenCount) );
1047*23b7c7b8SHermès Bélusca-Maïto             }
1048*23b7c7b8SHermès Bélusca-Maïto 
1049*23b7c7b8SHermès Bélusca-Maïto             //
1050*23b7c7b8SHermès Bélusca-Maïto             //  If this is a recursive close, just return here.
1051*23b7c7b8SHermès Bélusca-Maïto             //
1052*23b7c7b8SHermès Bélusca-Maïto 
1053*23b7c7b8SHermès Bélusca-Maïto             if ( RecursiveClose ) {
1054*23b7c7b8SHermès Bélusca-Maïto 
1055*23b7c7b8SHermès Bélusca-Maïto                 try_return( Status = STATUS_SUCCESS );
1056*23b7c7b8SHermès Bélusca-Maïto 
1057*23b7c7b8SHermès Bélusca-Maïto             } else {
1058*23b7c7b8SHermès Bélusca-Maïto 
1059*23b7c7b8SHermès Bélusca-Maïto                 break;
1060*23b7c7b8SHermès Bélusca-Maïto             }
1061*23b7c7b8SHermès Bélusca-Maïto 
1062*23b7c7b8SHermès Bélusca-Maïto 
1063*23b7c7b8SHermès Bélusca-Maïto         case UserDirectoryOpen:
1064*23b7c7b8SHermès Bélusca-Maïto         case UserFileOpen:
1065*23b7c7b8SHermès Bélusca-Maïto 
1066*23b7c7b8SHermès Bélusca-Maïto             DebugTrace(0, Dbg, "Close UserFileOpen/UserDirectoryOpen\n", 0);
1067*23b7c7b8SHermès Bélusca-Maïto 
1068*23b7c7b8SHermès Bélusca-Maïto             //
1069*23b7c7b8SHermès Bélusca-Maïto             //  Uninitialize the cache map if we no longer need to use it
1070*23b7c7b8SHermès Bélusca-Maïto             //
1071*23b7c7b8SHermès Bélusca-Maïto 
1072*23b7c7b8SHermès Bélusca-Maïto             if ((NodeType(Fcb) == FAT_NTC_DCB) &&
1073*23b7c7b8SHermès Bélusca-Maïto                 IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) &&
1074*23b7c7b8SHermès Bélusca-Maïto                 (Fcb->OpenCount == 1) &&
1075*23b7c7b8SHermès Bélusca-Maïto                 (Fcb->Specific.Dcb.DirectoryFile != NULL)) {
1076*23b7c7b8SHermès Bélusca-Maïto 
1077*23b7c7b8SHermès Bélusca-Maïto                 PFILE_OBJECT DirectoryFileObject = Fcb->Specific.Dcb.DirectoryFile;
1078*23b7c7b8SHermès Bélusca-Maïto 
1079*23b7c7b8SHermès Bélusca-Maïto                 DebugTrace(0, Dbg, "Uninitialize the stream file object\n", 0);
1080*23b7c7b8SHermès Bélusca-Maïto 
1081*23b7c7b8SHermès Bélusca-Maïto                 CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
1082*23b7c7b8SHermès Bélusca-Maïto 
1083*23b7c7b8SHermès Bélusca-Maïto                 //
1084*23b7c7b8SHermès Bélusca-Maïto                 //  Dereference the directory file.  This may cause a close
1085*23b7c7b8SHermès Bélusca-Maïto                 //  Irp to be processed, so we need to do this before we destroy
1086*23b7c7b8SHermès Bélusca-Maïto                 //  the Fcb.
1087*23b7c7b8SHermès Bélusca-Maïto                 //
1088*23b7c7b8SHermès Bélusca-Maïto 
1089*23b7c7b8SHermès Bélusca-Maïto                 Fcb->Specific.Dcb.DirectoryFile = NULL;
1090*23b7c7b8SHermès Bélusca-Maïto                 ObDereferenceObject( DirectoryFileObject );
1091*23b7c7b8SHermès Bélusca-Maïto             }
1092*23b7c7b8SHermès Bélusca-Maïto 
1093*23b7c7b8SHermès Bélusca-Maïto             Fcb->OpenCount -= 1;
1094*23b7c7b8SHermès Bélusca-Maïto             Vcb->OpenFileCount -= 1;
1095*23b7c7b8SHermès Bélusca-Maïto             if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; }
1096*23b7c7b8SHermès Bélusca-Maïto 
1097*23b7c7b8SHermès Bélusca-Maïto             FatDeleteCcb( &IrpContext, &Ccb );
1098*23b7c7b8SHermès Bélusca-Maïto 
1099*23b7c7b8SHermès Bélusca-Maïto             break;
1100*23b7c7b8SHermès Bélusca-Maïto 
1101*23b7c7b8SHermès Bélusca-Maïto         default:
1102*23b7c7b8SHermès Bélusca-Maïto 
1103*23b7c7b8SHermès Bélusca-Maïto #ifdef _MSC_VER
1104*23b7c7b8SHermès Bélusca-Maïto #pragma prefast( suppress: 28159, "if the type of open is unknown, we seriously messed up." )
1105*23b7c7b8SHermès Bélusca-Maïto #endif
1106*23b7c7b8SHermès Bélusca-Maïto             FatBugCheck( TypeOfOpen, 0, 0 );
1107*23b7c7b8SHermès Bélusca-Maïto         }
1108*23b7c7b8SHermès Bélusca-Maïto 
1109*23b7c7b8SHermès Bélusca-Maïto         //
1110*23b7c7b8SHermès Bélusca-Maïto         //  At this point we've cleaned up any on-disk structure that needs
1111*23b7c7b8SHermès Bélusca-Maïto         //  to be done, and we can now update the in-memory structures.
1112*23b7c7b8SHermès Bélusca-Maïto         //  Now if this is an unreferenced FCB or if it is
1113*23b7c7b8SHermès Bélusca-Maïto         //  an unreferenced DCB (not the root) then we can remove
1114*23b7c7b8SHermès Bélusca-Maïto         //  the fcb and set our ParentDcb to non null.
1115*23b7c7b8SHermès Bélusca-Maïto         //
1116*23b7c7b8SHermès Bélusca-Maïto 
1117*23b7c7b8SHermès Bélusca-Maïto         if (((NodeType(Fcb) == FAT_NTC_FCB) &&
1118*23b7c7b8SHermès Bélusca-Maïto              (Fcb->OpenCount == 0))
1119*23b7c7b8SHermès Bélusca-Maïto 
1120*23b7c7b8SHermès Bélusca-Maïto                 ||
1121*23b7c7b8SHermès Bélusca-Maïto 
1122*23b7c7b8SHermès Bélusca-Maïto              ((NodeType(Fcb) == FAT_NTC_DCB) &&
1123*23b7c7b8SHermès Bélusca-Maïto               (IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) &&
1124*23b7c7b8SHermès Bélusca-Maïto               (Fcb->OpenCount == 0) &&
1125*23b7c7b8SHermès Bélusca-Maïto               (Fcb->Specific.Dcb.DirectoryFileOpenCount == 0))) {
1126*23b7c7b8SHermès Bélusca-Maïto 
1127*23b7c7b8SHermès Bélusca-Maïto             ParentDcb = Fcb->ParentDcb;
1128*23b7c7b8SHermès Bélusca-Maïto 
1129*23b7c7b8SHermès Bélusca-Maïto             SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
1130*23b7c7b8SHermès Bélusca-Maïto 
1131*23b7c7b8SHermès Bélusca-Maïto             FatDeleteFcb( &IrpContext, &Fcb );
1132*23b7c7b8SHermès Bélusca-Maïto 
1133*23b7c7b8SHermès Bélusca-Maïto             //
1134*23b7c7b8SHermès Bélusca-Maïto             //  Uninitialize our parent's cache map if we no longer need
1135*23b7c7b8SHermès Bélusca-Maïto             //  to use it.
1136*23b7c7b8SHermès Bélusca-Maïto             //
1137*23b7c7b8SHermès Bélusca-Maïto 
1138*23b7c7b8SHermès Bélusca-Maïto             while ((NodeType(ParentDcb) == FAT_NTC_DCB) &&
1139*23b7c7b8SHermès Bélusca-Maïto                    IsListEmpty(&ParentDcb->Specific.Dcb.ParentDcbQueue) &&
1140*23b7c7b8SHermès Bélusca-Maïto                    (ParentDcb->OpenCount == 0) &&
1141*23b7c7b8SHermès Bélusca-Maïto                    (ParentDcb->Specific.Dcb.DirectoryFile != NULL)) {
1142*23b7c7b8SHermès Bélusca-Maïto 
1143*23b7c7b8SHermès Bélusca-Maïto                 PFILE_OBJECT DirectoryFileObject;
1144*23b7c7b8SHermès Bélusca-Maïto 
1145*23b7c7b8SHermès Bélusca-Maïto                 DirectoryFileObject = ParentDcb->Specific.Dcb.DirectoryFile;
1146*23b7c7b8SHermès Bélusca-Maïto 
1147*23b7c7b8SHermès Bélusca-Maïto                 DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0);
1148*23b7c7b8SHermès Bélusca-Maïto 
1149*23b7c7b8SHermès Bélusca-Maïto                 CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
1150*23b7c7b8SHermès Bélusca-Maïto 
1151*23b7c7b8SHermès Bélusca-Maïto                 ParentDcb->Specific.Dcb.DirectoryFile = NULL;
1152*23b7c7b8SHermès Bélusca-Maïto 
1153*23b7c7b8SHermès Bélusca-Maïto                 ObDereferenceObject( DirectoryFileObject );
1154*23b7c7b8SHermès Bélusca-Maïto 
1155*23b7c7b8SHermès Bélusca-Maïto                 //
1156*23b7c7b8SHermès Bélusca-Maïto                 //  Now, if the ObDereferenceObject() caused the final close
1157*23b7c7b8SHermès Bélusca-Maïto                 //  to come in, then blow away the Fcb and continue up,
1158*23b7c7b8SHermès Bélusca-Maïto                 //  otherwise wait for Mm to to dereference its file objects
1159*23b7c7b8SHermès Bélusca-Maïto                 //  and stop here..
1160*23b7c7b8SHermès Bélusca-Maïto                 //
1161*23b7c7b8SHermès Bélusca-Maïto 
1162*23b7c7b8SHermès Bélusca-Maïto                 if ( ParentDcb->Specific.Dcb.DirectoryFileOpenCount == 0) {
1163*23b7c7b8SHermès Bélusca-Maïto 
1164*23b7c7b8SHermès Bélusca-Maïto                     PDCB CurrentDcb;
1165*23b7c7b8SHermès Bélusca-Maïto 
1166*23b7c7b8SHermès Bélusca-Maïto                     CurrentDcb = ParentDcb;
1167*23b7c7b8SHermès Bélusca-Maïto                     ParentDcb = CurrentDcb->ParentDcb;
1168*23b7c7b8SHermès Bélusca-Maïto 
1169*23b7c7b8SHermès Bélusca-Maïto                     SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
1170*23b7c7b8SHermès Bélusca-Maïto 
1171*23b7c7b8SHermès Bélusca-Maïto                     FatDeleteFcb( &IrpContext, &CurrentDcb );
1172*23b7c7b8SHermès Bélusca-Maïto 
1173*23b7c7b8SHermès Bélusca-Maïto                 } else {
1174*23b7c7b8SHermès Bélusca-Maïto 
1175*23b7c7b8SHermès Bélusca-Maïto                     break;
1176*23b7c7b8SHermès Bélusca-Maïto                 }
1177*23b7c7b8SHermès Bélusca-Maïto             }
1178*23b7c7b8SHermès Bélusca-Maïto         }
1179*23b7c7b8SHermès Bélusca-Maïto 
1180*23b7c7b8SHermès Bélusca-Maïto         Status = STATUS_SUCCESS;
1181*23b7c7b8SHermès Bélusca-Maïto 
1182*23b7c7b8SHermès Bélusca-Maïto     try_exit: NOTHING;
1183*23b7c7b8SHermès Bélusca-Maïto     } _SEH2_FINALLY {
1184*23b7c7b8SHermès Bélusca-Maïto 
1185*23b7c7b8SHermès Bélusca-Maïto         DebugUnwind( FatCommonClose );
1186*23b7c7b8SHermès Bélusca-Maïto 
1187*23b7c7b8SHermès Bélusca-Maïto         //
1188*23b7c7b8SHermès Bélusca-Maïto         //  We are done processing the close.  If we are the top of the close
1189*23b7c7b8SHermès Bélusca-Maïto         //  chain, see if the VCB can go away.  We have biased the open count by
1190*23b7c7b8SHermès Bélusca-Maïto         //  one, so we need to take that into account.
1191*23b7c7b8SHermès Bélusca-Maïto         //
1192*23b7c7b8SHermès Bélusca-Maïto 
1193*23b7c7b8SHermès Bélusca-Maïto         if (!RecursiveClose) {
1194*23b7c7b8SHermès Bélusca-Maïto 
1195*23b7c7b8SHermès Bélusca-Maïto             //
1196*23b7c7b8SHermès Bélusca-Maïto             //  See if there is only one open left.  If so, it is ours.  We only want
1197*23b7c7b8SHermès Bélusca-Maïto             //  to check for a dismount if a dismount is not already in progress.
1198*23b7c7b8SHermès Bélusca-Maïto             //  We also only do this if the Vcb condition is not VcbGood and the
1199*23b7c7b8SHermès Bélusca-Maïto             //  caller can handle the VCB going away. This is determined by whether
1200*23b7c7b8SHermès Bélusca-Maïto             //  they passed in the VcbDeleted argument. This request also needs
1201*23b7c7b8SHermès Bélusca-Maïto             //  to be top level.
1202*23b7c7b8SHermès Bélusca-Maïto             //
1203*23b7c7b8SHermès Bélusca-Maïto 
1204*23b7c7b8SHermès Bélusca-Maïto             if (Vcb->OpenFileCount == 1 &&
1205*23b7c7b8SHermès Bélusca-Maïto                 Vcb->VcbCondition != VcbGood &&
1206*23b7c7b8SHermès Bélusca-Maïto                 !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS ) &&
1207*23b7c7b8SHermès Bélusca-Maïto                 ARGUMENT_PRESENT( VcbDeleted ) &&
1208*23b7c7b8SHermès Bélusca-Maïto                 TopLevel) {
1209*23b7c7b8SHermès Bélusca-Maïto 
1210*23b7c7b8SHermès Bélusca-Maïto                 //
1211*23b7c7b8SHermès Bélusca-Maïto                 //  We need the global lock, which must be acquired before the
1212*23b7c7b8SHermès Bélusca-Maïto                 //  VCB.  Since we already have the VCB, we have to drop and
1213*23b7c7b8SHermès Bélusca-Maïto                 //  reacquire here.  Note that we always want to wait from this
1214*23b7c7b8SHermès Bélusca-Maïto                 //  point on.  Note that the VCB cannot go away, since we have
1215*23b7c7b8SHermès Bélusca-Maïto                 //  biased the open file count.
1216*23b7c7b8SHermès Bélusca-Maïto                 //
1217*23b7c7b8SHermès Bélusca-Maïto 
1218*23b7c7b8SHermès Bélusca-Maïto                 FatReleaseVcb( &IrpContext,
1219*23b7c7b8SHermès Bélusca-Maïto                                Vcb );
1220*23b7c7b8SHermès Bélusca-Maïto 
1221*23b7c7b8SHermès Bélusca-Maïto                 SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT );
1222*23b7c7b8SHermès Bélusca-Maïto 
1223*23b7c7b8SHermès Bélusca-Maïto #ifdef _MSC_VER
1224*23b7c7b8SHermès Bélusca-Maïto #pragma prefast( suppress: 28137, "prefast wants the wait parameter in this macro expansion to be a constant, unfortunately this is not possible" )
1225*23b7c7b8SHermès Bélusca-Maïto #endif
1226*23b7c7b8SHermès Bélusca-Maïto                 FatAcquireExclusiveGlobal( &IrpContext );
1227*23b7c7b8SHermès Bélusca-Maïto 
1228*23b7c7b8SHermès Bélusca-Maïto                 FatAcquireExclusiveVcb( &IrpContext,
1229*23b7c7b8SHermès Bélusca-Maïto                                         Vcb );
1230*23b7c7b8SHermès Bélusca-Maïto 
1231*23b7c7b8SHermès Bélusca-Maïto                 //
1232*23b7c7b8SHermès Bélusca-Maïto                 //  We have our locks in the correct order.  Remove our
1233*23b7c7b8SHermès Bélusca-Maïto                 //  extra open and check for a dismount.  Note that if
1234*23b7c7b8SHermès Bélusca-Maïto                 //  something changed while we dropped the lock, it will
1235*23b7c7b8SHermès Bélusca-Maïto                 //  not matter, since the dismount code does the correct
1236*23b7c7b8SHermès Bélusca-Maïto                 //  checks to make sure the volume can really go away.
1237*23b7c7b8SHermès Bélusca-Maïto                 //
1238*23b7c7b8SHermès Bélusca-Maïto 
1239*23b7c7b8SHermès Bélusca-Maïto                 Vcb->OpenFileCount -= 1;
1240*23b7c7b8SHermès Bélusca-Maïto 
1241*23b7c7b8SHermès Bélusca-Maïto                 LocalVcbDeleted = FatCheckForDismount( &IrpContext,
1242*23b7c7b8SHermès Bélusca-Maïto                                                        Vcb,
1243*23b7c7b8SHermès Bélusca-Maïto                                                        FALSE );
1244*23b7c7b8SHermès Bélusca-Maïto 
1245*23b7c7b8SHermès Bélusca-Maïto                 FatReleaseGlobal( &IrpContext );
1246*23b7c7b8SHermès Bélusca-Maïto 
1247*23b7c7b8SHermès Bélusca-Maïto                 //
1248*23b7c7b8SHermès Bélusca-Maïto                 //  Let the caller know what happened, if they want this information.
1249*23b7c7b8SHermès Bélusca-Maïto                 //
1250*23b7c7b8SHermès Bélusca-Maïto 
1251*23b7c7b8SHermès Bélusca-Maïto                 if (ARGUMENT_PRESENT( VcbDeleted )) {
1252*23b7c7b8SHermès Bélusca-Maïto 
1253*23b7c7b8SHermès Bélusca-Maïto                     *VcbDeleted = LocalVcbDeleted;
1254*23b7c7b8SHermès Bélusca-Maïto                 }
1255*23b7c7b8SHermès Bélusca-Maïto 
1256*23b7c7b8SHermès Bélusca-Maïto             } else {
1257*23b7c7b8SHermès Bélusca-Maïto 
1258*23b7c7b8SHermès Bélusca-Maïto                 //
1259*23b7c7b8SHermès Bélusca-Maïto                 //  The volume cannot go away now.  Just remove our extra reference.
1260*23b7c7b8SHermès Bélusca-Maïto                 //
1261*23b7c7b8SHermès Bélusca-Maïto 
1262*23b7c7b8SHermès Bélusca-Maïto                 Vcb->OpenFileCount -= 1;
1263*23b7c7b8SHermès Bélusca-Maïto             }
1264*23b7c7b8SHermès Bélusca-Maïto 
1265*23b7c7b8SHermès Bélusca-Maïto             //
1266*23b7c7b8SHermès Bélusca-Maïto             //  If the VCB is still around, clear our recursion flag.
1267*23b7c7b8SHermès Bélusca-Maïto             //
1268*23b7c7b8SHermès Bélusca-Maïto 
1269*23b7c7b8SHermès Bélusca-Maïto             if (!LocalVcbDeleted) {
1270*23b7c7b8SHermès Bélusca-Maïto 
1271*23b7c7b8SHermès Bélusca-Maïto                 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS );
1272*23b7c7b8SHermès Bélusca-Maïto             }
1273*23b7c7b8SHermès Bélusca-Maïto         }
1274*23b7c7b8SHermès Bélusca-Maïto 
1275*23b7c7b8SHermès Bélusca-Maïto         //
1276*23b7c7b8SHermès Bélusca-Maïto         //  Only release the VCB if it did not go away.
1277*23b7c7b8SHermès Bélusca-Maïto         //
1278*23b7c7b8SHermès Bélusca-Maïto 
1279*23b7c7b8SHermès Bélusca-Maïto         if (!LocalVcbDeleted) {
1280*23b7c7b8SHermès Bélusca-Maïto 
1281*23b7c7b8SHermès Bélusca-Maïto             FatReleaseVcb( &IrpContext, Vcb );
1282*23b7c7b8SHermès Bélusca-Maïto         }
1283*23b7c7b8SHermès Bélusca-Maïto 
1284*23b7c7b8SHermès Bélusca-Maïto         DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status);
1285*23b7c7b8SHermès Bélusca-Maïto     } _SEH2_END;
1286*23b7c7b8SHermès Bélusca-Maïto 
1287*23b7c7b8SHermès Bélusca-Maïto     return Status;
1288*23b7c7b8SHermès Bélusca-Maïto }
1289*23b7c7b8SHermès Bélusca-Maïto 
1290