https://git.reactos.org/?p=reactos.git;a=commitdiff;h=195dc3048464db0ff58954d3920d1759230dec3c

commit 195dc3048464db0ff58954d3920d1759230dec3c
Author:     Victor Perevertkin <[email protected]>
AuthorDate: Tue Jul 9 17:22:28 2019 +0300
Commit:     Victor Perevertkin <[email protected]>
CommitDate: Sun Sep 29 13:24:31 2019 +0300

    [FREELDR] Add FAT caching to FAT filesystem driver.
    This significantly increases the reading speed
---
 boot/freeldr/freeldr/lib/fs/fat.c | 145 +++++++++++++++++++++++++++-----------
 1 file changed, 102 insertions(+), 43 deletions(-)

diff --git a/boot/freeldr/freeldr/lib/fs/fat.c 
b/boot/freeldr/freeldr/lib/fs/fat.c
index f16f03a57e1..b973a64dd70 100644
--- a/boot/freeldr/freeldr/lib/fs/fat.c
+++ b/boot/freeldr/freeldr/lib/fs/fat.c
@@ -39,21 +39,27 @@ BOOLEAN    FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, 
ULONG SectorNumber, ULO
 #define TAG_FAT_FILE 'FtaF'
 #define TAG_FAT_VOLUME 'VtaF'
 #define TAG_FAT_BUFFER 'BtaF'
+#define TAG_FAT_CACHE 'HtaF'
+
+#define FAT_MAX_CACHE_SIZE (256 * 1024) // 256 KiB, note: it should fit 
maximum FAT12 FAT size (6144 bytes)
 
 typedef struct _FAT_VOLUME_INFO
 {
-    ULONG BytesPerSector; /* Number of bytes per sector */
-    ULONG SectorsPerCluster; /* Number of sectors per cluster */
+    PUCHAR FatCache; /* A part of 1st FAT cached in memory */
+    PULONG FatCacheIndex; /* Cached sector's indexes */
+    ULONG FatCacheSize; /* Size of the cache in sectors */
     ULONG FatSectorStart; /* Starting sector of 1st FAT table */
     ULONG ActiveFatSectorStart; /* Starting sector of active FAT table */
-    ULONG NumberOfFats; /* Number of FAT tables */
     ULONG SectorsPerFat; /* Sectors per FAT table */
     ULONG RootDirSectorStart; /* Starting sector of the root directory 
(non-fat32) */
     ULONG RootDirSectors; /* Number of sectors of the root directory 
(non-fat32) */
     ULONG RootDirStartCluster; /* Starting cluster number of the root 
directory (fat32 only) */
     ULONG DataSectorStart; /* Starting sector of the data area */
-    ULONG FatType; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
     ULONG DeviceId;
+    UINT16 BytesPerSector; /* Number of bytes per sector */
+    UINT8 FatType; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
+    UINT8 NumberOfFats; /* Number of FAT tables */
+    UINT8 SectorsPerCluster; /* Number of sectors per cluster */
 } FAT_VOLUME_INFO;
 
 PFAT_VOLUME_INFO FatVolumes[MAX_FDS];
@@ -139,7 +145,7 @@ VOID FatSwapFatXDirEntry(PFATX_DIRENTRY Obj)
 BOOLEAN FatOpenVolume(PFAT_VOLUME_INFO Volume, PFAT_BOOTSECTOR BootSector, 
ULONGLONG PartitionSectorCount)
 {
     char ErrMsg[80];
-    ULONG FatSize;
+    ULONG FatSize, i;
     PFAT_BOOTSECTOR    FatVolumeBootSector;
     PFAT32_BOOTSECTOR Fat32VolumeBootSector;
     PFATX_BOOTSECTOR FatXVolumeBootSector;
@@ -315,6 +321,39 @@ BOOLEAN FatOpenVolume(PFAT_VOLUME_INFO Volume, 
PFAT_BOOTSECTOR BootSector, ULONG
         }
     }
 
+    Volume->FatCacheSize = min(Volume->SectorsPerFat, FAT_MAX_CACHE_SIZE / 
Volume->BytesPerSector);
+    TRACE("FAT cache is %d sectors, %d bytes\n", Volume->FatCacheSize, 
Volume->FatCacheSize * Volume->BytesPerSector);
+
+    Volume->FatCache = FrLdrTempAlloc(Volume->FatCacheSize * 
Volume->BytesPerSector, TAG_FAT_CACHE);
+    if (!Volume->FatCache)
+    {
+        FileSystemError("Cannot allocate memory for FAT cache");
+        return FALSE;
+    }
+
+    Volume->FatCacheIndex = FrLdrTempAlloc(Volume->FatCacheSize * 
sizeof(*Volume->FatCacheIndex), TAG_FAT_VOLUME);
+    if (!Volume->FatCacheIndex)
+    {
+        FileSystemError("Cannot allocate memory for FAT cache index");
+        FrLdrTempFree(Volume->FatCache, TAG_FAT_CACHE);
+        return FALSE;
+    }
+
+    // read the beginning of the FAT (or the whole one) to cache
+    if (!FatReadVolumeSectors(Volume, Volume->ActiveFatSectorStart, 
Volume->FatCacheSize, Volume->FatCache))
+    {
+        FileSystemError("Error when reading FAT cache");
+        FrLdrTempFree(Volume->FatCache, TAG_FAT_CACHE);
+        FrLdrTempFree(Volume->FatCacheIndex, TAG_FAT_VOLUME);
+        return FALSE;
+    }
+
+    // fill the index with sector numbers
+    for (i = 0; i < Volume->FatCacheSize; i++)
+    {
+        Volume->FatCacheIndex[i] = Volume->ActiveFatSectorStart + i;
+    }
+
     return TRUE;
 }
 
@@ -899,54 +938,76 @@ void FatParseShortFileName(PCHAR Buffer, PDIRENTRY 
DirEntry)
     //TRACE("FatParseShortFileName() ShortName = %s\n", Buffer);
 }
 
+/**
+ * @brief Reads 1-4 sectors from FAT using the cache
+ */
+static
+PUCHAR FatGetFatSector(PFAT_VOLUME_INFO Volume, UINT32 FatSectorNumber)
+{
+    UINT32 SectorNumAbsolute = Volume->ActiveFatSectorStart + FatSectorNumber;
+    UINT32 CacheIndex = FatSectorNumber % Volume->FatCacheSize;
+
+    ASSERT(FatSectorNumber < Volume->SectorsPerFat);
+
+    // cache miss
+    if (Volume->FatCacheIndex[CacheIndex] != SectorNumAbsolute)
+    {
+        UINT32 SectorsToRead = min(Volume->FatCacheSize - CacheIndex, 
min(Volume->SectorsPerFat - SectorNumAbsolute, 4));
+        UINT8 i;
+
+        if (!FatReadVolumeSectors(Volume, SectorNumAbsolute, SectorsToRead, 
&Volume->FatCache[CacheIndex * Volume->BytesPerSector]))
+        {
+            return NULL;
+        }
+
+        for (i = 0; i < SectorsToRead; i++)
+        {
+            Volume->FatCacheIndex[CacheIndex + i] = SectorNumAbsolute + i; 
+        }
+
+        TRACE("FAT cache miss: read sector 0x%x from disk\n", 
SectorNumAbsolute);
+    }
+    else
+    {
+        TRACE("FAT cache hit: sector 0x%x present\n", SectorNumAbsolute);
+    }
+
+    return &Volume->FatCache[CacheIndex * Volume->BytesPerSector];
+}
+
 /*
  * FatGetFatEntry()
  * returns the Fat entry for a given cluster number
  */
 BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* 
ClusterPointer)
 {
-    ULONG        fat = 0;
-    UINT32        FatOffset;
-    UINT32        ThisFatSecNum;
-    UINT32        ThisFatEntOffset;
-    ULONG SectorCount;
+    UINT32 FatOffset, ThisFatSecNum, ThisFatEntOffset, fat;
     PUCHAR ReadBuffer;
-    BOOLEAN Success = TRUE;
 
-    //TRACE("FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", 
Cluster);
-
-    // We need a buffer for 2 sectors
-    ReadBuffer = FrLdrTempAlloc(2 * Volume->BytesPerSector, TAG_FAT_BUFFER);
-    if (!ReadBuffer)
-    {
-        return FALSE;
-    }
+    TRACE("FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster);
 
     switch(Volume->FatType)
     {
     case FAT12:
 
         FatOffset = Cluster + (Cluster / 2);
-        ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / 
Volume->BytesPerSector);
+        ThisFatSecNum = FatOffset / Volume->BytesPerSector;
         ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
 
         TRACE("FatOffset: %d\n", FatOffset);
         TRACE("ThisFatSecNum: %d\n", ThisFatSecNum);
         TRACE("ThisFatEntOffset: %d\n", ThisFatEntOffset);
 
-        if (ThisFatEntOffset == (Volume->BytesPerSector - 1))
-        {
-            SectorCount = 2;
-        }
-        else
-        {
-            SectorCount = 1;
-        }
+        // The cluster pointer can span within two sectors, but the 
FatGetFatSector function
+        // reads 4 sectors most times, except when we are at the edge of FAT 
cache
+        // and/or FAT region on the disk. For FAT12 the whole FAT would be 
cached so
+        // there will be no situation when the first sector is at the end of 
the cache
+        // and the next one is in the beginning
 
-        if (!FatReadVolumeSectors(Volume, ThisFatSecNum, SectorCount, 
ReadBuffer))
+        ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
+        if (!ReadBuffer)
         {
-            Success = FALSE;
-            break;
+            return FALSE;
         }
 
         fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
@@ -962,13 +1023,13 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG 
Cluster, ULONG* ClusterPoi
     case FATX16:
 
         FatOffset = (Cluster * 2);
-        ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / 
Volume->BytesPerSector);
+        ThisFatSecNum = FatOffset / Volume->BytesPerSector;
         ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
 
-        if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, ReadBuffer))
+        ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
+        if (!ReadBuffer)
         {
-            Success = FALSE;
-            break;
+            return FALSE;
         }
 
         fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
@@ -980,10 +1041,11 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG 
Cluster, ULONG* ClusterPoi
     case FATX32:
 
         FatOffset = (Cluster * 4);
-        ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / 
Volume->BytesPerSector);
+        ThisFatSecNum = FatOffset / Volume->BytesPerSector;
         ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
 
-        if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, ReadBuffer))
+        ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
+        if (!ReadBuffer)
         {
             Success = FALSE;
             break;
@@ -997,17 +1059,14 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG 
Cluster, ULONG* ClusterPoi
 
     default:
         ERR("Unknown FAT type %d\n", Volume->FatType);
-        Success = FALSE;
-        break;
+        return FALSE;
     }
 
-    //TRACE("FAT entry is 0x%x.\n", fat);
-
-    FrLdrTempFree(ReadBuffer, TAG_FAT_BUFFER);
+    TRACE("FAT entry is 0x%x.\n", fat);
 
     *ClusterPointer = fat;
 
-    return Success;
+    return TRUE;
 }
 
 ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster)

Reply via email to