nixos/udev: compress firmware with zstd if possible

Closes #267442

$ nix path-info -Sh /nix/store/qj1dm7wfw5m3mxf1gn3fdm0az9y1h5ny-linux-firmware-20240312-xz
/nix/store/qj1dm7wfw5m3mxf1gn3fdm0az9y1h5ny-linux-firmware-20240312-xz 440.3M
$ nix path-info -Sh /nix/store/c3szcjxb3g990dbiz7llwmkaf0bi98j2-linux-firmware-20240312-zstd
/nix/store/c3szcjxb3g990dbiz7llwmkaf0bi98j2-linux-firmware-20240312-zstd 460.6M

This is an increase of 4.4%, but OTOH zstd has a significantly higher
decompression speed[1].

[1] https://gregoryszorc.com/blog/2017/03/07/better-compression-with-zstandard/

+60 -34
+4
nixos/doc/manual/release-notes/rl-2405.section.md
··· 53 53 - A new option `system.etc.overlay.enable` was added. If enabled, `/etc` is 54 54 mounted via an overlayfs instead of being created by a custom perl script. 55 55 56 + - For each supporting version of the Linux kernel firmware blobs and kernel modules 57 + are compressed with zstd. For firmware blobs this means an increase of 4.4% in size, however 58 + a significantly higher decompression speed. 59 + 56 60 - NixOS AMIs are now uploaded regularly to a new AWS Account. 57 61 Instructions on how to use them can be found on <https://nixos.github.io/amis>. 58 62 We are working on integration the data into the NixOS homepage.
+10 -4
nixos/modules/services/hardware/udev.nix
··· 167 167 mv etc/udev/hwdb.bin $out 168 168 ''; 169 169 170 - compressFirmware = firmware: if (config.boot.kernelPackages.kernelAtLeast "5.3" && (firmware.compressFirmware or true)) then 171 - pkgs.compressFirmwareXz firmware 172 - else 173 - id firmware; 170 + compressFirmware = firmware: 171 + let 172 + inherit (config.boot.kernelPackages) kernelAtLeast; 173 + in 174 + if ! (firmware.compressFirmware or true) then 175 + firmware 176 + else 177 + if kernelAtLeast "5.19" then pkgs.compressFirmwareZstd firmware 178 + else if kernelAtLeast "5.3" then pkgs.compressFirmwareXz firmware 179 + else firmware; 174 180 175 181 # Udev has a 512-character limit for ENV{PATH}, so create a symlink 176 182 # tree to work around this.
-29
pkgs/build-support/kernel/compress-firmware-xz.nix
··· 1 - { runCommand, lib }: 2 - 3 - firmware: 4 - 5 - let 6 - args = { 7 - allowedRequisites = []; 8 - } // lib.optionalAttrs (firmware ? meta) { inherit (firmware) meta; }; 9 - in 10 - 11 - runCommand "${firmware.name}-xz" args '' 12 - mkdir -p $out/lib 13 - (cd ${firmware} && find lib/firmware -type d -print0) | 14 - (cd $out && xargs -0 mkdir -v --) 15 - (cd ${firmware} && find lib/firmware -type f -print0) | 16 - (cd $out && xargs -0rtP "$NIX_BUILD_CORES" -n1 \ 17 - sh -c 'xz -9c -T1 -C crc32 --lzma2=dict=2MiB "${firmware}/$1" > "$1.xz"' --) 18 - (cd ${firmware} && find lib/firmware -type l) | while read link; do 19 - target="$(readlink "${firmware}/$link")" 20 - if [ -f "${firmware}/$link" ]; then 21 - ln -vs -- "''${target/^${firmware}/$out}.xz" "$out/$link.xz" 22 - else 23 - ln -vs -- "''${target/^${firmware}/$out}" "$out/$link" 24 - fi 25 - done 26 - 27 - echo "Checking for broken symlinks:" 28 - find -L $out -type l -print -execdir false -- '{}' '+' 29 - ''
+43
pkgs/build-support/kernel/compress-firmware.nix
··· 1 + { runCommand, lib, type ? "zstd", zstd }: 2 + 3 + firmware: 4 + 5 + let 6 + compressor = { 7 + xz = { 8 + ext = "xz"; 9 + nativeBuildInputs = [ ]; 10 + cmd = file: target: ''xz -9c -T1 -C crc32 --lzma2=dict=2MiB "${file}" > "${target}"''; 11 + }; 12 + zstd = { 13 + ext = "zst"; 14 + nativeBuildInputs = [ zstd ]; 15 + cmd = file: target: ''zstd -T1 -19 --long --check -f "${file}" -o "${target}"''; 16 + }; 17 + }.${type} or (throw "Unsupported compressor type for firmware."); 18 + 19 + args = { 20 + allowedRequisites = []; 21 + inherit (compressor) nativeBuildInputs; 22 + } // lib.optionalAttrs (firmware ? meta) { inherit (firmware) meta; }; 23 + in 24 + 25 + runCommand "${firmware.name}-${type}" args '' 26 + mkdir -p $out/lib 27 + (cd ${firmware} && find lib/firmware -type d -print0) | 28 + (cd $out && xargs -0 mkdir -v --) 29 + (cd ${firmware} && find lib/firmware -type f -print0) | 30 + (cd $out && xargs -0rtP "$NIX_BUILD_CORES" -n1 \ 31 + sh -c '${compressor.cmd "${firmware}/$1" "$1.${compressor.ext}"}' --) 32 + (cd ${firmware} && find lib/firmware -type l) | while read link; do 33 + target="$(readlink "${firmware}/$link")" 34 + if [ -f "${firmware}/$link" ]; then 35 + ln -vs -- "''${target/^${firmware}/$out}.${compressor.ext}" "$out/$link.${compressor.ext}" 36 + else 37 + ln -vs -- "''${target/^${firmware}/$out}" "$out/$link" 38 + fi 39 + done 40 + 41 + echo "Checking for broken symlinks:" 42 + find -L $out -type l -print -execdir false -- '{}' '+' 43 + ''
+3 -1
pkgs/top-level/all-packages.nix
··· 1314 1314 1315 1315 makeBinaryWrapper = callPackage ../build-support/setup-hooks/make-binary-wrapper { }; 1316 1316 1317 - compressFirmwareXz = callPackage ../build-support/kernel/compress-firmware-xz.nix { }; 1317 + compressFirmwareXz = callPackage ../build-support/kernel/compress-firmware.nix { type = "xz"; }; 1318 + 1319 + compressFirmwareZstd = callPackage ../build-support/kernel/compress-firmware.nix { type = "zstd"; }; 1318 1320 1319 1321 makeModulesClosure = { kernel, firmware, rootModules, allowMissing ? false }: 1320 1322 callPackage ../build-support/kernel/modules-closure.nix {