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