* FILE: drivers/fs/vfat/cleanup.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
+ * Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
{
IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
}
+ /* If that's the last open handle we just closed, try to see whether
+ * we can delay close operation
+ */
+ else if (!BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) && !BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE) &&
+ !BooleanFlagOn(pFcb->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME))
+ {
+ /* This is only allowed if that's a directory with no open files
+ * OR if it's a file with no section opened
+ * FIXME: only allow files for now
+ */
+#if 0
+ if ((vfatFCBIsDirectory(pFcb) && IsListEmpty(&pFcb->ParentListHead)) ||
+ (!vfatFCBIsDirectory(pFcb) && FileObject->SectionObjectPointer->DataSectionObject == NULL &&
+ FileObject->SectionObjectPointer->ImageSectionObject == NULL))
+#else
+ if (!vfatFCBIsDirectory(pFcb) && FileObject->SectionObjectPointer->DataSectionObject == NULL &&
+ FileObject->SectionObjectPointer->ImageSectionObject == NULL)
+#endif
+ {
+ DPRINT("Delaying close of: %wZ\n", &pFcb->PathNameU);
+ SetFlag(pFcb->Flags, FCB_DELAYED_CLOSE);
+ }
+ }
FileObject->Flags |= FO_CLEANUP_COMPLETE;
#ifdef KDBG
* FILE: drivers/filesystems/fastfat/close.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
+ * Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
/* FUNCTIONS ****************************************************************/
+VOID
+VfatCommonCloseFile(
+ PDEVICE_EXTENSION DeviceExt,
+ PVFATFCB pFcb)
+{
+ /* Nothing to do for volumes */
+ if (BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME))
+ {
+ return;
+ }
+
+ /* If cache is still initialized, release it
+ * This only affects directories
+ */
+ if (pFcb->OpenHandleCount == 0 && BooleanFlagOn(pFcb->Flags, FCB_CACHE_INITIALIZED))
+ {
+ PFILE_OBJECT tmpFileObject;
+ tmpFileObject = pFcb->FileObject;
+ if (tmpFileObject != NULL)
+ {
+ pFcb->FileObject = NULL;
+ CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
+ ClearFlag(pFcb->Flags, FCB_CACHE_INITIALIZED);
+ ObDereferenceObject(tmpFileObject);
+ }
+ }
+
+#ifdef KDBG
+ pFcb->Flags |= FCB_CLOSED;
+#endif
+
+ /* Release the FCB, we likely cause its deletion */
+ vfatReleaseFCB(DeviceExt, pFcb);
+}
+
+VOID
+NTAPI
+VfatCloseWorker(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context)
+{
+ PLIST_ENTRY Entry;
+ PVFATFCB pFcb;
+ PDEVICE_EXTENSION Vcb;
+ PVFAT_CLOSE_CONTEXT CloseContext;
+ BOOLEAN ConcurrentDeletion;
+
+ /* Start removing work items */
+ ExAcquireFastMutex(&VfatGlobalData->CloseMutex);
+ while (!IsListEmpty(&VfatGlobalData->CloseListHead))
+ {
+ Entry = RemoveHeadList(&VfatGlobalData->CloseListHead);
+ CloseContext = CONTAINING_RECORD(Entry, VFAT_CLOSE_CONTEXT, CloseListEntry);
+
+ /* One less */
+ --VfatGlobalData->CloseCount;
+ /* Reset its entry to detect concurrent deletions */
+ InitializeListHead(&CloseContext->CloseListEntry);
+ ExReleaseFastMutex(&VfatGlobalData->CloseMutex);
+
+ /* Get the elements */
+ Vcb = CloseContext->Vcb;
+ pFcb = CloseContext->Fcb;
+ ExAcquireResourceExclusiveLite(&Vcb->DirResource, TRUE);
+ /* If it didn't got deleted in between */
+ if (BooleanFlagOn(pFcb->Flags, FCB_DELAYED_CLOSE))
+ {
+ /* Close it! */
+ DPRINT("Late closing: %wZ\n", &pFcb->PathNameU);
+ ClearFlag(pFcb->Flags, FCB_DELAYED_CLOSE);
+ pFcb->CloseContext = NULL;
+ VfatCommonCloseFile(Vcb, pFcb);
+ ConcurrentDeletion = FALSE;
+ }
+ else
+ {
+ /* Otherwise, mark not to delete it */
+ ConcurrentDeletion = TRUE;
+ }
+ ExReleaseResourceLite(&Vcb->DirResource);
+
+ /* If we were the fastest, delete the context */
+ if (!ConcurrentDeletion)
+ {
+ ExFreeToPagedLookasideList(&VfatGlobalData->CloseContextLookasideList, CloseContext);
+ }
+
+ /* Lock again the list */
+ ExAcquireFastMutex(&VfatGlobalData->CloseMutex);
+ }
+
+ /* We're done, bye! */
+ VfatGlobalData->CloseWorkerRunning = FALSE;
+ ExReleaseFastMutex(&VfatGlobalData->CloseMutex);
+}
+
+NTSTATUS
+VfatPostCloseFile(
+ PDEVICE_EXTENSION DeviceExt,
+ PFILE_OBJECT FileObject)
+{
+ PVFAT_CLOSE_CONTEXT CloseContext;
+
+ /* Allocate a work item */
+ CloseContext = ExAllocateFromPagedLookasideList(&VfatGlobalData->CloseContextLookasideList);
+ if (CloseContext == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Set relevant fields */
+ CloseContext->Vcb = DeviceExt;
+ CloseContext->Fcb = FileObject->FsContext;
+ CloseContext->Fcb->CloseContext = CloseContext;
+
+ /* Acquire the lock to insert in list */
+ ExAcquireFastMutex(&VfatGlobalData->CloseMutex);
+
+ /* One more element */
+ InsertTailList(&VfatGlobalData->CloseListHead, &CloseContext->CloseListEntry);
+ ++VfatGlobalData->CloseCount;
+
+ /* If we have more than 16 items in list, and no worker thread
+ * start a new one
+ */
+ if (VfatGlobalData->CloseCount > 16 && !VfatGlobalData->CloseWorkerRunning)
+ {
+ VfatGlobalData->CloseWorkerRunning = TRUE;
+ IoQueueWorkItem(VfatGlobalData->CloseWorkItem, VfatCloseWorker, CriticalWorkQueue, NULL);
+ }
+
+ /* We're done */
+ ExReleaseFastMutex(&VfatGlobalData->CloseMutex);
+
+ return STATUS_SUCCESS;
+}
+
/*
* FUNCTION: Closes a file
*/
{
PVFATFCB pFcb;
PVFATCCB pCcb;
- BOOLEAN IsVolume;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("VfatCloseFile(DeviceExt %p, FileObject %p)\n",
return STATUS_SUCCESS;
}
- IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME);
- if (IsVolume)
+ if (pCcb)
{
- DPRINT("Volume\n");
- FileObject->FsContext2 = NULL;
+ vfatDestroyCCB(pCcb);
}
- else
- {
- if (pFcb->OpenHandleCount == 0 && BooleanFlagOn(pFcb->Flags, FCB_CACHE_INITIALIZED))
- {
- PFILE_OBJECT tmpFileObject;
- tmpFileObject = pFcb->FileObject;
- if (tmpFileObject != NULL)
- {
- pFcb->FileObject = NULL;
- CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
- ClearFlag(pFcb->Flags, FCB_CACHE_INITIALIZED);
- ObDereferenceObject(tmpFileObject);
- }
- }
-#ifdef KDBG
- pFcb->Flags |= FCB_CLOSED;
-#endif
- vfatReleaseFCB(DeviceExt, pFcb);
+ /* If we have to close immediately, or if delaying failed, close */
+ if (!BooleanFlagOn(pFcb->Flags, FCB_DELAYED_CLOSE) || !NT_SUCCESS(VfatPostCloseFile(DeviceExt, FileObject)))
+ {
+ VfatCommonCloseFile(DeviceExt, pFcb);
}
FileObject->FsContext2 = NULL;
FileObject->FsContext = NULL;
FileObject->SectionObjectPointer = NULL;
- if (pCcb)
- {
- vfatDestroyCCB(pCcb);
- }
-
#ifdef ENABLE_SWAPOUT
- if (IsVolume && DeviceExt->OpenHandleCount == 0)
+ if (BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME) && DeviceExt->OpenHandleCount == 0)
{
VfatCheckForDismount(DeviceExt, FALSE);
}
return STATUS_CANNOT_DELETE;
}
+ /* If that one was marked for closing, remove it */
+ if (BooleanFlagOn(Fcb->Flags, FCB_DELAYED_CLOSE))
+ {
+ BOOLEAN ConcurrentDeletion;
+ PVFAT_CLOSE_CONTEXT CloseContext;
+
+ /* Get the context */
+ CloseContext = Fcb->CloseContext;
+ /* Is someone already taking over? */
+ if (CloseContext != NULL)
+ {
+ ConcurrentDeletion = FALSE;
+ /* Lock list */
+ ExAcquireFastMutex(&VfatGlobalData->CloseMutex);
+ /* Check whether it was already removed, if not, do it */
+ if (!IsListEmpty(&CloseContext->CloseListEntry))
+ {
+ RemoveEntryList(&CloseContext->CloseListEntry);
+ --VfatGlobalData->CloseCount;
+ ConcurrentDeletion = TRUE;
+ }
+ ExReleaseFastMutex(&VfatGlobalData->CloseMutex);
+
+ /* It's not delayed anymore! */
+ ClearFlag(Fcb->Flags, FCB_DELAYED_CLOSE);
+ /* Release the extra reference (would have been removed by IRP_MJ_CLOSE) */
+ vfatReleaseFCB(DeviceExt, Fcb);
+ Fcb->CloseContext = NULL;
+ /* If no concurrent deletion, free work item */
+ if (!ConcurrentDeletion)
+ {
+ ExFreeToPagedLookasideList(&VfatGlobalData->CloseContextLookasideList, CloseContext);
+ }
+ }
+
+ DPRINT("Reusing delayed close FCB for %wZ\n", &Fcb->PathNameU);
+ }
+
DPRINT("Attaching FCB to fileObject\n");
Status = vfatAttachFCBToFileObject(DeviceExt, Fcb, FileObject);
if (!NT_SUCCESS(Status))
* FILE: drivers/fs/vfat/iface.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
+ * Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
* has been detected:
VfatGlobalData->Flags = VFAT_BREAK_ON_CORRUPTION; */
+ /* Delayed close support */
+ ExInitializeFastMutex(&VfatGlobalData->CloseMutex);
+ InitializeListHead(&VfatGlobalData->CloseListHead);
+ VfatGlobalData->CloseCount = 0;
+ VfatGlobalData->CloseWorkerRunning = FALSE;
+ VfatGlobalData->CloseWorkItem = IoAllocateWorkItem(DeviceObject);
+ if (VfatGlobalData->CloseWorkItem == NULL)
+ {
+ IoDeleteDevice(DeviceObject);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
DeviceObject->Flags |= DO_DIRECT_IO;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = VfatBuildRequest;
DriverObject->MajorFunction[IRP_MJ_CREATE] = VfatBuildRequest;
NULL, NULL, 0, sizeof(VFATCCB), TAG_CCB, 0);
ExInitializeNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList,
NULL, NULL, 0, sizeof(VFAT_IRP_CONTEXT), TAG_IRP, 0);
+ ExInitializePagedLookasideList(&VfatGlobalData->CloseContextLookasideList,
+ NULL, NULL, 0, sizeof(VFAT_CLOSE_CONTEXT), TAG_CLOSE, 0);
ExInitializeResourceLite(&VfatGlobalData->VolumeListLock);
InitializeListHead(&VfatGlobalData->VolumeListHead);
ListEntry = ListEntry->Flink)
{
Fcb = CONTAINING_RECORD(ListEntry, VFATFCB, FcbListEntry);
- DPRINT1("FCB %p (ref: %d, oc: %d %s %s) for FO %p with path: %.*S\n",
+ DPRINT1("FCB %p (ref: %d, oc: %d %s %s %s) for FO %p with path: %.*S\n",
Fcb, Fcb->RefCount, Fcb->OpenHandleCount,
((Fcb->Flags & FCB_CLEANED_UP) ? "U" : "NU"),
((Fcb->Flags & FCB_CLOSED) ? "C" : "NC"),
+ ((Fcb->Flags & FCB_DELAYED_CLOSE) ? "D" : "ND"),
Fcb->FileObject, Fcb->PathNameU.Length, Fcb->PathNameU.Buffer);
}
}
struct _VFATFCB;
struct _VFAT_DIRENTRY_CONTEXT;
struct _VFAT_MOVE_CONTEXT;
+struct _VFAT_CLOSE_CONTEXT;
typedef struct _HASHENTRY
{
NPAGED_LOOKASIDE_LIST FcbLookasideList;
NPAGED_LOOKASIDE_LIST CcbLookasideList;
NPAGED_LOOKASIDE_LIST IrpContextLookasideList;
+ PAGED_LOOKASIDE_LIST CloseContextLookasideList;
FAST_IO_DISPATCH FastIoDispatch;
CACHE_MANAGER_CALLBACKS CacheMgrCallbacks;
+ FAST_MUTEX CloseMutex;
+ ULONG CloseCount;
+ LIST_ENTRY CloseListHead;
+ BOOLEAN CloseWorkerRunning;
+ PIO_WORKITEM CloseWorkItem;
} VFAT_GLOBAL_DATA, *PVFAT_GLOBAL_DATA;
extern PVFAT_GLOBAL_DATA VfatGlobalData;
#define FCB_IS_PAGE_FILE 0x0008
#define FCB_IS_VOLUME 0x0010
#define FCB_IS_DIRTY 0x0020
+#define FCB_DELAYED_CLOSE 0x0040
#ifdef KDBG
-#define FCB_CLEANED_UP 0x0040
-#define FCB_CLOSED 0x0080
+#define FCB_CLEANED_UP 0x0080
+#define FCB_CLOSED 0x0100
#endif
#define NODE_TYPE_FCB ((CSHORT)0x0502)
FAST_MUTEX LastMutex;
ULONG LastCluster;
ULONG LastOffset;
+
+ struct _VFAT_CLOSE_CONTEXT * CloseContext;
} VFATFCB, *PVFATFCB;
#define CCB_DELETE_ON_CLOSE 0x0001
#define TAG_FCB 'BCFV'
#define TAG_IRP 'PRIV'
#define TAG_VFAT 'TAFV'
+#define TAG_CLOSE 'xtaF'
#define ENTRIES_PER_SECTOR (BLOCKSIZE / sizeof(FATDirEntry))
BOOLEAN InPlace;
} VFAT_MOVE_CONTEXT, *PVFAT_MOVE_CONTEXT;
+typedef struct _VFAT_CLOSE_CONTEXT
+{
+ PDEVICE_EXTENSION Vcb;
+ PVFATFCB Fcb;
+ LIST_ENTRY CloseListEntry;
+} VFAT_CLOSE_CONTEXT, *PVFAT_CLOSE_CONTEXT;
+
FORCEINLINE
NTSTATUS
VfatMarkIrpContextForQueue(PVFAT_IRP_CONTEXT IrpContext)