repart: Some fixes for --copy-from= (#42976)
A bunch of things I noticed that aren't correct about `--copy-from` and grain sizes + paddings.
This commit is contained in:
@@ -609,11 +609,12 @@
|
||||
<listitem><para>Instructs <command>systemd-repart</command> to synthesize partition definitions from
|
||||
the partition table in the given image or device. This option can be specified multiple times to
|
||||
synthesize definitions from each of the given images or devices. The generated definitions will copy
|
||||
the partitions into the destination partition table. The copied partitions will have the same size,
|
||||
metadata and contents but might have a different partition number and might be located at a different
|
||||
offset in the destination partition table. These definitions can be combined with partition
|
||||
definitions read from regular partition definition files. The synthesized definitions take precedence
|
||||
over the definitions read from partition definition files.</para>
|
||||
the partitions into the destination partition table. The copied partitions will have the same or a
|
||||
slightly larger size (partitions may be enlarged to align to the new grain or sector size), metadata
|
||||
and contents but might have a different partition number and might be located at a different offset
|
||||
in the destination partition table. These definitions can be combined with partition definitions read
|
||||
from regular partition definition files. The synthesized definitions take precedence over the
|
||||
definitions read from partition definition files.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
+31
-7
@@ -3287,10 +3287,12 @@ static int determine_current_padding(
|
||||
struct fdisk_partition *p,
|
||||
uint64_t secsz,
|
||||
uint64_t grainsz,
|
||||
uint64_t *ret) {
|
||||
uint64_t *ret,
|
||||
bool *ret_is_last_partition) {
|
||||
|
||||
size_t n_partitions;
|
||||
uint64_t offset, next = UINT64_MAX;
|
||||
bool is_last_partition = false;
|
||||
|
||||
assert(c);
|
||||
assert(t);
|
||||
@@ -3330,6 +3332,8 @@ static int determine_current_padding(
|
||||
}
|
||||
|
||||
if (next == UINT64_MAX) {
|
||||
is_last_partition = true;
|
||||
|
||||
/* No later partition? In that case check the end of the usable area */
|
||||
next = sym_fdisk_get_last_lba(c);
|
||||
assert(next < UINT64_MAX);
|
||||
@@ -3346,6 +3350,9 @@ static int determine_current_padding(
|
||||
offset = round_up_size(offset, grainsz);
|
||||
next = round_down_size(next, grainsz);
|
||||
|
||||
if (ret_is_last_partition)
|
||||
*ret_is_last_partition = is_last_partition;
|
||||
|
||||
*ret = LESS_BY(next, offset); /* Saturated subtraction, rounding might have fucked things up */
|
||||
return 0;
|
||||
}
|
||||
@@ -3355,7 +3362,7 @@ static int context_copy_from_one(Context *context, const char *src) {
|
||||
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
|
||||
_cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
|
||||
Partition *last = NULL;
|
||||
unsigned long secsz, grainsz;
|
||||
unsigned long secsz;
|
||||
size_t n_partitions;
|
||||
int r;
|
||||
|
||||
@@ -3374,7 +3381,6 @@ static int context_copy_from_one(Context *context, const char *src) {
|
||||
return log_error_errno(r, "Failed to create fdisk context: %m");
|
||||
|
||||
secsz = sym_fdisk_get_sector_size(c);
|
||||
grainsz = sym_fdisk_get_grain_size(c);
|
||||
|
||||
/* Insist on a power of two, and that it's a multiple of 512, i.e. the traditional sector size. */
|
||||
if (secsz < 512 || !ISPOWEROF2(secsz))
|
||||
@@ -3396,6 +3402,7 @@ static int context_copy_from_one(Context *context, const char *src) {
|
||||
uint64_t sz, start, padding;
|
||||
sd_id128_t ptid, id;
|
||||
GptPartitionType type;
|
||||
bool is_last_partition;
|
||||
|
||||
p = sym_fdisk_table_get_partition(t, i);
|
||||
if (!p)
|
||||
@@ -3455,11 +3462,14 @@ static int context_copy_from_one(Context *context, const char *src) {
|
||||
if (!np->split_name_format)
|
||||
return log_oom();
|
||||
|
||||
r = determine_current_padding(c, t, p, secsz, grainsz, &padding);
|
||||
/* Pass grain size of 1 to disable rounding by grain as we don't know the grain size
|
||||
* of the old image. We'll round paddings to the grain size of the new image later. */
|
||||
r = determine_current_padding(c, t, p, secsz, /* grainsz= */ 1, &padding, &is_last_partition);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
np->padding_min = np->padding_max = padding;
|
||||
if (!is_last_partition)
|
||||
np->padding_min = np->padding_max = padding;
|
||||
|
||||
np->copy_blocks_path = strdup(src);
|
||||
if (!np->copy_blocks_path)
|
||||
@@ -4055,7 +4065,14 @@ static int context_load_partition_table(Context *context) {
|
||||
pp->current_partition = p;
|
||||
sym_fdisk_ref_partition(p);
|
||||
|
||||
r = determine_current_padding(c, t, p, secsz, grainsz, &pp->current_padding);
|
||||
r = determine_current_padding(
|
||||
c,
|
||||
t,
|
||||
p,
|
||||
secsz,
|
||||
grainsz,
|
||||
&pp->current_padding,
|
||||
/* ret_is_last_partition= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -4088,7 +4105,14 @@ static int context_load_partition_table(Context *context) {
|
||||
np->current_partition = p;
|
||||
sym_fdisk_ref_partition(p);
|
||||
|
||||
r = determine_current_padding(c, t, p, secsz, grainsz, &np->current_padding);
|
||||
r = determine_current_padding(
|
||||
c,
|
||||
t,
|
||||
p,
|
||||
secsz,
|
||||
grainsz,
|
||||
&np->current_padding,
|
||||
/* ret_is_last_partition= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -451,6 +451,123 @@ $imgs/zzz8 : start= 6422488, size= 131072, type=4D21B016-B534-45C2-A9FB
|
||||
losetup -d "$loop"
|
||||
}
|
||||
|
||||
testcase_copy_from_grain_padding() {
|
||||
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"
|
||||
|
||||
truncate -s 80MiB "$imgs/copy_from"
|
||||
sfdisk "$imgs/copy_from" <<EOF
|
||||
label: gpt
|
||||
grain: 4194304
|
||||
|
||||
size=40961, type=${root_guid}, uuid=837c3d67-21b3-478e-be82-7e7f83bf96d3
|
||||
size=10240, type=${xbootldr_guid}, uuid=4985c03e-eecb-4fe0-9f65-3f6345782214
|
||||
EOF
|
||||
|
||||
output=$(sfdisk --dump "$imgs/copy_from")
|
||||
|
||||
# Padding between partition 1 and 2 is 8191 sectors
|
||||
assert_in "$imgs/copy_from1 : start= 8192, size= 40961, type=${root_guid}," "$output"
|
||||
assert_in "$imgs/copy_from2 : start= 57344, size= 10240, type=${xbootldr_guid}," "$output"
|
||||
|
||||
truncate -s 100MiB "$imgs/copy_to"
|
||||
output=$(systemd-repart --offline="$OFFLINE" \
|
||||
--empty=allow \
|
||||
--definitions="$defs" \
|
||||
--seed="$seed" \
|
||||
--dry-run=no \
|
||||
--json=pretty \
|
||||
--copy-from="$imgs/copy_from" \
|
||||
--grain-size=512 \
|
||||
"$imgs/copy_to")
|
||||
|
||||
output=$(sfdisk --dump "$imgs/copy_to")
|
||||
|
||||
assert_in "$imgs/copy_to1 : start= 2048, size= 40961, type=${root_guid}," "$output"
|
||||
# We set new grain-size to 1 sector, so padding now should be 8191 sectors again
|
||||
assert_in "$imgs/copy_to2 : start= 51200, size= 10240, type=${xbootldr_guid}," "$output"
|
||||
}
|
||||
|
||||
testcase_copy_from_respects_new_grain() {
|
||||
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"
|
||||
|
||||
truncate -s 80MiB "$imgs/copy_from"
|
||||
sfdisk "$imgs/copy_from" <<EOF
|
||||
label: gpt
|
||||
|
||||
size=20480, type=${root_guid}, uuid=837c3d67-21b3-478e-be82-7e7f83bf96d3
|
||||
size=10240, type=${xbootldr_guid}, uuid=4985c03e-eecb-4fe0-9f65-3f6345782214
|
||||
EOF
|
||||
|
||||
truncate -s 100MiB "$imgs/copy_to"
|
||||
output=$(systemd-repart --offline="$OFFLINE" \
|
||||
--empty=allow \
|
||||
--definitions="$defs" \
|
||||
--seed="$seed" \
|
||||
--dry-run=no \
|
||||
--json=pretty \
|
||||
--copy-from="$imgs/copy_from" \
|
||||
--grain-size=4194304 \
|
||||
"$imgs/copy_to")
|
||||
|
||||
output=$(sfdisk --dump "$imgs/copy_to")
|
||||
|
||||
assert_in "$imgs/copy_to1 : start= 8192, size= 24576, type=${root_guid}," "$output"
|
||||
assert_in "$imgs/copy_to2 : start= 32768, size= 16384, type=${xbootldr_guid}," "$output"
|
||||
}
|
||||
|
||||
testcase_copy_from_no_padding_at_beginning_and_end() {
|
||||
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"
|
||||
|
||||
tee "$defs/03-esp.conf" <<EOF
|
||||
[Partition]
|
||||
Type=esp
|
||||
EOF
|
||||
|
||||
truncate -s 80MiB "$imgs/copy_from"
|
||||
sfdisk "$imgs/copy_from" <<EOF
|
||||
label: gpt
|
||||
|
||||
start=2280, size=20480, type=${root_guid}, uuid=837c3d67-21b3-478e-be82-7e7f83bf96d3
|
||||
start=22760, size=10240, type=${xbootldr_guid}, uuid=4985c03e-eecb-4fe0-9f65-3f6345782214
|
||||
EOF
|
||||
|
||||
truncate -s 60MiB "$imgs/copy_to"
|
||||
output=$(systemd-repart --offline="$OFFLINE" \
|
||||
--empty=allow \
|
||||
--definitions="$defs" \
|
||||
--seed="$seed" \
|
||||
--dry-run=no \
|
||||
--json=pretty \
|
||||
--copy-from="$imgs/copy_from" \
|
||||
"$imgs/copy_to")
|
||||
|
||||
output=$(sfdisk --dump "$imgs/copy_to")
|
||||
|
||||
assert_in "first-lba: 2048" "$output"
|
||||
assert_in "last-lba: 122846" "$output"
|
||||
assert_in "$imgs/copy_to1 : start= 2048, size= 20480, type=${root_guid}," "$output"
|
||||
assert_in "$imgs/copy_to2 : start= 22528, size= 10240, type=${xbootldr_guid}," "$output"
|
||||
assert_in "$imgs/copy_to3 : start= 32768, size= 90072, type=${esp_guid}," "$output"
|
||||
}
|
||||
|
||||
testcase_dropin() {
|
||||
local defs imgs output
|
||||
|
||||
|
||||
Reference in New Issue
Block a user