diff --git a/src/repart/repart.c b/src/repart/repart.c index c1eeb498a8..1b1ad673c9 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -4333,6 +4333,15 @@ static int context_dump_partitions(Context *context) { (void) table_set_align_percent(t, table_get_cell(t, 0, 11), 100); (void) table_set_align_percent(t, table_get_cell(t, 0, 12), 100); + size_t n_partitions = 0; + LIST_FOREACH(partitions, p, context->partitions) { + if (p->dropped) + continue; + + n_partitions++; + } + + size_t cur_n_partition = 0; LIST_FOREACH(partitions, p, context->partitions) { _cleanup_free_ char *size_change = NULL, *padding_change = NULL, *partname = NULL, *rh = NULL; char uuid_buffer[SD_ID128_UUID_STRING_MAX]; @@ -4341,6 +4350,8 @@ static int context_dump_partitions(Context *context) { if (p->dropped) continue; + cur_n_partition++; + if (p->current_size == UINT64_MAX) activity = "create"; else if (p->current_size != p->new_size) @@ -4381,10 +4392,10 @@ static int context_dump_partitions(Context *context) { TABLE_UINT64, p->offset, TABLE_UINT64, p->current_size == UINT64_MAX ? 0 : p->current_size, TABLE_UINT64, p->new_size, - TABLE_STRING, size_change, TABLE_SET_COLOR, !p->partitions_next && sum_size > 0 ? ansi_underline() : NULL, + TABLE_STRING, size_change, TABLE_SET_COLOR, cur_n_partition == n_partitions && sum_size > 0 ? ansi_underline() : NULL, TABLE_UINT64, p->current_padding == UINT64_MAX ? 0 : p->current_padding, TABLE_UINT64, p->new_padding, - TABLE_STRING, padding_change, TABLE_SET_COLOR, !p->partitions_next && sum_padding > 0 ? ansi_underline() : NULL, + TABLE_STRING, padding_change, TABLE_SET_COLOR, cur_n_partition == n_partitions && sum_padding > 0 ? ansi_underline() : NULL, TABLE_STRING, activity ?: "unchanged", TABLE_STRING, rh, TABLE_STRV, p->drop_in_files, @@ -11261,6 +11272,57 @@ static int determine_auto_size( return 0; } +static void context_sort_partitions(Context *context) { + assert(context); + + Partition *p; + LIST_HEAD(Partition, new_partitions) = NULL; + LIST_HEAD(Partition, existing_partitions) = NULL; + LIST_HEAD(Partition, dropped_partitions) = NULL; + + while ((p = LIST_POP(partitions, context->partitions))) { + if (p->allocated_to_area) + LIST_APPEND(partitions, new_partitions, p); + else if (p->dropped) + LIST_APPEND(partitions, dropped_partitions, p); + else + LIST_APPEND(partitions, existing_partitions, p); + } + + /* First sort existing partitions by their offset */ + while ((p = LIST_POP(partitions, existing_partitions))) { + Partition *cursor = NULL; + + assert(p->offset != UINT64_MAX); + + LIST_FOREACH(partitions, q, context->partitions) + if (p->offset > q->offset) + cursor = q; + + LIST_INSERT_AFTER(partitions, context->partitions, cursor, p); + } + + /* Then insert the partitions we'll newly create in the free areas */ + while ((p = LIST_POP(partitions, new_partitions))) { + FreeArea *a = p->allocated_to_area; + Partition *cursor = a->after; + + /* Advance past partitions of this area that we already inserted */ + LIST_FOREACH(partitions, q, context->partitions) + if (q->allocated_to_area == a) + cursor = q; + + LIST_INSERT_AFTER(partitions, context->partitions, cursor, p); + } + + /* Finally append any dropped partitions to the end of the list */ + while ((p = LIST_POP(partitions, dropped_partitions))) { + assert(p->offset == UINT64_MAX); + + LIST_APPEND(partitions, context->partitions, p); + } +} + static int context_ponder(Context *context) { int r; @@ -11305,6 +11367,10 @@ static int context_ponder(Context *context) { p->definition_path, p->supplement_for->definition_path); } + /* Now that we know which new partition goes into which free area, reorder + * the partitions list so that the list is in the right order. */ + context_sort_partitions(context); + /* Now assign free space according to the weight logic */ r = context_grow_partitions(context); if (r < 0) diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh index ddab61f1dc..88d486ebc0 100755 --- a/test/units/TEST-58-REPART.sh +++ b/test/units/TEST-58-REPART.sh @@ -706,6 +706,149 @@ EOF assert_in "$imgs/unaligned3 : start= 3662944, size= 17308536, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\"" "$output" } +testcase_output_order() { + 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 "*** Ensure the order of the partition list is correct ***" + + # make this one min size 20MiB so that it has to be assigned slot 4 + tee "$defs/01-home.conf" < 0B", + "activity" : "unchanged" + }, + { + "type" : "swap", + "label" : "swap", + "uuid" : "78c92db8-3d2b-4823-b0dc-792b78f66f1e", + "partno" : 3, + "file" : "$defs/02-swap.conf", + "node" : "$imgs/order4", + "offset" : 16777216, + "old_size" : 0, + "raw_size" : 14680064, + "size" : "-> 14M", + "old_padding" : 0, + "raw_padding" : 0, + "padding" : "-> 0B", + "activity" : "create" + }, + { + "type" : "esp", + "label" : "esp", + "uuid" : "91c30bc9-0187-4db6-81a2-c648294197f8", + "partno" : 2, + "file" : "$defs/03-esp.conf", + "node" : "$imgs/order3", + "offset" : 31457280, + "old_size" : 10485760, + "raw_size" : 26202112, + "size" : "10M -> 24.9M", + "old_padding" : 41922560, + "raw_padding" : 0, + "padding" : "39.9M -> 0B", + "activity" : "resize" + }, + { + "type" : "home", + "label" : "home", + "uuid" : "4980595d-d74a-483a-aa9e-9903879a0ee5", + "partno" : 4, + "file" : "$defs/01-home.conf", + "node" : "$imgs/order5", + "offset" : 57659392, + "old_size" : 0, + "raw_size" : 26206208, + "size" : "-> 24.9M", + "old_padding" : 0, + "raw_padding" : 0, + "padding" : "-> 0B", + "activity" : "create" + } +] +EOF + + output=$(sfdisk --dump "$imgs/order") + + assert_in "$imgs/order1 : start= 2048, size= 20480, type=${root_guid}," "$output" + assert_in "$imgs/order2 : start= 22528, size= 10240, type=${xbootldr_guid}," "$output" + assert_in "$imgs/order3 : start= 61440, size= 51176, type=${esp_guid}," "$output" + assert_in "$imgs/order4 : start= 32768, size= 28672, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F," "$output" + assert_in "$imgs/order5 : start= 112616, size= 51184, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915," "$output" +} + testcase_issue_21817() { local defs imgs output