|
|
@@ -74,12 +74,12 @@ 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_size_t size = store ? lfs->cfg->cache_size : lfs->cfg->prog_size;
|
|
|
+ lfs_size_t nsize = store ? lfs->cfg->cache_size : lfs->cfg->prog_size;
|
|
|
rcache->block = block;
|
|
|
- rcache->off = lfs_aligndown(off, size);
|
|
|
- rcache->size = size;
|
|
|
+ rcache->off = lfs_aligndown(off, nsize);
|
|
|
+ rcache->size = nsize;
|
|
|
int err = lfs->cfg->read(lfs->cfg, rcache->block,
|
|
|
- rcache->off, rcache->buffer, size);
|
|
|
+ rcache->off, rcache->buffer, nsize);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
@@ -127,6 +127,19 @@ static int lfs_cache_crc(lfs_t *lfs,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) {
|
|
|
+ // do not zero, cheaper if cache is readonly or only going to be
|
|
|
+ // written with identical data (during relocates)
|
|
|
+ (void)lfs;
|
|
|
+ rcache->block = 0xffffffff;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) {
|
|
|
+ // zero to avoid information leak
|
|
|
+ memset(pcache->buffer, 0xff, lfs->cfg->prog_size);
|
|
|
+ pcache->block = 0xffffffff;
|
|
|
+}
|
|
|
+
|
|
|
static int lfs_cache_flush(lfs_t *lfs,
|
|
|
lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) {
|
|
|
if (pcache->block != 0xffffffff) {
|
|
|
@@ -140,7 +153,7 @@ static int lfs_cache_flush(lfs_t *lfs,
|
|
|
|
|
|
if (validate) {
|
|
|
// check data on disk
|
|
|
- rcache->block = 0xffffffff;
|
|
|
+ lfs_cache_drop(lfs, rcache);
|
|
|
int res = lfs_cache_cmp(lfs, NULL, rcache, pcache->block,
|
|
|
pcache->off, pcache->buffer, diff);
|
|
|
if (res < 0) {
|
|
|
@@ -152,7 +165,7 @@ static int lfs_cache_flush(lfs_t *lfs,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pcache->block = 0xffffffff;
|
|
|
+ lfs_cache_zero(lfs, pcache);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
@@ -234,7 +247,7 @@ static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
|
|
|
}
|
|
|
|
|
|
static int lfs_bd_sync(lfs_t *lfs) {
|
|
|
- lfs->rcache.block = 0xffffffff;
|
|
|
+ lfs_cache_drop(lfs, &lfs->rcache);
|
|
|
|
|
|
int err = lfs_cache_flush(lfs, &lfs->pcache, &lfs->rcache, false);
|
|
|
if (err) {
|
|
|
@@ -253,6 +266,7 @@ static int32_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2],
|
|
|
static int lfs_fs_relocate(lfs_t *lfs,
|
|
|
const lfs_block_t oldpair[2], lfs_block_t newpair[2]);
|
|
|
static int lfs_fs_forceconsistency(lfs_t *lfs);
|
|
|
+static int lfs_deinit(lfs_t *lfs);
|
|
|
|
|
|
|
|
|
/// Block allocator ///
|
|
|
@@ -294,7 +308,8 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
|
|
|
|
|
|
// check if we have looked at all blocks since last ack
|
|
|
if (lfs->free.ack == 0) {
|
|
|
- LFS_WARN("No more free space %d", lfs->free.i + lfs->free.off);
|
|
|
+ LFS_WARN("No more free space %"PRIu32,
|
|
|
+ lfs->free.i + lfs->free.off);
|
|
|
return LFS_ERR_NOSPC;
|
|
|
}
|
|
|
|
|
|
@@ -517,7 +532,7 @@ static int lfs_commitattr(lfs_t *lfs, struct lfs_commit *commit,
|
|
|
// special case for moves
|
|
|
return lfs_commitmove(lfs, commit,
|
|
|
lfs_tagsize(tag), lfs_tagid(tag),
|
|
|
- buffer, NULL);
|
|
|
+ buffer, NULL);
|
|
|
}
|
|
|
|
|
|
// check if we fit
|
|
|
@@ -549,7 +564,7 @@ static int lfs_commitattr(lfs_t *lfs, struct lfs_commit *commit,
|
|
|
for (lfs_off_t i = 0; i < size; i++) {
|
|
|
// rely on caching to make this efficient
|
|
|
uint8_t dat;
|
|
|
- int err = lfs_bd_read(lfs, disk->block, disk->off+i, &dat, 1);
|
|
|
+ err = lfs_bd_read(lfs, disk->block, disk->off+i, &dat, 1);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
@@ -723,7 +738,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
|
|
|
// the revision may be valid
|
|
|
int err = lfs_bd_read(lfs, dir->pair[0], 0, &dir->rev, 4);
|
|
|
dir->rev = lfs_fromle32(dir->rev);
|
|
|
- if (err) {
|
|
|
+ if (err && err != LFS_ERR_CORRUPT) {
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
@@ -752,11 +767,16 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
// find the block with the most recent revision
|
|
|
uint32_t rev[2];
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
- int err = lfs_bd_read(lfs, dir->pair[i], 0, &rev[i], sizeof(rev[i]));
|
|
|
- if (err) {
|
|
|
+ int err = lfs_cache_read(lfs, &lfs->pcache, &lfs->rcache, false,
|
|
|
+ dir->pair[i], 0, &rev[i], sizeof(rev[i]));
|
|
|
+ rev[i] = lfs_fromle32(rev[i]);
|
|
|
+ if (err && err != LFS_ERR_CORRUPT) {
|
|
|
return err;
|
|
|
}
|
|
|
- rev[i] = lfs_fromle32(rev[i]);
|
|
|
+
|
|
|
+ if (err == LFS_ERR_CORRUPT) {
|
|
|
+ rev[i] = rev[(i+1)%2] - 1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (lfs_scmp(rev[1], rev[0]) > 0) {
|
|
|
@@ -788,6 +808,11 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
int err = lfs_bd_read(lfs, dir->pair[0],
|
|
|
off, &tag, sizeof(tag));
|
|
|
if (err) {
|
|
|
+ if (err == LFS_ERR_CORRUPT) {
|
|
|
+ // can't continue?
|
|
|
+ dir->erased = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
@@ -809,9 +834,13 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
if (lfs_tagtype(tag) == LFS_TYPE_CRC) {
|
|
|
// check the crc attr
|
|
|
uint32_t dcrc;
|
|
|
- int err = lfs_bd_read(lfs, dir->pair[0],
|
|
|
+ err = lfs_bd_read(lfs, dir->pair[0],
|
|
|
off+sizeof(tag), &dcrc, sizeof(dcrc));
|
|
|
if (err) {
|
|
|
+ if (err == LFS_ERR_CORRUPT) {
|
|
|
+ dir->erased = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
return err;
|
|
|
}
|
|
|
dcrc = lfs_fromle32(dcrc);
|
|
|
@@ -834,7 +863,10 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
err = lfs_bd_crc(lfs, dir->pair[0],
|
|
|
off+sizeof(tag), lfs_tagsize(tag), &crc);
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ if (err == LFS_ERR_CORRUPT) {
|
|
|
+ dir->erased = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (lfs_tagid(tag) < 0x3ff && lfs_tagid(tag) >= tempcount) {
|
|
|
@@ -846,7 +878,10 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
temptail, sizeof(temptail));
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ if (err == LFS_ERR_CORRUPT) {
|
|
|
+ dir->erased = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
lfs_pairfromle32(temptail);
|
|
|
} else if (lfs_tagsubtype(tag) == LFS_TYPE_GLOBALS) {
|
|
|
@@ -854,7 +889,10 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
&templocals, sizeof(templocals));
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ if (err == LFS_ERR_CORRUPT) {
|
|
|
+ dir->erased = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
} else if (lfs_tagsubtype(tag) == LFS_TYPE_DELETE) {
|
|
|
LFS_ASSERT(tempcount > 0);
|
|
|
@@ -870,6 +908,10 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
int res = lfs_bd_cmp(lfs, dir->pair[0], off+sizeof(tag),
|
|
|
findbuffer, lfs_tagsize(tag));
|
|
|
if (res < 0) {
|
|
|
+ if (res == LFS_ERR_CORRUPT) {
|
|
|
+ dir->erased = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
@@ -904,7 +946,8 @@ static int32_t lfs_dir_find(lfs_t *lfs,
|
|
|
lfs_pairswap(rev);
|
|
|
}
|
|
|
|
|
|
- LFS_ERROR("Corrupted dir pair at %d %d", dir->pair[0], dir->pair[1]);
|
|
|
+ LFS_ERROR("Corrupted dir pair at %"PRIu32" %"PRIu32,
|
|
|
+ dir->pair[0], dir->pair[1]);
|
|
|
return LFS_ERR_CORRUPT;
|
|
|
}
|
|
|
|
|
|
@@ -1051,7 +1094,7 @@ static int lfs_dir_compact(lfs_t *lfs,
|
|
|
split:
|
|
|
// commit no longer fits, need to split dir,
|
|
|
// drop caches and create tail
|
|
|
- lfs->pcache.block = 0xffffffff;
|
|
|
+ lfs_cache_drop(lfs, &lfs->pcache);
|
|
|
|
|
|
if (ack == -1) {
|
|
|
// If we can't fit in this block, we won't fit in next block
|
|
|
@@ -1081,15 +1124,16 @@ split:
|
|
|
|
|
|
relocate:
|
|
|
//commit was corrupted
|
|
|
- LFS_DEBUG("Bad block at %d", dir->pair[1]);
|
|
|
+ LFS_DEBUG("Bad block at %"PRIu32,
|
|
|
+ dir->pair[1]);
|
|
|
|
|
|
// drop caches and prepare to relocate block
|
|
|
relocated = true;
|
|
|
- lfs->pcache.block = 0xffffffff;
|
|
|
+ lfs_cache_drop(lfs, &lfs->pcache);
|
|
|
|
|
|
// can't relocate superblock, filesystem is now frozen
|
|
|
if (lfs_paircmp(oldpair, (const lfs_block_t[2]){0, 1}) == 0) {
|
|
|
- LFS_WARN("Superblock %d has become unwritable", oldpair[1]);
|
|
|
+ LFS_WARN("Superblock %"PRIu32" has become unwritable", oldpair[1]);
|
|
|
return LFS_ERR_CORRUPT;
|
|
|
}
|
|
|
|
|
|
@@ -1108,7 +1152,7 @@ relocate:
|
|
|
lfs_globalzero(&lfs->locals);
|
|
|
} else {
|
|
|
// update references if we relocated
|
|
|
- LFS_DEBUG("Relocating %d %d to %d %d",
|
|
|
+ LFS_DEBUG("Relocating %"PRIu32" %"PRIu32" to %"PRIu32" %"PRIu32,
|
|
|
oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]);
|
|
|
int err = lfs_fs_relocate(lfs, oldpair, dir->pair);
|
|
|
if (err) {
|
|
|
@@ -1174,15 +1218,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!dir->erased) {
|
|
|
-compact:
|
|
|
- // fall back to compaction
|
|
|
- lfs->pcache.block = 0xffffffff;
|
|
|
- int err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count);
|
|
|
- if (err) {
|
|
|
- return err;
|
|
|
- }
|
|
|
- } else {
|
|
|
+ if (dir->erased) {
|
|
|
// try to commit
|
|
|
struct lfs_commit commit = {
|
|
|
.block = dir->pair[0],
|
|
|
@@ -1241,6 +1277,14 @@ compact:
|
|
|
// successful commit, update globals
|
|
|
lfs_globalxor(&dir->locals, &lfs->locals);
|
|
|
lfs_globalzero(&lfs->locals);
|
|
|
+ } else {
|
|
|
+compact:
|
|
|
+ // fall back to compaction
|
|
|
+ lfs_cache_drop(lfs, &lfs->pcache);
|
|
|
+ int err = lfs_dir_compact(lfs, dir, attrs, dir, 0, dir->count);
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// update globals that are affected
|
|
|
@@ -1583,7 +1627,7 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
|
|
|
return LFS_ERR_INVAL;
|
|
|
}
|
|
|
|
|
|
- int err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail);
|
|
|
+ err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
@@ -1752,10 +1796,10 @@ static int lfs_ctzextend(lfs_t *lfs,
|
|
|
}
|
|
|
|
|
|
relocate:
|
|
|
- LFS_DEBUG("Bad block at %d", nblock);
|
|
|
+ LFS_DEBUG("Bad block at %"PRIu32, nblock);
|
|
|
|
|
|
// just clear cache and try a new block
|
|
|
- pcache->block = 0xffffffff;
|
|
|
+ lfs_cache_drop(lfs, pcache);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1849,7 +1893,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
|
|
|
|
|
// get next slot and create entry to remember name
|
|
|
file->id = file->m.count;
|
|
|
- int err = lfs_dir_commit(lfs, &file->m,
|
|
|
+ err = lfs_dir_commit(lfs, &file->m,
|
|
|
LFS_MKATTR(LFS_TYPE_REG, file->id, path, nlen,
|
|
|
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, file->id, NULL, 0,
|
|
|
NULL)));
|
|
|
@@ -1902,7 +1946,6 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
|
|
}
|
|
|
|
|
|
// allocate buffer if needed
|
|
|
- file->cache.block = 0xffffffff;
|
|
|
if (file->cfg->buffer) {
|
|
|
file->cache.buffer = file->cfg->buffer;
|
|
|
} else {
|
|
|
@@ -1913,6 +1956,9 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // zero to avoid information leak
|
|
|
+ lfs_cache_zero(lfs, &file->cache);
|
|
|
+
|
|
|
if (lfs_tagtype(tag) == LFS_TYPE_INLINESTRUCT) {
|
|
|
// load inline files
|
|
|
file->ctz.head = 0xfffffffe;
|
|
|
@@ -2009,7 +2055,7 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) {
|
|
|
file->cache.block = lfs->pcache.block;
|
|
|
file->cache.off = lfs->pcache.off;
|
|
|
file->cache.size = lfs->pcache.size;
|
|
|
- lfs->pcache.block = 0xffffffff;
|
|
|
+ lfs_cache_zero(lfs, &lfs->pcache);
|
|
|
|
|
|
file->block = nblock;
|
|
|
return 0;
|
|
|
@@ -2036,7 +2082,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
|
|
|
.pos = file->pos,
|
|
|
.cache = lfs->rcache,
|
|
|
};
|
|
|
- lfs->rcache.block = 0xffffffff;
|
|
|
+ lfs_cache_drop(lfs, &lfs->rcache);
|
|
|
|
|
|
while (file->pos < file->ctz.size) {
|
|
|
// copy over a byte at a time, leave it up to caching
|
|
|
@@ -2054,8 +2100,8 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
|
|
|
|
|
|
// keep our reference to the rcache in sync
|
|
|
if (lfs->rcache.block != 0xffffffff) {
|
|
|
- orig.cache.block = 0xffffffff;
|
|
|
- lfs->rcache.block = 0xffffffff;
|
|
|
+ lfs_cache_drop(lfs, &orig.cache);
|
|
|
+ lfs_cache_drop(lfs, &lfs->rcache);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -2073,7 +2119,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
|
|
|
break;
|
|
|
|
|
|
relocate:
|
|
|
- LFS_DEBUG("Bad block at %d", file->block);
|
|
|
+ LFS_DEBUG("Bad block at %"PRIu32, file->block);
|
|
|
err = lfs_file_relocate(lfs, file);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
@@ -2123,7 +2169,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
|
|
|
|
|
|
// commit file data and attributes
|
|
|
lfs_ctztole32(&file->ctz);
|
|
|
- int err = lfs_dir_commit(lfs, &file->m,
|
|
|
+ err = lfs_dir_commit(lfs, &file->m,
|
|
|
LFS_MKATTR(type, file->id, buffer, size,
|
|
|
LFS_MKATTR(LFS_FROM_ATTRS, file->id, file->cfg->attrs, 0,
|
|
|
NULL)));
|
|
|
@@ -2284,7 +2330,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
|
|
|
}
|
|
|
|
|
|
// mark cache as dirty since we may have read data into it
|
|
|
- file->cache.block = 0xffffffff;
|
|
|
+ lfs_cache_zero(lfs, &file->cache);
|
|
|
}
|
|
|
|
|
|
// extend file with new blocks
|
|
|
@@ -2482,7 +2528,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
|
|
|
}
|
|
|
lfs_pairfromle32(pair);
|
|
|
|
|
|
- int err = lfs_dir_fetch(lfs, &dir, pair);
|
|
|
+ err = lfs_dir_fetch(lfs, &dir, pair);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
@@ -2504,7 +2550,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
|
|
|
}
|
|
|
|
|
|
if (lfs_tagtype(tag) == LFS_TYPE_DIR) {
|
|
|
- int err = lfs_fs_pred(lfs, dir.pair, &cwd);
|
|
|
+ err = lfs_fs_pred(lfs, dir.pair, &cwd);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
@@ -2571,7 +2617,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|
|
lfs_pairfromle32(prevpair);
|
|
|
|
|
|
// must be empty before removal
|
|
|
- int err = lfs_dir_fetch(lfs, &prevdir, prevpair);
|
|
|
+ err = lfs_dir_fetch(lfs, &prevdir, prevpair);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
@@ -2616,7 +2662,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
|
|
}
|
|
|
|
|
|
if (prevtag != LFS_ERR_NOENT && lfs_tagtype(prevtag) == LFS_TYPE_DIR) {
|
|
|
- int err = lfs_fs_pred(lfs, prevdir.pair, &newcwd);
|
|
|
+ err = lfs_fs_pred(lfs, prevdir.pair, &newcwd);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
}
|
|
|
@@ -2697,6 +2743,7 @@ static inline void lfs_superblocktole32(lfs_superblock_t *superblock) {
|
|
|
|
|
|
static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
lfs->cfg = cfg;
|
|
|
+ int err = 0;
|
|
|
|
|
|
// check that block size is a multiple of cache size is a multiple
|
|
|
// of prog and read sizes
|
|
|
@@ -2709,27 +2756,31 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
<= lfs->cfg->block_size);
|
|
|
|
|
|
// setup read cache
|
|
|
- lfs->rcache.block = 0xffffffff;
|
|
|
if (lfs->cfg->read_buffer) {
|
|
|
lfs->rcache.buffer = lfs->cfg->read_buffer;
|
|
|
} else {
|
|
|
lfs->rcache.buffer = lfs_malloc(lfs->cfg->cache_size);
|
|
|
if (!lfs->rcache.buffer) {
|
|
|
- return LFS_ERR_NOMEM;
|
|
|
+ err = LFS_ERR_NOMEM;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// setup program cache
|
|
|
- lfs->pcache.block = 0xffffffff;
|
|
|
if (lfs->cfg->prog_buffer) {
|
|
|
lfs->pcache.buffer = lfs->cfg->prog_buffer;
|
|
|
} else {
|
|
|
lfs->pcache.buffer = lfs_malloc(lfs->cfg->cache_size);
|
|
|
if (!lfs->pcache.buffer) {
|
|
|
- return LFS_ERR_NOMEM;
|
|
|
+ err = LFS_ERR_NOMEM;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // zero to avoid information leaks
|
|
|
+ lfs_cache_zero(lfs, &lfs->rcache);
|
|
|
+ lfs_cache_zero(lfs, &lfs->pcache);
|
|
|
+
|
|
|
// setup lookahead, must be multiple of 32-bits
|
|
|
LFS_ASSERT(lfs->cfg->lookahead % 32 == 0);
|
|
|
LFS_ASSERT(lfs->cfg->lookahead > 0);
|
|
|
@@ -2738,7 +2789,8 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
} else {
|
|
|
lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead/8);
|
|
|
if (!lfs->free.buffer) {
|
|
|
- return LFS_ERR_NOMEM;
|
|
|
+ err = LFS_ERR_NOMEM;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -2773,6 +2825,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
lfs_globalzero(&lfs->locals);
|
|
|
|
|
|
return 0;
|
|
|
+
|
|
|
+cleanup:
|
|
|
+ lfs_deinit(lfs);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
static int lfs_deinit(lfs_t *lfs) {
|
|
|
@@ -2809,19 +2865,19 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
lfs_mdir_t dir;
|
|
|
err = lfs_dir_alloc(lfs, &dir);
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
// write root directory
|
|
|
lfs_mdir_t root;
|
|
|
err = lfs_dir_alloc(lfs, &root);
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
err = lfs_dir_commit(lfs, &root, NULL);
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
lfs->root[0] = root.pair[0];
|
|
|
@@ -2850,16 +2906,18 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
lfs_pairfromle32(lfs->root);
|
|
|
lfs_superblockfromle32(&superblock);
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
// sanity check that fetch works
|
|
|
err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1});
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
- return lfs_deinit(lfs);
|
|
|
+cleanup:
|
|
|
+ lfs_deinit(lfs);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
@@ -2878,7 +2936,7 @@ 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) {
|
|
|
- return err;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
lfs_superblock_t superblock;
|
|
|
@@ -2886,7 +2944,8 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)),
|
|
|
&superblock);
|
|
|
if (res < 0) {
|
|
|
- return res;
|
|
|
+ err = res;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
lfs_superblockfromle32(&superblock);
|
|
|
|
|
|
@@ -2899,24 +2958,28 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
uint16_t minor_version = (0xffff & (superblock.version >> 0));
|
|
|
if ((major_version != LFS_DISK_VERSION_MAJOR ||
|
|
|
minor_version > LFS_DISK_VERSION_MINOR)) {
|
|
|
- LFS_ERROR("Invalid version %d.%d", major_version, minor_version);
|
|
|
- return LFS_ERR_INVAL;
|
|
|
+ LFS_ERROR("Invalid version %"PRIu32".%"PRIu32,
|
|
|
+ major_version, minor_version);
|
|
|
+ err = LFS_ERR_INVAL;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
res = lfs_dir_get(lfs, &superdir, 0x7ffff000,
|
|
|
LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, sizeof(lfs->root)),
|
|
|
&lfs->root);
|
|
|
if (res < 0) {
|
|
|
- return res;
|
|
|
+ err = res;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
lfs_pairfromle32(lfs->root);
|
|
|
|
|
|
// check superblock configuration
|
|
|
if (superblock.attr_max) {
|
|
|
if (superblock.attr_max > lfs->attr_max) {
|
|
|
- LFS_ERROR("Unsupported attr_max (%d > %d)",
|
|
|
+ LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")",
|
|
|
superblock.attr_max, lfs->attr_max);
|
|
|
- return LFS_ERR_INVAL;
|
|
|
+ err = LFS_ERR_INVAL;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
lfs->attr_max = superblock.attr_max;
|
|
|
@@ -2924,9 +2987,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
|
|
|
if (superblock.name_max) {
|
|
|
if (superblock.name_max > lfs->name_max) {
|
|
|
- LFS_ERROR("Unsupported name_max (%d > %d)",
|
|
|
+ LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")",
|
|
|
superblock.name_max, lfs->name_max);
|
|
|
- return LFS_ERR_INVAL;
|
|
|
+ err = LFS_ERR_INVAL;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
lfs->name_max = superblock.name_max;
|
|
|
@@ -2934,9 +2998,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
|
|
|
if (superblock.inline_max) {
|
|
|
if (superblock.inline_max > lfs->inline_max) {
|
|
|
- LFS_ERROR("Unsupported inline_max (%d > %d)",
|
|
|
+ LFS_ERROR("Unsupported inline_max (%"PRIu32" > %"PRIu32")",
|
|
|
superblock.inline_max, lfs->inline_max);
|
|
|
- return LFS_ERR_INVAL;
|
|
|
+ err = LFS_ERR_INVAL;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
lfs->inline_max = superblock.inline_max;
|
|
|
@@ -2945,9 +3010,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
// scan for any global updates
|
|
|
lfs_mdir_t dir = {.tail = {0, 1}};
|
|
|
while (!lfs_pairisnull(dir.tail)) {
|
|
|
- int err = lfs_dir_fetch(lfs, &dir, dir.tail);
|
|
|
+ err = lfs_dir_fetch(lfs, &dir, dir.tail);
|
|
|
if (err) {
|
|
|
- return err;
|
|
|
+ err = LFS_ERR_INVAL;
|
|
|
+ goto cleanup;
|
|
|
}
|
|
|
|
|
|
// xor together indirect deletes
|
|
|
@@ -2959,13 +3025,17 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
|
|
lfs_globalxor(&lfs->globals, &lfs->locals);
|
|
|
lfs_globalzero(&lfs->locals);
|
|
|
if (!lfs_pairisnull(lfs->globals.s.movepair)) {
|
|
|
- LFS_DEBUG("Found move %d %d %d",
|
|
|
+ LFS_DEBUG("Found move %"PRIu32" %"PRIu32" %"PRIu32,
|
|
|
lfs->globals.s.movepair[0],
|
|
|
lfs->globals.s.movepair[1],
|
|
|
lfs->globals.s.moveid);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
+
|
|
|
+cleanup:
|
|
|
+ lfs_unmount(lfs);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
int lfs_unmount(lfs_t *lfs) {
|
|
|
@@ -3009,7 +3079,7 @@ int lfs_fs_traverse(lfs_t *lfs,
|
|
|
lfs_ctzfromle32(&ctz);
|
|
|
|
|
|
if (lfs_tagtype(tag) == LFS_TYPE_CTZSTRUCT) {
|
|
|
- int err = lfs_ctztraverse(lfs, &lfs->rcache, NULL,
|
|
|
+ err = lfs_ctztraverse(lfs, &lfs->rcache, NULL,
|
|
|
ctz.head, ctz.size, cb, data);
|
|
|
if (err) {
|
|
|
return err;
|
|
|
@@ -3099,7 +3169,8 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|
|
const lfs_block_t oldpair[2], lfs_block_t newpair[2]) {
|
|
|
// update internal root
|
|
|
if (lfs_paircmp(oldpair, lfs->root) == 0) {
|
|
|
- LFS_DEBUG("Relocating root %d %d", newpair[0], newpair[1]);
|
|
|
+ LFS_DEBUG("Relocating root %"PRIu32" %"PRIu32,
|
|
|
+ newpair[0], newpair[1]);
|
|
|
lfs->root[0] = newpair[0];
|
|
|
lfs->root[1] = newpair[1];
|
|
|
}
|
|
|
@@ -3144,7 +3215,7 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|
|
// just replace bad pair, no desync can occur
|
|
|
parent.tail[0] = newpair[0];
|
|
|
parent.tail[1] = newpair[1];
|
|
|
- int err = lfs_dir_commit(lfs, &parent,
|
|
|
+ err = lfs_dir_commit(lfs, &parent,
|
|
|
LFS_MKATTR(LFS_TYPE_TAIL + parent.split, 0x3ff,
|
|
|
parent.tail, sizeof(parent.tail),
|
|
|
NULL));
|
|
|
@@ -3158,7 +3229,7 @@ static int lfs_fs_relocate(lfs_t *lfs,
|
|
|
|
|
|
static int lfs_fs_forceconsistency(lfs_t *lfs) {
|
|
|
if (!lfs->globals.s.deorphaned) {
|
|
|
- LFS_DEBUG("Found orphans %d",
|
|
|
+ LFS_DEBUG("Found orphans %"PRIu32,
|
|
|
lfs->globals.s.deorphaned);
|
|
|
|
|
|
// Fix any orphans
|
|
|
@@ -3183,7 +3254,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
|
|
|
|
|
|
if (tag == LFS_ERR_NOENT) {
|
|
|
// we are an orphan
|
|
|
- LFS_DEBUG("Fixing orphan %d %d",
|
|
|
+ LFS_DEBUG("Fixing orphan %"PRIu32" %"PRIu32,
|
|
|
pdir.tail[0], pdir.tail[1]);
|
|
|
|
|
|
pdir.tail[0] = dir.tail[0];
|
|
|
@@ -3208,7 +3279,8 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
|
|
|
|
|
|
if (!lfs_pairsync(pair, pdir.tail)) {
|
|
|
// we have desynced
|
|
|
- LFS_DEBUG("Fixing half-orphan %d %d", pair[0], pair[1]);
|
|
|
+ LFS_DEBUG("Fixing half-orphan %"PRIu32" %"PRIu32,
|
|
|
+ pair[0], pair[1]);
|
|
|
|
|
|
pdir.tail[0] = pair[0];
|
|
|
pdir.tail[1] = pair[1];
|
|
|
@@ -3233,7 +3305,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) {
|
|
|
|
|
|
if (lfs->globals.s.moveid != 0x3ff) {
|
|
|
// Fix bad moves
|
|
|
- LFS_DEBUG("Fixing move %d %d %d",
|
|
|
+ LFS_DEBUG("Fixing move %"PRIu32" %"PRIu32" %"PRIu32,
|
|
|
lfs->globals.s.movepair[0],
|
|
|
lfs->globals.s.movepair[1],
|
|
|
lfs->globals.s.moveid);
|
|
|
@@ -3291,6 +3363,7 @@ int lfs_fs_setattr(lfs_t *lfs,
|
|
|
}
|
|
|
|
|
|
static int lfs_fs_size_count(void *p, lfs_block_t block) {
|
|
|
+ (void)block;
|
|
|
lfs_size_t *size = p;
|
|
|
*size += 1;
|
|
|
return 0;
|