mirror of
https://github.com/reactos/reactos.git
synced 2025-06-03 00:10:39 +00:00
[FREELDR] Add FAT caching to FAT filesystem driver.
This significantly increases the reading speed
This commit is contained in:
parent
be1f95527a
commit
195dc30484
1 changed files with 102 additions and 43 deletions
|
@ -39,21 +39,27 @@ BOOLEAN FatReadVolumeSectors(PFAT_VOLUME_INFO Volume, ULONG SectorNumber, ULO
|
||||||
#define TAG_FAT_FILE 'FtaF'
|
#define TAG_FAT_FILE 'FtaF'
|
||||||
#define TAG_FAT_VOLUME 'VtaF'
|
#define TAG_FAT_VOLUME 'VtaF'
|
||||||
#define TAG_FAT_BUFFER 'BtaF'
|
#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
|
typedef struct _FAT_VOLUME_INFO
|
||||||
{
|
{
|
||||||
ULONG BytesPerSector; /* Number of bytes per sector */
|
PUCHAR FatCache; /* A part of 1st FAT cached in memory */
|
||||||
ULONG SectorsPerCluster; /* Number of sectors per cluster */
|
PULONG FatCacheIndex; /* Cached sector's indexes */
|
||||||
|
ULONG FatCacheSize; /* Size of the cache in sectors */
|
||||||
ULONG FatSectorStart; /* Starting sector of 1st FAT table */
|
ULONG FatSectorStart; /* Starting sector of 1st FAT table */
|
||||||
ULONG ActiveFatSectorStart; /* Starting sector of active FAT table */
|
ULONG ActiveFatSectorStart; /* Starting sector of active FAT table */
|
||||||
ULONG NumberOfFats; /* Number of FAT tables */
|
|
||||||
ULONG SectorsPerFat; /* Sectors per FAT table */
|
ULONG SectorsPerFat; /* Sectors per FAT table */
|
||||||
ULONG RootDirSectorStart; /* Starting sector of the root directory (non-fat32) */
|
ULONG RootDirSectorStart; /* Starting sector of the root directory (non-fat32) */
|
||||||
ULONG RootDirSectors; /* Number of sectors 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 RootDirStartCluster; /* Starting cluster number of the root directory (fat32 only) */
|
||||||
ULONG DataSectorStart; /* Starting sector of the data area */
|
ULONG DataSectorStart; /* Starting sector of the data area */
|
||||||
ULONG FatType; /* FAT12, FAT16, FAT32, FATX16 or FATX32 */
|
|
||||||
ULONG DeviceId;
|
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;
|
} FAT_VOLUME_INFO;
|
||||||
|
|
||||||
PFAT_VOLUME_INFO FatVolumes[MAX_FDS];
|
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)
|
BOOLEAN FatOpenVolume(PFAT_VOLUME_INFO Volume, PFAT_BOOTSECTOR BootSector, ULONGLONG PartitionSectorCount)
|
||||||
{
|
{
|
||||||
char ErrMsg[80];
|
char ErrMsg[80];
|
||||||
ULONG FatSize;
|
ULONG FatSize, i;
|
||||||
PFAT_BOOTSECTOR FatVolumeBootSector;
|
PFAT_BOOTSECTOR FatVolumeBootSector;
|
||||||
PFAT32_BOOTSECTOR Fat32VolumeBootSector;
|
PFAT32_BOOTSECTOR Fat32VolumeBootSector;
|
||||||
PFATX_BOOTSECTOR FatXVolumeBootSector;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,54 +938,76 @@ void FatParseShortFileName(PCHAR Buffer, PDIRENTRY DirEntry)
|
||||||
//TRACE("FatParseShortFileName() ShortName = %s\n", Buffer);
|
//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()
|
* FatGetFatEntry()
|
||||||
* returns the Fat entry for a given cluster number
|
* returns the Fat entry for a given cluster number
|
||||||
*/
|
*/
|
||||||
BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPointer)
|
BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPointer)
|
||||||
{
|
{
|
||||||
ULONG fat = 0;
|
UINT32 FatOffset, ThisFatSecNum, ThisFatEntOffset, fat;
|
||||||
UINT32 FatOffset;
|
|
||||||
UINT32 ThisFatSecNum;
|
|
||||||
UINT32 ThisFatEntOffset;
|
|
||||||
ULONG SectorCount;
|
|
||||||
PUCHAR ReadBuffer;
|
PUCHAR ReadBuffer;
|
||||||
BOOLEAN Success = TRUE;
|
|
||||||
|
|
||||||
//TRACE("FatGetFatEntry() Retrieving FAT entry for cluster %d.\n", Cluster);
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(Volume->FatType)
|
switch(Volume->FatType)
|
||||||
{
|
{
|
||||||
case FAT12:
|
case FAT12:
|
||||||
|
|
||||||
FatOffset = Cluster + (Cluster / 2);
|
FatOffset = Cluster + (Cluster / 2);
|
||||||
ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / Volume->BytesPerSector);
|
ThisFatSecNum = FatOffset / Volume->BytesPerSector;
|
||||||
ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
|
ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
|
||||||
|
|
||||||
TRACE("FatOffset: %d\n", FatOffset);
|
TRACE("FatOffset: %d\n", FatOffset);
|
||||||
TRACE("ThisFatSecNum: %d\n", ThisFatSecNum);
|
TRACE("ThisFatSecNum: %d\n", ThisFatSecNum);
|
||||||
TRACE("ThisFatEntOffset: %d\n", ThisFatEntOffset);
|
TRACE("ThisFatEntOffset: %d\n", ThisFatEntOffset);
|
||||||
|
|
||||||
if (ThisFatEntOffset == (Volume->BytesPerSector - 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
|
||||||
SectorCount = 2;
|
// 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
|
||||||
else
|
// and the next one is in the beginning
|
||||||
{
|
|
||||||
SectorCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FatReadVolumeSectors(Volume, ThisFatSecNum, SectorCount, ReadBuffer))
|
ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
|
||||||
|
if (!ReadBuffer)
|
||||||
{
|
{
|
||||||
Success = FALSE;
|
return FALSE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
|
fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
|
||||||
|
@ -962,13 +1023,13 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
|
||||||
case FATX16:
|
case FATX16:
|
||||||
|
|
||||||
FatOffset = (Cluster * 2);
|
FatOffset = (Cluster * 2);
|
||||||
ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / Volume->BytesPerSector);
|
ThisFatSecNum = FatOffset / Volume->BytesPerSector;
|
||||||
ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
|
ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
|
||||||
|
|
||||||
if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, ReadBuffer))
|
ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
|
||||||
|
if (!ReadBuffer)
|
||||||
{
|
{
|
||||||
Success = FALSE;
|
return FALSE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
|
fat = *((USHORT *) (ReadBuffer + ThisFatEntOffset));
|
||||||
|
@ -980,10 +1041,11 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
|
||||||
case FATX32:
|
case FATX32:
|
||||||
|
|
||||||
FatOffset = (Cluster * 4);
|
FatOffset = (Cluster * 4);
|
||||||
ThisFatSecNum = Volume->ActiveFatSectorStart + (FatOffset / Volume->BytesPerSector);
|
ThisFatSecNum = FatOffset / Volume->BytesPerSector;
|
||||||
ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
|
ThisFatEntOffset = (FatOffset % Volume->BytesPerSector);
|
||||||
|
|
||||||
if (!FatReadVolumeSectors(Volume, ThisFatSecNum, 1, ReadBuffer))
|
ReadBuffer = FatGetFatSector(Volume, ThisFatSecNum);
|
||||||
|
if (!ReadBuffer)
|
||||||
{
|
{
|
||||||
Success = FALSE;
|
Success = FALSE;
|
||||||
break;
|
break;
|
||||||
|
@ -997,17 +1059,14 @@ BOOLEAN FatGetFatEntry(PFAT_VOLUME_INFO Volume, ULONG Cluster, ULONG* ClusterPoi
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERR("Unknown FAT type %d\n", Volume->FatType);
|
ERR("Unknown FAT type %d\n", Volume->FatType);
|
||||||
Success = FALSE;
|
return FALSE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TRACE("FAT entry is 0x%x.\n", fat);
|
TRACE("FAT entry is 0x%x.\n", fat);
|
||||||
|
|
||||||
FrLdrTempFree(ReadBuffer, TAG_FAT_BUFFER);
|
|
||||||
|
|
||||||
*ClusterPointer = fat;
|
*ClusterPointer = fat;
|
||||||
|
|
||||||
return Success;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
|
ULONG FatCountClustersInChain(PFAT_VOLUME_INFO Volume, ULONG StartCluster)
|
||||||
|
|
Loading…
Reference in a new issue