ReactOS  0.4.15-dev-509-g96a357b
close.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7  Close.c
8 
9 Abstract:
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_)
49 VOID
50 FatQueueClose (
51  IN PCLOSE_CONTEXT CloseContext,
53  );
54 
55 _Requires_lock_held_(_Global_critical_region_)
57 FatRemoveClose (
59  PVCB LastVcbHint OPTIONAL
60  );
61 
62 IO_WORKITEM_ROUTINE FatCloseWorker;
63 
64 VOID
65 NTAPI
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 
83 NTAPI
84 FatFsdClose (
85  _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
87  )
88 
89 /*++
90 
91 Routine Description:
92 
93  This routine implements the FSD part of Close.
94 
95 Arguments:
96 
97  VolumeDeviceObject - Supplies the volume device object where the
98  file exists
99 
100  Irp - Supplies the Irp being processed
101 
102 Return 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) &&
188  !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) &&
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) ||
282  (TypeOfOpen == DirectoryFile) ||
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 
323 VOID
324 NTAPI
328  )
329 /*++
330 
331 Routine Description:
332 
333  This routine is a shim between the IO worker package and FatFspClose.
334 
335 Arguments:
336 
337  DeviceObject - Registration device object, unused
338  Context - Context value, unused
339 
340 Return 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_)
359 VOID
360 FatFspClose (
362  )
363 
364 /*++
365 
366 Routine Description:
367 
368  This routine implements the FSP part of Close.
369 
370 Arguments:
371 
372  Vcb - If present, tells us to only close file objects opened on the
373  specified volume.
374 
375 Return 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 
417  if (!FatData.ShutdownStarted) {
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_)
557 VOID
558 FatQueueClose (
559  IN PCLOSE_CONTEXT CloseContext,
561  )
562 
563 /*++
564 
565 Routine Description:
566 
567  Enqueue a deferred close to one of the two delayed close queues.
568 
569 Arguments:
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 
576 Return 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 
612  if (!FatData.AsyncCloseActive) {
613 
615  StartWorker = TRUE;
616  }
617  }
618 
620 
621  if (StartWorker) {
622 
624  }
625 }
626 
627 
628 _Requires_lock_held_(_Global_critical_region_)
630 FatRemoveClose (
631  PVCB Vcb OPTIONAL,
632  PVCB LastVcbHint OPTIONAL
633  )
634 
635 /*++
636 
637 Routine Description:
638 
639  Dequeue a deferred close from one of the two delayed close queues.
640 
641 Arguments:
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 
648 Return 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_)
833 NTSTATUS
834 FatCommonClose (
835  IN PVCB Vcb,
836  IN PFCB Fcb,
837  IN PCCB Ccb,
839  IN BOOLEAN Wait,
841  OUT PBOOLEAN VcbDeleted OPTIONAL
842  )
843 
844 /*++
845 
846 Routine 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 
858 Arguments:
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 
869 Return Value:
870 
871  NTSTATUS - The return status for the operation
872 
873 --*/
874 
875 {
877  PDCB ParentDcb;
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 
946  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS) &&
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 
986  case VirtualVolumeFile:
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 
1127  ParentDcb = Fcb->ParentDcb;
1128 
1129  SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
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 
1169  SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
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 
ULONG NTAPI ExGetExclusiveWaiterCount(IN PERESOURCE Resource)
Definition: resource.c:1535
#define IsFileObjectReadOnly(FO)
Definition: fatprocs.h:2863
#define IN
Definition: typedefs.h:39
PIO_WORKITEM FatCloseItem
Definition: fatstruc.h:144
#define TRUE
Definition: types.h:120
#define FatReleaseGlobal(IRPCONTEXT)
Definition: fatprocs.h:1636
#define IRP_CONTEXT_FLAG_WAIT
Definition: cdstruc.h:1221
#define FsRtlEnterFileSystem
BOOLEAN FatIsIrpTopLevel(IN PIRP Irp)
Definition: fatdata.c:817
PCLOSE_CONTEXT FatAllocateCloseContext(IN PVCB Vcb)
struct _Entry Entry
Definition: kefuncs.h:627
#define FsRtlExitFileSystem
#define FatCompleteRequest(IRPCONTEXT, IRP, STATUS)
Definition: fatprocs.h:2630
_In_ PIRP Irp
Definition: csq.h:116
enum _TYPE_OF_OPEN TypeOfOpen
Definition: fatstruc.h:207
_Requires_lock_held_(_Global_critical_region_)
Definition: close.c:57
ERESOURCE Resource
Definition: fatstruc.h:403
struct _FCB::@711::@713 Dcb
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
Definition: cdstruc.h:908
#define VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS
Definition: fatstruc.h:574
Definition: cdstruc.h:1073
LONG NTSTATUS
Definition: precomp.h:26
#define FatDeviceIsFatFsdo(D)
Definition: fatprocs.h:3092
#define DebugTrace(INDENT, LEVEL, X, Y)
Definition: fatdata.h:313
#define FILE_OPENED
Definition: nt_native.h:769
#define Dbg
Definition: close.c:29
ULONG FatMaxDelayedCloseCount
Definition: close.c:31
Definition: cdstruc.h:504
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
BOOLEAN ShutdownStarted
Definition: fatstruc.h:107
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB ParentDcb
Definition: create.c:4137
#define InsertTailList(ListHead, Entry)
BOOLEAN HighAsync
Definition: fatstruc.h:121
struct _FCB * ParentDcb
Definition: fatstruc.h:835
#define FatNull
Definition: fatdata.h:321
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define _In_opt_
Definition: no_sal2.h:213
_SEH2_TRY
Definition: create.c:4226
IN PFCB IN PCCB IN TYPE_OF_OPEN IN BOOLEAN IN BOOLEAN TopLevel
Definition: fatprocs.h:2410
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
BOOLEAN NTAPI ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, IN BOOLEAN Wait)
Definition: resource.c:770
LIST_ENTRY DelayedCloseList
Definition: fatstruc.h:138
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN TypeOfOpen
Definition: cdprocs.h:588
VOID FatDeleteCcb(IN PIRP_CONTEXT IrpContext, IN PCCB *Ccb)
Definition: strucsup.c:2242
#define IO_DISK_INCREMENT
Definition: iotypes.h:570
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
long LONG
Definition: pedump.c:60
#define FatGetFcbOplock(F)
Definition: fatprocs.h:1656
#define FatBugCheck(A, B, C)
Definition: nodetype.h:104
#define PsGetCurrentProcess
Definition: psfuncs.h:17
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:11
_In_ BOOLEAN DelayClose
Definition: mmfuncs.h:593
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define IoCompleteRequest
Definition: irp.c:1240
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
NodeType
Definition: Node.h:5
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:588
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define FatReleaseCloseMutex()
Definition: close.c:39
ULONG NTAPI ExGetSharedWaiterCount(IN PERESOURCE Resource)
Definition: resource.c:1558
#define DebugUnwind(X)
Definition: fatdata.h:315
LIST_ENTRY GlobalLinks
Definition: fatstruc.h:202
FAT_DATA FatData
Definition: fatdata.c:56
VOID FatDeleteFcb(IN PIRP_CONTEXT IrpContext, IN PFCB *Fcb)
Definition: strucsup.c:1940
BOOLEAN AsyncCloseActive
Definition: fatstruc.h:100
#define CCB_FLAG_READ_ONLY
Definition: fatstruc.h:1274
#define STATUS_PENDING
Definition: ntstatus.h:82
#define try_return(S)
Definition: cdprocs.h:2179
BOOLEAN Free
Definition: fatstruc.h:208
LIST_ENTRY VcbLinks
Definition: fatstruc.h:203
#define ARGUMENT_PRESENT(ArgumentPointer)
CLONG OpenFileCount
Definition: fatstruc.h:311
#define Vcb
Definition: cdprocs.h:1415
VOID NTAPI WorkerThread(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
Definition: database.c:1148
#define FCB_STATE_DELAY_CLOSE
Definition: fatstruc.h:1202
PEPROCESS OurProcess
Definition: fatstruc.h:74
#define FatIsFileOplockable(F)
Definition: fatprocs.h:2848
#define _Inout_
Definition: no_sal2.h:244
#define FSRTL_FSP_TOP_LEVEL_IRP
Definition: fsrtltypes.h:59
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
#define VCB_STATE_FLAG_CREATE_IN_PROGRESS
Definition: fatstruc.h:565
* PFILE_OBJECT
Definition: iotypes.h:1957
ULONG Flags
Definition: ntfs.h:532
BOOLEAN HighDelayed
Definition: fatstruc.h:122
char * PBOOLEAN
Definition: retypes.h:11
#define IRP_MJ_CLOSE
Definition: rdpdr.c:45
VOID NTAPI IoSetTopLevelIrp(IN PIRP Irp)
Definition: irp.c:2000
#define InterlockedDecrement
Definition: armddk.h:52
#define FAT_NTC_IRP_CONTEXT
Definition: nodetype.h:33
#define VOID
Definition: acefi.h:82
enum _TYPE_OF_OPEN TYPE_OF_OPEN
_Inout_ PFILE_OBJECT _In_ TYPE_OF_OPEN PFCB _In_opt_ PCCB Ccb
Definition: cdprocs.h:588
#define NOTHING
Definition: env_spec_w32.h:461
Definition: typedefs.h:118
#define FlagOn(_F, _SF)
Definition: ext2fs.h:179
union _FCB::@711 Specific
DRIVER_DISPATCH(nfs41_FsdDispatch)
#define FatAcquireCloseMutex()
Definition: close.c:34
ClearFlag(Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT)
#define VCB_STATE_FLAG_CLOSE_IN_PROGRESS
Definition: fatstruc.h:563
Status
Definition: gdiplustypes.h:24
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 _In_
Definition: no_sal2.h:204
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1569
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
#define SetFlag(_F, _SF)
Definition: ext2fs.h:187
PFILE_OBJECT FileObject
Definition: iotypes.h:2815
_SEH2_END
Definition: create.c:4400
ULONG DelayedCloseCount
Definition: fatstruc.h:137
BOOLEAN NTAPI CcUninitializeCacheMap(IN PFILE_OBJECT FileObject, IN OPTIONAL PLARGE_INTEGER TruncateSize, IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)
Definition: fssup.c:286
ULONG FatExceptionFilter(IN PIRP_CONTEXT IrpContext, IN PEXCEPTION_POINTERS ExceptionPointer)
Definition: fatdata.c:204
#define FatAcquireExclusiveVcb(IC, V)
Definition: fatprocs.h:1460
#define FO_CLEANUP_COMPLETE
Definition: iotypes.h:1749
#define FAT_NTC_ROOT_DCB
Definition: nodetype.h:31
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4137
#define VCB_STATE_FLAG_DELETED_FCB
Definition: fatstruc.h:564
_SEH2_FINALLY
Definition: create.c:4371
#define FatReleaseVcb(IRPCONTEXT, Vcb)
Definition: fatprocs.h:1640
CLONG OpenCount
Definition: fatstruc.h:880
#define FAT_NTC_DCB
Definition: nodetype.h:30
VOID NTAPI FatCloseWorker(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
Definition: close.c:325
#define OUT
Definition: typedefs.h:40
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
_In_ PFCB Fcb
Definition: cdprocs.h:159
LIST_ENTRY AsyncCloseList
Definition: fatstruc.h:131
return STATUS_SUCCESS
Definition: btrfs.c:3014
#define CCB_FLAG_CLOSE_CONTEXT
Definition: fatstruc.h:1323
ULONG FcbState
Definition: cdstruc.h:977
TYPE_OF_OPEN FatDecodeFileObject(_In_ PFILE_OBJECT FileObject, _Outptr_ PVCB *Vcb, _Outptr_ PFCB *FcbOrDcb, _Outptr_ PCCB *Ccb)
Definition: filobsup.c:176
#define FAT_NTC_FCB
Definition: nodetype.h:29
base of all file and directory entries
Definition: entries.h:82
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
VOID FatDeallocateCcbStrings(IN PCCB Ccb)
Definition: strucsup.c:2197
ULONG AsyncCloseCount
Definition: fatstruc.h:130
#define _Function_class_(x)
Definition: no_sal2.h:202
#define FatAcquireExclusiveGlobal(IRPCONTEXT)
Definition: fatprocs.h:1387
#define PAGED_CODE()
IN BOOLEAN Wait
Definition: fatprocs.h:1538
#define NT_ASSERT
Definition: rtlfuncs.h:3312
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68