Skip to content

Commit 15c47a6

Browse files
committed
feat(dracut.sh): add "--cpio-reflink" option for requesting GNU cpio reflinks
The new GNU cpio "--reflink" parameter sees it use copy_file_range() when copying between source and destination, allowing for copy-on-write optimization if supported by the underlying filesystem (e.g. Btrfs or XFS). When calling cpio with --reflink the file list is piped through padcpio to ensure optimal alignment for extent sharing. Microcode and initramfs proper archives are chained together using the new cpio "--chain" parameter, which ensures that subsequent archives are appended in a reflink friendly fashion. RFC: This shouldn't be merged until GNU cpio --reflink --chain patches have made it upstream. Signed-off-by: David Disseldorp <ddiss@suse.de>
1 parent 0ee332b commit 15c47a6

File tree

3 files changed

+87
-19
lines changed

3 files changed

+87
-19
lines changed

dracut-bash-completion.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ _dracut() {
3232
--local --hostonly --no-hostonly --fstab --help --bzip2 --lzma
3333
--xz --zstd --no-compress --gzip --list-modules --show-modules --keep
3434
--printsize --regenerate-all --noimageifnotneeded --early-microcode
35-
--no-early-microcode --print-cmdline --reproducible --uefi'
35+
--no-early-microcode --print-cmdline --reproducible --uefi
36+
--cpio-reflink'
3637
[ARG]='-a -m -o -d -I -k -c -L --kver --add --force-add --add-drivers
3738
--omit-drivers --modules --omit --drivers --filesystems --install
3839
--fwdir --libdirs --fscks --add-fstab --mount --device --nofscks

dracut.8.asc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,15 @@ will not be able to boot.
531531
Specifies the kernel image, which to include in the UEFI executable. The default is
532532
_/lib/modules/<KERNEL-VERSION>/vmlinuz_ or _/boot/vmlinuz-<KERNEL-VERSION>_
533533
534+
**--cpio-reflink**::
535+
Attempt to use the GNU cpio --reflink option, which optimizes archive creation for
536+
copy-on-write filesystems by using the copy_file_range(2) syscall. When specified,
537+
initramfs archives are also padded to ensure optimal data alignment for extent
538+
sharing. To retain reflink data deduplication benefits, this should be used
539+
alongside the **--no-compress** and **--no-strip** parameters, with initramfs
540+
source files, **--tmpdir** staging area and destination all on the same
541+
copy-on-write capable filesystem.
542+
534543
ENVIRONMENT
535544
-----------
536545

dracut.sh

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ Creates initial ramdisk images for preloading modules
228228
otherwise you will not be able to boot.
229229
--no-compress Do not compress the generated initramfs. This will
230230
override any other compression options.
231+
--cpio-reflink Request that cpio perform reflinks for file data.
231232
--list-modules List all available dracut modules.
232233
-M, --show-modules Print included module's name to standard output during
233234
build.
@@ -414,6 +415,7 @@ rearrange_params() {
414415
--long zstd \
415416
--long no-compress \
416417
--long gzip \
418+
--long cpio-reflink \
417419
--long list-modules \
418420
--long show-modules \
419421
--long keep \
@@ -772,6 +774,7 @@ while :; do
772774
--zstd) compress_l="zstd" ;;
773775
--no-compress) _no_compress_l="cat" ;;
774776
--gzip) compress_l="gzip" ;;
777+
--cpio-reflink) cpio_reflink="yes" ;;
775778
--list-modules) do_list="yes" ;;
776779
-M | --show-modules)
777780
show_modules_l="yes"
@@ -1147,6 +1150,28 @@ trap 'exit 1;' SIGINT
11471150
readonly initdir="${DRACUT_TMPDIR}/initramfs"
11481151
mkdir -p "$initdir"
11491152
1153+
if [[ $cpio_reflink == "yes" ]]; then
1154+
if [[ "$(cpio --help)" == *--reflink* ]]; then
1155+
# both XFS and Btrfs require data to be FS block-size aligned for proper
1156+
# extent sharing / reflinks. padcpio ensures this.
1157+
if [[ -d "$dracutbasedir/skipcpio" ]]; then
1158+
padcpio="$dracutbasedir/skipcpio/padcpio"
1159+
else
1160+
padcpio="$dracutbasedir/padcpio"
1161+
fi
1162+
if [[ -x "$padcpio" ]]; then
1163+
# align based on statfs optimal transfer size
1164+
padcpio_align=$(stat --file-system -c "%s" -- "$initdir")
1165+
else
1166+
dinfo "cpio-reflink ignored due to lack of padcpio"
1167+
unset cpio_reflink
1168+
fi
1169+
else
1170+
dinfo "cpio-reflink ignored due to lack of support in $(which cpio)"
1171+
unset cpio_reflink
1172+
fi
1173+
fi
1174+
11501175
# shellcheck disable=SC2154
11511176
if [[ $early_microcode == yes ]] || { [[ $acpi_override == yes ]] && [[ -d $acpi_table_dir ]]; }; then
11521177
readonly early_cpio_dir="${DRACUT_TMPDIR}/earlycpio"
@@ -2196,6 +2221,8 @@ if dracut_module_included "squash"; then
21962221
fi
21972222
21982223
if [[ $do_strip == yes ]] && ! [[ $DRACUT_FIPS_MODE ]]; then
2224+
# warn that stripping files negates (dedup) benefits of using reflink
2225+
[ -n "$cpio_reflink" ] && dinfo "inefficient: strip is enabled alongside cpio reflink"
21992226
dinfo "*** Stripping files ***"
22002227
find "$initdir" -type f \
22012228
-executable -not -path '*/lib/modules/*.ko' -print0 \
@@ -2266,15 +2293,28 @@ if [[ $create_early_cpio == yes ]]; then
22662293
fi
22672294
22682295
# The microcode blob is _before_ the initramfs blob, not after
2269-
if ! (
2270-
umask 077
2271-
cd "$early_cpio_dir/d"
2272-
find . -print0 | sort -z \
2273-
| cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null \
2274-
${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet > "${DRACUT_TMPDIR}/initramfs.img"
2275-
); then
2276-
dfatal "dracut: creation of $outfile failed"
2277-
exit 1
2296+
if [[ -n "$cpio_reflink" ]]; then
2297+
if ! (
2298+
umask 077
2299+
cd "$early_cpio_dir/d"
2300+
find . -print0 | sort -z | "$padcpio" --min "$padcpio_align" --align "$padcpio_align" \
2301+
| cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null \
2302+
${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet --reflink -O "${DRACUT_TMPDIR}/initramfs.img"
2303+
); then
2304+
dfatal "dracut: creation of reflinked $outfile failed"
2305+
exit 1
2306+
fi
2307+
else
2308+
if ! (
2309+
umask 077
2310+
cd "$early_cpio_dir/d"
2311+
find . -print0 | sort -z \
2312+
| cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null \
2313+
${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet > "${DRACUT_TMPDIR}/initramfs.img"
2314+
); then
2315+
dfatal "dracut: creation of $outfile failed"
2316+
exit 1
2317+
fi
22782318
fi
22792319
fi
22802320
@@ -2325,15 +2365,33 @@ case $compress in
23252365
;;
23262366
esac
23272367
2328-
if ! (
2329-
umask 077
2330-
cd "$initdir"
2331-
find . -print0 | sort -z \
2332-
| cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null ${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet \
2333-
| $compress >> "${DRACUT_TMPDIR}/initramfs.img"
2334-
); then
2335-
dfatal "dracut: creation of $outfile failed"
2336-
exit 1
2368+
if [[ -n "$cpio_reflink" && "$compress" == "cat" ]]; then
2369+
# determine padding offset if we're appending to microcode
2370+
i=$(stat -c "%s" -- "${DRACUT_TMPDIR}/initramfs.img" 2>/dev/null)
2371+
if ! (
2372+
umask 077
2373+
cd "$initdir"
2374+
find . -print0 | sort -z \
2375+
| "$padcpio" --min "$padcpio_align" --align "$padcpio_align" ${i:+--offset "$i"} \
2376+
| cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null \
2377+
${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet --reflink ${i:+--chain} \
2378+
-O "${DRACUT_TMPDIR}/initramfs.img"
2379+
); then
2380+
dfatal "dracut: creation of reflinked $outfile failed"
2381+
exit 1
2382+
fi
2383+
else
2384+
[ -n "$cpio_reflink" ] && dinfo "cpio-reflink ignored due to compression"
2385+
if ! (
2386+
umask 077
2387+
cd "$initdir"
2388+
find . -print0 | sort -z \
2389+
| cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null ${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet \
2390+
| $compress >> "${DRACUT_TMPDIR}/initramfs.img"
2391+
); then
2392+
dfatal "dracut: creation of $outfile failed"
2393+
exit 1
2394+
fi
23372395
fi
23382396
23392397
# shellcheck disable=SC2154

0 commit comments

Comments
 (0)