diff --git a/lfs.c b/lfs.c index baf2c1ae70d..dd479165b99 100644 --- a/lfs.c +++ b/lfs.c @@ -2703,6 +2703,16 @@ static inline void lfs_superblocktole32(lfs_superblock_t *superblock) { static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { lfs->cfg = cfg; + // check that block size is a multiple of cache size is a multiple + // of prog and read sizes + LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->read_size == 0); + LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->prog_size == 0); + LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->cache_size == 0); + + // check that the block size is large enough to fit ctz pointers + LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) + <= lfs->cfg->block_size); + // setup read cache lfs->rcache.block = 0xffffffff; if (lfs->cfg->read_buffer) { @@ -2725,7 +2735,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { } } - // setup lookahead, round down to nearest 32-bits + // setup lookahead, must be multiple of 32-bits LFS_ASSERT(lfs->cfg->lookahead % 32 == 0); LFS_ASSERT(lfs->cfg->lookahead > 0); if (lfs->cfg->lookahead_buffer) { @@ -2737,22 +2747,12 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { } } - // check that block size is a multiple of cache size is a multiple - // of prog and read sizes - LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->read_size == 0); - LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->prog_size == 0); - LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->cache_size == 0); - - // check that the block size is large enough to fit ctz pointers - LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) - <= lfs->cfg->block_size); - // check that the size limits are sane LFS_ASSERT(lfs->cfg->inline_size <= LFS_INLINE_MAX); - LFS_ASSERT(lfs->cfg->inline_size <= lfs->cfg->read_size); // TODO + LFS_ASSERT(lfs->cfg->inline_size <= lfs->cfg->cache_size); lfs->inline_size = lfs->cfg->inline_size; if (!lfs->inline_size) { - lfs->inline_size = lfs_min(LFS_INLINE_MAX, lfs->cfg->read_size); + lfs->inline_size = lfs_min(LFS_INLINE_MAX, lfs->cfg->cache_size); } LFS_ASSERT(lfs->cfg->attr_size <= LFS_ATTR_MAX); @@ -2841,9 +2841,9 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { .block_size = lfs->cfg->block_size, .block_count = lfs->cfg->block_count, - .inline_size = lfs->inline_size, .attr_size = lfs->attr_size, .name_size = lfs->name_size, + .inline_size = lfs->inline_size, }; lfs_superblocktole32(&superblock); @@ -2883,9 +2883,6 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { lfs_mdir_t superdir; err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1}); if (err) { - if (err == LFS_ERR_CORRUPT) { - LFS_ERROR("Invalid superblock at %d %d", 0, 1); - } return err; } @@ -2899,8 +2896,8 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { lfs_superblockfromle32(&superblock); if (memcmp(superblock.magic, "littlefs", 8) != 0) { - LFS_ERROR("Invalid superblock at %d %d", 0, 1); - return LFS_ERR_CORRUPT; + LFS_ERROR("Invalid superblock \"%.8s\"", superblock.magic); + return LFS_ERR_INVAL; } uint16_t major_version = (0xffff & (superblock.version >> 16)); @@ -2919,16 +2916,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { } lfs_pairfromle32(lfs->root); - if (superblock.inline_size) { - if (superblock.inline_size > lfs->inline_size) { - LFS_ERROR("Unsupported inline size (%d > %d)", - superblock.inline_size, lfs->inline_size); - return LFS_ERR_INVAL; - } - - lfs->inline_size = superblock.inline_size; - } - + // check superblock configuration if (superblock.attr_size) { if (superblock.attr_size > lfs->attr_size) { LFS_ERROR("Unsupported attr size (%d > %d)", @@ -2949,6 +2937,16 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { lfs->name_size = superblock.name_size; } + if (superblock.inline_size) { + if (superblock.inline_size > lfs->inline_size) { + LFS_ERROR("Unsupported inline size (%d > %d)", + superblock.inline_size, lfs->inline_size); + return LFS_ERR_INVAL; + } + + lfs->inline_size = superblock.inline_size; + } + // scan for any global updates lfs_mdir_t dir = {.tail = {0, 1}}; while (!lfs_pairisnull(dir.tail)) { diff --git a/lfs.h b/lfs.h index d4d0639f200..088b27f7a15 100644 --- a/lfs.h +++ b/lfs.h @@ -50,31 +50,29 @@ typedef int32_t lfs_soff_t; typedef uint32_t lfs_block_t; -// Maximum inline file size in bytes. Large inline files require a larger -// read and prog cache, but if a file can be inline it does not need its own -// data block. LFS_ATTR_MAX + LFS_INLINE_MAX must be <= 0xffff. Stored in -// superblock and must be respected by other littlefs drivers. -// TODO doc -#ifndef LFS_INLINE_MAX -#define LFS_INLINE_MAX 0xfff -#endif - // Maximum size of all attributes per file in bytes, may be redefined but a -// a smaller LFS_ATTR_MAX has no benefit. LFS_ATTR_MAX + LFS_INLINE_MAX -// must be <= 0xffff. Stored in superblock and must be respected by other +// a smaller LFS_ATTR_MAX has no benefit. Stored in 12-bits and limited +// to <= 0xfff. Stored in superblock and must be respected by other // littlefs drivers. -// TODO doc #ifndef LFS_ATTR_MAX #define LFS_ATTR_MAX 0xfff #endif -// Max name size in bytes, may be redefined to reduce the size of the -// info struct. Stored in superblock and must be respected by other -// littlefs drivers. +// Maximum name size in bytes, may be redefined to reduce the size of the +// info struct. Limited to <= LFS_ATTR_MAX. Stored in superblock and must +// be respected by other littlefs drivers. #ifndef LFS_NAME_MAX #define LFS_NAME_MAX 0xff #endif +// Maximum inline file size in bytes. Large inline files require a larger +// cache size, but if a file can be inline it does not need its own data +// block. Limited to <= LFS_ATTR_MAX and <= cache_size. Stored in superblock +// and must be respected by other littlefs drivers. +#ifndef LFS_INLINE_MAX +#define LFS_INLINE_MAX 0xfff +#endif + // Possible error codes, these are negative to allow // valid positive return values enum lfs_error { @@ -110,7 +108,7 @@ enum lfs_type { LFS_TYPE_TAIL = 0x0c0, LFS_TYPE_SOFTTAIL = 0x0c0, LFS_TYPE_HARDTAIL = 0x0c1, - LFS_TYPE_CRC = 0x0f0, // TODO are trailing ones useful? + LFS_TYPE_CRC = 0x0f0, LFS_TYPE_INLINESTRUCT = 0x040, LFS_TYPE_CTZSTRUCT = 0x041, @@ -216,15 +214,8 @@ struct lfs_config { // lookahead block. void *lookahead_buffer; - // Optional upper limit on inlined files in bytes. Large inline files - // require a larger read and prog cache, but if a file can be inlined it - // does not need its own data block. Must be smaller than the read size - // and prog size. Defaults to min(LFS_INLINE_MAX, read_size) when zero. - // Stored in superblock and must be respected by other littlefs drivers. - lfs_size_t inline_size; - - // Optional upper limit on attributes per file in bytes. No downside for - // larger attributes size but must be less than LFS_ATTR_MAX. Defaults to + // Optional upper limit on file attributes in bytes. No downside for larger + // attributes size but must be less than LFS_ATTR_MAX. Defaults to // LFS_ATTR_MAX when zero.Stored in superblock and must be respected by // other littlefs drivers. lfs_size_t attr_size; @@ -234,6 +225,13 @@ struct lfs_config { // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in // superblock and must be respected by other littlefs drivers. lfs_size_t name_size; + + // Optional upper limit on inlined files in bytes. Large inline files + // require a larger cache size, but if a file can be inlined it does not + // need its own data block. Must be smaller than cache_size and less than + // LFS_INLINE_MAX. Defaults to min(LFS_INLINE_MAX, read_size) when zero. + // Stored in superblock and must be respected by other littlefs drivers. + lfs_size_t inline_size; }; // File info structure @@ -355,9 +353,9 @@ typedef struct lfs_superblock { lfs_size_t block_size; lfs_size_t block_count; - lfs_size_t inline_size; lfs_size_t attr_size; lfs_size_t name_size; + lfs_size_t inline_size; } lfs_superblock_t; typedef struct lfs_free { @@ -381,9 +379,11 @@ typedef struct lfs { lfs_free_t free; const struct lfs_config *cfg; - lfs_size_t inline_size; + lfs_size_t block_size; + lfs_size_t block_count; lfs_size_t attr_size; lfs_size_t name_size; + lfs_size_t inline_size; } lfs_t;