From 0ea9bdfec8fb898fcd9db15383e041aec2306d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Mon, 13 Jul 2026 13:56:03 +0200 Subject: [PATCH 1/2] repart: Fix growing the partition preceding a FreeArea from leftover space The "Donate to preceding partition" logic is dead code since commit 19903a4 ("repart: split out context_grow_partition_one()"). context_grow_partition_one() gets passed a free area and a partition, and it has an early-return check to ensure the partition it got passed belongs to the free area it got passed. That means we compare the FreeArea a to the FreeArea a->after->allocated_to_area, which always yields FALSE. Fix the behavior of donating any left over space to the preceding partition by adding that partition to the loop below (and relying on the partitions list being ordered according to physical partition offsets). Since this behavior is not that easy to trigger, mention how to trigger it in a comment, and add a test for it as well. --- src/repart/repart.c | 25 ++++------- test/units/TEST-58-REPART.sh | 86 ++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 17 deletions(-) diff --git a/src/repart/repart.c b/src/repart/repart.c index 271056a06a..d245cab539 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -1652,23 +1652,14 @@ static bool context_grow_partitions_phase( return !try_again; } -static void context_grow_partition_one(Context *context, FreeArea *a, Partition *p, uint64_t *span) { +static void context_grow_partition_one(Context *context, Partition *p, uint64_t *span) { uint64_t m; assert(context); - assert(a); assert(p); assert(span); - if (*span == 0) - return; - - if (p->allocated_to_area != a) - return; - - if (PARTITION_IS_FOREIGN(p)) - return; - + assert(*span > 0); assert(p->new_size != UINT64_MAX); /* Calculate new size and align. */ @@ -1708,15 +1699,15 @@ static int context_grow_partitions_on_free_area(Context *context, FreeArea *a) { if (context_grow_partitions_phase(context, a, phase, &span, &weight_sum)) phase++; /* go to the next phase */ - /* We still have space left over? Donate to preceding partition if we have one */ - if (span > 0 && a->after) - context_grow_partition_one(context, a, a->after, &span); - /* What? Even still some space left (maybe because there was no preceding partition, or it had a - * size limit), then let's donate it to whoever wants it. */ + /* What? Even still some space left (because one partition had max_size < share + * and another had min_size > share), then let's donate it to whoever wants it. */ if (span > 0) LIST_FOREACH(partitions, p, context->partitions) { - context_grow_partition_one(context, a, p, &span); + if (p->allocated_to_area != a && p->padding_area != a) + continue; + + context_grow_partition_one(context, p, &span); if (span == 0) break; } diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh index 863023454e..8593a86c86 100755 --- a/test/units/TEST-58-REPART.sh +++ b/test/units/TEST-58-REPART.sh @@ -2703,6 +2703,92 @@ EOF assert_in "$imgs/gap.img3 : start= 22528, size= 20480, type=$usr_guid, uuid=$usr_uuid, name=\"part-b\"" "$output" } +testcase_distribute_leftover_space() { + local defs imgs output + + defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")" + imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")" + # shellcheck disable=SC2064 + trap "rm -rf '$defs' '$imgs'" RETURN + chmod 0755 "$defs" + + echo "*** Left over space after distributing according to weights should still be assigned ***" + + tee "$defs/01-esp.conf" < Date: Mon, 13 Jul 2026 16:37:56 +0200 Subject: [PATCH 2/2] repart: Make use of partitions list being ordered by offsets while looping Let's do the same thing we did above with the last commit here too and make use of the partitions list being ordered by physical offsets. This makes the code a little simpler. --- src/repart/repart.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/repart/repart.c b/src/repart/repart.c index d245cab539..bc6df85b26 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -1717,15 +1717,12 @@ static int context_grow_partitions_on_free_area(Context *context, FreeArea *a) { Partition *last_partition = NULL; LIST_FOREACH(partitions, p, context->partitions) - if (p->allocated_to_area == a) + if (p->allocated_to_area == a || p->padding_area == a) last_partition = p; if (last_partition) { assert(last_partition->new_padding != UINT64_MAX); last_partition->new_padding += round_down_size(span, context->grain_size); - } else if (a->after) { - assert(a->after->new_padding != UINT64_MAX); - a->after->new_padding += round_down_size(span, context->grain_size); } }