]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: respect minimum sector size for ESP/VFAT partitions 37899/head
authorLennart Poettering <lennart@poettering.net>
Wed, 25 Jun 2025 09:02:05 +0000 (11:02 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 26 Jun 2025 12:52:20 +0000 (14:52 +0200)
Fixes: #37801
man/repart.d.xml
src/repart/repart.c
test/units/TEST-58-REPART.sh
test/units/TEST-87-AUX-UTILS-VM.validatefs.sh

index eb628ffc1692ccdda68b7df9fb11537982e48968..d3a8f6fcea702719262a05c9938ebd5f2d70da99 100644 (file)
         and the placing algorithm restarted. By default, a minimum size constraint of 10M and no maximum size
         constraint is set.</para>
 
+        <para>If <varname>Format=</varname> is set, the minimum size is automatically raised to the minimum
+        file system size for the selected file system type, if known. Moreover, for the ESP/XBOOTLDR
+        partitions the minimum is raised to 100M (for 512b sector images) or 260M (for 4K sector images)
+        automatically, if specified smaller.</para>
+
         <xi:include href="version-info.xml" xpointer="v245"/></listitem>
       </varlistentry>
 
index 937d4dcd89512205897079bb207cfa9a4fa8edd9..ca211702bfc2ec702f9194d828371c201680d16f 100644 (file)
  * filesystems will then also be compatible with sector sizes 512, 1024 and 2048. */
 #define DEFAULT_FILESYSTEM_SECTOR_SIZE 4096ULL
 
+/* Minimum sizes for the ESP depending on sector size. What the minimum is, is severely underdocumented, but
+ * it appears for 4K sector size it must be 260M, and otherwise 100M. This is what Microsoft says here:
+ *
+ * https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/configure-uefigpt-based-hard-drive-partitions?view=windows-11
+ * https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/oem-deployment-of-windows-desktop-editions-sample-scripts?view=windows-11&preserve-view=true#-createpartitions-uefitxt
+ */
+#define ESP_MIN_SIZE (100 * U64_MB)
+#define ESP_MIN_SIZE_4K (260 * U64_MB)
+
 #define APIVFS_TMP_DIRS_NULSTR "proc\0sys\0dev\0tmp\0run\0var/tmp\0"
 
 #define AUTOMATIC_FSTAB_HEADER_START "# Start section ↓ of automatically generated fstab by systemd-repart"
@@ -929,6 +938,21 @@ static uint64_t partition_fs_sector_size(const Context *c, const Partition *p) {
         return MAX(ss, c->sector_size);
 }
 
+static uint64_t partition_fstype_min_size(const Context *c, const Partition *p) {
+        assert(c);
+        assert(p);
+
+        /* If a file system type is configured, then take it into consideration for the minimum partition
+         * size */
+
+        if (IN_SET(p->type.designator, PARTITION_ESP, PARTITION_XBOOTLDR) && streq_ptr(p->format, "vfat")) {
+                uint64_t ss = partition_fs_sector_size(c, p);
+                return ss >= 4096 ? ESP_MIN_SIZE_4K : ESP_MIN_SIZE;
+        }
+
+        return minimal_size_by_fs_name(p->format);
+}
+
 static uint64_t partition_min_size(const Context *context, const Partition *p) {
         uint64_t sz, override_min;
 
@@ -964,8 +988,8 @@ static uint64_t partition_min_size(const Context *context, const Partition *p) {
                         uint64_t f;
 
                         /* If we shall synthesize a file system, take minimal fs size into account (assumed to be 4K if not known) */
-                        f = p->format ? round_up_size(minimal_size_by_fs_name(p->format), context->grain_size) : UINT64_MAX;
-                        d += f == UINT64_MAX ? context->grain_size : f;
+                        f = partition_fstype_min_size(context, p);
+                        d += f == UINT64_MAX ? context->grain_size : round_up_size(f, context->grain_size);
                 }
 
                 if (d > sz)
index 97e378361341be080168eaa6bed40076d2eff51d..aa472df99ad7418d86cdb444b82302a4c1e489fd 100755 (executable)
@@ -565,9 +565,9 @@ EOF
 
     output=$(sfdisk --dump "$imgs/zzz")
 
-    assert_in "$imgs/zzz1 : start=        2048, size=       20480, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=39107B09-615D-48FB-BA37-C663885FCE67, name=\"esp\"" "$output"
-    assert_in "$imgs/zzz2 : start=       22528, size=       65536, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\"" "$output"
-    assert_in "$imgs/zzz3 : start=       88064, size=       65536, type=${usr_guid}, uuid=${usr_uuid}, name=\"usr-${architecture}\", attrs=\"GUID:60\"" "$output"
+    assert_in "$imgs/zzz1 : start=        2048, size=      532480, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=39107B09-615D-48FB-BA37-C663885FCE67, name=\"esp\"" "$output"
+    assert_in "$imgs/zzz2 : start=      534528, size=       65536, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\"" "$output"
+    assert_in "$imgs/zzz3 : start=      600064, size=       65536, type=${usr_guid}, uuid=${usr_uuid}, name=\"usr-${architecture}\", attrs=\"GUID:60\"" "$output"
 
     if systemd-detect-virt --quiet --container; then
         echo "Skipping second part of copy blocks tests in container."
@@ -1573,7 +1573,7 @@ EOF
     systemd-repart --empty=create --size=auto --dry-run=no --definitions="$defs" "$image"
 
     output=$(sfdisk -d "$image")
-    assert_in "${image}1 : start=        2048, size=      204800, type=${esp_guid}" "$output"
+    assert_in "${image}1 : start=        2048, size=      532480, type=${esp_guid}" "$output"
     assert_not_in "${image}2" "$output"
 
     # Disk with small ESP => ESP grows
@@ -1586,12 +1586,12 @@ EOF
     systemd-repart --dry-run=no --definitions="$defs" "$image"
 
     output=$(sfdisk -d "$image")
-    assert_in "${image}1 : start=        2048, size=      204800, type=${esp_guid}" "$output"
+    assert_in "${image}1 : start=        2048, size=      532480, type=${esp_guid}" "$output"
     assert_not_in "${image}2" "$output"
 
     # Disk with small ESP that can't grow => XBOOTLDR created
 
-    truncate -s 150M "$image"
+    truncate -s 400M "$image"
     sfdisk "$image" <<EOF
 label: gpt
 size=10M, type=${esp_guid},
@@ -1602,7 +1602,7 @@ EOF
 
     output=$(sfdisk -d "$image")
     assert_in "${image}1 : start=        2048, size=       20480, type=${esp_guid}" "$output"
-    assert_in "${image}3 : start=       43008, size=      264152, type=${xbootldr_guid}" "$output"
+    assert_in "${image}3 : start=       43008, size=      776152, type=${xbootldr_guid}" "$output"
 
     # Disk with existing XBOOTLDR partition => XBOOTLDR grows, small ESP created
 
@@ -1614,8 +1614,8 @@ EOF
     systemd-repart --dry-run=no --definitions="$defs" "$image"
 
     output=$(sfdisk -d "$image")
-    assert_in "${image}1 : start=        2048, size=      204800, type=${xbootldr_guid}" "$output"
-    assert_in "${image}2 : start=      206848, size=      100312, type=${esp_guid}" "$output"
+    assert_in "${image}1 : start=        2048, size=      284632, type=${xbootldr_guid}" "$output"
+    assert_in "${image}2 : start=      286680, size=      532480, type=${esp_guid}" "$output"
 }
 
 OFFLINE="yes"
index ede0d71019554281c0b17a81f6d5395d90a02277..86120975be73f8b341818e40a18b4282dc389d17 100755 (executable)
@@ -74,7 +74,7 @@ MountPoint=/somewhere/else
 Format=ext4
 EOF
 
-systemd-repart --dry-run=no --empty=create --size=256M --definitions=/tmp/validatefs-test /var/tmp/validatefs-test.raw
+systemd-repart --dry-run=no --empty=create --size=410M --definitions=/tmp/validatefs-test /var/tmp/validatefs-test.raw
 
 systemd-dissect --mount --mkdir /var/tmp/validatefs-test.raw /tmp/validatefs-test.mount