Эх сурвалжийг харах

Fixed allocation-eviction issue when erase state is multiple of block_cycles+1

This rather interesting corner-case arises in lfs_dir_alloc anytime the
uninitialized revision count happens to be a multiple of block_cycles+1.

For example, the source of the bug found by tim-nordell-nimbelink:

rev = 2742492087
block_cycles = 100

2742492087 % (100+1) = 0

The reason for this weird block_cycles+1 case is due to a fix for a
previous bug in fe957de. To avoid aliasing, which would cause metadata
pairs to wear unevenly, block_cycles incremented to the next odd number.

Normally, littlefs tweaks the revision count of blocks during
lfs_dir_alloc in order to make sure evictions can't happen on the first
compact. Otherwise, higher-level logic such as lfs_format would break.

However, this wasn't updated with the aliasing fix in fe957de, so
lfs_dir_alloc was only rounding the revision count to the nearest even
number.

The current fix is to change the logic in lfs_dir_alloc to explicitly
check for the eviction condition and increment if eviction would occur.

Found by tim-nordell-nimbelink
Christopher Haster 5 жил өмнө
parent
commit
d04c1392c0
1 өөрчлөгдсөн 6 нэмэгдсэн , 2 устгасан
  1. 6 2
      lfs.c

+ 6 - 2
lfs.c

@@ -1375,8 +1375,12 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
         return err;
     }
 
-    // make sure we don't immediately evict
-    dir->rev += dir->rev & 1;
+    // make sure we don't immediately evict, see lfs_dir_compact for why
+    // this check is so complicated
+    if (lfs->cfg->block_cycles > 0 &&
+            (dir->rev + 1) % ((lfs->cfg->block_cycles+1)|1) == 0) {
+        dir->rev += 1;
+    }
 
     // set defaults
     dir->off = sizeof(dir->rev);