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