diff --git a/.travis.yml b/.travis.yml index 88ff484..755c602 100644 --- a/.travis.yml +++ b/.travis.yml @@ -214,14 +214,20 @@ jobs: - NAME=littlefs-minimal - CC="arm-linux-gnueabi-gcc --static -mthumb" - CFLAGS="-Werror - -DLFS_STATICCFG -DLFS_FILE_STATICCFG + -DLFS_BD_READ + -DLFS_BD_PROG + -DLFS_BD_ERASE + -DLFS_BD_SYNC -DLFS_READ_SIZE=16 -DLFS_PROG_SIZE=16 -DLFS_BLOCK_SIZE=512 -DLFS_BLOCK_COUNT=1024 - -DLFS_BLOCK_CYCLES=-1 + -DLFS_BLOCK_CYCLES=1024 -DLFS_BUFFER_SIZE=64 -DLFS_LOOKAHEAD_SIZE=16 + -DLFS_NAME_LIMIT=0 + -DLFS_FILE_LIMIT=0 + -DLFS_ATTR_LIMIT=0 -DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR" if: branch !~ -prefix$ install: diff --git a/lfs.c b/lfs.c index 09462e7..9ed3625 100644 --- a/lfs.c +++ b/lfs.c @@ -7,68 +7,6 @@ #include "lfs.h" -/// Configuration mapping /// -#ifdef LFS_STATICCFG -// direct config towards user defines -#define LFS_CFG_BD_READ(lfs, block, off, buffer, size) \ - ((void)lfs, lfs_bd_read(block, off, buffer, size)) -#define LFS_CFG_BD_PROG(lfs, block, off, buffer, size) \ - ((void)lfs, lfs_bd_prog(block, off, buffer, size)) -#define LFS_CFG_BD_ERASE(lfs, block) \ - ((void)lfs, lfs_bd_erase(block)) -#define LFS_CFG_BD_SYNC(lfs) \ - ((void)lfs, lfs_bd_sync()) -#define LFS_CFG_READ_SIZE(lfs) ((void)lfs, LFS_READ_SIZE) -#define LFS_CFG_PROG_SIZE(lfs) ((void)lfs, LFS_PROG_SIZE) -#define LFS_CFG_BLOCK_SIZE(lfs) ((void)lfs, LFS_BLOCK_SIZE) -#define LFS_CFG_BLOCK_COUNT(lfs) ((void)lfs, LFS_BLOCK_COUNT) -#define LFS_CFG_BLOCK_CYCLES(lfs) ((void)lfs, LFS_BLOCK_CYCLES) -#define LFS_CFG_BUFFER_SIZE(lfs) ((void)lfs, LFS_BUFFER_SIZE) -#define LFS_CFG_LOOKAHEAD_SIZE(lfs) ((void)lfs, LFS_LOOKAHEAD_SIZE) -#define LFS_CFG_READ_BUFFER(lfs) ((void)lfs, LFS_READ_BUFFER) -#define LFS_CFG_PROG_BUFFER(lfs) ((void)lfs, LFS_PROG_BUFFER) -#define LFS_CFG_LOOKAHEAD_BUFFER(lfs) ((void)lfs, LFS_LOOKAHEAD_BUFFER) -#define LFS_CFG_NAME_MAX(lfs) ((void)lfs, LFS_NAME_MAX) -#define LFS_CFG_FILE_MAX(lfs) ((void)lfs, LFS_FILE_MAX) -#define LFS_CFG_ATTR_MAX(lfs) ((void)lfs, LFS_ATTR_MAX) -#else -// direct config towards dynamic lfs_cfg struct -#define LFS_CFG_BD_READ(lfs, block, off, buffer, size) \ - lfs->cfg->bd_read(lfs->cfg->bd_ctx, block, off, buffer, size) -#define LFS_CFG_BD_PROG(lfs, block, off, buffer, size) \ - lfs->cfg->bd_prog(lfs->cfg->bd_ctx, block, off, buffer, size) -#define LFS_CFG_BD_ERASE(lfs, block) \ - lfs->cfg->bd_erase(lfs->cfg->bd_ctx, block) -#define LFS_CFG_BD_SYNC(lfs) \ - lfs->cfg->bd_sync(lfs->cfg->bd_ctx) -#define LFS_CFG_READ_SIZE(lfs) lfs->cfg->read_size -#define LFS_CFG_PROG_SIZE(lfs) lfs->cfg->prog_size -#define LFS_CFG_BLOCK_SIZE(lfs) lfs->cfg->block_size -#define LFS_CFG_BLOCK_COUNT(lfs) lfs->cfg->block_count -#define LFS_CFG_BLOCK_CYCLES(lfs) lfs->cfg->block_cycles -#define LFS_CFG_BUFFER_SIZE(lfs) lfs->cfg->buffer_size -#define LFS_CFG_LOOKAHEAD_SIZE(lfs) lfs->cfg->lookahead_size -#define LFS_CFG_READ_BUFFER(lfs) lfs->cfg->read_buffer -#define LFS_CFG_PROG_BUFFER(lfs) lfs->cfg->prog_buffer -#define LFS_CFG_LOOKAHEAD_BUFFER(lfs) lfs->cfg->lookahead_buffer -#define LFS_CFG_NAME_MAX(lfs) lfs->cfg->name_max -#define LFS_CFG_FILE_MAX(lfs) lfs->cfg->file_max -#define LFS_CFG_ATTR_MAX(lfs) lfs->cfg->attr_max -#endif - -#ifdef LFS_FILE_STATICCFG -// direct config towards user defines -#define LFS_FILE_CFG_BUFFER(file) LFS_FILE_BUFFER -#define LFS_FILE_CFG_ATTRS(file) LFS_FILE_ATTRS -#define LFS_FILE_CFG_ATTR_COUNT(file) LFS_FILE_ATTR_COUNT -#else -// direct config towards dynamic lfs_cfg struct -#define LFS_FILE_CFG_BUFFER(file) file->cfg->buffer -#define LFS_FILE_CFG_ATTRS(file) file->cfg->attrs -#define LFS_FILE_CFG_ATTR_COUNT(file) file->cfg->attr_count -#endif - - /// Internal littlefs constants /// #define LFS_BLOCK_NULL ((lfs_block_t)-1) #define LFS_BLOCK_INLINE ((lfs_block_t)-2) @@ -83,7 +21,8 @@ static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) { static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) { // zero to avoid information leak - memset(pcache->buffer, 0xff, LFS_CFG_BUFFER_SIZE(lfs)); + (void)lfs; + memset(pcache->buffer, 0xff, LFS_CFG_BUFFER_SIZE(lfs->cfg)); pcache->block = LFS_BLOCK_NULL; } @@ -91,9 +30,10 @@ static int lfs_cache_read(lfs_t *lfs, const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) { + (void)lfs; uint8_t *data = buffer; - if (block >= LFS_CFG_BLOCK_COUNT(lfs) || - off+size > LFS_CFG_BLOCK_SIZE(lfs)) { + if (block >= LFS_CFG_BLOCK_COUNT(lfs->cfg) || + off+size > LFS_CFG_BLOCK_SIZE(lfs->cfg)) { return LFS_ERR_CORRUPT; } @@ -134,11 +74,11 @@ static int lfs_cache_read(lfs_t *lfs, diff = lfs_min(diff, rcache->off-off); } - if (size >= hint && off % LFS_CFG_READ_SIZE(lfs) == 0 && - size >= LFS_CFG_READ_SIZE(lfs)) { + if (size >= hint && off % LFS_CFG_READ_SIZE(lfs->cfg) == 0 && + size >= LFS_CFG_READ_SIZE(lfs->cfg)) { // bypass cache? - diff = lfs_aligndown(diff, LFS_CFG_READ_SIZE(lfs)); - int err = LFS_CFG_BD_READ(lfs, block, off, data, diff); + diff = lfs_aligndown(diff, LFS_CFG_READ_SIZE(lfs->cfg)); + int err = LFS_CFG_BD_READ(lfs->cfg, block, off, data, diff); if (err) { return err; } @@ -150,16 +90,16 @@ static int lfs_cache_read(lfs_t *lfs, } // load to cache, first condition can no longer fail - LFS_ASSERT(block < LFS_CFG_BLOCK_COUNT(lfs)); + LFS_ASSERT(block < LFS_CFG_BLOCK_COUNT(lfs->cfg)); rcache->block = block; - rcache->off = lfs_aligndown(off, LFS_CFG_READ_SIZE(lfs)); + rcache->off = lfs_aligndown(off, LFS_CFG_READ_SIZE(lfs->cfg)); rcache->size = lfs_min( lfs_min( - lfs_alignup(off+hint, LFS_CFG_READ_SIZE(lfs)), - LFS_CFG_BLOCK_SIZE(lfs)) + lfs_alignup(off+hint, LFS_CFG_READ_SIZE(lfs->cfg)), + LFS_CFG_BLOCK_SIZE(lfs->cfg)) - rcache->off, - LFS_CFG_BUFFER_SIZE(lfs)); - int err = LFS_CFG_BD_READ(lfs, rcache->block, + LFS_CFG_BUFFER_SIZE(lfs->cfg)); + int err = LFS_CFG_BD_READ(lfs->cfg, rcache->block, rcache->off, rcache->buffer, rcache->size); LFS_ASSERT(err <= 0); if (err) { @@ -202,9 +142,10 @@ static int lfs_cache_cmp(lfs_t *lfs, static int lfs_cache_flush(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { if (pcache->block != LFS_BLOCK_NULL && pcache->block != LFS_BLOCK_INLINE) { - LFS_ASSERT(pcache->block < LFS_CFG_BLOCK_COUNT(lfs)); - lfs_size_t diff = lfs_alignup(pcache->size, LFS_CFG_PROG_SIZE(lfs)); - int err = LFS_CFG_BD_PROG(lfs, pcache->block, + LFS_ASSERT(pcache->block < LFS_CFG_BLOCK_COUNT(lfs->cfg)); + lfs_size_t diff = lfs_alignup(pcache->size, + LFS_CFG_PROG_SIZE(lfs->cfg)); + int err = LFS_CFG_BD_PROG(lfs->cfg, pcache->block, pcache->off, pcache->buffer, diff); LFS_ASSERT(err <= 0); if (err) { @@ -241,7 +182,7 @@ static int lfs_cache_sync(lfs_t *lfs, return err; } - err = LFS_CFG_BD_SYNC(lfs); + err = LFS_CFG_BD_SYNC(lfs->cfg); LFS_ASSERT(err <= 0); return err; } @@ -251,16 +192,17 @@ static int lfs_cache_prog(lfs_t *lfs, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { const uint8_t *data = buffer; - LFS_ASSERT(block == LFS_BLOCK_INLINE || block < LFS_CFG_BLOCK_COUNT(lfs)); - LFS_ASSERT(off + size <= LFS_CFG_BLOCK_SIZE(lfs)); + LFS_ASSERT(block == LFS_BLOCK_INLINE || + block < LFS_CFG_BLOCK_COUNT(lfs->cfg)); + LFS_ASSERT(off + size <= LFS_CFG_BLOCK_SIZE(lfs->cfg)); while (size > 0) { if (block == pcache->block && off >= pcache->off && - off < pcache->off + LFS_CFG_BUFFER_SIZE(lfs)) { + off < pcache->off + LFS_CFG_BUFFER_SIZE(lfs->cfg)) { // already fits in pcache? lfs_size_t diff = lfs_min(size, - LFS_CFG_BUFFER_SIZE(lfs) - (off-pcache->off)); + LFS_CFG_BUFFER_SIZE(lfs->cfg) - (off-pcache->off)); memcpy(&pcache->buffer[off-pcache->off], data, diff); data += diff; @@ -268,7 +210,7 @@ static int lfs_cache_prog(lfs_t *lfs, size -= diff; pcache->size = lfs_max(pcache->size, off - pcache->off); - if (pcache->size == LFS_CFG_BUFFER_SIZE(lfs)) { + if (pcache->size == LFS_CFG_BUFFER_SIZE(lfs->cfg)) { // eagerly flush out pcache if we fill up int err = lfs_cache_flush(lfs, pcache, rcache, validate); if (err) { @@ -285,7 +227,7 @@ static int lfs_cache_prog(lfs_t *lfs, // prepare pcache, first condition can no longer fail pcache->block = block; - pcache->off = lfs_aligndown(off, LFS_CFG_PROG_SIZE(lfs)); + pcache->off = lfs_aligndown(off, LFS_CFG_PROG_SIZE(lfs->cfg)); pcache->size = 0; } @@ -293,8 +235,9 @@ static int lfs_cache_prog(lfs_t *lfs, } static int lfs_cache_erase(lfs_t *lfs, lfs_block_t block) { - LFS_ASSERT(block < LFS_CFG_BLOCK_COUNT(lfs)); - int err = LFS_CFG_BD_ERASE(lfs, block); + (void)lfs; + LFS_ASSERT(block < LFS_CFG_BLOCK_COUNT(lfs->cfg)); + int err = LFS_CFG_BD_ERASE(lfs->cfg, block); LFS_ASSERT(err <= 0); return err; } @@ -460,18 +403,18 @@ static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) { superblock->version = lfs_fromle32(superblock->version); superblock->block_size = lfs_fromle32(superblock->block_size); superblock->block_count = lfs_fromle32(superblock->block_count); - superblock->name_max = lfs_fromle32(superblock->name_max); - superblock->file_max = lfs_fromle32(superblock->file_max); - superblock->attr_max = lfs_fromle32(superblock->attr_max); + superblock->name_limit = lfs_fromle32(superblock->name_limit); + superblock->file_limit = lfs_fromle32(superblock->file_limit); + superblock->attr_limit = lfs_fromle32(superblock->attr_limit); } static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { superblock->version = lfs_tole32(superblock->version); superblock->block_size = lfs_tole32(superblock->block_size); superblock->block_count = lfs_tole32(superblock->block_count); - superblock->name_max = lfs_tole32(superblock->name_max); - superblock->file_max = lfs_tole32(superblock->file_max); - superblock->attr_max = lfs_tole32(superblock->attr_max); + superblock->name_limit = lfs_tole32(superblock->name_limit); + superblock->file_limit = lfs_tole32(superblock->file_limit); + superblock->attr_limit = lfs_tole32(superblock->attr_limit); } @@ -506,7 +449,7 @@ static int lfs1_traverse(lfs_t *lfs, static int lfs_alloc_lookahead(void *p, lfs_block_t block) { lfs_t *lfs = (lfs_t*)p; lfs_block_t off = ((block - lfs->free.off) - + LFS_CFG_BLOCK_COUNT(lfs)) % LFS_CFG_BLOCK_COUNT(lfs); + + LFS_CFG_BLOCK_COUNT(lfs->cfg)) % LFS_CFG_BLOCK_COUNT(lfs->cfg); if (off < lfs->free.size) { lfs->free.buffer[off / 32] |= 1U << (off % 32); @@ -516,13 +459,13 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) { } static void lfs_alloc_ack(lfs_t *lfs) { - lfs->free.ack = LFS_CFG_BLOCK_COUNT(lfs); + lfs->free.ack = LFS_CFG_BLOCK_COUNT(lfs->cfg); } // Invalidate the lookahead buffer. This is done during mounting and // failed traversals static void lfs_alloc_reset(lfs_t *lfs) { - lfs->free.off = lfs->seed % LFS_CFG_BLOCK_SIZE(lfs); + lfs->free.off = lfs->seed % LFS_CFG_BLOCK_SIZE(lfs->cfg); lfs->free.size = 0; lfs->free.i = 0; lfs_alloc_ack(lfs); @@ -537,7 +480,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) { // found a free block - *block = (lfs->free.off + off) % LFS_CFG_BLOCK_COUNT(lfs); + *block = (lfs->free.off + off) % LFS_CFG_BLOCK_COUNT(lfs->cfg); // eagerly find next off so an alloc ack can // discredit old lookahead blocks @@ -560,12 +503,14 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { } lfs->free.off = (lfs->free.off + lfs->free.size) - % LFS_CFG_BLOCK_COUNT(lfs); - lfs->free.size = lfs_min(8*LFS_CFG_LOOKAHEAD_SIZE(lfs), lfs->free.ack); + % LFS_CFG_BLOCK_COUNT(lfs->cfg); + lfs->free.size = lfs_min( + 8*LFS_CFG_LOOKAHEAD_SIZE(lfs->cfg), + lfs->free.ack); lfs->free.i = 0; // find mask of free blocks from tree - memset(lfs->free.buffer, 0, LFS_CFG_LOOKAHEAD_SIZE(lfs)); + memset(lfs->free.buffer, 0, LFS_CFG_LOOKAHEAD_SIZE(lfs->cfg)); int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); if (err) { lfs_alloc_reset(lfs); @@ -649,7 +594,7 @@ static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir, lfs_tag_t gmask, lfs_tag_t gtag, lfs_off_t off, void *buffer, lfs_size_t size) { uint8_t *data = buffer; - if (off+size > LFS_CFG_BLOCK_SIZE(lfs)) { + if (off+size > LFS_CFG_BLOCK_SIZE(lfs->cfg)) { return LFS_ERR_CORRUPT; } @@ -692,9 +637,10 @@ static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir, // load to cache, first condition can no longer fail rcache->block = LFS_BLOCK_INLINE; - rcache->off = lfs_aligndown(off, LFS_CFG_READ_SIZE(lfs)); - rcache->size = lfs_min(lfs_alignup(off+hint, LFS_CFG_READ_SIZE(lfs)), - LFS_CFG_BUFFER_SIZE(lfs)); + rcache->off = lfs_aligndown(off, LFS_CFG_READ_SIZE(lfs->cfg)); + rcache->size = lfs_min( + lfs_alignup(off+hint, LFS_CFG_READ_SIZE(lfs->cfg)), + LFS_CFG_BUFFER_SIZE(lfs->cfg)); int err = lfs_dir_getslice(lfs, dir, gmask, gtag, rcache->off, rcache->buffer, rcache->size); if (err < 0) { @@ -837,8 +783,8 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, // if either block address is invalid we return LFS_ERR_CORRUPT here, // otherwise later writes to the pair could fail - if (pair[0] >= LFS_CFG_BLOCK_COUNT(lfs) || - pair[1] >= LFS_CFG_BLOCK_COUNT(lfs)) { + if (pair[0] >= LFS_CFG_BLOCK_COUNT(lfs->cfg) || + pair[1] >= LFS_CFG_BLOCK_COUNT(lfs->cfg)) { return LFS_ERR_CORRUPT; } @@ -884,7 +830,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, lfs_tag_t tag; off += lfs_tag_dsize(ptag); int err = lfs_cache_read(lfs, - NULL, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs), + NULL, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs->cfg), dir->pair[0], off, &tag, sizeof(tag)); if (err) { if (err == LFS_ERR_CORRUPT) { @@ -901,9 +847,10 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, // next commit not yet programmed or we're not in valid range if (!lfs_tag_isvalid(tag)) { dir->erased = (lfs_tag_type1(ptag) == LFS_TYPE_CRC && - dir->off % LFS_CFG_PROG_SIZE(lfs) == 0); + dir->off % LFS_CFG_PROG_SIZE(lfs->cfg) == 0); break; - } else if (off + lfs_tag_dsize(tag) > LFS_CFG_BLOCK_SIZE(lfs)) { + } else if (off + lfs_tag_dsize(tag) + > LFS_CFG_BLOCK_SIZE(lfs->cfg)) { dir->erased = false; break; } @@ -914,7 +861,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, // check the crc attr uint32_t dcrc; err = lfs_cache_read(lfs, - NULL, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs), + NULL, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs->cfg), dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc)); if (err) { if (err == LFS_ERR_CORRUPT) { @@ -955,7 +902,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, for (lfs_off_t j = sizeof(tag); j < lfs_tag_dsize(tag); j++) { uint8_t dat; err = lfs_cache_read(lfs, - NULL, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs), + NULL, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs->cfg), dir->pair[0], off+j, &dat, 1); if (err) { if (err == LFS_ERR_CORRUPT) { @@ -988,7 +935,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, tempsplit = (lfs_tag_chunk(tag) & 1); err = lfs_cache_read(lfs, - NULL, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs), + NULL, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs->cfg), dir->pair[0], off+sizeof(tag), &temptail, 8); if (err) { if (err == LFS_ERR_CORRUPT) { @@ -1099,7 +1046,7 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir, } lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name); + LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_limit+1), info->name); if (tag < 0) { return (int)tag; } @@ -1329,7 +1276,7 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { const uint32_t crc1 = commit->crc; // align to program units const lfs_off_t end = lfs_alignup(off1 + 2*sizeof(uint32_t), - LFS_CFG_PROG_SIZE(lfs)); + LFS_CFG_PROG_SIZE(lfs->cfg)); // create crc tags to fill up remainder of commit, note that // padding is not crced, which lets fetches skip padding but @@ -1551,9 +1498,9 @@ static int lfs_dir_compact(lfs_t *lfs, // cleanup delete, and we cap at half a block to give room // for metadata updates. if (end - begin < 0xff && - size <= lfs_min(LFS_CFG_BLOCK_SIZE(lfs) - 36, - lfs_alignup(LFS_CFG_BLOCK_SIZE(lfs)/2, - LFS_CFG_PROG_SIZE(lfs)))) { + size <= lfs_min(LFS_CFG_BLOCK_SIZE(lfs->cfg) - 36, + lfs_alignup(LFS_CFG_BLOCK_SIZE(lfs->cfg)/2, + LFS_CFG_PROG_SIZE(lfs->cfg)))) { break; } @@ -1567,7 +1514,8 @@ static int lfs_dir_compact(lfs_t *lfs, // if we fail to split, we may be able to overcompact, unless // we're too big for even the full block, in which case our // only option is to error - if (err == LFS_ERR_NOSPC && size <= LFS_CFG_BLOCK_SIZE(lfs) - 36) { + if (err == LFS_ERR_NOSPC && size + <= LFS_CFG_BLOCK_SIZE(lfs->cfg) - 36) { break; } return err; @@ -1584,8 +1532,8 @@ static int lfs_dir_compact(lfs_t *lfs, // 1. block_cycles = 1, which would prevent relocations from terminating // 2. block_cycles = 2n, which, due to aliasing, would only ever relocate // one metadata block in the pair, effectively making this useless - if (LFS_CFG_BLOCK_CYCLES(lfs) > 0 && - (dir->rev % ((LFS_CFG_BLOCK_CYCLES(lfs)+1)|1) == 0)) { + if (LFS_CFG_BLOCK_CYCLES(lfs->cfg) > 0 && + (dir->rev % ((LFS_CFG_BLOCK_CYCLES(lfs->cfg)+1)|1) == 0)) { if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { // oh no! we're writing too much to the superblock, // should we expand? @@ -1596,7 +1544,7 @@ static int lfs_dir_compact(lfs_t *lfs, // do we have extra space? littlefs can't reclaim this space // by itself, so expand cautiously - if ((lfs_size_t)res < LFS_CFG_BLOCK_COUNT(lfs)/2) { + if ((lfs_size_t)res < LFS_CFG_BLOCK_COUNT(lfs->cfg)/2) { LFS_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev); int err = lfs_dir_split(lfs, dir, attrs, attrcount, source, begin, end); @@ -1637,7 +1585,7 @@ static int lfs_dir_compact(lfs_t *lfs, .crc = 0xffffffff, .begin = 0, - .end = LFS_CFG_BLOCK_SIZE(lfs) - 8, + .end = LFS_CFG_BLOCK_SIZE(lfs->cfg) - 8, }; // erase block to write to @@ -1728,7 +1676,7 @@ static int lfs_dir_compact(lfs_t *lfs, } // successful compaction, swap dir pair to indicate most recent - LFS_ASSERT(commit.off % LFS_CFG_PROG_SIZE(lfs) == 0); + LFS_ASSERT(commit.off % LFS_CFG_PROG_SIZE(lfs->cfg) == 0); lfs_pair_swap(dir->pair); dir->count = end - begin; dir->off = commit.off; @@ -1787,7 +1735,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 && f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) && - f->ctz.size > LFS_CFG_BUFFER_SIZE(lfs)) { + f->ctz.size > LFS_CFG_BUFFER_SIZE(lfs->cfg)) { int err = lfs_file_outline(lfs, f); if (err) { return err; @@ -1845,7 +1793,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, .crc = 0xffffffff, .begin = dir->off, - .end = LFS_CFG_BLOCK_SIZE(lfs) - 8, + .end = LFS_CFG_BLOCK_SIZE(lfs->cfg) - 8, }; // traverse attrs that need to be written out @@ -1901,7 +1849,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, } // successful commit, update dir - LFS_ASSERT(commit.off % LFS_CFG_PROG_SIZE(lfs) == 0); + LFS_ASSERT(commit.off % LFS_CFG_PROG_SIZE(lfs->cfg) == 0); dir->off = commit.off; dir->etag = commit.ptag; // and update gstate @@ -1990,7 +1938,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { // check that name fits lfs_size_t nlen = strlen(path); - if (nlen > lfs->name_max) { + if (nlen > lfs->name_limit) { LFS_TRACE("lfs_mkdir -> %d", LFS_ERR_NAMETOOLONG); return LFS_ERR_NAMETOOLONG; } @@ -2255,8 +2203,9 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { /// File index list operations /// static int lfs_ctz_index(lfs_t *lfs, lfs_off_t *off) { + (void)lfs; lfs_off_t size = *off; - lfs_off_t b = LFS_CFG_BLOCK_SIZE(lfs) - 2*4; + lfs_off_t b = LFS_CFG_BLOCK_SIZE(lfs->cfg) - 2*4; lfs_off_t i = size / b; if (i == 0) { return 0; @@ -2333,7 +2282,7 @@ static int lfs_ctz_extend(lfs_t *lfs, noff = noff + 1; // just copy out the last block if it is incomplete - if (noff != LFS_CFG_BLOCK_SIZE(lfs)) { + if (noff != LFS_CFG_BLOCK_SIZE(lfs->cfg)) { for (lfs_off_t i = 0; i < noff; i++) { uint8_t data; err = lfs_cache_read(lfs, @@ -2481,7 +2430,7 @@ static int lfs_file_opencommon(lfs_t *lfs, lfs_file_t *file, // check that name fits lfs_size_t nlen = strlen(path); - if (nlen > lfs->name_max) { + if (nlen > lfs->name_limit) { err = LFS_ERR_NAMETOOLONG; goto cleanup; } @@ -2518,16 +2467,17 @@ static int lfs_file_opencommon(lfs_t *lfs, lfs_file_t *file, lfs_ctz_fromle32(&file->ctz); } -#if !defined(LFS_FILE_STATICCFG) || LFS_FILE_ATTR_COUNT > 0 +#if !defined(LFS_FILE_ATTR_COUNT) || LFS_FILE_ATTR_COUNT > 0 // fetch attrs - for (unsigned i = 0; i < LFS_FILE_CFG_ATTR_COUNT(file); i++) { + for (unsigned i = 0; i < LFS_FILE_CFG_ATTR_COUNT(file->cfg); i++) { if ((file->flags & 3) != LFS_O_WRONLY) { lfs_stag_t res = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x7ff, 0x3ff, 0), LFS_MKTAG( - LFS_TYPE_USERATTR + LFS_FILE_CFG_ATTRS(file)[i].type, - file->id, LFS_FILE_CFG_ATTRS(file)[i].size), - LFS_FILE_CFG_ATTRS(file)[i].buffer); + LFS_TYPE_USERATTR + + LFS_FILE_CFG_ATTRS(file->cfg)[i].type, + file->id, LFS_FILE_CFG_ATTRS(file->cfg)[i].size), + LFS_FILE_CFG_ATTRS(file->cfg)[i].buffer); if (res < 0 && res != LFS_ERR_NOENT) { err = res; goto cleanup; @@ -2535,7 +2485,7 @@ static int lfs_file_opencommon(lfs_t *lfs, lfs_file_t *file, } if ((file->flags & 3) != LFS_O_RDONLY) { - if (LFS_FILE_CFG_ATTRS(file)[i].size > lfs->attr_max) { + if (LFS_FILE_CFG_ATTRS(file->cfg)[i].size > lfs->attr_limit) { err = LFS_ERR_NOSPC; goto cleanup; } @@ -2546,10 +2496,10 @@ static int lfs_file_opencommon(lfs_t *lfs, lfs_file_t *file, #endif // allocate buffer if needed - if (LFS_FILE_CFG_BUFFER(file)) { - file->cache.buffer = LFS_FILE_CFG_BUFFER(file); + if (LFS_FILE_CFG_BUFFER(file->cfg)) { + file->cache.buffer = LFS_FILE_CFG_BUFFER(file->cfg); } else { - file->cache.buffer = lfs_malloc(LFS_CFG_BUFFER_SIZE(lfs)); + file->cache.buffer = lfs_malloc(LFS_CFG_BUFFER_SIZE(lfs->cfg)); if (!file->cache.buffer) { err = LFS_ERR_NOMEM; goto cleanup; @@ -2566,7 +2516,7 @@ static int lfs_file_opencommon(lfs_t *lfs, lfs_file_t *file, file->flags |= LFS_F_INLINE; file->cache.block = file->ctz.head; file->cache.off = 0; - file->cache.size = LFS_CFG_BUFFER_SIZE(lfs); + file->cache.size = LFS_CFG_BUFFER_SIZE(lfs->cfg); // don't always read (may be new/trunc file) if (file->ctz.size > 0) { @@ -2634,7 +2584,7 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { } // clean up memory - if (!LFS_FILE_CFG_BUFFER(file)) { + if (!LFS_FILE_CFG_BUFFER(file->cfg)) { lfs_free(file->cache.buffer); } @@ -2696,7 +2646,8 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { } // copy over new state of file - memcpy(file->cache.buffer, lfs->pcache.buffer, LFS_CFG_BUFFER_SIZE(lfs)); + memcpy(file->cache.buffer, lfs->pcache.buffer, + LFS_CFG_BUFFER_SIZE(lfs->cfg)); file->cache.block = lfs->pcache.block; file->cache.off = lfs->pcache.off; file->cache.size = lfs->pcache.size; @@ -2773,7 +2724,8 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { // write out what we have while (true) { - int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache, true); + int err = lfs_cache_flush(lfs, + &file->cache, &lfs->rcache, true); if (err) { if (err == LFS_ERR_CORRUPT) { goto relocate; @@ -2849,7 +2801,8 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( {LFS_MKTAG(type, file->id, size), buffer}, {LFS_MKTAG(LFS_FROM_USERATTRS, file->id, - LFS_FILE_CFG_ATTR_COUNT(file)), LFS_FILE_CFG_ATTRS(file)})); + LFS_FILE_CFG_ATTR_COUNT(file->cfg)), + LFS_FILE_CFG_ATTRS(file->cfg)})); if (err) { file->flags |= LFS_F_ERRED; LFS_TRACE("lfs_file_sync -> %d", err); @@ -2894,7 +2847,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, while (nsize > 0) { // check if we need a new block if (!(file->flags & LFS_F_READING) || - file->off == LFS_CFG_BLOCK_SIZE(lfs)) { + file->off == LFS_CFG_BLOCK_SIZE(lfs->cfg)) { if (!(file->flags & LFS_F_INLINE)) { int err = lfs_ctz_find(lfs, NULL, &file->cache, file->ctz.head, file->ctz.size, @@ -2912,10 +2865,11 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, } // read as much as we can in current block - lfs_size_t diff = lfs_min(nsize, LFS_CFG_BLOCK_SIZE(lfs) - file->off); + lfs_size_t diff = lfs_min(nsize, + LFS_CFG_BLOCK_SIZE(lfs->cfg) - file->off); if (file->flags & LFS_F_INLINE) { int err = lfs_dir_getread(lfs, &file->m, - NULL, &file->cache, LFS_CFG_BLOCK_SIZE(lfs), + NULL, &file->cache, LFS_CFG_BLOCK_SIZE(lfs->cfg), LFS_MKTAG(0xfff, 0x1ff, 0), LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), file->off, data, diff); @@ -2925,7 +2879,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, } } else { int err = lfs_cache_read(lfs, - NULL, &file->cache, LFS_CFG_BLOCK_SIZE(lfs), + NULL, &file->cache, LFS_CFG_BLOCK_SIZE(lfs->cfg), file->block, file->off, data, diff); if (err) { LFS_TRACE("lfs_file_read -> %d", err); @@ -2966,7 +2920,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, file->pos = file->ctz.size; } - if (file->pos + size > lfs->file_max) { + if (file->pos + size > lfs->file_limit) { // Larger than file limit? LFS_TRACE("lfs_file_write -> %d", LFS_ERR_FBIG); return LFS_ERR_FBIG; @@ -2989,7 +2943,8 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, if ((file->flags & LFS_F_INLINE) && lfs_max(file->pos+nsize, file->ctz.size) > lfs_min(0x3fe, lfs_min( - LFS_CFG_BUFFER_SIZE(lfs), LFS_CFG_BLOCK_SIZE(lfs)/8))) { + LFS_CFG_BUFFER_SIZE(lfs->cfg), + LFS_CFG_BLOCK_SIZE(lfs->cfg)/8))) { // inline file doesn't fit anymore int err = lfs_file_outline(lfs, file); if (err) { @@ -3002,7 +2957,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, while (nsize > 0) { // check if we need a new block if (!(file->flags & LFS_F_WRITING) || - file->off == LFS_CFG_BLOCK_SIZE(lfs)) { + file->off == LFS_CFG_BLOCK_SIZE(lfs->cfg)) { if (!(file->flags & LFS_F_INLINE)) { if (!(file->flags & LFS_F_WRITING) && file->pos > 0) { // find out which block we're extending from @@ -3038,7 +2993,8 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, } // program as much as we can in current block - lfs_size_t diff = lfs_min(nsize, LFS_CFG_BLOCK_SIZE(lfs) - file->off); + lfs_size_t diff = lfs_min(nsize, + LFS_CFG_BLOCK_SIZE(lfs->cfg) - file->off); while (true) { int err = lfs_cache_prog(lfs, &file->cache, &lfs->rcache, true, file->block, file->off, data, diff); @@ -3097,7 +3053,7 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, npos = file->ctz.size + off; } - if (npos > lfs->file_max) { + if (npos > lfs->file_limit) { // file position out of range LFS_TRACE("lfs_file_seek -> %d", LFS_ERR_INVAL); return LFS_ERR_INVAL; @@ -3343,7 +3299,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { if (prevtag == LFS_ERR_NOENT) { // check that name fits lfs_size_t nlen = strlen(newpath); - if (nlen > lfs->name_max) { + if (nlen > lfs->name_limit) { LFS_TRACE("lfs_rename -> %d", LFS_ERR_NAMETOOLONG); return LFS_ERR_NAMETOOLONG; } @@ -3473,7 +3429,7 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, tag = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x7ff, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_USERATTR + type, - id, lfs_min(size, lfs->attr_max)), + id, lfs_min(size, lfs->attr_limit)), buffer); if (tag < 0) { if (tag == LFS_ERR_NOENT) { @@ -3516,7 +3472,7 @@ int lfs_setattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size) { LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", (void*)lfs, path, type, buffer, size); - if (size > lfs->attr_max) { + if (size > lfs->attr_limit) { LFS_TRACE("lfs_setattr -> %d", LFS_ERR_NOSPC); return LFS_ERR_NOSPC; } @@ -3540,19 +3496,22 @@ static int lfs_initcommon(lfs_t *lfs) { // validate that the lfs-cfg sizes were initiated properly before // performing any arithmetic logics with them - LFS_ASSERT(LFS_CFG_READ_SIZE(lfs) != 0); - LFS_ASSERT(LFS_CFG_PROG_SIZE(lfs) != 0); - LFS_ASSERT(LFS_CFG_BUFFER_SIZE(lfs) != 0); + LFS_ASSERT(LFS_CFG_READ_SIZE(lfs->cfg) != 0); + LFS_ASSERT(LFS_CFG_PROG_SIZE(lfs->cfg) != 0); + LFS_ASSERT(LFS_CFG_BUFFER_SIZE(lfs->cfg) != 0); // check that block size is a multiple of cache size is a multiple // of prog and read sizes - LFS_ASSERT(LFS_CFG_BUFFER_SIZE(lfs) % LFS_CFG_READ_SIZE(lfs) == 0); - LFS_ASSERT(LFS_CFG_BUFFER_SIZE(lfs) % LFS_CFG_PROG_SIZE(lfs) == 0); - LFS_ASSERT(LFS_CFG_BLOCK_SIZE(lfs) % LFS_CFG_BUFFER_SIZE(lfs) == 0); + LFS_ASSERT(LFS_CFG_BUFFER_SIZE(lfs->cfg) + % LFS_CFG_READ_SIZE(lfs->cfg) == 0); + LFS_ASSERT(LFS_CFG_BUFFER_SIZE(lfs->cfg) + % LFS_CFG_PROG_SIZE(lfs->cfg) == 0); + LFS_ASSERT(LFS_CFG_BLOCK_SIZE(lfs->cfg) + % LFS_CFG_BUFFER_SIZE(lfs->cfg) == 0); // check that the block size is large enough to fit ctz pointers - LFS_ASSERT(4*lfs_npw2(0xffffffff / (LFS_CFG_BLOCK_SIZE(lfs)-2*4)) - <= LFS_CFG_BLOCK_SIZE(lfs)); + LFS_ASSERT(4*lfs_npw2(0xffffffff / (LFS_CFG_BLOCK_SIZE(lfs->cfg)-2*4)) + <= LFS_CFG_BLOCK_SIZE(lfs->cfg)); // block_cycles = 0 is no longer supported. // @@ -3560,14 +3519,13 @@ static int lfs_initcommon(lfs_t *lfs) { // metadata logs as a part of wear leveling. Suggested values are in the // range of 100-1000, or set block_cycles to -1 to disable block-level // wear-leveling. - LFS_ASSERT(LFS_CFG_BLOCK_CYCLES(lfs) != 0); - + LFS_ASSERT(LFS_CFG_BLOCK_CYCLES(lfs->cfg) != 0); // setup read cache - if (LFS_CFG_READ_BUFFER(lfs)) { - lfs->rcache.buffer = LFS_CFG_READ_BUFFER(lfs); + if (LFS_CFG_READ_BUFFER(lfs->cfg)) { + lfs->rcache.buffer = LFS_CFG_READ_BUFFER(lfs->cfg); } else { - lfs->rcache.buffer = lfs_malloc(LFS_CFG_BUFFER_SIZE(lfs)); + lfs->rcache.buffer = lfs_malloc(LFS_CFG_BUFFER_SIZE(lfs->cfg)); if (!lfs->rcache.buffer) { err = LFS_ERR_NOMEM; goto cleanup; @@ -3575,10 +3533,10 @@ static int lfs_initcommon(lfs_t *lfs) { } // setup program cache - if (LFS_CFG_PROG_BUFFER(lfs)) { - lfs->pcache.buffer = LFS_CFG_PROG_BUFFER(lfs); + if (LFS_CFG_PROG_BUFFER(lfs->cfg)) { + lfs->pcache.buffer = LFS_CFG_PROG_BUFFER(lfs->cfg); } else { - lfs->pcache.buffer = lfs_malloc(LFS_CFG_BUFFER_SIZE(lfs)); + lfs->pcache.buffer = lfs_malloc(LFS_CFG_BUFFER_SIZE(lfs->cfg)); if (!lfs->pcache.buffer) { err = LFS_ERR_NOMEM; goto cleanup; @@ -3590,13 +3548,13 @@ static int lfs_initcommon(lfs_t *lfs) { lfs_cache_zero(lfs, &lfs->pcache); // setup lookahead, must be multiple of 64-bits, 32-bit aligned - LFS_ASSERT(LFS_CFG_LOOKAHEAD_SIZE(lfs) > 0); - LFS_ASSERT(LFS_CFG_LOOKAHEAD_SIZE(lfs) % 8 == 0 && - (uintptr_t)LFS_CFG_LOOKAHEAD_BUFFER(lfs) % 4 == 0); - if (LFS_CFG_LOOKAHEAD_BUFFER(lfs)) { - lfs->free.buffer = LFS_CFG_LOOKAHEAD_BUFFER(lfs); + LFS_ASSERT(LFS_CFG_LOOKAHEAD_SIZE(lfs->cfg) > 0); + LFS_ASSERT(LFS_CFG_LOOKAHEAD_SIZE(lfs->cfg) % 8 == 0 && + (uintptr_t)LFS_CFG_LOOKAHEAD_BUFFER(lfs->cfg) % 4 == 0); + if (LFS_CFG_LOOKAHEAD_BUFFER(lfs->cfg)) { + lfs->free.buffer = LFS_CFG_LOOKAHEAD_BUFFER(lfs->cfg); } else { - lfs->free.buffer = lfs_malloc(LFS_CFG_LOOKAHEAD_SIZE(lfs)); + lfs->free.buffer = lfs_malloc(LFS_CFG_LOOKAHEAD_SIZE(lfs->cfg)); if (!lfs->free.buffer) { err = LFS_ERR_NOMEM; goto cleanup; @@ -3604,22 +3562,22 @@ static int lfs_initcommon(lfs_t *lfs) { } // check that the size limits are sane - LFS_ASSERT(LFS_CFG_NAME_MAX(lfs) <= LFS_NAME_MAX); - lfs->name_max = LFS_CFG_NAME_MAX(lfs); - if (!lfs->name_max) { - lfs->name_max = LFS_NAME_MAX; + LFS_ASSERT(LFS_CFG_NAME_LIMIT(lfs->cfg) <= LFS_NAME_MAX); + lfs->name_limit = LFS_CFG_NAME_LIMIT(lfs->cfg); + if (!lfs->name_limit) { + lfs->name_limit = LFS_NAME_MAX; } - LFS_ASSERT(LFS_CFG_FILE_MAX(lfs) <= LFS_FILE_MAX); - lfs->file_max = LFS_CFG_FILE_MAX(lfs); - if (!lfs->file_max) { - lfs->file_max = LFS_FILE_MAX; + LFS_ASSERT(LFS_CFG_FILE_LIMIT(lfs->cfg) <= LFS_FILE_MAX); + lfs->file_limit = LFS_CFG_FILE_LIMIT(lfs->cfg); + if (!lfs->file_limit) { + lfs->file_limit = LFS_FILE_MAX; } - LFS_ASSERT(LFS_CFG_ATTR_MAX(lfs) <= LFS_ATTR_MAX); - lfs->attr_max = LFS_CFG_ATTR_MAX(lfs); - if (!lfs->attr_max) { - lfs->attr_max = LFS_ATTR_MAX; + LFS_ASSERT(LFS_CFG_ATTR_LIMIT(lfs->cfg) <= LFS_ATTR_MAX); + lfs->attr_limit = LFS_CFG_ATTR_LIMIT(lfs->cfg); + if (!lfs->attr_limit) { + lfs->attr_limit = LFS_ATTR_MAX; } // setup default state @@ -3643,15 +3601,15 @@ cleanup: static int lfs_deinit(lfs_t *lfs) { // free allocated memory - if (!LFS_CFG_READ_BUFFER(lfs)) { + if (!LFS_CFG_READ_BUFFER(lfs->cfg)) { lfs_free(lfs->rcache.buffer); } - if (!LFS_CFG_PROG_BUFFER(lfs)) { + if (!LFS_CFG_PROG_BUFFER(lfs->cfg)) { lfs_free(lfs->pcache.buffer); } - if (!LFS_CFG_LOOKAHEAD_BUFFER(lfs)) { + if (!LFS_CFG_LOOKAHEAD_BUFFER(lfs->cfg)) { lfs_free(lfs->free.buffer); } @@ -3667,10 +3625,10 @@ static int lfs_formatcommon(lfs_t *lfs) { } // create free lookahead - memset(lfs->free.buffer, 0, LFS_CFG_LOOKAHEAD_SIZE(lfs)); + memset(lfs->free.buffer, 0, LFS_CFG_LOOKAHEAD_SIZE(lfs->cfg)); lfs->free.off = 0; - lfs->free.size = lfs_min(8*LFS_CFG_LOOKAHEAD_SIZE(lfs), - LFS_CFG_BLOCK_COUNT(lfs)); + lfs->free.size = lfs_min(8*LFS_CFG_LOOKAHEAD_SIZE(lfs->cfg), + LFS_CFG_BLOCK_COUNT(lfs->cfg)); lfs->free.i = 0; lfs_alloc_ack(lfs); @@ -3684,11 +3642,11 @@ static int lfs_formatcommon(lfs_t *lfs) { // write one superblock lfs_superblock_t superblock = { .version = LFS_DISK_VERSION, - .block_size = LFS_CFG_BLOCK_SIZE(lfs), - .block_count = LFS_CFG_BLOCK_COUNT(lfs), - .name_max = lfs->name_max, - .file_max = lfs->file_max, - .attr_max = lfs->attr_max, + .block_size = LFS_CFG_BLOCK_SIZE(lfs->cfg), + .block_count = LFS_CFG_BLOCK_COUNT(lfs->cfg), + .name_limit = lfs->name_limit, + .file_limit = lfs->file_limit, + .attr_limit = lfs->attr_limit, }; lfs_superblock_tole32(&superblock); @@ -3739,15 +3697,15 @@ int lfs_formatcfg(lfs_t *lfs, const struct lfs_cfg *cfg) { ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", + ".name_limit=%"PRIu32", .file_limit=%"PRIu32", " + ".attr_limit=%"PRIu32"})", (void*)lfs, (void*)cfg, cfg->ctx, (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); + cfg->name_limit, cfg->file_limit, cfg->attr_limit); lfs->cfg = cfg; int err = lfs_formatcommon(lfs); LFS_TRACE("lfs_formatcfg -> %d", err); @@ -3765,7 +3723,7 @@ static int lfs_mountcommon(lfs_t *lfs) { lfs_mdir_t dir = {.tail = {0, 1}}; lfs_block_t cycle = 0; while (!lfs_pair_isnull(dir.tail)) { - if (cycle >= LFS_CFG_BLOCK_COUNT(lfs)/2) { + if (cycle >= LFS_CFG_BLOCK_COUNT(lfs->cfg)/2) { // loop detected err = LFS_ERR_CORRUPT; goto cleanup; @@ -3813,37 +3771,37 @@ static int lfs_mountcommon(lfs_t *lfs) { } // check superblock configuration - if (superblock.name_max) { - if (superblock.name_max > lfs->name_max) { - LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")", - superblock.name_max, lfs->name_max); + if (superblock.name_limit) { + if (superblock.name_limit > lfs->name_limit) { + LFS_ERROR("Unsupported name_limit (%"PRIu32" > %"PRIu32")", + superblock.name_limit, lfs->name_limit); err = LFS_ERR_INVAL; goto cleanup; } - lfs->name_max = superblock.name_max; + lfs->name_limit = superblock.name_limit; } - if (superblock.file_max) { - if (superblock.file_max > lfs->file_max) { - LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")", - superblock.file_max, lfs->file_max); + if (superblock.file_limit) { + if (superblock.file_limit > lfs->file_limit) { + LFS_ERROR("Unsupported file_limit (%"PRIu32" > %"PRIu32")", + superblock.file_limit, lfs->file_limit); err = LFS_ERR_INVAL; goto cleanup; } - lfs->file_max = superblock.file_max; + lfs->file_limit = superblock.file_limit; } - if (superblock.attr_max) { - if (superblock.attr_max > lfs->attr_max) { - LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")", - superblock.attr_max, lfs->attr_max); + if (superblock.attr_limit) { + if (superblock.attr_limit > lfs->attr_limit) { + LFS_ERROR("Unsupported attr_limit (%"PRIu32" > %"PRIu32")", + superblock.attr_limit, lfs->attr_limit); err = LFS_ERR_INVAL; goto cleanup; } - lfs->attr_max = superblock.attr_max; + lfs->attr_limit = superblock.attr_limit; } } @@ -3900,15 +3858,15 @@ int lfs_mountcfg(lfs_t *lfs, const struct lfs_cfg *cfg) { ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", + ".name_limit=%"PRIu32", .file_limit=%"PRIu32", " + ".attr_limit=%"PRIu32"})", (void*)lfs, (void*)cfg, cfg->ctx, (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); + cfg->name_limit, cfg->file_limit, cfg->attr_limit); lfs->cfg = cfg; int err = lfs_mountcommon(lfs); LFS_TRACE("lfs_mountcfg -> %d", err); @@ -3946,7 +3904,7 @@ int lfs_fs_traverseraw(lfs_t *lfs, lfs_block_t cycle = 0; while (!lfs_pair_isnull(dir.tail)) { - if (cycle >= LFS_CFG_BLOCK_COUNT(lfs)/2) { + if (cycle >= LFS_CFG_BLOCK_COUNT(lfs->cfg)/2) { // loop detected return LFS_ERR_CORRUPT; } @@ -4037,7 +3995,7 @@ static int lfs_fs_pred(lfs_t *lfs, pdir->tail[1] = 1; lfs_block_t cycle = 0; while (!lfs_pair_isnull(pdir->tail)) { - if (cycle >= LFS_CFG_BLOCK_COUNT(lfs)/2) { + if (cycle >= LFS_CFG_BLOCK_COUNT(lfs->cfg)/2) { // loop detected return LFS_ERR_CORRUPT; } @@ -4070,7 +4028,7 @@ static int lfs_fs_parent_match(void *data, lfs_block_t child[2]; int err = lfs_cache_read(lfs, - &lfs->pcache, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs), + &lfs->pcache, &lfs->rcache, LFS_CFG_BLOCK_SIZE(lfs->cfg), disk->block, disk->off, &child, sizeof(child)); if (err) { return err; @@ -4087,7 +4045,7 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2], parent->tail[1] = 1; lfs_block_t cycle = 0; while (!lfs_pair_isnull(parent->tail)) { - if (cycle >= LFS_CFG_BLOCK_COUNT(lfs)/2) { + if (cycle >= LFS_CFG_BLOCK_COUNT(lfs->cfg)/2) { // loop detected return LFS_ERR_CORRUPT; } @@ -4529,7 +4487,7 @@ static int lfs1_dir_fetch(lfs_t *lfs, } if ((0x7fffffff & test.size) < sizeof(test)+4 || - (0x7fffffff & test.size) > LFS_CFG_BLOCK_SIZE(lfs)) { + (0x7fffffff & test.size) > LFS_CFG_BLOCK_SIZE(lfs->cfg)) { continue; } @@ -4962,11 +4920,11 @@ static int lfs_migratecommon(lfs_t *lfs) { lfs_superblock_t superblock = { .version = LFS_DISK_VERSION, - .block_size = LFS_CFG_BLOCK_SIZE(lfs), - .block_count = LFS_CFG_BLOCK_COUNT(lfs), - .name_max = lfs->name_max, - .file_max = lfs->file_max, - .attr_max = lfs->attr_max, + .block_size = LFS_CFG_BLOCK_SIZE(lfs->cfg), + .block_count = LFS_CFG_BLOCK_COUNT(lfs->cfg), + .name_limit = lfs->name_limit, + .file_limit = lfs->file_limit, + .attr_limit = lfs->attr_limit, }; lfs_superblock_tole32(&superblock); @@ -5016,15 +4974,15 @@ int lfs_migratecfg(lfs_t *lfs, const struct lfs_cfg *cfg) { ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", + ".name_limit=%"PRIu32", .file_limit=%"PRIu32", " + ".attr_limit=%"PRIu32"})", (void*)lfs, (void*)cfg, cfg->ctx, (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); + cfg->name_limit, cfg->file_limit, cfg->attr_limit); lfs->cfg = cfg; int err = lfs_migratecommon(lfs); LFS_TRACE("lfs_migratecfg -> %d", err); diff --git a/lfs.h b/lfs.h index ac3d421..faae3c3 100644 --- a/lfs.h +++ b/lfs.h @@ -46,8 +46,13 @@ typedef uint32_t lfs_block_t; // info struct. Limited to <= 1022. Stored in superblock and must be // respected by other littlefs drivers. #ifndef LFS_NAME_MAX +#if defined(LFS_NAME_LIMIT) && \ + LFS_NAME_LIMIT > 0 && LFS_NAME_MAX <= 1022 +#define LFS_NAME_MAX LFS_NAME_LIMIT +#else #define LFS_NAME_MAX 255 #endif +#endif // Maximum size of a file in bytes, may be redefined to limit to support other // drivers. Limited on disk to <= 4294967296. However, above 2147483647 the @@ -55,14 +60,24 @@ typedef uint32_t lfs_block_t; // incorrect values due to using signed integers. Stored in superblock and // must be respected by other littlefs drivers. #ifndef LFS_FILE_MAX +#if defined(LFS_FILE_LIMIT) && \ + LFS_FILE_LIMIT > 0 && LFS_FILE_LIMIT <= 4294967296 +#define LFS_FILE_MAX LFS_FILE_LIMIT +#else #define LFS_FILE_MAX 2147483647 #endif +#endif // Maximum size of custom attributes in bytes, may be redefined, but there is // no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. #ifndef LFS_ATTR_MAX +#if defined(LFS_ATTR_LIMIT) && \ + LFS_ATTR_LIMIT > 0 && LFS_ATTR_LIMIT <= 1022 +#define LFS_ATTR_MAX LFS_FILE_LIMIT +#else #define LFS_ATTR_MAX 1022 #endif +#endif // File types enum lfs_type { @@ -125,50 +140,129 @@ enum lfs_whence_flags { }; -#if !defined(LFS_STATICCFG) // Configuration provided during initialization of the littlefs + +// If every config option is provided at compile time, littlefs switches +// to "LFS_STATICCFG" mode. The dynamic lfs_cfg struct is not included in +// the lfs_t struct, and *cfg functions are no longer available. +#if defined(LFS_BD_READ) && \ + defined(LFS_BD_PROG) && \ + defined(LFS_BD_ERASE) && \ + defined(LFS_BD_SYNC) && \ + defined(LFS_READ_SIZE) && \ + defined(LFS_PROG_SIZE) && \ + defined(LFS_BLOCK_SIZE) && \ + defined(LFS_BLOCK_COUNT) && \ + defined(LFS_BLOCK_CYCLES) && \ + defined(LFS_BUFFER_SIZE) && \ + defined(LFS_LOOKAHEAD_SIZE) && \ + defined(LFS_READ_BUFFER) && \ + defined(LFS_PROG_BUFFER) && \ + defined(LFS_LOOKAHEAD_BUFFER) && \ + defined(LFS_NAME_LIMIT) && \ + defined(LFS_FILE_LIMIT) && \ + defined(LFS_ATTR_LIMIT) +#define LFS_STATICCFG +#endif + +// Dynamic config struct +#ifndef LFS_STATICCFG struct lfs_cfg { +#endif // Opaque user provided context that can be used to pass // information to the block device operations + #if !(defined(LFS_BD_READ) && \ + defined(LFS_BD_PROG) && \ + defined(LFS_BD_ERASE) && \ + defined(LFS_BD_SYNC)) void *bd_ctx; + #endif // Read a region in a block. Negative error codes are propogated // to the user. + #ifndef LFS_BD_READ int (*bd_read)(void *ctx, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size); + #define LFS_CFG_BD_READ(cfg, block, off, buffer, size) \ + (cfg)->bd_read((cfg)->bd_ctx, block, off, buffer, size) + #else + #define LFS_CFG_BD_READ(cfg, block, off, buffer, size) \ + lfs_bd_read(block, off, buffer, size) + #endif // Program a region in a block. The block must have previously // been erased. Negative error codes are propogated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. + #ifndef LFS_BD_PROG int (*bd_prog)(void *ctx, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size); + #define LFS_CFG_BD_PROG(cfg, block, off, buffer, size) \ + (cfg)->bd_prog((cfg)->bd_ctx, block, off, buffer, size) + #else + #define LFS_CFG_BD_PROG(cfg, block, off, buffer, size) \ + lfs_bd_prog(block, off, buffer, size) + #endif // Erase a block. A block must be erased before being programmed. // The state of an erased block is undefined. Negative error codes // are propogated to the user. // May return LFS_ERR_CORRUPT if the block should be considered bad. + #ifndef LFS_BD_ERASE int (*bd_erase)(void *ctx, lfs_block_t block); + #define LFS_CFG_BD_ERASE(cfg, block) \ + (cfg)->bd_erase((cfg)->bd_ctx, block) + #else + #define LFS_CFG_BD_ERASE(cfg, block) \ + lfs_bd_erase(block) + #endif // Sync the state of the underlying block device. Negative error codes // are propogated to the user. + #ifndef LFS_BD_SYNC int (*bd_sync)(void *ctx); + #define LFS_CFG_BD_SYNC(cfg) \ + (cfg)->bd_sync((cfg)->bd_ctx) + #else + #define LFS_CFG_BD_SYNC(cfg) \ + lfs_bd_sync() + #endif // Minimum size of a block read. All read operations will be a // multiple of this value. + #ifndef LFS_READ_SIZE lfs_size_t read_size; + #define LFS_CFG_READ_SIZE(cfg) (cfg)->read_size + #else + #define LFS_CFG_READ_SIZE(cfg) LFS_READ_SIZE + #endif // Minimum size of a block program. All program operations will be a // multiple of this value. + #ifndef LFS_PROG_SIZE lfs_size_t prog_size; + #define LFS_CFG_PROG_SIZE(cfg) (cfg)->prog_size + #else + #define LFS_CFG_PROG_SIZE(cfg) LFS_PROG_SIZE + #endif // Size of an erasable block. This does not impact ram consumption and // may be larger than the physical erase size. However, non-inlined files // take up at minimum one block. Must be a multiple of the read // and program sizes. + #ifndef LFS_BLOCK_SIZE lfs_size_t block_size; + #define LFS_CFG_BLOCK_SIZE(cfg) (cfg)->block_size + #else + #define LFS_CFG_BLOCK_SIZE(cfg) LFS_BLOCK_SIZE + #endif // Number of erasable blocks on the device. + #ifndef LFS_BLOCK_COUNT lfs_size_t block_count; + #define LFS_CFG_BLOCK_COUNT(cfg) (cfg)->block_count + #else + #define LFS_CFG_BLOCK_COUNT(cfg) LFS_BLOCK_COUNT + #endif // Number of erase cycles before littlefs evicts metadata logs and moves // the metadata to another block. Suggested values are in the @@ -176,104 +270,139 @@ struct lfs_cfg { // of less consistent wear distribution. // // Set to -1 to disable block-level wear-leveling. + #ifndef LFS_BLOCK_CYCLES int32_t block_cycles; + #define LFS_CFG_BLOCK_CYCLES(cfg) (cfg)->block_cycles + #else + #define LFS_CFG_BLOCK_CYCLES(cfg) LFS_BLOCK_CYCLES + #endif // Size of internal buffers used to cache slices of blocks in RAM. // The littlefs needs a read buffer, a program buffer, and one additional // buffer per file. Larger buffers can improve performance by storing more // data and reducing the number of disk accesses. Must be a multiple of // the read and program sizes, and a factor of the block size. + #ifndef LFS_BUFFER_SIZE lfs_size_t buffer_size; + #define LFS_CFG_BUFFER_SIZE(cfg) (cfg)->buffer_size + #else + #define LFS_CFG_BUFFER_SIZE(cfg) LFS_BUFFER_SIZE + #endif // Size of the lookahead buffer in bytes. A larger lookahead buffer // increases the number of blocks found during an allocation pass. The // lookahead buffer is stored as a compact bitmap, so each byte of RAM // can track 8 blocks. Must be a multiple of 8. + #ifndef LFS_LOOKAHEAD_SIZE lfs_size_t lookahead_size; + #define LFS_CFG_LOOKAHEAD_SIZE(cfg) (cfg)->lookahead_size + #else + #define LFS_CFG_LOOKAHEAD_SIZE(cfg) LFS_LOOKAHEAD_SIZE + #endif // Optional statically allocated read buffer. Must be cache_size. // By default lfs_malloc is used to allocate this buffer. + #ifndef LFS_READ_BUFFER void *read_buffer; + #define LFS_CFG_READ_BUFFER(cfg) (cfg)->read_buffer + #else + #define LFS_CFG_READ_BUFFER(cfg) LFS_READ_BUFFER + #endif // Optional statically allocated program buffer. Must be cache_size. // By default lfs_malloc is used to allocate this buffer. + #ifndef LFS_PROG_BUFFER void *prog_buffer; + #define LFS_CFG_PROG_BUFFER(cfg) (cfg)->prog_buffer + #else + #define LFS_CFG_PROG_BUFFER(cfg) LFS_PROG_BUFFER + #endif // Optional statically allocated lookahead buffer. Must be lookahead_size // and aligned to a 32-bit boundary. By default lfs_malloc is used to // allocate this buffer. + #ifndef LFS_LOOKAHEAD_BUFFER void *lookahead_buffer; + #define LFS_CFG_LOOKAHEAD_BUFFER(cfg) (cfg)->lookahead_buffer + #else + #define LFS_CFG_LOOKAHEAD_BUFFER(cfg) LFS_LOOKAHEAD_BUFFER + #endif // Optional upper limit on length of file names in bytes. No downside for // larger names except the size of the info struct which is controlled by // 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_max; + #ifndef LFS_NAME_LIMIT + lfs_size_t name_limit; + #define LFS_CFG_NAME_LIMIT(cfg) (cfg)->name_limit + #else + #define LFS_CFG_NAME_LIMIT(cfg) LFS_NAME_LIMIT + #endif // Optional upper limit on files in bytes. No downside for larger files // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored // in superblock and must be respected by other littlefs drivers. - lfs_size_t file_max; + #ifndef LFS_FILE_LIMIT + lfs_size_t file_limit; + #define LFS_CFG_FILE_LIMIT(cfg) (cfg)->file_limit + #else + #define LFS_CFG_FILE_LIMIT(cfg) LFS_FILE_LIMIT + #endif // Optional upper limit on custom attributes in bytes. No downside for // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to // LFS_ATTR_MAX when zero. - lfs_size_t attr_max; + #ifndef LFS_ATTR_LIMIT + lfs_size_t attr_limit; + #define LFS_CFG_ATTR_LIMIT(cfg) (cfg)->attr_limit + #else + #define LFS_CFG_ATTR_LIMIT(cfg) LFS_ATTR_LIMIT + #endif +#ifndef LFS_STATICCFG }; -#else -// Static configuration if LFS_STATICCFG is defined, there are defaults -// for some of these, but some are required. For full documentation, see -// the lfs_cfg struct above. +#endif -// Block device operations -int lfs_bd_read(lfs_block_t block, +// Configurable callbacks are a bit special, when LFS_BD_* is defined, +// LFS_CFG_* instead expands into a call to an extern lfs_bd_*, which +// must be defined by the user. This preserves type-safety of the +// callbacks. +#ifdef LFS_BD_READ +extern int lfs_bd_read(lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size); -int lfs_bd_prog(lfs_block_t block, +#endif +#ifdef LFS_BD_PROG +extern int lfs_bd_prog(lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size); -int lfs_bd_erase(lfs_block_t block); -int lfs_bd_sync(void); - -// Required configuration -#ifndef LFS_READ_SIZE -#error "LFS_STATICCFG requires LFS_READ_SIZE" #endif -#ifndef LFS_PROG_SIZE -#error "LFS_STATICCFG requires LFS_PROG_SIZE" +#ifdef LFS_BD_ERASE +extern int lfs_bd_erase(lfs_block_t block); #endif -#ifndef LFS_BLOCK_SIZE -#error "LFS_STATICCFG requires LFS_BLOCK_SIZE" -#endif -#ifndef LFS_BLOCK_COUNT -#error "LFS_STATICCFG requires LFS_BLOCK_COUNT" -#endif -#ifndef LFS_BLOCK_CYCLES -#error "LFS_STATICCFG requires LFS_BLOCK_CYCLES" -#endif -#ifndef LFS_BUFFER_SIZE -#error "LFS_STATICCFG requires LFS_BUFFER_SIZE" -#endif -#ifndef LFS_LOOKAHEAD_SIZE -#error "LFS_STATICCFG requires LFS_LOOKAHEAD_SIZE" +#ifdef LFS_BD_SYNC +extern int lfs_bd_sync(void); #endif -// Optional configuration -#ifndef LFS_READ_BUFFER -#define LFS_READ_BUFFER NULL -#endif -#ifndef LFS_PROG_BUFFER -#define LFS_PROG_BUFFER NULL -#endif -#ifndef LFS_LOOKAHEAD_BUFFER -#define LFS_LOOKAHEAD_BUFFER NULL -#endif +// If every config option is provided at compile time, littlefs switches +// to "LFS_FILE_STATICCFG" mode. The dynamic lfs_file_cfg struct is not +// included in the lfs_file_t struct, and *cfg functions are no longer +// available. +#if defined(LFS_FILE_BUFFER) && \ + defined(LFS_FILE_ATTRS) && \ + defined(LFS_FILE_ATTR_COUNT) +#define LFS_STATICCFG #endif -#if !defined(LFS_FILE_STATICCFG) +#ifndef LFS_FILE_STATICCFG // Optional configuration provided during lfs_file_opencfg struct lfs_file_cfg { +#endif // Optional statically allocated file buffer. Must be cache_size. // By default lfs_malloc is used to allocate this buffer. + #ifndef LFS_FILE_BUFFER void *buffer; + #define LFS_FILE_CFG_BUFFER(cfg) (cfg)->buffer + #else + #define LFS_FILE_CFG_BUFFER(cfg) LFS_FILE_BUFFER + #endif // Optional list of custom attributes related to the file. If the file // is opened with read access, these attributes will be read from disk @@ -286,23 +415,22 @@ struct lfs_file_cfg { // than the buffer, it will be padded with zeros. If the stored attribute // is larger, then it will be silently truncated. If the attribute is not // found, it will be created implicitly. + #ifndef LFS_FILE_ATTRS struct lfs_attr *attrs; + #define LFS_FILE_CFG_ATTRS(cfg) (cfg)->attrs + #else + #define LFS_FILE_CFG_ATTRS(cfg) LFS_FILE_ATTRS + #endif // Number of custom attributes in the list + #ifndef LFS_FILE_ATTR_COUNT lfs_size_t attr_count; + #define LFS_FILE_CFG_ATTR_COUNT(cfg) (cfg)->attr_count + #else + #define LFS_FILE_CFG_ATTR_COUNT(cfg) LFS_FILE_ATTR_COUNT + #endif +#ifndef LFS_FILE_STATICCFG }; -#else -// Static configuration if LFS_FILE_STATICCFG is defined. For full -// documentation, see the lfs_file_cfg struct above. -#ifndef LFS_FILE_BUFFER -#define LFS_FILE_BUFFER NULL -#endif -#ifndef LFS_FILE_ATTRS -#define LFS_FILE_ATTRS ((struct lfs_attr*)NULL) -#endif -#ifndef LFS_FILE_ATTR_COUNT -#define LFS_FILE_ATTR_COUNT 0 -#endif #endif // File info structure @@ -392,9 +520,9 @@ typedef struct lfs_superblock { uint32_t version; lfs_size_t block_size; lfs_size_t block_count; - lfs_size_t name_max; - lfs_size_t file_max; - lfs_size_t attr_max; + lfs_size_t name_limit; + lfs_size_t file_limit; + lfs_size_t attr_limit; } lfs_superblock_t; typedef struct lfs_gstate { @@ -431,9 +559,9 @@ typedef struct lfs { #ifndef LFS_STATICCFG const struct lfs_cfg *cfg; #endif - lfs_size_t name_max; - lfs_size_t file_max; - lfs_size_t attr_max; + lfs_size_t name_limit; + lfs_size_t file_limit; + lfs_size_t attr_limit; #ifdef LFS_MIGRATE struct lfs1 *lfs1; diff --git a/scripts/test.py b/scripts/test.py index 80a9241..4ecd9f0 100755 --- a/scripts/test.py +++ b/scripts/test.py @@ -84,6 +84,17 @@ DEFINES = { 'LFS_ERASE_CYCLES': 0, 'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_PROGERROR', } +CFG = { + 'read_size': 'LFS_READ_SIZE', + 'prog_size': 'LFS_PROG_SIZE', + 'read_size': 'LFS_READ_SIZE', + 'prog_size': 'LFS_PROG_SIZE', + 'block_size': 'LFS_BLOCK_SIZE', + 'block_count': 'LFS_BLOCK_COUNT', + 'block_cycles': 'LFS_BLOCK_CYCLES', + 'buffer_size': 'LFS_BUFFER_SIZE', + 'lookahead_size': 'LFS_LOOKAHEAD_SIZE', +} PROLOGUE = """ // prologue __attribute__((unused)) lfs_t lfs; @@ -97,18 +108,12 @@ PROLOGUE = """ __attribute__((unused)) int err; __attribute__((unused)) const struct lfs_cfg cfg = { - .bd_ctx = &bd, - .bd_read = lfs_testbd_readctx, - .bd_prog = lfs_testbd_progctx, - .bd_erase = lfs_testbd_erasectx, - .bd_sync = lfs_testbd_syncctx, - .read_size = LFS_READ_SIZE, - .prog_size = LFS_PROG_SIZE, - .block_size = LFS_BLOCK_SIZE, - .block_count = LFS_BLOCK_COUNT, - .block_cycles = LFS_BLOCK_CYCLES, - .buffer_size = LFS_BUFFER_SIZE, - .lookahead_size = LFS_LOOKAHEAD_SIZE, + .bd_ctx = &bd, + .bd_read = lfs_testbd_readctx, + .bd_prog = lfs_testbd_progctx, + .bd_erase = lfs_testbd_erasectx, + .bd_sync = lfs_testbd_syncctx, +%(cfg)s }; __attribute__((unused)) const struct lfs_testbd_cfg bdcfg = { @@ -202,7 +207,11 @@ class TestCase: for k in sorted(self.perms[0].defines) if k not in self.defines))) - f.write(PROLOGUE) + f.write(PROLOGUE % dict( + cfg='\n'.join( + 8*' '+'.%s = %s,\n' % (k, d) + for k, d in sorted(CFG.items()) + if d not in self.suite.defines))) f.write('\n') f.write(4*' '+'// test case %d\n' % self.caseno) f.write(4*' '+'#line %d "%s"\n' % (self.code_lineno, self.suite.path)) diff --git a/tests/test_alloc.toml b/tests/test_alloc.toml index 07f63c2..fc8a1e5 100644 --- a/tests/test_alloc.toml +++ b/tests/test_alloc.toml @@ -492,17 +492,17 @@ code = ''' // create one block hole for half a directory lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; - for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { + for (lfs_size_t i = 0; i < LFS_BLOCK_SIZE; i += 2) { memcpy(&buffer[i], "hi", 2); } - lfs_file_write(&lfs, &file, buffer, cfg.block_size) => cfg.block_size; + lfs_file_write(&lfs, &file, buffer, LFS_BLOCK_SIZE) => LFS_BLOCK_SIZE; lfs_file_close(&lfs, &file) => 0; lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < (cfg.block_count-4)*(cfg.block_size-8); + i < (LFS_BLOCK_COUNT-4)*(LFS_BLOCK_SIZE-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -518,10 +518,10 @@ code = ''' lfs_mkdir(&lfs, "splitdir") => 0; lfs_file_open(&lfs, &file, "splitdir/bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; - for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { + for (lfs_size_t i = 0; i < LFS_BLOCK_SIZE; i += 2) { memcpy(&buffer[i], "hi", 2); } - lfs_file_write(&lfs, &file, buffer, 2*cfg.block_size) => LFS_ERR_NOSPC; + lfs_file_write(&lfs, &file, buffer, 2*LFS_BLOCK_SIZE) => LFS_ERR_NOSPC; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; @@ -541,7 +541,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2)/2)*(cfg.block_size-8); + i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -552,7 +552,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); + i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -569,7 +569,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2)/2)*(cfg.block_size-8); + i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -583,7 +583,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); + i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -606,7 +606,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2)/2)*(cfg.block_size-8); + i < ((LFS_BLOCK_COUNT-2)/2)*(LFS_BLOCK_SIZE-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -617,7 +617,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); + i < ((LFS_BLOCK_COUNT-2+1)/2)*(LFS_BLOCK_SIZE-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -634,7 +634,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8); + i < ((LFS_BLOCK_COUNT-2)/2 - 1)*(LFS_BLOCK_SIZE-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } diff --git a/tests/test_truncate.toml b/tests/test_truncate.toml index 4fffb4a..8eafdcb 100644 --- a/tests/test_truncate.toml +++ b/tests/test_truncate.toml @@ -100,7 +100,7 @@ code = ''' lfs_file_open(&lfs, &file, "sequence", LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; - size = lfs_min(lfs.cfg->buffer_size, sizeof(buffer)/2); + size = lfs_min(LFS_BUFFER_SIZE, sizeof(buffer)/2); lfs_size_t qsize = size / 4; uint8_t *wb = buffer; uint8_t *rb = buffer + size;