diff options
author | Christopher Haster <chaster@utexas.edu> | 2019-01-30 06:53:56 +0300 |
---|---|---|
committer | Christopher Haster <chaster@utexas.edu> | 2019-01-30 07:43:19 +0300 |
commit | 95c1a6339ddd9e0dbbc19bf0be0c37f629af2b5d (patch) | |
tree | 448e93c20db940dc7485bd23f4108a804b003bb4 | |
parent | 173c21215159236b2d93caf2856636d29680ef79 (diff) |
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
-rw-r--r-- | lfs.c | 10 |
1 files changed, 5 insertions, 5 deletions
@@ -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? |