From afe4a6dbb7df62982baab8212bba5d90010dfbac Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Wed, 17 Feb 2021 01:05:37 +0100 Subject: [PATCH] feat(dracut.sh): add "--enhanced-cpio" option for calling dracut-cpio The new dracut-cpio binary is capable of performing copy-on-write optimized initramfs archive creation, but due to the rust dependency isn't built / installed by default. This change adds a new "--enhanced-cpio" parameter for dracut which sees dracut-cpio called for archive creation instead of GNU cpio. Signed-off-by: David Disseldorp --- dracut.sh | 95 +++++++++++++++++++++++++++++------- man/dracut.8.asc | 9 ++++ shell-completion/bash/dracut | 3 +- 3 files changed, 88 insertions(+), 19 deletions(-) diff --git a/dracut.sh b/dracut.sh index 0f111e80..867febe1 100755 --- a/dracut.sh +++ b/dracut.sh @@ -226,6 +226,7 @@ Creates initial ramdisk images for preloading modules otherwise you will not be able to boot. --no-compress Do not compress the generated initramfs. This will override any other compression options. + --enhanced-cpio Attempt to reflink cpio file data using dracut-cpio. --list-modules List all available dracut modules. -M, --show-modules Print included module's name to standard output during build. @@ -412,6 +413,7 @@ rearrange_params() { --long zstd \ --long no-compress \ --long gzip \ + --long enhanced-cpio \ --long list-modules \ --long show-modules \ --long keep \ @@ -770,6 +772,7 @@ while :; do --zstd) compress_l="zstd" ;; --no-compress) _no_compress_l="cat" ;; --gzip) compress_l="gzip" ;; + --enhanced-cpio) enhanced_cpio_l="yes" ;; --list-modules) do_list="yes" ;; -M | --show-modules) show_modules_l="yes" @@ -982,6 +985,7 @@ stdloglvl=$((stdloglvl + verbosity_mod_l)) [[ $tmpdir ]] || tmpdir="$dracutsysrootdir"/var/tmp [[ $INITRD_COMPRESS ]] && compress=$INITRD_COMPRESS [[ $compress_l ]] && compress=$compress_l +[[ $enhanced_cpio_l ]] && enhanced_cpio=$enhanced_cpio_l [[ $show_modules_l ]] && show_modules=$show_modules_l [[ $nofscks_l ]] && nofscks="yes" [[ $ro_mnt_l ]] && ro_mnt="yes" @@ -1188,6 +1192,19 @@ else exit 1 fi +if [[ $enhanced_cpio == "yes" ]]; then + enhanced_cpio="$dracutbasedir/dracut-cpio" + if [[ -x $enhanced_cpio ]]; then + # align based on statfs optimal transfer size + cpio_align=$(stat --file-system -c "%s" -- "$initdir") + else + dinfo "--enhanced-cpio ignored due to lack of dracut-cpio" + unset enhanced_cpio + fi +else + unset enhanced_cpio +fi + # shellcheck disable=SC2154 if [[ $no_kernel != yes ]] && ! [[ -d $srcmods ]]; then printf "%s\n" "dracut: Cannot find module directory $srcmods" >&2 @@ -2252,6 +2269,8 @@ if dracut_module_included "squash"; then fi if [[ $do_strip == yes ]] && ! [[ $DRACUT_FIPS_MODE ]]; then + # stripping files negates (dedup) benefits of using reflink + [[ -n $enhanced_cpio ]] && ddebug "strip is enabled alongside cpio reflink" dinfo "*** Stripping files ***" find "$initdir" -type f \ -executable -not -path '*/lib/modules/*.ko' -print0 \ @@ -2322,15 +2341,29 @@ if [[ $create_early_cpio == yes ]]; then fi # The microcode blob is _before_ the initramfs blob, not after - if ! ( - umask 077 - cd "$early_cpio_dir/d" - find . -print0 | sort -z \ - | cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null \ - ${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet > "${DRACUT_TMPDIR}/initramfs.img" - ); then - dfatal "dracut: creation of $outfile failed" - exit 1 + if [[ -n $enhanced_cpio ]]; then + if ! ( + umask 077 + cd "$early_cpio_dir/d" + find . -print0 | sort -z \ + | $enhanced_cpio --null ${cpio_owner:+--owner "$cpio_owner"} \ + --mtime 0 --data-align "$cpio_align" --truncate-existing \ + "${DRACUT_TMPDIR}/initramfs.img" + ); then + dfatal "dracut-cpio: creation of $outfile failed" + exit 1 + fi + else + if ! ( + umask 077 + cd "$early_cpio_dir/d" + find . -print0 | sort -z \ + | cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null \ + ${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet > "${DRACUT_TMPDIR}/initramfs.img" + ); then + dfatal "dracut: creation of $outfile failed" + exit 1 + fi fi fi @@ -2386,15 +2419,41 @@ if [[ $compress == $DRACUT_COMPRESS_ZSTD* ]] && ! check_kernel_config CONFIG_RD_ compress="cat" fi -if ! ( - umask 077 - cd "$initdir" - find . -print0 | sort -z \ - | cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null ${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet \ - | $compress >> "${DRACUT_TMPDIR}/initramfs.img" -); then - dfatal "dracut: creation of $outfile failed" - exit 1 +if [[ -n $enhanced_cpio ]]; then + if [[ $compress == "cat" ]]; then + # dracut-cpio appends by default, so any ucode remains + cpio_outfile="${DRACUT_TMPDIR}/initramfs.img" + else + ddebug "$compress compression enabled alongside cpio reflink" + # dracut-cpio doesn't output to stdout, so stage for compression + cpio_outfile="${DRACUT_TMPDIR}/initramfs.img.uncompressed" + fi + + if ! ( + umask 077 + cd "$initdir" + find . -print0 | sort -z \ + | $enhanced_cpio --null ${cpio_owner:+--owner "$cpio_owner"} \ + --mtime 0 --data-align "$cpio_align" "$cpio_outfile" || exit 1 + [[ $compress == "cat" ]] && exit 0 + $compress < "$cpio_outfile" >> "${DRACUT_TMPDIR}/initramfs.img" \ + && rm "$cpio_outfile" + ); then + dfatal "dracut-cpio: creation of $outfile failed" + exit 1 + fi + unset cpio_outfile +else + if ! ( + umask 077 + cd "$initdir" + find . -print0 | sort -z \ + | cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null ${cpio_owner:+-R "$cpio_owner"} -H newc -o --quiet \ + | $compress >> "${DRACUT_TMPDIR}/initramfs.img" + ); then + dfatal "dracut: creation of $outfile failed" + exit 1 + fi fi # shellcheck disable=SC2154 diff --git a/man/dracut.8.asc b/man/dracut.8.asc index 515e32db..708166bd 100644 --- a/man/dracut.8.asc +++ b/man/dracut.8.asc @@ -530,6 +530,15 @@ will not be able to boot. Specifies the kernel image, which to include in the UEFI executable. The default is _/lib/modules//vmlinuz_ or _/boot/vmlinuz-_ +**--enhanced-cpio**:: + Attempt to use the dracut-cpio binary, which optimizes archive creation for + copy-on-write filesystems by using the copy_file_range(2) syscall via Rust's + io::copy(). When specified, initramfs archives are also padded to ensure + optimal data alignment for extent sharing. To retain reflink data + deduplication benefits, this should be used alongside the **--no-compress** + and **--no-strip** parameters, with initramfs source files, **--tmpdir** + staging area and destination all on the same copy-on-write capable filesystem. + ENVIRONMENT ----------- diff --git a/shell-completion/bash/dracut b/shell-completion/bash/dracut index 286fd1ce..d20b307f 100644 --- a/shell-completion/bash/dracut +++ b/shell-completion/bash/dracut @@ -32,7 +32,8 @@ _dracut() { --local --hostonly --no-hostonly --fstab --help --bzip2 --lzma --xz --zstd --no-compress --gzip --list-modules --show-modules --keep --printsize --regenerate-all --noimageifnotneeded --early-microcode - --no-early-microcode --print-cmdline --reproducible --uefi' + --no-early-microcode --print-cmdline --reproducible --uefi + --enhanced-cpio' [ARG]='-a -m -o -d -I -k -c -L --kver --add --force-add --add-drivers --omit-drivers --modules --omit --drivers --filesystems --install --fwdir --libdirs --fscks --add-fstab --mount --device --nofscks