From e82ebb8da21c06d0050c5cdff8149f1f5aab5e44 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Mon, 18 Dec 2023 00:42:05 -0600 Subject: [PATCH] Prevented attempts to append to block when crystal < prog_size This will always fail due to prog alignment, but we won't notice because the align flag gets set in the flush loop. So it's not a _hard_ error, but results in an unnecessary btree commit and a bunch of extra reading. Some of these checks aren't necessary if crystal_thresh >= prog_size, which should always be the case, but wanting crystal_size=0 to be a shorthand for "no crystallization" makes it's possible. Maybe we should set crystal_thresh = lfs_max32(crystal_thresh, prog_size) in the future... --- lfs.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lfs.c b/lfs.c index 0c1e1d2c..1ec2c064 100644 --- a/lfs.c +++ b/lfs.c @@ -9888,12 +9888,18 @@ static int lfsr_ftree_flush(lfs_t *lfs, // wait, found block-level erased-state? if (tag == LFSR_TAG_BLOCK && becksum.size != -1 + // data not truncated? && bptr.data.u.disk.off + lfsr_data_size(&bptr.data) == bptr.cksize - && pos - (bid-(weight-1)) - >= lfsr_data_size(&bptr.data)) { + // not clobbering data? + && crystal_start - (bid-(weight-1)) + >= lfsr_data_size(&bptr.data) + // enough for prog alignment? + && crystal_end - crystal_start + >= lfs->cfg->prog_size) { LFS_ASSERT(bptr.cksize + becksum.size <= lfs->cfg->block_size); + err = lfsr_ecksum_validate(lfs, &becksum, bptr.data.u.disk.block, bptr.cksize); if (err && err != LFS_ERR_CORRUPT) { @@ -9943,7 +9949,9 @@ static int lfsr_ftree_flush(lfs_t *lfs, } // below our crystallization threshold? fallback to writing fragments - if (crystal_end - crystal_start < lfs->cfg->crystal_thresh) { + if (crystal_end - crystal_start < lfs->cfg->crystal_thresh + // enough for prog alignment? + || crystal_end - crystal_start < lfs->cfg->prog_size) { break; } @@ -9980,10 +9988,15 @@ static int lfsr_ftree_flush(lfs_t *lfs, // wait, found block-level erased-state? if (tag == LFSR_TAG_BLOCK && becksum.size != -1 + // data not truncated? && bptr.data.u.disk.off + lfsr_data_size(&bptr.data) == bptr.cksize + // not clobbering data? && crystal_start - (bid-(weight-1)) - >= lfsr_data_size(&bptr.data)) { + >= lfsr_data_size(&bptr.data) + // enough for prog alignment? + && crystal_end - crystal_start + >= lfs->cfg->prog_size) { LFS_ASSERT(bptr.cksize + becksum.size <= lfs->cfg->block_size);