From 5aed6159f73e2c382b66d71f15145b5d95252df4 Mon Sep 17 00:00:00 2001 From: Chris Kirby Date: Wed, 28 May 2025 13:48:22 -0500 Subject: [PATCH] Don't overrun the block budget in server_log_merge_free_work(). This fixes a potential fence post failure like the following: error: 1 holders exceeded alloc budget av: bef 7407 now 7392, fr: bef 8185 now 7672 The code is only accounting for the freed btree blocks, not the dirtying of other items. So it's possible to be at exactly (COMMIT_HOLD_ALLOC_BUDGET / 2), dirty some log btree blocks, loop again, then consume another (COMMIT_HOLD_ALLOC_BUDGET / 2) and blow past the total budget. In this example, we went over by 13 blocks. By only consuming up to 1/8 of the budget on each loop, and committing when we have consumed 3/4 of the budget, we can avoid the fence post condition. Signed-off-by: Chris Kirby --- kmod/src/server.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmod/src/server.c b/kmod/src/server.c index 9244f8d2..1fc18025 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -2531,7 +2531,7 @@ static void server_log_merge_free_work(struct work_struct *work) ret = scoutfs_btree_free_blocks(sb, &server->alloc, &server->wri, &fr.key, - &fr.root, COMMIT_HOLD_ALLOC_BUDGET / 2); + &fr.root, COMMIT_HOLD_ALLOC_BUDGET / 8); if (ret < 0) { err_str = "freeing log btree"; break; @@ -2550,7 +2550,7 @@ static void server_log_merge_free_work(struct work_struct *work) /* freed blocks are in allocator, we *have* to update fr */ BUG_ON(ret < 0); - if (server_hold_alloc_used_since(sb, &hold) >= COMMIT_HOLD_ALLOC_BUDGET / 2) { + if (server_hold_alloc_used_since(sb, &hold) >= (COMMIT_HOLD_ALLOC_BUDGET * 3) / 4) { mutex_unlock(&server->logs_mutex); ret = server_apply_commit(sb, &hold, ret); commit = false;