Fixed corner case in block_cycles eviction logic

The problem was when we allocate a dir-pair, it's possible for the
revision count to immediately overflow and the dir-pair be evicted and
returned to the unused blocks without being written even once. In the
case that block_cycles = 1, this made it impossible to ever create a
dir-pair, even in lfs_format.

I've also added a bit of logic to lfs_dir_alloc that will prevent
any immediate evictions because of the revision count.

found by TheLoneWolfling
This commit is contained in:
Christopher Haster 2019-01-29 21:53:56 -06:00
parent 173c212151
commit 95c1a6339d

10
lfs.c
View File

@ -1316,15 +1316,14 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
int err = lfs_bd_read(lfs,
NULL, &lfs->rcache, sizeof(dir->rev),
dir->pair[0], 0, &dir->rev, sizeof(dir->rev));
if (err) {
return err;
}
dir->rev = lfs_fromle32(dir->rev);
if (err && err != LFS_ERR_CORRUPT) {
return err;
}
// make sure we don't immediately evict
dir->rev += dir->rev & 1;
// set defaults
dir->off = sizeof(dir->rev);
dir->etag = 0xffffffff;
@ -1457,7 +1456,8 @@ static int lfs_dir_compact(lfs_t *lfs,
// increment revision count
dir->rev += 1;
if (lfs->cfg->block_cycles && dir->rev % lfs->cfg->block_cycles == 0) {
if (lfs->cfg->block_cycles &&
(dir->rev % (lfs->cfg->block_cycles+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?