1
0
Fork 0
forked from len0rd/rockbox

fat: Allow use of variable logical sector sizes

Only used if MAX_LOG_SECTOR_SIZE is defined

This allows a single build to seamlessly work with (eg) 512B or 4K sectors.

Change-Id: I85d2a6612afca6a1d7a3bd49c588b5745ab2b220
This commit is contained in:
Solomon Peachy 2024-11-04 19:48:17 -05:00
parent e519356c47
commit 7ecab006c0
3 changed files with 84 additions and 41 deletions

View file

@ -103,12 +103,12 @@ static int alloc_filestr(struct filestr_desc **filep)
}
/* return the file size in sectors */
static inline unsigned long filesize_sectors(file_size_t size)
static inline unsigned long filesize_sectors(uint16_t sector_size, file_size_t size)
{
/* overflow proof whereas "(x + y - 1) / y" is not */
unsigned long numsectors = size / SECTOR_SIZE;
unsigned long numsectors = size / sector_size;
if (size % SECTOR_SIZE)
if (size % sector_size)
numsectors++;
return numsectors;
@ -199,7 +199,8 @@ file_error:
/* Handle syncing all file's streams to the truncation */
static void handle_truncate(struct filestr_desc * const file, file_size_t size)
{
unsigned long filesectors = filesize_sectors(size);
uint16_t sector_size = fat_file_sector_size(file->stream.fatstr.fatfilep);
unsigned long filesectors = filesize_sectors(sector_size, size);
struct filestr_base *s = NULL;
while ((s = fileobj_get_next_stream(&file->stream, s)))
@ -229,9 +230,11 @@ static int ftruncate_internal(struct filestr_desc *file, file_size_t size,
file_size_t cursize = *file->sizep;
file_size_t truncsize = MIN(size, cursize);
uint16_t sector_size = fat_file_sector_size(file->stream.fatstr.fatfilep);
if (write_now)
{
unsigned long sector = filesize_sectors(truncsize);
unsigned long sector = filesize_sectors(sector_size, truncsize);
struct filestr_cache *const cachep = file->stream.cachep;
if (cachep->flags == (FSC_NEW|FSC_DIRTY) &&
@ -244,7 +247,7 @@ static int ftruncate_internal(struct filestr_desc *file, file_size_t size,
{
/* no space left on device; further truncation needed */
discard_cache(file);
truncsize = ALIGN_DOWN(truncsize - 1, SECTOR_SIZE);
truncsize = ALIGN_DOWN(truncsize - 1, sector_size);
sector--;
rc = rc2;
}
@ -292,6 +295,7 @@ static int fsync_internal(struct filestr_desc *file)
file_size_t size = *file->sizep;
unsigned int foflags = fileobj_get_flags(&file->stream);
uint16_t sector_size = fat_file_sector_size(file->stream.fatstr.fatfilep);
/* flush sector cache? */
struct filestr_cache *const cachep = file->stream.cachep;
@ -302,7 +306,7 @@ static int fsync_internal(struct filestr_desc *file)
{
/* no space left on device so this must be dropped */
discard_cache(file);
size = ALIGN_DOWN(size - 1, SECTOR_SIZE);
size = ALIGN_DOWN(size - 1, sector_size);
foflags |= FO_TRUNC;
rc = rc2;
}
@ -649,15 +653,16 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte,
struct filestr_cache * const cachep = file->stream.cachep;
void * const bufstart = buf;
uint16_t sector_size = fat_file_sector_size(file->stream.fatstr.fatfilep);
const unsigned long filesectors = filesize_sectors(size);
unsigned long sector = file->offset / SECTOR_SIZE;
unsigned long sectoroffs = file->offset % SECTOR_SIZE;
const unsigned long filesectors = filesize_sectors(sector_size, size);
unsigned long sector = file->offset / sector_size;
unsigned long sectoroffs = file->offset % sector_size;
/* any head bytes? */
if (sectoroffs)
{
size_t headbytes = MIN(nbyte, SECTOR_SIZE - sectoroffs);
size_t headbytes = MIN(nbyte, sector_size - sectoroffs);
rc = readwrite_partial(file, cachep, sector, sectoroffs, buf, headbytes,
filesectors, write);
if (rc <= 0)
@ -676,7 +681,7 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte,
}
/* read/write whole sectors right into/from the supplied buffer */
unsigned long sectorcount = nbyte / SECTOR_SIZE;
unsigned long sectorcount = nbyte / sector_size;
while (sectorcount)
{
@ -728,8 +733,8 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte,
}
else
{
buf += rc * SECTOR_SIZE;
nbyte -= rc * SECTOR_SIZE;
buf += rc * sector_size;
nbyte -= rc * sector_size;
sector += rc;
sectorcount -= rc;
@ -745,9 +750,9 @@ static ssize_t readwrite(struct filestr_desc *file, void *buf, size_t nbyte,
if (UNLIKELY(sectorcount && sector == cachep->sector))
{
/* do this one sector with the cache */
readwrite_cache(cachep, buf, 0, SECTOR_SIZE, write);
buf += SECTOR_SIZE;
nbyte -= SECTOR_SIZE;
readwrite_cache(cachep, buf, 0, sector_size, write);
buf += sector_size;
nbyte -= sector_size;
sector++;
sectorcount--;
}

View file

@ -35,6 +35,7 @@
#include "rbunicode.h"
#include "debug.h"
#include "panic.h"
#include "disk.h"
/*#define LOGF_ENABLE*/
#include "logf.h"
@ -162,9 +163,15 @@ union raw_dirent
#define FAT_NTRES_LC_NAME 0x08
#define FAT_NTRES_LC_EXT 0x10
#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4)
#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2)
#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE)
#ifdef MAX_LOG_SECTOR_SIZE
#define LOG_SECTOR_SIZE(bpb) fat_bpb->sector_size
#else
#define LOG_SECTOR_SIZE(bpb) SECTOR_SIZE
#endif
#define CLUSTERS_PER_FAT_SECTOR (LOG_SECTOR_SIZE(fat_bpb) / 4)
#define CLUSTERS_PER_FAT16_SECTOR (LOG_SECTOR_SIZE(fat_bpb) / 2)
#define DIR_ENTRIES_PER_SECTOR (LOG_SECTOR_SIZE(fat_bpb) / DIR_ENTRY_SIZE)
#define DIR_ENTRY_SIZE 32
#define FAT_BAD_MARK 0x0ffffff7
#define FAT_EOF_MARK 0x0ffffff8
@ -208,8 +215,10 @@ struct bpb;
static void update_fsinfo32(struct bpb *fat_bpb);
/* Note: This struct doesn't hold the raw values after mounting if
* bpb_bytspersec isn't 512. All sector counts are normalized to 512 byte
* physical sectors. */
* bpb_bytspersec isn't the same as the underlying device's logical
sector size. Sector counts are then normalized to that sector
size.
*/
static struct bpb
{
unsigned long bpb_bytspersec; /* Bytes per sector, typically 512 */
@ -263,12 +272,19 @@ static struct bpb
int BPB_FN_DECL(update_fat_entry, unsigned long, unsigned long);
void BPB_FN_DECL(fat_recalc_free_internal);
#endif /* HAVE_FAT16SUPPORT */
#ifdef MAX_LOG_SECTOR_SIZE
uint16_t sector_size;
#endif
} fat_bpbs[NUM_VOLUMES]; /* mounted partition info */
#ifdef STORAGE_NEEDS_BOUNCE_BUFFER
#ifdef MAX_LOG_SECTOR_SIZE
#define BOUNCE_SECTOR_SIZE MAX_LOG_SECTOR_SIZE
#else
#define BOUNCE_SECTOR_SIZE SECTOR_SIZE
#endif
#define FAT_BOUNCE_SECTORS 10
static uint8_t fat_bounce_buffers[NUM_VOLUMES][SECTOR_SIZE*FAT_BOUNCE_SECTORS] STORAGE_ALIGN_ATTR;
static uint8_t fat_bounce_buffers[NUM_VOLUMES][BOUNCE_SECTOR_SIZE*FAT_BOUNCE_SECTORS] STORAGE_ALIGN_ATTR;
#define FAT_BOUNCE_BUFFER(bpb) \
(fat_bounce_buffers[IF_MV_VOL((bpb)->volume)])
#endif
@ -394,7 +410,7 @@ static void raw_dirent_set_fstclus(union raw_dirent *ent, long fstclus)
static int bpb_is_sane(struct bpb *fat_bpb)
{
if (fat_bpb->bpb_bytspersec % SECTOR_SIZE)
if (fat_bpb->bpb_bytspersec % LOG_SECTOR_SIZE(fat_bpb))
{
DEBUGF("%s() - Error: sector size is not sane (%lu)\n",
__func__, fat_bpb->bpb_bytspersec);
@ -402,9 +418,9 @@ static int bpb_is_sane(struct bpb *fat_bpb)
}
/* The fat_bpb struct does not hold the raw value of bpb_bytspersec, the
* value is multiplied in cases where bpb_bytspersec != SECTOR_SIZE. We need
* value is multiplied in cases where bpb_bytspersec != sector_size. We need
* to undo that multiplication before we do the sanity check. */
unsigned long secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
unsigned long secmult = fat_bpb->bpb_bytspersec / LOG_SECTOR_SIZE(fat_bpb);
if (fat_bpb->bpb_secperclus * fat_bpb->bpb_bytspersec / secmult > 128*1024ul)
{
@ -1141,7 +1157,7 @@ static int fat_mount_internal(struct bpb *fat_bpb)
}
fat_bpb->bpb_bytspersec = BYTES2INT16(buf, BPB_BYTSPERSEC);
unsigned long secmult = fat_bpb->bpb_bytspersec / SECTOR_SIZE;
unsigned long secmult = fat_bpb->bpb_bytspersec / LOG_SECTOR_SIZE(fat_bpb);
/* Sanity check is performed later */
fat_bpb->bpb_secperclus = secmult * buf[BPB_SECPERCLUS];
@ -1426,7 +1442,7 @@ static int fat_extend_dir(struct bpb *fat_bpb, struct fat_filestr *dirstr)
FAT_ERROR(-2);
}
memset(sec, 0, SECTOR_SIZE);
memset(sec, 0, LOG_SECTOR_SIZE(fat_bpb));
dc_dirty_buf(sec);
dc_unlock_cache();
}
@ -1981,6 +1997,15 @@ static int free_cluster_chain(struct bpb *fat_bpb, long startcluster)
/** File entity functions **/
int fat_file_sector_size(const struct fat_file *file)
{
#ifdef MAX_LOG_SECTOR_SIZE
const struct bpb *fat_bpb = FAT_BPB(file->volume);
#endif
return LOG_SECTOR_SIZE(fat_bpb);
}
int fat_create_file(struct fat_file *parent, const char *name,
uint8_t attr, struct fat_file *file,
struct fat_direntry *fatent)
@ -2362,11 +2387,11 @@ int fat_closewrite(struct fat_filestr *filestr, uint32_t size,
count++;
}
uint32_t len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE;
uint32_t len = count * fat_bpb->bpb_secperclus * LOG_SECTOR_SIZE(fat_bpb);
DEBUGF("File is %lu clusters (chainlen=%lu, size=%lu)\n",
count, len, size );
if (len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE)
if (len > size + fat_bpb->bpb_secperclus * LOG_SECTOR_SIZE(fat_bpb))
panicf("Cluster chain is too long\n");
if (len < size)
@ -2429,22 +2454,22 @@ static long transfer(struct bpb *fat_bpb, sector_t start, long count,
if(UNLIKELY(STORAGE_OVERLAP((uintptr_t)buf))) {
void* xfer_buf = FAT_BOUNCE_BUFFER(fat_bpb);
while(count > 0) {
int xfer_count = MIN(count, FAT_BOUNCE_SECTORS);
int xfer_count = MIN(count*LOG_SECTOR_SIZE(fat_bpb), (FAT_BOUNCE_SECTORS * BOUNCE_SECTOR_SIZE)) / LOG_SECTOR_SIZE(fat_bpb);
if(write) {
memcpy(xfer_buf, buf, xfer_count * SECTOR_SIZE);
memcpy(xfer_buf, buf, xfer_count * LOG_SECTOR_SIZE(fat_bpb));
rc = storage_write_sectors(IF_MD(fat_bpb->drive,)
start + fat_bpb->startsector, xfer_count, xfer_buf);
} else {
rc = storage_read_sectors(IF_MD(fat_bpb->drive,)
start + fat_bpb->startsector, xfer_count, xfer_buf);
memcpy(buf, xfer_buf, xfer_count * SECTOR_SIZE);
memcpy(buf, xfer_buf, xfer_count * LOG_SECTOR_SIZE(fat_bpb));
}
if(rc < 0)
break;
buf += xfer_count * SECTOR_SIZE;
buf += xfer_count * LOG_SECTOR_SIZE(fat_bpb);
start += xfer_count;
count -= xfer_count;
}
@ -2571,7 +2596,7 @@ long fat_readwrite(struct fat_filestr *filestr, unsigned long sectorcount,
FAT_ERROR(rc * 10 - 2);
transferred += count;
buf += count * SECTOR_SIZE;
buf += count * LOG_SECTOR_SIZE(fat_bpb);
count = 0;
}
@ -2744,6 +2769,11 @@ int fat_readdir(struct fat_filestr *dirstr, struct fat_dirscan_info *scan,
scan->entries = 0;
#ifdef MAX_LOG_SECTOR_SIZE
struct fat_file *file = dirstr->fatfilep;
const struct bpb *fat_bpb = FAT_BPB(file->volume);
#endif
while (1)
{
unsigned int direntry = ++scan->entry;
@ -2863,7 +2893,6 @@ void fat_rewinddir(struct fat_dirscan_info *scan)
scan->entries = 0;
}
/** Mounting and unmounting functions **/
bool fat_ismounted(IF_MV_NONVOID(int volume))
@ -2888,6 +2917,10 @@ int fat_mount(IF_MV(int volume,) IF_MD(int drive,) unsigned long startsector)
fat_bpb->drive = drive;
#endif
#ifdef MAX_LOG_SECTOR_SIZE
fat_bpb->sector_size = disk_get_log_sector_size(IF_MD(drive));
#endif
rc = fat_mount_internal(fat_bpb);
if (rc < 0)
FAT_ERROR(rc * 10 - 2);
@ -2927,6 +2960,9 @@ int fat_unmount(IF_MV_NONVOID(int volume))
/** Debug screen stuff **/
#ifdef MAX_LOG_SECTOR_SIZE
/* This isn't necessarily the same as storage's logical sector size;
we can have situations where the filesystem (and partition table)
uses a larger "virtual sector" than the underlying storage device */
int fat_get_bytes_per_sector(IF_MV_NONVOID(int volume))
{
int bytes = 0;
@ -2945,7 +2981,7 @@ unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume))
struct bpb * const fat_bpb = FAT_BPB(volume);
if (fat_bpb)
size = fat_bpb->bpb_secperclus * SECTOR_SIZE;
size = fat_bpb->bpb_secperclus * LOG_SECTOR_SIZE(fat_bpb);
return size;
}
@ -2967,7 +3003,7 @@ bool fat_size(IF_MV(int volume,) sector_t *size, sector_t *free)
if (!fat_bpb)
return false;
unsigned long factor = fat_bpb->bpb_secperclus * SECTOR_SIZE / 1024;
unsigned long factor = fat_bpb->bpb_secperclus * LOG_SECTOR_SIZE(fat_bpb) / 1024;
if (size) *size = fat_bpb->dataclusters * factor;
if (free) *free = fat_bpb->fsinfo.freecount * factor;

View file

@ -143,6 +143,8 @@ int fat_rename(struct fat_file *parent, struct fat_file *file,
int fat_modtime(struct fat_file *parent, struct fat_file *file,
time_t modtime);
int fat_file_sector_size(const struct fat_file *file);
/** File stream functions **/
int fat_closewrite(struct fat_filestr *filestr, uint32_t size,
struct fat_direntry *fatentp);