[FASTFAT_NEW]

- Implement asynchronous and delayed close operations.
- Fix a logical bug in FatiClose code, which led to always closing the file object (and freeing respective FCB/VCB/CCB), and then checking flags and queuing a delayed close. Instead, it should only try to close if it's not marked as a delayed close.
- Support stuff added (queues, mutex for closing lists, etc).
- Misc cleanup, debug silencing.

svn path=/trunk/; revision=48525
This commit is contained in:
Aleksey Bragin 2010-08-12 21:59:22 +00:00
parent 8d3e4feb39
commit e68f31b46a
7 changed files with 366 additions and 46 deletions

View file

@ -11,6 +11,16 @@
#define NDEBUG
#include "fastfat.h"
VOID NTAPI
FatQueueClose(IN PCLOSE_CONTEXT CloseContext,
IN BOOLEAN DelayClose);
PCLOSE_CONTEXT NTAPI
FatRemoveClose(PVCB Vcb OPTIONAL,
PVCB LastVcbHint OPTIONAL);
const ULONG FatMaxDelayedCloseCount = 16;
/* FUNCTIONS ****************************************************************/
NTSTATUS
@ -246,8 +256,8 @@ FatiClose(IN PFAT_IRP_CONTEXT IrpContext,
PVCB Vcb;
PFCB Fcb;
PCCB Ccb;
BOOLEAN TopLevel, Wait, VcbDeleted = FALSE;
NTSTATUS Status;
BOOLEAN TopLevel, Wait, VcbDeleted = FALSE, DelayedClose = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
PCLOSE_CONTEXT CloseContext = NULL;
TopLevel = FatIsTopLevelIrp(Irp);
@ -265,16 +275,57 @@ FatiClose(IN PFAT_IRP_CONTEXT IrpContext,
/* It's possible to wait only if we are top level or not a system process */
Wait = TopLevel && (PsGetCurrentProcess() != FatGlobalData.SystemProcess);
/* Call the common handler */
Status = FatiCommonClose(Vcb, Fcb, Ccb, TypeOfOpen, Wait, &VcbDeleted);
if (((TypeOfOpen == UserFileOpen ||
TypeOfOpen == UserDirectoryOpen) &&
/* Determine if it's a delayed close, by flags first */
if ((TypeOfOpen == UserFileOpen || TypeOfOpen == UserDirectoryOpen) &&
(Fcb->State & FCB_STATE_DELAY_CLOSE) &&
!FatGlobalData.ShutdownStarted) ||
Status == STATUS_PENDING)
!FatGlobalData.ShutdownStarted)
{
DPRINT1("TODO: Queue a pending close request\n");
DelayedClose = TRUE;
}
/* If close is not delayed, try to perform the close operation */
if (!DelayedClose)
Status = FatiCommonClose(Vcb, Fcb, Ccb, TypeOfOpen, Wait, &VcbDeleted);
/* We have to delay close if either it's defined by a flag or it was not possible
to perform it synchronously */
if (DelayedClose || Status == STATUS_PENDING)
{
DPRINT1("Queuing a pending close, Vcb %p, Fcb %p, Ccb %p\n", Vcb, Fcb, Ccb);
/* Check if a close context should be allocated */
if (TypeOfOpen == VirtualVolumeFile)
{
ASSERT(Vcb->CloseContext != NULL);
CloseContext = Vcb->CloseContext;
Vcb->CloseContext = NULL;
CloseContext->Free = TRUE;
}
else if (TypeOfOpen == DirectoryFile ||
TypeOfOpen == EaFile)
{
UNIMPLEMENTED;
//CloseContext = FatAllocateCloseContext(Vcb);
//ASSERT(CloseContext != NULL);
CloseContext->Free = TRUE;
}
else
{
//TODO: FatDeallocateCcbStrings( Ccb );
/* Set CloseContext to a buffer inside Ccb */
CloseContext = &Ccb->CloseContext;
CloseContext->Free = FALSE;
SetFlag(Ccb->Flags, CCB_CLOSE_CONTEXT);
}
/* Save all info in the close context */
CloseContext->Vcb = Vcb;
CloseContext->Fcb = Fcb;
CloseContext->TypeOfOpen = TypeOfOpen;
/* Queue the close */
FatQueueClose(CloseContext, (BOOLEAN)(Fcb && FlagOn(Fcb->State, FCB_STATE_DELAY_CLOSE)));
}
else
{
@ -351,4 +402,250 @@ FatClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
return Status;
}
VOID
NTAPI
FatPendingClose(IN PVCB Vcb OPTIONAL)
{
PCLOSE_CONTEXT CloseContext;
PVCB CurrentVcb = NULL;
PVCB LastVcb = NULL;
BOOLEAN FreeContext;
ULONG Loops = 0;
/* Do the top-level IRP trick */
if (!Vcb) IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
while ((CloseContext = FatRemoveClose(Vcb, LastVcb)))
{
if (!Vcb)
{
if (!FatGlobalData.ShutdownStarted)
{
if (CloseContext->Vcb != CurrentVcb)
{
Loops = 0;
/* Release previous VCB */
if (CurrentVcb)
ExReleaseResourceLite(&CurrentVcb->Resource);
/* Lock the new VCB */
CurrentVcb = CloseContext->Vcb;
(VOID)ExAcquireResourceExclusiveLite(&CurrentVcb->Resource, TRUE);
}
else
{
/* Try to lock */
if (++Loops >= 20)
{
if (ExGetSharedWaiterCount(&CurrentVcb->Resource) +
ExGetExclusiveWaiterCount(&CurrentVcb->Resource))
{
ExReleaseResourceLite(&CurrentVcb->Resource);
(VOID)ExAcquireResourceExclusiveLite(&CurrentVcb->Resource, TRUE);
}
Loops = 0;
}
}
/* Check open count */
if (CurrentVcb->OpenFileCount <= 1)
{
ExReleaseResourceLite(&CurrentVcb->Resource);
CurrentVcb = NULL;
}
}
else if (CurrentVcb)
{
ExReleaseResourceLite(&CurrentVcb->Resource);
CurrentVcb = NULL;
}
}
LastVcb = CurrentVcb;
/* Remember if we should free the context */
FreeContext = CloseContext->Free;
FatiCommonClose(CloseContext->Vcb,
CloseContext->Fcb,
(FreeContext ? NULL : CONTAINING_RECORD(CloseContext, CCB, CloseContext)),
CloseContext->TypeOfOpen,
TRUE,
NULL);
/* Free context if necessary */
if (FreeContext) ExFreePool(CloseContext);
}
/* Release VCB if necessary */
if (CurrentVcb) ExReleaseResourceLite(&CurrentVcb->Resource);
/* Reset top level IRP */
if (!Vcb) IoSetTopLevelIrp( NULL );
}
VOID
NTAPI
FatCloseWorker(IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context)
{
FsRtlEnterFileSystem();
FatPendingClose((PVCB)Context);
FsRtlExitFileSystem();
}
VOID
NTAPI
FatQueueClose(IN PCLOSE_CONTEXT CloseContext,
IN BOOLEAN DelayClose)
{
BOOLEAN RunWorker = FALSE;
/* Acquire the close lists mutex */
ExAcquireFastMutexUnsafe(&FatCloseQueueMutex);
/* Add it to the desired list */
if (DelayClose)
{
InsertTailList(&FatGlobalData.DelayedCloseList,
&CloseContext->GlobalLinks);
InsertTailList(&CloseContext->Vcb->DelayedCloseList,
&CloseContext->VcbLinks);
FatGlobalData.DelayedCloseCount++;
if (FatGlobalData.DelayedCloseCount > FatMaxDelayedCloseCount &&
!FatGlobalData.AsyncCloseActive)
{
FatGlobalData.AsyncCloseActive = TRUE;
RunWorker = TRUE;
}
}
else
{
InsertTailList(&FatGlobalData.AsyncCloseList,
&CloseContext->GlobalLinks);
InsertTailList(&CloseContext->Vcb->AsyncCloseList,
&CloseContext->VcbLinks);
FatGlobalData.AsyncCloseCount++;
if (!FatGlobalData.AsyncCloseActive)
{
FatGlobalData.AsyncCloseActive = TRUE;
RunWorker = TRUE;
}
}
/* Release the close lists mutex */
ExReleaseFastMutexUnsafe(&FatCloseQueueMutex);
if (RunWorker)
IoQueueWorkItem(FatGlobalData.FatCloseItem, FatCloseWorker, CriticalWorkQueue, NULL);
}
PCLOSE_CONTEXT
NTAPI
FatRemoveClose(PVCB Vcb OPTIONAL,
PVCB LastVcbHint OPTIONAL)
{
PLIST_ENTRY Entry;
PCLOSE_CONTEXT CloseContext;
BOOLEAN IsWorker = FALSE;
/* Acquire the close lists mutex */
ExAcquireFastMutexUnsafe(&FatCloseQueueMutex);
if (!Vcb) IsWorker = TRUE;
if (Vcb == NULL && LastVcbHint != NULL)
{
// TODO: A very special case of overflowing the queue
UNIMPLEMENTED;
}
/* Usual processing from a worker thread */
if (!Vcb)
{
TryToCloseAgain:
/* Is there anything in the async close list */
if (!IsListEmpty(&FatGlobalData.AsyncCloseList))
{
Entry = RemoveHeadList(&FatGlobalData.AsyncCloseList);
FatGlobalData.AsyncCloseCount--;
CloseContext = CONTAINING_RECORD(Entry,
CLOSE_CONTEXT,
GlobalLinks);
RemoveEntryList(&CloseContext->VcbLinks);
} else if (!IsListEmpty(&FatGlobalData.DelayedCloseList) &&
(FatGlobalData.DelayedCloseCount > FatMaxDelayedCloseCount/2 ||
FatGlobalData.ShutdownStarted))
{
/* In case of a shutdown or when delayed queue is filled at half - perform closing */
Entry = RemoveHeadList(&FatGlobalData.DelayedCloseList);
FatGlobalData.DelayedCloseCount--;
CloseContext = CONTAINING_RECORD(Entry,
CLOSE_CONTEXT,
GlobalLinks);
RemoveEntryList(&CloseContext->VcbLinks);
}
else
{
/* Nothing to close */
CloseContext = NULL;
if (IsWorker) FatGlobalData.AsyncCloseActive = FALSE;
}
}
else
{
if (!IsListEmpty(&Vcb->AsyncCloseList))
{
/* Is there anything in the async close list */
Entry = RemoveHeadList(&Vcb->AsyncCloseList);
FatGlobalData.AsyncCloseCount--;
CloseContext = CONTAINING_RECORD(Entry,
CLOSE_CONTEXT,
VcbLinks);
RemoveEntryList(&CloseContext->GlobalLinks);
}
else if (!IsListEmpty(&Vcb->DelayedCloseList))
{
/* Process delayed close list */
Entry = RemoveHeadList(&Vcb->DelayedCloseList);
FatGlobalData.DelayedCloseCount--;
CloseContext = CONTAINING_RECORD(Entry,
CLOSE_CONTEXT,
VcbLinks);
RemoveEntryList(&CloseContext->GlobalLinks);
}
else if (LastVcbHint)
{
/* Try again */
goto TryToCloseAgain;
}
else
{
/* Nothing to close */
CloseContext = NULL;
}
}
/* Release the close lists mutex */
ExReleaseFastMutexUnsafe(&FatCloseQueueMutex);
return CloseContext;
}
/* EOF */

View file

@ -111,13 +111,6 @@ FatCreateRootDcb(IN PFAT_IRP_CONTEXT IrpContext,
#endif
UNIMPLEMENTED;
}
/* Initialize free dirent bitmap */
RtlInitializeBitMap(&Dcb->Dcb.FreeBitmap, NULL, 0);
/* Fill the dirent bitmap */
DPRINT1("Filling the free dirent bitmap is missing\n");
//FatCheckFreeDirentBitmap( IrpContext, Dcb );
}
PFCB

View file

@ -14,6 +14,7 @@
/* GLOBALS ******************************************************************/
FAT_GLOBAL_DATA FatGlobalData;
FAST_MUTEX FatCloseQueueMutex;
/* FUNCTIONS ****************************************************************/
@ -109,6 +110,12 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
/* Initialize synchronization resource for the global data */
ExInitializeResourceLite(&FatGlobalData.Resource);
/* Initialize queued close stuff */
InitializeListHead(&FatGlobalData.AsyncCloseList);
InitializeListHead(&FatGlobalData.DelayedCloseList);
FatGlobalData.FatCloseItem = IoAllocateWorkItem(DeviceObject);
ExInitializeFastMutex(&FatCloseQueueMutex);
/* Initialize global VCB list */
InitializeListHead(&FatGlobalData.VcbListHead);

View file

@ -16,6 +16,7 @@
#define TAG_FCB 'BCFV'
#define TAG_IRP 'PRIV'
#define TAG_VFAT 'TAFV'
#define TAG_FSD_CLOSE_CONTEXT 'CLCV'
/* Global resource acquire/release */
@ -183,6 +184,8 @@ FatNoopRelease(IN PVOID Context);
/* --------------------------------------------------------- fastfat.c */
extern FAST_MUTEX FatCloseQueueMutex;
PFAT_IRP_CONTEXT NTAPI
FatBuildIrpContext(PIRP Irp, BOOLEAN CanWait);

View file

@ -163,6 +163,10 @@ FatInitializeVcb(IN PFAT_IRP_CONTEXT IrpContext,
/* Initialize VCB's resource */
ExInitializeResourceLite(&Vcb->Resource);
/* Initialize close queue lists */
InitializeListHead(&Vcb->AsyncCloseList);
InitializeListHead(&Vcb->DelayedCloseList);
/* Initialize CC */
CcInitializeCacheMap(Vcb->StreamFileObject,
(PCC_FILE_SIZES)&Vcb->Header.AllocationSize,
@ -243,6 +247,9 @@ FatUninitializeVcb(IN PVCB Vcb)
Vcb->StreamFileObject = NULL;
}
/* Free ContextClose if it's not freed up already */
if (Vcb->CloseContext) ExFreePool(Vcb->CloseContext);
/* Free notifications stuff */
FsRtlNotifyUninitializeSync(&Vcb->NotifySync);

View file

@ -39,6 +39,16 @@ typedef struct _FAT_GLOBAL_DATA
/* Jan 1, 1980 System Time */
LARGE_INTEGER DefaultFileTime;
/* Queued close */
ULONG AsyncCloseCount;
ULONG DelayedCloseCount;
LIST_ENTRY AsyncCloseList;
LIST_ENTRY DelayedCloseList;
PIO_WORKITEM FatCloseItem;
/* Various flags */
BOOLEAN AsyncCloseActive;
/* FullFAT integration */
FF_IOMAN *Ioman;
FF_ERROR FF_Error;
@ -171,6 +181,8 @@ typedef struct _VCB
VCB_CONDITION Condition;
ERESOURCE Resource;
struct _CLOSE_CONTEXT *CloseContext;
LIST_ENTRY AsyncCloseList;
LIST_ENTRY DelayedCloseList;
/* Direct volume access */
SHARE_ACCESS ShareAccess;
@ -239,6 +251,18 @@ typedef struct _VOLUME_DEVICE_OBJECT
VCB Vcb; /* Must be the last entry! */
};
} VOLUME_DEVICE_OBJECT, *PVOLUME_DEVICE_OBJECT;
typedef enum _TYPE_OF_OPEN
{
UnopenedFileObject,
UserFileOpen,
UserDirectoryOpen,
UserVolumeOpen,
VirtualVolumeFile,
DirectoryFile,
EaFile
} TYPE_OF_OPEN;
//
// Short name always exists in FAT
//
@ -342,8 +366,6 @@ typedef struct _FCB
PFILE_OBJECT DirectoryFile;
/* Directory data stream (just handy to have it). */
//PFILE_OBJECT StreamFileObject;
/* Bitmap to search for free dirents. */
RTL_BITMAP FreeBitmap;
/* Names */
PRTL_SPLAY_LINKS SplayLinksAnsi;
PRTL_SPLAY_LINKS SplayLinksUnicode;
@ -388,28 +410,6 @@ typedef struct _FAT_FIND_DIRENT_CONTEXT
BOOLEAN Valid8dot3Name;
} FAT_FIND_DIRENT_CONTEXT, *PFAT_FIND_DIRENT_CONTEXT;
typedef struct _CCB
{
CSHORT NodeTypeCode;
CSHORT NodeByteSize;
LARGE_INTEGER CurrentByteOffset;
ULONG Entry;
UNICODE_STRING SearchPattern;
UCHAR Flags;
} CCB, *PCCB;
typedef enum _TYPE_OF_OPEN
{
UnopenedFileObject,
UserFileOpen,
UserDirectoryOpen,
UserVolumeOpen,
VirtualVolumeFile,
DirectoryFile,
EaFile
} TYPE_OF_OPEN;
typedef struct _CLOSE_CONTEXT
{
LIST_ENTRY GlobalLinks;
@ -421,6 +421,18 @@ typedef struct _CLOSE_CONTEXT
BOOLEAN Free;
} CLOSE_CONTEXT, *PCLOSE_CONTEXT;
typedef struct _CCB
{
CSHORT NodeTypeCode;
CSHORT NodeByteSize;
LARGE_INTEGER CurrentByteOffset;
ULONG Entry;
UNICODE_STRING SearchPattern;
UCHAR Flags;
CLOSE_CONTEXT CloseContext;
} CCB, *PCCB;
typedef enum _FILE_TIME_INDEX
{
FileCreationTime = 0,
@ -432,9 +444,10 @@ typedef enum _FILE_TIME_INDEX
#define CCB_SEARCH_RETURN_SINGLE_ENTRY 0x01
#define CCB_SEARCH_PATTERN_LEGAL_8DOT3 0x02
#define CCB_SEARCH_PATTERN_HAS_WILD_CARD 0x04
#define CCB_DASD_IO 0x10
#define CCB_READ_ONLY 0x20
#define CCB_DELETE_ON_CLOSE 0x40
#define CCB_COMPLETE_DISMOUNT 0x80
#define CCB_DASD_IO 0x08
#define CCB_READ_ONLY 0x10
#define CCB_DELETE_ON_CLOSE 0x20
#define CCB_COMPLETE_DISMOUNT 0x40
#define CCB_CLOSE_CONTEXT 0x80
extern FAT_GLOBAL_DATA FatGlobalData;

View file

@ -171,7 +171,7 @@ FatUserFsCtrl(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
break;
default:
DPRINT1("FatUserFsCtrl(), unhandled fs control code 0x%x\n", Code);
DPRINT("FatUserFsCtrl(), unhandled fs control code 0x%x\n", Code);
Status = STATUS_INVALID_DEVICE_REQUEST;
FatCompleteRequest(IrpContext, Irp, Status);
}