From 2d62d2f4c9f4743e090ce503fd5d4f9eb104da70 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 4 Oct 2024 13:19:40 -0500 Subject: [PATCH] Fixed metadata_max==prog_size commit->end calculation The inconsistency here between the use of block_size vs metadata_max was suspicious. Turns out there's a bug when metadata_max == prog_size. We correctly use metadata_max for the block_size/2 check, but we weren't using it for the block_size-40 check. The second check seems unnecessary after the first, but it protects against running out of space in a commit for commit-related metadata (checksums, tail pointers, etc) when we can't program half-blocks. Turns out this is also needed when limiting metadata_max to a single prog, otherwise we risk erroring with LFS_ERR_NOSPC early. Found by ajheck, dpkristensen, NLLK, and likely others. --- lfs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lfs.c b/lfs.c index d35d5d6d..1f8c9c65 100644 --- a/lfs.c +++ b/lfs.c @@ -2128,13 +2128,14 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir, // And we cap at half a block to avoid degenerate cases with // nearly-full metadata blocks. // + lfs_size_t metadata_max = (lfs->cfg->metadata_max) + ? lfs->cfg->metadata_max + : lfs->cfg->block_size; if (end - split < 0xff && size <= lfs_min( - lfs->cfg->block_size - 40, + metadata_max - 40, lfs_alignup( - (lfs->cfg->metadata_max - ? lfs->cfg->metadata_max - : lfs->cfg->block_size)/2, + metadata_max/2, lfs->cfg->prog_size))) { break; }