[FASTFAT] Don't delay any other close once shutdown has started
[reactos.git] / drivers / filesystems / fastfat / close.c
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 */
25 if (BooleanFlagOn(pFcb->Flags, 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 */