mirror of
https://github.com/reactos/reactos.git
synced 2024-11-19 13:33:42 +00:00
[FASTFAT] Implement delayed close
When we're about to close a file (ie, forget everything about it
and release any associated structure), actually delay it.
This allows keep data fresh in memory for faster reuse in case
it would be required. The effective closing will only happen after some time.
For specific operations, this will produce a real speed up in ReactOS.
For instance, with that patch, Winamp starts within seconds, instead of dozen
of minutes.
In most cases, it will bring ReactOS to performances it had before fixing
the huge leak in FastFAT (commit 94ead99
) without leaking the whole FS.
For now, due to regressions, this is only activated for files and not
for directories. Once it gets fixed, it will be enabled for both.
CORE-14826
CORE-14917
This commit is contained in:
parent
b2d2e3433b
commit
50b00f0fcc
6 changed files with 244 additions and 32 deletions
|
@ -4,6 +4,7 @@
|
|||
* FILE: drivers/fs/vfat/cleanup.c
|
||||
* PURPOSE: VFAT Filesystem
|
||||
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
|
||||
* Pierre Schweitzer (pierre@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
@ -127,6 +128,29 @@ VfatCleanupFile(
|
|||
{
|
||||
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
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* FILE: drivers/filesystems/fastfat/close.c
|
||||
* PURPOSE: VFAT Filesystem
|
||||
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
|
||||
* Pierre Schweitzer (pierre@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
@ -15,6 +16,143 @@
|
|||
|
||||
/* 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
|
||||
*/
|
||||
|
@ -25,7 +163,6 @@ VfatCloseFile(
|
|||
{
|
||||
PVFATFCB pFcb;
|
||||
PVFATCCB pCcb;
|
||||
BOOLEAN IsVolume;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
DPRINT("VfatCloseFile(DeviceExt %p, FileObject %p)\n",
|
||||
|
@ -40,44 +177,23 @@ VfatCloseFile(
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -370,6 +370,44 @@ VfatOpenFile(
|
|||
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))
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* FILE: drivers/fs/vfat/iface.c
|
||||
* PURPOSE: VFAT Filesystem
|
||||
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
|
||||
* Pierre Schweitzer (pierre@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
@ -95,6 +96,18 @@ DriverEntry(
|
|||
* 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;
|
||||
|
@ -132,6 +145,8 @@ DriverEntry(
|
|||
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);
|
||||
|
|
|
@ -109,10 +109,11 @@ vfatKdbgHandler(
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -269,6 +269,7 @@ typedef struct
|
|||
struct _VFATFCB;
|
||||
struct _VFAT_DIRENTRY_CONTEXT;
|
||||
struct _VFAT_MOVE_CONTEXT;
|
||||
struct _VFAT_CLOSE_CONTEXT;
|
||||
|
||||
typedef struct _HASHENTRY
|
||||
{
|
||||
|
@ -408,8 +409,14 @@ typedef struct
|
|||
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;
|
||||
|
@ -420,9 +427,10 @@ 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)
|
||||
|
@ -510,6 +518,8 @@ typedef struct _VFATFCB
|
|||
FAST_MUTEX LastMutex;
|
||||
ULONG LastCluster;
|
||||
ULONG LastOffset;
|
||||
|
||||
struct _VFAT_CLOSE_CONTEXT * CloseContext;
|
||||
} VFATFCB, *PVFATFCB;
|
||||
|
||||
#define CCB_DELETE_ON_CLOSE 0x0001
|
||||
|
@ -528,6 +538,7 @@ typedef struct _VFATCCB
|
|||
#define TAG_FCB 'BCFV'
|
||||
#define TAG_IRP 'PRIV'
|
||||
#define TAG_VFAT 'TAFV'
|
||||
#define TAG_CLOSE 'xtaF'
|
||||
|
||||
#define ENTRIES_PER_SECTOR (BLOCKSIZE / sizeof(FATDirEntry))
|
||||
|
||||
|
@ -588,6 +599,13 @@ typedef struct _VFAT_MOVE_CONTEXT
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue