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