Author: fireball Date: Thu Aug 12 21:59:22 2010 New Revision: 48525
URL: http://svn.reactos.org/svn/reactos?rev=48525&view=rev Log: [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.
Modified: trunk/reactos/drivers/filesystems/fastfat_new/close.c trunk/reactos/drivers/filesystems/fastfat_new/dir.c trunk/reactos/drivers/filesystems/fastfat_new/fastfat.c trunk/reactos/drivers/filesystems/fastfat_new/fastfat.h trunk/reactos/drivers/filesystems/fastfat_new/fat.c trunk/reactos/drivers/filesystems/fastfat_new/fatstruc.h trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c
Modified: trunk/reactos/drivers/filesystems/fastfat_new/close.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/close.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/close.c [iso-8859-1] Thu Aug 12 21:59:22 2010 @@ -10,6 +10,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 ****************************************************************/
@@ -246,8 +256,8 @@ 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 @@ /* 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) - { - DPRINT1("TODO: Queue a pending close request\n"); + !FatGlobalData.ShutdownStarted) + { + 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 @@ 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 */
Modified: trunk/reactos/drivers/filesystems/fastfat_new/dir.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/dir.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/dir.c [iso-8859-1] Thu Aug 12 21:59:22 2010 @@ -111,13 +111,6 @@ #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
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fastfat.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fastfat.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fastfat.c [iso-8859-1] Thu Aug 12 21:59:22 2010 @@ -14,6 +14,7 @@ /* GLOBALS ******************************************************************/
FAT_GLOBAL_DATA FatGlobalData; +FAST_MUTEX FatCloseQueueMutex;
/* FUNCTIONS ****************************************************************/
@@ -109,6 +110,12 @@ /* 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);
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fastfat.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fastfat.h [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fastfat.h [iso-8859-1] Thu Aug 12 21:59:22 2010 @@ -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 */ @@ -182,6 +183,8 @@ FatNoopRelease(IN PVOID Context);
/* --------------------------------------------------------- fastfat.c */ + +extern FAST_MUTEX FatCloseQueueMutex;
PFAT_IRP_CONTEXT NTAPI FatBuildIrpContext(PIRP Irp, BOOLEAN CanWait);
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fat.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fat.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fat.c [iso-8859-1] Thu Aug 12 21:59:22 2010 @@ -163,6 +163,10 @@ /* 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 @@ Vcb->StreamFileObject = NULL; }
+ /* Free ContextClose if it's not freed up already */ + if (Vcb->CloseContext) ExFreePool(Vcb->CloseContext); + /* Free notifications stuff */ FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fatstruc.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fatstruc.h [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fatstruc.h [iso-8859-1] Thu Aug 12 21:59:22 2010 @@ -39,6 +39,16 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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;
Modified: trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/filesystems/fastfat... ============================================================================== --- trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c [iso-8859-1] (original) +++ trunk/reactos/drivers/filesystems/fastfat_new/fsctl.c [iso-8859-1] Thu Aug 12 21:59:22 2010 @@ -171,7 +171,7 @@ 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); }