diff --git a/man/repart.d.xml b/man/repart.d.xml
index eb628ffc16..d3a8f6fcea 100644
--- a/man/repart.d.xml
+++ b/man/repart.d.xml
@@ -341,6 +341,11 @@
and the placing algorithm restarted. By default, a minimum size constraint of 10M and no maximum size
constraint is set.
+ If Format= 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.
+
diff --git a/src/repart/repart.c b/src/repart/repart.c
index 937d4dcd89..ca211702bf 100644
--- a/src/repart/repart.c
+++ b/src/repart/repart.c
@@ -105,6 +105,15 @@
* 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)
diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh
index 97e3783613..aa472df99a 100755
--- a/test/units/TEST-58-REPART.sh
+++ b/test/units/TEST-58-REPART.sh
@@ -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" < 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"
diff --git a/test/units/TEST-87-AUX-UTILS-VM.validatefs.sh b/test/units/TEST-87-AUX-UTILS-VM.validatefs.sh
index ede0d71019..86120975be 100755
--- a/test/units/TEST-87-AUX-UTILS-VM.validatefs.sh
+++ b/test/units/TEST-87-AUX-UTILS-VM.validatefs.sh
@@ -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