From: Jonas Dreßler Date: Mon, 6 Jul 2026 16:23:51 +0000 (+0200) Subject: repart: Properly pre-calculate auto size of images X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=04e3d8933b2b61691e2352642536697464d97c41;p=thirdparty%2Fsystemd.git repart: Properly pre-calculate auto size of images When passing --size=auto to repart, it will pre-calculate the image size and resize the image to that size before partitioning. Currently, that fails when passing a large grain size, complaining that the auto-sized image is too small to fit the data. The reason for this is that the current code simply assumes the GPT metadata size taken away from the usable size by fdisk is static (1044KiB), when it actually is more complicated than that: There's two ranges of GPT metadata: One at the beginning of the image, and one at the end of the image. And there's the first usable block that is defined by fdisk when creating the partition table. The static value of 1044KiB usually works, because fdisk sets the first usable block to 1MiB (so 1024KiB), leaving 20KiB of leeway for the secondary GPT at the end of the image. Now as soon as the first partition starts at an offset higher than 1024KiB, we lose the 20KiB leeway for the secondary GPT, and the partitions will no longer fit. What we should do, is first of all round up to the grain size instead of 4096 (as that's the minimum offset our first partition will start at), and second of all properly subtract the secondary GPT at the end. Also confirm we don't regress on this anymore by adding a test that uses a 2MiB grain size, breaking the old code. --- diff --git a/src/repart/repart.c b/src/repart/repart.c index cf4f670401e..5ba535e032d 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -100,9 +100,6 @@ /* We know up front we're never going to put more than this in a verity sig partition. */ #define VERITY_SIG_SIZE (HARD_MIN_SIZE*4ULL) -/* libfdisk takes off slightly more than 1M of the disk size when creating a GPT disk label */ -#define GPT_METADATA_SIZE (1044ULL*1024ULL) - /* LUKS2 takes off 16M of the partition size with its metadata by default */ #define LUKS2_METADATA_SIZE (16ULL*1024ULL*1024ULL) @@ -11250,12 +11247,26 @@ static int determine_auto_size( assert(c); - minimal_size = round_up_size(GPT_METADATA_SIZE, 4096); + /* At the beginning of the image, some size is reserved for: + * Protective MBR (1 block) + GPT header (1 block) + + * Primary partition table (minimum 16KiB) = (2 * c->sector_size) + (16 * 1024) + * + * Note that fdisk usually sets the first usable block to 1MiB (at least for + * disks larger than 4MiB), so we just force it to that as well. If fdisk + * decides to set it lower, we made the image a bit larger than necessary, + * if it sets it higher, we'd have a problem. */ + minimal_size = 1024 * 1024; + /* Of course need to align the start to our grain size as well */ + minimal_size = round_up_size(minimal_size, c->grain_size); + + /* At the end of the image, there is size reserved for: + * Secondary partition table (minimum 16KiB) + GPT header (1 block) */ + minimal_size += (16 * 1024) + c->sector_size; if (c->from_scratch) current_size = 0; else - current_size = round_up_size(GPT_METADATA_SIZE, 4096); + current_size = minimal_size; foreign_size = 0; diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh index bd33e93d592..9970dac662b 100755 --- a/test/units/TEST-58-REPART.sh +++ b/test/units/TEST-58-REPART.sh @@ -370,7 +370,7 @@ label-id: 1D2CE291-7CCE-4F7D-BC83-FDB49AD74EBD device: $imgs/zzz unit: sectors first-lba: 2048 -last-lba: 6422494 +last-lba: 6422487 $imgs/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\" $imgs/zzz2 : start= 593904, size= 591856, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\" $imgs/zzz3 : start= 1185760, size= 591864, type=${root_guid}, uuid=${root_uuid2}, name=\"root-${architecture}-2\", attrs=\"GUID:59\" @@ -434,7 +434,7 @@ label-id: 1D2CE291-7CCE-4F7D-BC83-FDB49AD74EBD device: $imgs/zzz unit: sectors first-lba: 2048 -last-lba: 6553566 +last-lba: 6553559 $imgs/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\" $imgs/zzz2 : start= 593904, size= 591856, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\" $imgs/zzz3 : start= 1185760, size= 591864, type=${root_guid}, uuid=${root_uuid2}, name=\"root-${architecture}-2\", attrs=\"GUID:59\" @@ -568,6 +568,51 @@ EOF assert_in "$imgs/copy_to3 : start= 32768, size= 90072, type=${esp_guid}," "$output" } +testcase_size_auto_with_grain_size() { + 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/01-esp.conf" <