mirror of
https://github.com/reactos/reactos.git
synced 2024-07-06 04:35:07 +00:00
![Pierre Schweitzer](/assets/img/avatar_default.png)
Once a directory is crossed (opened or a child is opened), associated FCB structure is created in FastFAT, but also a stream FO for caching. Up to now, due to an extra reference taken by the stream file object, even when the directory was no longer used, the directory was kept in memory: the FCB was never deleted, the file object was never dereferenced, and the cache never released. The immediate effect of this bug is that our FAT driver was leaking every directory that was used affecting the whole OS situation. In case of directories intensive operation (like extraction the ReactOS source code in ReactOS ;-)), we were just killin the whole OS RAM without any way to release it and recover. The other side effects: IOs were faster as half of the FS was always permanant in RAM. This commit fixes the issue by forcing the FSD to release the FO, and the cache when a directory is no longer used, leading to its destruction in RAM. Downside: on IO intensive operation, expect slowdowns, obviously, there's less caching now. But more efficient! CORE-14557
193 lines
5.6 KiB
C
193 lines
5.6 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: drivers/fs/vfat/cleanup.c
|
|
* PURPOSE: VFAT Filesystem
|
|
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "vfat.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
/*
|
|
* FUNCTION: Cleans up after a file has been closed.
|
|
*/
|
|
static
|
|
NTSTATUS
|
|
VfatCleanupFile(
|
|
PVFAT_IRP_CONTEXT IrpContext)
|
|
{
|
|
PVFATFCB pFcb;
|
|
PVFATCCB pCcb;
|
|
BOOLEAN IsVolume;
|
|
PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
|
|
PFILE_OBJECT FileObject = IrpContext->FileObject;
|
|
|
|
DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n",
|
|
IrpContext->DeviceExt, FileObject);
|
|
|
|
/* FIXME: handle file/directory deletion here */
|
|
pFcb = (PVFATFCB)FileObject->FsContext;
|
|
if (!pFcb)
|
|
return STATUS_SUCCESS;
|
|
|
|
IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME);
|
|
if (IsVolume)
|
|
{
|
|
pFcb->OpenHandleCount--;
|
|
DeviceExt->OpenHandleCount--;
|
|
|
|
if (pFcb->OpenHandleCount != 0)
|
|
{
|
|
IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!ExAcquireResourceExclusiveLite(&pFcb->MainResource,
|
|
BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
|
|
{
|
|
return STATUS_PENDING;
|
|
}
|
|
if(!ExAcquireResourceExclusiveLite(&pFcb->PagingIoResource,
|
|
BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
|
|
{
|
|
ExReleaseResourceLite(&pFcb->MainResource);
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
pCcb = FileObject->FsContext2;
|
|
if (BooleanFlagOn(pCcb->Flags, CCB_DELETE_ON_CLOSE))
|
|
{
|
|
pFcb->Flags |= FCB_DELETE_PENDING;
|
|
}
|
|
|
|
/* Notify about the cleanup */
|
|
FsRtlNotifyCleanup(IrpContext->DeviceExt->NotifySync,
|
|
&(IrpContext->DeviceExt->NotifyList),
|
|
FileObject->FsContext2);
|
|
|
|
pFcb->OpenHandleCount--;
|
|
DeviceExt->OpenHandleCount--;
|
|
|
|
if (!vfatFCBIsDirectory(pFcb) &&
|
|
FsRtlAreThereCurrentFileLocks(&pFcb->FileLock))
|
|
{
|
|
/* remove all locks this process have on this file */
|
|
FsRtlFastUnlockAll(&pFcb->FileLock,
|
|
FileObject,
|
|
IoGetRequestorProcess(IrpContext->Irp),
|
|
NULL);
|
|
}
|
|
|
|
if (BooleanFlagOn(pFcb->Flags, FCB_IS_DIRTY))
|
|
{
|
|
VfatUpdateEntry (pFcb, vfatVolumeIsFatX(DeviceExt));
|
|
}
|
|
|
|
if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
|
|
pFcb->OpenHandleCount == 0)
|
|
{
|
|
if (vfatFCBIsDirectory(pFcb) &&
|
|
!VfatIsDirectoryEmpty(DeviceExt, pFcb))
|
|
{
|
|
pFcb->Flags &= ~FCB_DELETE_PENDING;
|
|
}
|
|
else
|
|
{
|
|
PFILE_OBJECT tmpFileObject;
|
|
tmpFileObject = pFcb->FileObject;
|
|
if (tmpFileObject != NULL)
|
|
{
|
|
pFcb->FileObject = NULL;
|
|
CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
|
|
ClearFlag(pFcb->Flags, FCB_CACHE_INITIALIZED);
|
|
ObDereferenceObject(tmpFileObject);
|
|
}
|
|
|
|
pFcb->RFCB.ValidDataLength.QuadPart = 0;
|
|
pFcb->RFCB.FileSize.QuadPart = 0;
|
|
pFcb->RFCB.AllocationSize.QuadPart = 0;
|
|
}
|
|
}
|
|
|
|
/* Uninitialize the cache (should be done even if caching was never initialized) */
|
|
CcUninitializeCacheMap(FileObject, &pFcb->RFCB.FileSize, NULL);
|
|
|
|
if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
|
|
pFcb->OpenHandleCount == 0)
|
|
{
|
|
VfatDelEntry(DeviceExt, pFcb, NULL);
|
|
|
|
vfatReportChange(DeviceExt,
|
|
pFcb,
|
|
(vfatFCBIsDirectory(pFcb) ?
|
|
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
|
|
FILE_ACTION_REMOVED);
|
|
}
|
|
|
|
if (pFcb->OpenHandleCount != 0)
|
|
{
|
|
IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
|
|
}
|
|
|
|
FileObject->Flags |= FO_CLEANUP_COMPLETE;
|
|
|
|
ExReleaseResourceLite(&pFcb->PagingIoResource);
|
|
ExReleaseResourceLite(&pFcb->MainResource);
|
|
}
|
|
|
|
#ifdef ENABLE_SWAPOUT
|
|
if (IsVolume && BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING))
|
|
{
|
|
VfatCheckForDismount(DeviceExt, FALSE);
|
|
}
|
|
#endif
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* FUNCTION: Cleans up after a file has been closed.
|
|
*/
|
|
NTSTATUS
|
|
VfatCleanup(
|
|
PVFAT_IRP_CONTEXT IrpContext)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("VfatCleanup(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
|
|
|
|
if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
|
|
{
|
|
IrpContext->Irp->IoStatus.Information = 0;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
|
|
BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
|
|
{
|
|
return VfatMarkIrpContextForQueue(IrpContext);
|
|
}
|
|
|
|
Status = VfatCleanupFile(IrpContext);
|
|
|
|
ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
return VfatMarkIrpContextForQueue(IrpContext);
|
|
}
|
|
|
|
IrpContext->Irp->IoStatus.Information = 0;
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|