diff --git a/src/repart/repart.c b/src/repart/repart.c index dbf261bb26..456aed41bd 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -6785,7 +6785,8 @@ static int context_mkfs(Context *context) { * have to populate using the filesystem's mkfs's --root= (or equivalent) option. To do that, * we need to set up the final directory tree beforehand. */ - if (partition_needs_populate(p) && (!t->loop || fstype_is_ro(p->format))) { + if (partition_needs_populate(p) && + (!t->loop || fstype_is_ro(p->format) || (streq_ptr(p->format, "btrfs") && p->compression))) { if (!mkfs_supports_root_option(p->format)) return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Loop device access is required to populate %s filesystems.", @@ -8533,7 +8534,7 @@ static int context_minimize(Context *context) { return r; } - if (!d || fstype_is_ro(p->format)) { + if (!d || fstype_is_ro(p->format) || (streq_ptr(p->format, "btrfs") && p->compression)) { if (!mkfs_supports_root_option(p->format)) return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Loop device access is required to populate %s filesystems.", diff --git a/src/shared/mkfs-util.c b/src/shared/mkfs-util.c index 629d02207c..455c627ff6 100644 --- a/src/shared/mkfs-util.c +++ b/src/shared/mkfs-util.c @@ -466,17 +466,22 @@ int make_filesystem( return log_oom(); if (compression) { - _cleanup_free_ char *c = NULL; + if (!root) + log_warning("Btrfs compression setting ignored because no files are being copied. " + "Compression= can only be applied when CopyFiles= is also specified."); + else { + _cleanup_free_ char *c = NULL; - c = strdup(compression); - if (!c) - return log_oom(); + c = strdup(compression); + if (!c) + return log_oom(); - if (compression_level && !strextend(&c, ":", compression_level)) - return log_oom(); + if (compression_level && !strextend(&c, ":", compression_level)) + return log_oom(); - if (strv_extend_many(&argv, "--compress", c) < 0) - return log_oom(); + if (strv_extend_many(&argv, "--compress", c) < 0) + return log_oom(); + } } /* mkfs.btrfs unconditionally warns about several settings changing from v5.15 onwards which diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh index b752af3f4d..251c337425 100755 --- a/test/units/TEST-58-REPART.sh +++ b/test/units/TEST-58-REPART.sh @@ -1685,6 +1685,76 @@ EOF grep -q 'UUID=[0-9a-f-]* /home btrfs discard,rw,nodev,suid,exec,subvol=@home,zstd:1,noatime,lazytime 0 1' "$root"/etc/fstab } +testcase_btrfs_compression() { + local defs imgs loop output + + if ! systemd-analyze compare-versions "$(btrfs --version | head -n 1 | awk '{ print $2 }')" ge v6.13; then + echo "btrfs-progs is not installed or older than v6.13, skipping test." + return 0 + fi + + defs="$(mktemp -d)" + imgs="$(mktemp -d)" + # shellcheck disable=SC2064 + trap "rm -rf '$defs' '$imgs'" RETURN + chmod 0755 "$defs" + + echo "*** testcase for btrfs compression with CopyFiles (OFFLINE=$OFFLINE) ***" + + # Must not be in tmpfs due to exclusions. It also must be large and + # compressible so that the compression check succeeds later. + src=/etc/test-source-file + dd if=/dev/zero of="$src" bs=1M count=1 2>/dev/null + + tee "$defs/btrfs-compressed.conf" <&1 | tee "$imgs/repart-output.txt" + rm "$src" + + output=$(cat "$imgs/repart-output.txt") + + assert_in "Rootdir from:" "$output" + assert_in "Compress:" "$output" + + if [[ "$OFFLINE" == "yes" ]] || systemd-detect-virt --quiet --container; then + echo "Skipping mount verification (requires loop devices)" + return 0 + fi + loop="$(losetup -P --show --find "$imgs/btrfs-compressed.img")" + # shellcheck disable=SC2064 + trap "umount '$imgs/mount' 2>/dev/null || true; losetup -d '$loop' 2>/dev/null || true; rm -rf '$defs' '$imgs'" RETURN + echo "Loop device: $loop" + udevadm wait --timeout=60 --settle "${loop:?}p1" + + mkdir -p "$imgs/mount" + mount -t btrfs "${loop:?}p1" "$imgs/mount" + + [[ -f "$imgs/mount/test-file" ]] + [[ "$(stat -c%s "$imgs/mount/test-file")" == "1048576" ]] + + if command -v compsize &>/dev/null; then + output=$(compsize "$imgs/mount/test-file" 2>&1) + assert_in "zstd" "$output" + fi + + umount "$imgs/mount" + losetup -d "$loop" +} + testcase_varlink_list_devices() { REPART="$(which systemd-repart)" varlinkctl introspect "$REPART"