xref: /reactos/drivers/filesystems/fastfat/close.c (revision f4d29a74)
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     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     if (pCcb)
181     {
182         vfatDestroyCCB(pCcb);
183     }
184 
185     /* If we have to close immediately, or if delaying failed, close */
186     if (VfatGlobalData->ShutdownStarted || !BooleanFlagOn(pFcb->Flags, FCB_DELAYED_CLOSE) ||
187         !NT_SUCCESS(VfatPostCloseFile(DeviceExt, FileObject)))
188     {
189         VfatCommonCloseFile(DeviceExt, pFcb);
190     }
191 
192     FileObject->FsContext2 = NULL;
193     FileObject->FsContext = NULL;
194     FileObject->SectionObjectPointer = NULL;
195 
196 #ifdef ENABLE_SWAPOUT
197     if (BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME) && DeviceExt->OpenHandleCount == 0)
198     {
199         VfatCheckForDismount(DeviceExt, FALSE);
200     }
201 #endif
202 
203     return Status;
204 }
205 
206 /*
207  * FUNCTION: Closes a file
208  */
209 NTSTATUS
210 VfatClose(
211     PVFAT_IRP_CONTEXT IrpContext)
212 {
213     NTSTATUS Status;
214 
215     DPRINT("VfatClose(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
216 
217     if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
218     {
219         DPRINT("Closing file system\n");
220         IrpContext->Irp->IoStatus.Information = 0;
221         return STATUS_SUCCESS;
222     }
223     if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
224     {
225         return VfatMarkIrpContextForQueue(IrpContext);
226     }
227 
228     Status = VfatCloseFile(IrpContext->DeviceExt, IrpContext->FileObject);
229     ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
230 
231     IrpContext->Irp->IoStatus.Information = 0;
232 
233     return Status;
234 }
235 
236 /* EOF */
237