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