xref: /reactos/drivers/filesystems/vfatfs/close.c (revision 84344399)
1 /*
2  * PROJECT:     VFAT Filesystem
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     File close routines
5  * COPYRIGHT:   Copyright 1998 Jason Filby <jasonfilby@yahoo.com>
6  *              Copyright 2014-2018 Pierre Schweitzer <pierre@reactos.org>
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include "vfat.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* FUNCTIONS ****************************************************************/
17 
18 VOID
19 VfatCommonCloseFile(
20     PDEVICE_EXTENSION DeviceExt,
21     PVFATFCB pFcb)
22 {
23     /* Nothing to do for volumes or for the FAT file object */
24     if (BooleanFlagOn(pFcb->Flags, FCB_IS_FAT | FCB_IS_VOLUME))
25     {
26         return;
27     }
28 
29     /* If cache is still initialized, release it
30      * This only affects directories
31      */
32     if (pFcb->OpenHandleCount == 0 && BooleanFlagOn(pFcb->Flags, FCB_CACHE_INITIALIZED))
33     {
34         PFILE_OBJECT tmpFileObject;
35         tmpFileObject = pFcb->FileObject;
36         if (tmpFileObject != NULL)
37         {
38             pFcb->FileObject = NULL;
39             CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
40             ClearFlag(pFcb->Flags, FCB_CACHE_INITIALIZED);
41             ObDereferenceObject(tmpFileObject);
42         }
43     }
44 
45 #ifdef KDBG
46     pFcb->Flags |= FCB_CLOSED;
47 #endif
48 
49     /* Release the FCB, we likely cause its deletion */
50     vfatReleaseFCB(DeviceExt, pFcb);
51 }
52 
53 VOID
54 NTAPI
55 VfatCloseWorker(
56     IN PDEVICE_OBJECT DeviceObject,
57     IN PVOID Context)
58 {
59     PLIST_ENTRY Entry;
60     PVFATFCB pFcb;
61     PDEVICE_EXTENSION Vcb;
62     PVFAT_CLOSE_CONTEXT CloseContext;
63     BOOLEAN ConcurrentDeletion;
64 
65     /* Start removing work items */
66     ExAcquireFastMutex(&VfatGlobalData->CloseMutex);
67     while (!IsListEmpty(&VfatGlobalData->CloseListHead))
68     {
69         Entry = RemoveHeadList(&VfatGlobalData->CloseListHead);
70         CloseContext = CONTAINING_RECORD(Entry, VFAT_CLOSE_CONTEXT, CloseListEntry);
71 
72         /* One less */
73         --VfatGlobalData->CloseCount;
74         /* Reset its entry to detect concurrent deletions */
75         InitializeListHead(&CloseContext->CloseListEntry);
76         ExReleaseFastMutex(&VfatGlobalData->CloseMutex);
77 
78         /* Get the elements */
79         Vcb = CloseContext->Vcb;
80         pFcb = CloseContext->Fcb;
81         ExAcquireResourceExclusiveLite(&Vcb->DirResource, TRUE);
82         /* If it didn't got deleted in between */
83         if (BooleanFlagOn(pFcb->Flags, FCB_DELAYED_CLOSE))
84         {
85             /* Close it! */
86             DPRINT("Late closing: %wZ\n", &pFcb->PathNameU);
87             ClearFlag(pFcb->Flags, FCB_DELAYED_CLOSE);
88             pFcb->CloseContext = NULL;
89             VfatCommonCloseFile(Vcb, pFcb);
90             ConcurrentDeletion = FALSE;
91         }
92         else
93         {
94             /* Otherwise, mark not to delete it */
95             ConcurrentDeletion = TRUE;
96         }
97         ExReleaseResourceLite(&Vcb->DirResource);
98 
99         /* If we were the fastest, delete the context */
100         if (!ConcurrentDeletion)
101         {
102             ExFreeToPagedLookasideList(&VfatGlobalData->CloseContextLookasideList, CloseContext);
103         }
104 
105         /* Lock again the list */
106         ExAcquireFastMutex(&VfatGlobalData->CloseMutex);
107     }
108 
109     /* We're done, bye! */
110     VfatGlobalData->CloseWorkerRunning = FALSE;
111     ExReleaseFastMutex(&VfatGlobalData->CloseMutex);
112 }
113 
114 NTSTATUS
115 VfatPostCloseFile(
116     PDEVICE_EXTENSION DeviceExt,
117     PFILE_OBJECT FileObject)
118 {
119     PVFAT_CLOSE_CONTEXT CloseContext;
120 
121     /* Allocate a work item */
122     CloseContext = ExAllocateFromPagedLookasideList(&VfatGlobalData->CloseContextLookasideList);
123     if (CloseContext == NULL)
124     {
125         return STATUS_INSUFFICIENT_RESOURCES;
126     }
127 
128     /* Set relevant fields */
129     CloseContext->Vcb = DeviceExt;
130     CloseContext->Fcb = FileObject->FsContext;
131     CloseContext->Fcb->CloseContext = CloseContext;
132 
133     /* Acquire the lock to insert in list */
134     ExAcquireFastMutex(&VfatGlobalData->CloseMutex);
135 
136     /* One more element */
137     InsertTailList(&VfatGlobalData->CloseListHead, &CloseContext->CloseListEntry);
138     ++VfatGlobalData->CloseCount;
139 
140     /* If we have more than 16 items in list, and no worker thread
141      * start a new one
142      */
143     if (VfatGlobalData->CloseCount > 16 && !VfatGlobalData->CloseWorkerRunning)
144     {
145         VfatGlobalData->CloseWorkerRunning = TRUE;
146         IoQueueWorkItem(VfatGlobalData->CloseWorkItem, VfatCloseWorker, CriticalWorkQueue, NULL);
147     }
148 
149     /* We're done */
150     ExReleaseFastMutex(&VfatGlobalData->CloseMutex);
151 
152     return STATUS_SUCCESS;
153 }
154 
155 /*
156  * FUNCTION: Closes a file
157  */
158 NTSTATUS
159 VfatCloseFile(
160     PDEVICE_EXTENSION DeviceExt,
161     PFILE_OBJECT FileObject)
162 {
163     PVFATFCB pFcb;
164     PVFATCCB pCcb;
165     BOOLEAN IsVolume;
166     NTSTATUS Status = STATUS_SUCCESS;
167 
168     DPRINT("VfatCloseFile(DeviceExt %p, FileObject %p)\n",
169             DeviceExt, FileObject);
170 
171     /* FIXME : update entry in directory? */
172     pCcb = (PVFATCCB) (FileObject->FsContext2);
173     pFcb = (PVFATFCB) (FileObject->FsContext);
174 
175     if (pFcb == NULL)
176     {
177         return STATUS_SUCCESS;
178     }
179 
180     IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME);
181 
182     if (pCcb)
183     {
184         vfatDestroyCCB(pCcb);
185     }
186 
187     /* If we have to close immediately, or if delaying failed, close */
188     if (VfatGlobalData->ShutdownStarted || !BooleanFlagOn(pFcb->Flags, FCB_DELAYED_CLOSE) ||
189         !NT_SUCCESS(VfatPostCloseFile(DeviceExt, FileObject)))
190     {
191         VfatCommonCloseFile(DeviceExt, pFcb);
192     }
193 
194     FileObject->FsContext2 = NULL;
195     FileObject->FsContext = NULL;
196     FileObject->SectionObjectPointer = NULL;
197 
198 #ifdef ENABLE_SWAPOUT
199     if (IsVolume && DeviceExt->OpenHandleCount == 0)
200     {
201         VfatCheckForDismount(DeviceExt, FALSE);
202     }
203 #endif
204 
205     return Status;
206 }
207 
208 /*
209  * FUNCTION: Closes a file
210  */
211 NTSTATUS
212 VfatClose(
213     PVFAT_IRP_CONTEXT IrpContext)
214 {
215     NTSTATUS Status;
216 
217     DPRINT("VfatClose(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
218 
219     if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
220     {
221         DPRINT("Closing file system\n");
222         IrpContext->Irp->IoStatus.Information = 0;
223         return STATUS_SUCCESS;
224     }
225     if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
226     {
227         return VfatMarkIrpContextForQueue(IrpContext);
228     }
229 
230     Status = VfatCloseFile(IrpContext->DeviceExt, IrpContext->FileObject);
231     ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
232 
233     IrpContext->Irp->IoStatus.Information = 0;
234 
235     return Status;
236 }
237 
238 /* EOF */
239