2005-08-24 18:29:45 +00:00
|
|
|
/*
|
2022-09-24 13:24:08 +00:00
|
|
|
* PROJECT: VFAT Filesystem
|
|
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
|
|
* PURPOSE: Cleanup routines
|
|
|
|
* COPYRIGHT: Copyright 1998 Jason Filby <jasonfilby@yahoo.com>
|
|
|
|
* Copyright 2014-2018 Pierre Schweitzer <pierre@reactos.org>
|
2001-03-07 13:44:41 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
|
|
|
#include "vfat.h"
|
|
|
|
|
2013-12-19 16:20:28 +00:00
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
2001-03-07 13:44:41 +00:00
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION: Cleans up after a file has been closed.
|
2019-06-25 19:03:14 +00:00
|
|
|
* Returns whether the device was deleted
|
2001-03-07 13:44:41 +00:00
|
|
|
*/
|
2013-12-09 18:48:13 +00:00
|
|
|
static
|
2019-06-25 19:03:14 +00:00
|
|
|
BOOLEAN
|
2013-12-09 18:48:13 +00:00
|
|
|
VfatCleanupFile(
|
|
|
|
PVFAT_IRP_CONTEXT IrpContext)
|
2001-03-07 13:44:41 +00:00
|
|
|
{
|
2008-01-12 17:20:11 +00:00
|
|
|
PVFATFCB pFcb;
|
2017-05-02 19:33:14 +00:00
|
|
|
PVFATCCB pCcb;
|
2017-09-19 21:19:55 +00:00
|
|
|
BOOLEAN IsVolume;
|
2014-10-30 20:56:40 +00:00
|
|
|
PDEVICE_EXTENSION DeviceExt = IrpContext->DeviceExt;
|
2008-01-12 17:20:11 +00:00
|
|
|
PFILE_OBJECT FileObject = IrpContext->FileObject;
|
2019-06-25 19:03:14 +00:00
|
|
|
BOOLEAN Deleted = FALSE;
|
2008-01-12 17:20:11 +00:00
|
|
|
|
|
|
|
DPRINT("VfatCleanupFile(DeviceExt %p, FileObject %p)\n",
|
|
|
|
IrpContext->DeviceExt, FileObject);
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2008-01-12 17:20:11 +00:00
|
|
|
/* FIXME: handle file/directory deletion here */
|
2013-12-09 18:48:13 +00:00
|
|
|
pFcb = (PVFATFCB)FileObject->FsContext;
|
2008-01-12 17:20:11 +00:00
|
|
|
if (!pFcb)
|
2019-06-25 19:03:14 +00:00
|
|
|
return FALSE;
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2017-09-19 21:19:55 +00:00
|
|
|
IsVolume = BooleanFlagOn(pFcb->Flags, FCB_IS_VOLUME);
|
|
|
|
if (IsVolume)
|
2003-10-11 17:51:56 +00:00
|
|
|
{
|
2008-01-12 17:20:11 +00:00
|
|
|
pFcb->OpenHandleCount--;
|
2017-12-17 17:20:04 +00:00
|
|
|
DeviceExt->OpenHandleCount--;
|
2006-12-31 16:43:40 +00:00
|
|
|
|
2008-01-12 17:20:11 +00:00
|
|
|
if (pFcb->OpenHandleCount != 0)
|
|
|
|
{
|
|
|
|
IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-22 19:29:10 +00:00
|
|
|
ExAcquireResourceExclusiveLite(&pFcb->MainResource, TRUE);
|
|
|
|
ExAcquireResourceExclusiveLite(&pFcb->PagingIoResource, TRUE);
|
2008-01-12 17:20:11 +00:00
|
|
|
|
2017-05-02 19:33:14 +00:00
|
|
|
pCcb = FileObject->FsContext2;
|
|
|
|
if (BooleanFlagOn(pCcb->Flags, CCB_DELETE_ON_CLOSE))
|
|
|
|
{
|
|
|
|
pFcb->Flags |= FCB_DELETE_PENDING;
|
|
|
|
}
|
|
|
|
|
2014-03-12 19:58:11 +00:00
|
|
|
/* Notify about the cleanup */
|
|
|
|
FsRtlNotifyCleanup(IrpContext->DeviceExt->NotifySync,
|
|
|
|
&(IrpContext->DeviceExt->NotifyList),
|
|
|
|
FileObject->FsContext2);
|
|
|
|
|
2008-01-12 17:20:11 +00:00
|
|
|
pFcb->OpenHandleCount--;
|
2014-10-30 20:56:40 +00:00
|
|
|
DeviceExt->OpenHandleCount--;
|
2006-12-31 16:43:40 +00:00
|
|
|
|
2016-08-11 11:41:25 +00:00
|
|
|
if (!vfatFCBIsDirectory(pFcb) &&
|
2008-01-12 17:20:11 +00:00
|
|
|
FsRtlAreThereCurrentFileLocks(&pFcb->FileLock))
|
|
|
|
{
|
|
|
|
/* remove all locks this process have on this file */
|
|
|
|
FsRtlFastUnlockAll(&pFcb->FileLock,
|
|
|
|
FileObject,
|
|
|
|
IoGetRequestorProcess(IrpContext->Irp),
|
|
|
|
NULL);
|
|
|
|
}
|
2006-12-31 16:43:40 +00:00
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(pFcb->Flags, FCB_IS_DIRTY))
|
2008-01-12 17:20:11 +00:00
|
|
|
{
|
2018-05-18 12:03:20 +00:00
|
|
|
VfatUpdateEntry (DeviceExt, pFcb);
|
2008-01-12 17:20:11 +00:00
|
|
|
}
|
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
|
2008-01-12 17:29:26 +00:00
|
|
|
pFcb->OpenHandleCount == 0)
|
2008-01-12 17:20:11 +00:00
|
|
|
{
|
2016-08-11 11:41:25 +00:00
|
|
|
if (vfatFCBIsDirectory(pFcb) &&
|
2017-02-17 22:25:03 +00:00
|
|
|
!VfatIsDirectoryEmpty(DeviceExt, pFcb))
|
2006-12-31 16:43:40 +00:00
|
|
|
{
|
2016-08-11 11:41:25 +00:00
|
|
|
pFcb->Flags &= ~FCB_DELETE_PENDING;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PFILE_OBJECT tmpFileObject;
|
|
|
|
tmpFileObject = pFcb->FileObject;
|
|
|
|
if (tmpFileObject != NULL)
|
|
|
|
{
|
|
|
|
pFcb->FileObject = NULL;
|
|
|
|
CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
|
[FASTFAT] Don't leak directories FILE_OBJECT, FCB and cache entries.
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
2018-04-26 16:25:19 +00:00
|
|
|
ClearFlag(pFcb->Flags, FCB_CACHE_INITIALIZED);
|
2016-08-11 11:41:25 +00:00
|
|
|
ObDereferenceObject(tmpFileObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
pFcb->RFCB.ValidDataLength.QuadPart = 0;
|
|
|
|
pFcb->RFCB.FileSize.QuadPart = 0;
|
|
|
|
pFcb->RFCB.AllocationSize.QuadPart = 0;
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
2008-01-12 17:20:11 +00:00
|
|
|
}
|
2008-11-21 10:17:14 +00:00
|
|
|
|
2008-11-21 13:45:40 +00:00
|
|
|
/* Uninitialize the cache (should be done even if caching was never initialized) */
|
|
|
|
CcUninitializeCacheMap(FileObject, &pFcb->RFCB.FileSize, NULL);
|
2008-11-21 10:17:14 +00:00
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(pFcb->Flags, FCB_DELETE_PENDING) &&
|
2015-03-28 16:58:53 +00:00
|
|
|
pFcb->OpenHandleCount == 0)
|
|
|
|
{
|
|
|
|
VfatDelEntry(DeviceExt, pFcb, NULL);
|
|
|
|
|
2018-01-07 13:16:11 +00:00
|
|
|
vfatReportChange(DeviceExt,
|
|
|
|
pFcb,
|
2018-01-07 14:07:22 +00:00
|
|
|
(vfatFCBIsDirectory(pFcb) ?
|
|
|
|
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
|
2018-01-07 13:16:11 +00:00
|
|
|
FILE_ACTION_REMOVED);
|
2015-03-28 16:58:53 +00:00
|
|
|
}
|
|
|
|
|
2008-01-12 17:20:11 +00:00
|
|
|
if (pFcb->OpenHandleCount != 0)
|
|
|
|
{
|
|
|
|
IoRemoveShareAccess(FileObject, &pFcb->FCBShareAccess);
|
|
|
|
}
|
2018-08-20 17:43:43 +00:00
|
|
|
/* FIXME: causes FS corruption and breaks selfhosting/testbots and so on */
|
|
|
|
#if 0
|
[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
2018-08-18 15:04:02 +00:00
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
if ((vfatFCBIsDirectory(pFcb) && IsListEmpty(&pFcb->ParentListHead)) ||
|
|
|
|
(!vfatFCBIsDirectory(pFcb) && FileObject->SectionObjectPointer->DataSectionObject == NULL &&
|
|
|
|
FileObject->SectionObjectPointer->ImageSectionObject == NULL))
|
|
|
|
{
|
|
|
|
DPRINT("Delaying close of: %wZ\n", &pFcb->PathNameU);
|
|
|
|
SetFlag(pFcb->Flags, FCB_DELAYED_CLOSE);
|
|
|
|
}
|
|
|
|
}
|
2018-08-20 17:43:43 +00:00
|
|
|
#endif
|
2006-12-31 16:43:40 +00:00
|
|
|
|
2008-01-12 17:20:11 +00:00
|
|
|
FileObject->Flags |= FO_CLEANUP_COMPLETE;
|
2018-04-28 07:34:10 +00:00
|
|
|
#ifdef KDBG
|
|
|
|
pFcb->Flags |= FCB_CLEANED_UP;
|
|
|
|
#endif
|
2006-12-31 16:43:40 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
ExReleaseResourceLite(&pFcb->PagingIoResource);
|
|
|
|
ExReleaseResourceLite(&pFcb->MainResource);
|
2003-10-11 17:51:56 +00:00
|
|
|
}
|
2008-01-12 17:20:11 +00:00
|
|
|
|
2014-11-29 20:26:07 +00:00
|
|
|
#ifdef ENABLE_SWAPOUT
|
2017-09-19 21:19:55 +00:00
|
|
|
if (IsVolume && BooleanFlagOn(DeviceExt->Flags, VCB_DISMOUNT_PENDING))
|
2014-11-10 22:11:36 +00:00
|
|
|
{
|
2019-06-25 19:03:14 +00:00
|
|
|
Deleted = VfatCheckForDismount(DeviceExt, TRUE);
|
2014-11-10 22:11:36 +00:00
|
|
|
}
|
2014-11-29 20:26:07 +00:00
|
|
|
#endif
|
2014-11-10 22:11:36 +00:00
|
|
|
|
2019-06-25 19:03:14 +00:00
|
|
|
return Deleted;
|
2001-03-07 13:44:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION: Cleans up after a file has been closed.
|
|
|
|
*/
|
2013-12-09 18:48:13 +00:00
|
|
|
NTSTATUS
|
|
|
|
VfatCleanup(
|
|
|
|
PVFAT_IRP_CONTEXT IrpContext)
|
2001-03-07 13:44:41 +00:00
|
|
|
{
|
2019-06-25 19:03:14 +00:00
|
|
|
BOOLEAN Deleted;
|
2001-03-07 13:44:41 +00:00
|
|
|
|
2008-01-12 17:20:11 +00:00
|
|
|
DPRINT("VfatCleanup(DeviceObject %p, Irp %p)\n", IrpContext->DeviceObject, IrpContext->Irp);
|
2001-03-07 13:44:41 +00:00
|
|
|
|
2008-01-12 17:20:11 +00:00
|
|
|
if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
|
|
|
|
{
|
2015-05-15 16:03:29 +00:00
|
|
|
IrpContext->Irp->IoStatus.Information = 0;
|
|
|
|
return STATUS_SUCCESS;
|
2008-01-12 17:20:11 +00:00
|
|
|
}
|
2002-05-15 18:05:00 +00:00
|
|
|
|
2018-05-22 19:29:10 +00:00
|
|
|
ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE);
|
2019-06-25 19:03:14 +00:00
|
|
|
Deleted = VfatCleanupFile(IrpContext);
|
|
|
|
if (!Deleted) ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
|
2001-11-02 22:47:36 +00:00
|
|
|
|
2008-01-12 17:20:11 +00:00
|
|
|
IrpContext->Irp->IoStatus.Information = 0;
|
2019-06-25 19:03:14 +00:00
|
|
|
return STATUS_SUCCESS;
|
2001-03-07 13:44:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|