Removed unnecessary randomization of offsets in lfs_alloc_reset

On first read, randomizing the allocators offset may seem appropriate
for lfs_alloc_reset. However, it ends up using the filesystem-fed
pseudorandom seed in situations it wasn't designed for.

As noted by gtaska, the combination of using xors for feeding the seed
and multiple traverses of the same CRCs can cause the seed to flip to
zeros with concerning frequency.

Removed the randomization from lfs_alloc_reset, leaving it in only
lfs_mount.

Found by gtaska
This commit is contained in:
Christopher Haster
2020-11-20 00:18:13 -06:00
parent 480cdd9f81
commit 1ae4b36f2a

18
lfs.c
View File

@@ -452,14 +452,16 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
return 0; return 0;
} }
// indicate allocated blocks have been committed into the filesystem, this
// is to prevent blocks from being garbage collected in the middle of a
// commit operation
static void lfs_alloc_ack(lfs_t *lfs) { static void lfs_alloc_ack(lfs_t *lfs) {
lfs->free.ack = lfs->cfg->block_count; lfs->free.ack = lfs->cfg->block_count;
} }
// Invalidate the lookahead buffer. This is done during mounting and // drop the lookahead buffer, this is done during mounting and failed
// failed traversals // traversals in order to avoid invalid lookahead state
static void lfs_alloc_reset(lfs_t *lfs) { static void lfs_alloc_drop(lfs_t *lfs) {
lfs->free.off = lfs->seed % lfs->cfg->block_count;
lfs->free.size = 0; lfs->free.size = 0;
lfs->free.i = 0; lfs->free.i = 0;
lfs_alloc_ack(lfs); lfs_alloc_ack(lfs);
@@ -505,7 +507,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size);
int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true);
if (err) { if (err) {
lfs_alloc_reset(lfs); lfs_alloc_drop(lfs);
return err; return err;
} }
} }
@@ -3797,8 +3799,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag); lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag);
lfs->gdisk = lfs->gstate; lfs->gdisk = lfs->gstate;
// setup free lookahead // setup free lookahead, to distribute allocations uniformly across
lfs_alloc_reset(lfs); // boots, we start the allocator at a random location
lfs->free.off = lfs->seed % lfs->cfg->block_count;
lfs_alloc_drop(lfs);
LFS_TRACE("lfs_mount -> %d", 0); LFS_TRACE("lfs_mount -> %d", 0);
return 0; return 0;