repart: make COW behavior configurable

systemd-repart currently forces newly created image files into NOCOW mode.
That prevents files from being reflinked into the image, making image builds
slower and increasing their disk usage on filesystems that support cloning.

Add a tristate --cow= option. By default, leave the filesystem or parent
directory COW policy unchanged. With --cow=yes, explicitly enable COW; with
--cow=no, retain the previous behavior of forcing NOCOW. Add XO_COW as the
counterpart to XO_NOCOW so xopenat_full() applies either policy while retaining
its normal creation-error cleanup.

Document the new option and extend TEST-58-REPART to verify inherited COW and
NOCOW policies as well as explicit COW and NOCOW overrides. Compare the unset
behavior with the filesystem default so the test also works on nodatacow
mounts, and skip it when the inode attribute is unsupported.

Signed-off-by: Daan De Meyer <daan@amutable.com>
This commit is contained in:
Daan De Meyer
2026-07-15 09:22:58 +02:00
committed by Lennart Poettering
parent d153b49473
commit 28b1e4ea16
5 changed files with 140 additions and 10 deletions
+102
View File
@@ -94,6 +94,108 @@ else
exit 1
fi
testcase_cow() {
local attrs cow_image default_nocow defs image imgs nocow_image probe
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
# Skip the checks entirely if the underlying filesystem does not support the attribute.
if ! chattr -C "$imgs"; then
echo "NOCOW is not supported on $imgs, skipping tests"
return
fi
probe="$imgs/probe"
touch "$probe"
if ! chattr +C "$probe"; then
echo "NOCOW is not supported on $imgs, skipping tests"
return
fi
if ! chattr -C "$probe"; then
echo "COW is not supported on $imgs, skipping tests"
return
fi
rm "$probe"
chattr +C "$imgs"
image="$imgs/inherit-nocow.raw"
systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \
--empty=create \
--size=16M \
--cow=auto \
--dry-run=no \
"$image"
attrs="$(lsattr -d -- "$image")"
assert_neq "$attrs" ""
read -r attrs _ <<<"$attrs"
assert_in "C" "$attrs"
cow_image="$imgs/cow.raw"
systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \
--empty=create \
--size=16M \
--cow=yes \
--dry-run=no \
"$cow_image"
attrs="$(lsattr -d -- "$cow_image")"
assert_neq "$attrs" ""
read -r attrs _ <<<"$attrs"
assert_not_in "C" "$attrs"
chattr -C "$imgs"
probe="$imgs/probe"
touch "$probe"
attrs="$(lsattr -d -- "$probe")"
assert_neq "$attrs" ""
read -r attrs _ <<<"$attrs"
if [[ "$attrs" == *C* ]]; then
default_nocow=1
else
default_nocow=0
fi
rm "$probe"
image="$imgs/inherit-cow.raw"
systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \
--empty=create \
--size=16M \
--dry-run=no \
"$image"
attrs="$(lsattr -d -- "$image")"
assert_neq "$attrs" ""
read -r attrs _ <<<"$attrs"
if (( default_nocow )); then
assert_in "C" "$attrs"
else
assert_not_in "C" "$attrs"
fi
nocow_image="$imgs/nocow.raw"
systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \
--empty=create \
--size=16M \
--cow=no \
--dry-run=no \
"$nocow_image"
attrs="$(lsattr -d -- "$nocow_image")"
assert_neq "$attrs" ""
read -r attrs _ <<<"$attrs"
assert_in "C" "$attrs"
}
testcase_basic() {
local defs imgs output
local loop volume