diff options
| author | Maxim Cournoyer <maxim.cournoyer@gmail.com> | 2024-05-12 20:51:50 -0400 |
|---|---|---|
| committer | Maxim Cournoyer <maxim.cournoyer@gmail.com> | 2024-05-29 22:01:23 -0400 |
| commit | afacfa33ec4b52cb9ffb9b0a7a0c1e68cf264673 (patch) | |
| tree | 9d811f1d85d4ae892604ca421d653ea53fb654a0 | |
| parent | b72b6063cebbcfd64d43f5b05ba8470eb11c3f65 (diff) | |
gnu: linux-libre: Enable Zstd compression of kernel modules.
This brings the on disk size of the kernel from 164 MiB to 144 MiB, or about
12%.
* gnu/packages/linux.scm (default-extra-linux-options)
[version>=5.13]: Enable CONFIG_MODULE_COMPRESS_ZSTD, else
CONFIG_MODULE_COMPRESS_GZIP.
(make-linux-libre*) [phases] {set-environment}: Set ZSTD_CLEVEL environment
variable to 19.
[native-inputs]: Add zstd.
* gnu/build/linux-modules.scm (module-regex): Add .zst to regexp. Update doc.
(modinfo-section-contents): Extend support to Zstd compressed module.
(dot-ko): Register the 'zstd compression type.
(ensure-dot-ko, file-name->module-name, load-linux-module*)
(module-name->file-name/guess, write-module-name-database)
(write-module-alias-database, write-module-device-database): Update doc.
(module-name-lookup): Also consider zstd-compressed modules.
* gnu/installer.scm (installer-program): Add guile-zstd extension to gexp.
* gnu/system/linux-initrd.scm (flat-linux-module-directory): Likewise.
Decompress zstd-compressed modules for use in initrd.
* guix/profiles.scm (linux-module-database): Add guile-zstd extension to gexp.
Change-Id: Ide899dc5c58ea5033583b1a91a92c025fc8d901a
| -rw-r--r-- | gnu/build/linux-modules.scm | 62 | ||||
| -rw-r--r-- | gnu/installer.scm | 1 | ||||
| -rw-r--r-- | gnu/packages/linux.scm | 13 | ||||
| -rw-r--r-- | gnu/system/linux-initrd.scm | 6 | ||||
| -rw-r--r-- | guix/profiles.scm | 7 |
5 files changed, 57 insertions, 32 deletions
diff --git a/gnu/build/linux-modules.scm b/gnu/build/linux-modules.scm index 68c32ff8738..32baf6c5259 100644 --- a/gnu/build/linux-modules.scm +++ b/gnu/build/linux-modules.scm | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> | 3 | ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> |
| 4 | ;;; Copyright © 2018 Danny Milosavljevic <dannym@scratchpost.org> | 4 | ;;; Copyright © 2018 Danny Milosavljevic <dannym@scratchpost.org> |
| 5 | ;;; Copyright © 2023 Tobias Geerinckx-Rice <me@tobias.gr> | 5 | ;;; Copyright © 2023 Tobias Geerinckx-Rice <me@tobias.gr> |
| 6 | ;;; Copyright © 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com> | ||
| 6 | ;;; | 7 | ;;; |
| 7 | ;;; This file is part of GNU Guix. | 8 | ;;; This file is part of GNU Guix. |
| 8 | ;;; | 9 | ;;; |
| @@ -26,6 +27,7 @@ | |||
| 26 | #:use-module ((guix build utils) #:select (find-files invoke)) | 27 | #:use-module ((guix build utils) #:select (find-files invoke)) |
| 27 | #:use-module (guix build union) | 28 | #:use-module (guix build union) |
| 28 | #:autoload (zlib) (call-with-gzip-input-port) | 29 | #:autoload (zlib) (call-with-gzip-input-port) |
| 30 | #:autoload (zstd) (call-with-zstd-input-port) | ||
| 29 | #:use-module (rnrs io ports) | 31 | #:use-module (rnrs io ports) |
| 30 | #:use-module (rnrs bytevectors) | 32 | #:use-module (rnrs bytevectors) |
| 31 | #:use-module (srfi srfi-1) | 33 | #:use-module (srfi srfi-1) |
| @@ -108,24 +110,29 @@ string list." | |||
| 108 | (cons (string->symbol (string-take str =)) | 110 | (cons (string->symbol (string-take str =)) |
| 109 | (string-drop str (+ 1 =))))) | 111 | (string-drop str (+ 1 =))))) |
| 110 | 112 | ||
| 111 | ;; Matches kernel modules, without compression, with GZIP compression or with | 113 | ;; Matches kernel modules, without compression, with GZIP, XZ or ZSTD |
| 112 | ;; XZ compression. | 114 | ;; compression. |
| 113 | (define module-regex "\\.ko(\\.gz|\\.xz)?$") | 115 | (define module-regex "\\.ko(\\.gz|\\.xz|\\.zst)?$") |
| 114 | 116 | ||
| 115 | (define (modinfo-section-contents file) | 117 | (define (modinfo-section-contents file) |
| 116 | "Return the contents of the '.modinfo' section of FILE as a list of | 118 | "Return the contents of the '.modinfo' section of FILE as a list of |
| 117 | key/value pairs.." | 119 | key/value pairs.." |
| 120 | (define (decompress-file decompressor file) | ||
| 121 | (let ((port (open-file file "r0"))) | ||
| 122 | (dynamic-wind | ||
| 123 | (lambda () | ||
| 124 | #t) | ||
| 125 | (lambda () | ||
| 126 | (decompressor port get-bytevector-all)) | ||
| 127 | (lambda () | ||
| 128 | (close-port port))))) | ||
| 129 | |||
| 118 | (define (get-bytevector file) | 130 | (define (get-bytevector file) |
| 119 | (cond | 131 | (cond |
| 120 | ((string-suffix? ".ko.gz" file) | 132 | ((string-suffix? ".ko.gz" file) |
| 121 | (let ((port (open-file file "r0"))) | 133 | (decompress-file call-with-gzip-input-port file)) |
| 122 | (dynamic-wind | 134 | ((string-suffix? ".ko.zst" file) |
| 123 | (lambda () | 135 | (decompress-file call-with-zstd-input-port file)) |
| 124 | #t) | ||
| 125 | (lambda () | ||
| 126 | (call-with-gzip-input-port port get-bytevector-all)) | ||
| 127 | (lambda () | ||
| 128 | (close-port port))))) | ||
| 129 | (else | 136 | (else |
| 130 | (call-with-input-file file get-bytevector-all)))) | 137 | (call-with-input-file file get-bytevector-all)))) |
| 131 | 138 | ||
| @@ -213,11 +220,12 @@ modules that can be postloaded, of the soft dependencies of module FILE." | |||
| 213 | (let ((suffix (match compression | 220 | (let ((suffix (match compression |
| 214 | ('xz ".ko.xz") | 221 | ('xz ".ko.xz") |
| 215 | ('gzip ".ko.gz") | 222 | ('gzip ".ko.gz") |
| 223 | ('zstd ".ko.zst") | ||
| 216 | (else ".ko")))) | 224 | (else ".ko")))) |
| 217 | (string-append name suffix))) | 225 | (string-append name suffix))) |
| 218 | 226 | ||
| 219 | (define (ensure-dot-ko name compression) | 227 | (define (ensure-dot-ko name compression) |
| 220 | "Return NAME with a '.ko[.gz|.xz]' suffix appended, unless it already has | 228 | "Return NAME with a '.ko[.gz|.xz|.zst]' suffix appended, unless it already has |
| 221 | it." | 229 | it." |
| 222 | (if (string-contains name ".ko") | 230 | (if (string-contains name ".ko") |
| 223 | name | 231 | name |
| @@ -235,7 +243,7 @@ underscores." | |||
| 235 | 243 | ||
| 236 | (define (file-name->module-name file) | 244 | (define (file-name->module-name file) |
| 237 | "Return the module name corresponding to FILE, stripping the trailing | 245 | "Return the module name corresponding to FILE, stripping the trailing |
| 238 | '.ko[.gz|.xz]' and normalizing it." | 246 | '.ko[.gz|.xz|.zst]' and normalizing it." |
| 239 | (normalize-module-name (strip-extension (basename file)))) | 247 | (normalize-module-name (strip-extension (basename file)))) |
| 240 | 248 | ||
| 241 | (define (find-module-file directory module) | 249 | (define (find-module-file directory module) |
| @@ -333,11 +341,11 @@ not a file name." | |||
| 333 | (recursive? #t) | 341 | (recursive? #t) |
| 334 | (lookup-module dot-ko) | 342 | (lookup-module dot-ko) |
| 335 | (black-list (module-black-list))) | 343 | (black-list (module-black-list))) |
| 336 | "Load Linux module from FILE, the name of a '.ko[.gz|.xz]' file; return true | 344 | "Load Linux module from FILE, the name of a '.ko[.gz|.xz|.zst]' file; return |
| 337 | on success, false otherwise. When RECURSIVE? is true, load its dependencies | 345 | true on success, false otherwise. When RECURSIVE? is true, load its |
| 338 | first (à la 'modprobe'.) The actual files containing modules depended on are | 346 | dependencies first (à la 'modprobe'.) The actual files containing modules |
| 339 | obtained by calling LOOKUP-MODULE with the module name. Modules whose name | 347 | depended on are obtained by calling LOOKUP-MODULE with the module name. |
| 340 | appears in BLACK-LIST are not loaded." | 348 | Modules whose name appears in BLACK-LIST are not loaded." |
| 341 | (define (black-listed? module) | 349 | (define (black-listed? module) |
| 342 | (let ((result (member module black-list))) | 350 | (let ((result (member module black-list))) |
| 343 | (when result | 351 | (when result |
| @@ -695,7 +703,7 @@ are required to access DEVICE." | |||
| 695 | "Guess the file name corresponding to NAME, a module name. That doesn't | 703 | "Guess the file name corresponding to NAME, a module name. That doesn't |
| 696 | always work because sometimes underscores in NAME map to hyphens (e.g., | 704 | always work because sometimes underscores in NAME map to hyphens (e.g., |
| 697 | \"input-leds.ko\"), sometimes not (e.g., \"mac_hid.ko\"). If the module is | 705 | \"input-leds.ko\"), sometimes not (e.g., \"mac_hid.ko\"). If the module is |
| 698 | compressed then COMPRESSED can be set to 'xz or 'gzip, depending on the | 706 | compressed then COMPRESSED can be set to 'zstd, 'xz or 'gzip, depending on the |
| 699 | compression type." | 707 | compression type." |
| 700 | (string-append directory "/" (ensure-dot-ko name compression))) | 708 | (string-append directory "/" (ensure-dot-ko name compression))) |
| 701 | 709 | ||
| @@ -707,6 +715,8 @@ compression type." | |||
| 707 | (let ((names (list | 715 | (let ((names (list |
| 708 | (module-name->file-name/guess directory name) | 716 | (module-name->file-name/guess directory name) |
| 709 | (module-name->file-name/guess directory name | 717 | (module-name->file-name/guess directory name |
| 718 | #:compression 'zstd) | ||
| 719 | (module-name->file-name/guess directory name | ||
| 710 | #:compression 'xz) | 720 | #:compression 'xz) |
| 711 | (module-name->file-name/guess directory name | 721 | (module-name->file-name/guess directory name |
| 712 | #:compression 'gzip)))) | 722 | #:compression 'gzip)))) |
| @@ -729,8 +739,8 @@ compression type." | |||
| 729 | 739 | ||
| 730 | (define (write-module-name-database directory) | 740 | (define (write-module-name-database directory) |
| 731 | "Write a database that maps \"module names\" as they appear in the relevant | 741 | "Write a database that maps \"module names\" as they appear in the relevant |
| 732 | ELF section of '.ko[.gz|.xz]' files, to actual file names. This format is | 742 | ELF section of '.ko[.gz|.xz|.zst]' files, to actual file names. This format |
| 733 | Guix-specific. It aims to deal with inconsistent naming, in particular | 743 | is Guix-specific. It aims to deal with inconsistent naming, in particular |
| 734 | hyphens vs. underscores." | 744 | hyphens vs. underscores." |
| 735 | (define mapping | 745 | (define mapping |
| 736 | (map (lambda (file) | 746 | (map (lambda (file) |
| @@ -749,8 +759,8 @@ hyphens vs. underscores." | |||
| 749 | (pretty-print mapping port)))) | 759 | (pretty-print mapping port)))) |
| 750 | 760 | ||
| 751 | (define (write-module-alias-database directory) | 761 | (define (write-module-alias-database directory) |
| 752 | "Traverse the '.ko[.gz|.xz]' files in DIRECTORY and create the corresponding | 762 | "Traverse the '.ko[.gz|.xz|.zst]' files in DIRECTORY and create the |
| 753 | 'modules.alias' file." | 763 | corresponding 'modules.alias' file." |
| 754 | (define aliases | 764 | (define aliases |
| 755 | (map (lambda (file) | 765 | (map (lambda (file) |
| 756 | (cons (file-name->module-name file) (module-aliases file))) | 766 | (cons (file-name->module-name file) (module-aliases file))) |
| @@ -796,9 +806,9 @@ are found, return a tuple (DEVNAME TYPE MAJOR MINOR), otherwise return #f." | |||
| 796 | (char-set-complement (char-set #\-))) | 806 | (char-set-complement (char-set #\-))) |
| 797 | 807 | ||
| 798 | (define (write-module-device-database directory) | 808 | (define (write-module-device-database directory) |
| 799 | "Traverse the '.ko[.gz|.xz]' files in DIRECTORY and create the corresponding | 809 | "Traverse the '.ko[.gz|.xz|.zst]' files in DIRECTORY and create the |
| 800 | 'modules.devname' file. This file contains information about modules that can | 810 | corresponding 'modules.devname' file. This file contains information about |
| 801 | be loaded on-demand, such as file system modules." | 811 | modules that can be loaded on-demand, such as file system modules." |
| 802 | (define aliases | 812 | (define aliases |
| 803 | (filter-map (lambda (file) | 813 | (filter-map (lambda (file) |
| 804 | (match (aliases->device-tuple (module-aliases file)) | 814 | (match (aliases->device-tuple (module-aliases file)) |
diff --git a/gnu/installer.scm b/gnu/installer.scm index 3b06b4f01b7..3792fc7e350 100644 --- a/gnu/installer.scm +++ b/gnu/installer.scm | |||
| @@ -386,6 +386,7 @@ purposes." | |||
| 386 | guile-json-3 guile-git guile-webutils | 386 | guile-json-3 guile-git guile-webutils |
| 387 | guile-gnutls | 387 | guile-gnutls |
| 388 | guile-zlib ;for (gnu build linux-modules) | 388 | guile-zlib ;for (gnu build linux-modules) |
| 389 | guile-zstd ;for (gnu build linux-modules) | ||
| 389 | (current-guix)) | 390 | (current-guix)) |
| 390 | (with-imported-modules `(,@(source-module-closure | 391 | (with-imported-modules `(,@(source-module-closure |
| 391 | `(,@modules | 392 | `(,@modules |
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm index db2b0f4bda6..2575f687da2 100644 --- a/gnu/packages/linux.scm +++ b/gnu/packages/linux.scm | |||
| @@ -874,6 +874,10 @@ ARCH and optionally VARIANT, or #f if there is no such configuration." | |||
| 874 | ,@(if (version>=? version "5.13") | 874 | ,@(if (version>=? version "5.13") |
| 875 | '(("BPF_UNPRIV_DEFAULT_OFF" . #t)) | 875 | '(("BPF_UNPRIV_DEFAULT_OFF" . #t)) |
| 876 | '()) | 876 | '()) |
| 877 | ;; Compress kernel modules via Zstd. | ||
| 878 | ,(if (version>=? version "5.13") | ||
| 879 | '("CONFIG_MODULE_COMPRESS_ZSTD" . #t) | ||
| 880 | '("CONFIG_MODULE_COMPRESS_GZIP" . #t)) | ||
| 877 | ;; Some very mild hardening. | 881 | ;; Some very mild hardening. |
| 878 | ("CONFIG_SECURITY_DMESG_RESTRICT" . #t) | 882 | ("CONFIG_SECURITY_DMESG_RESTRICT" . #t) |
| 879 | ;; All kernels should have NAMESPACES options enabled | 883 | ;; All kernels should have NAMESPACES options enabled |
| @@ -1063,7 +1067,10 @@ ARCH and optionally VARIANT, or #f if there is no such configuration." | |||
| 1063 | "EXTRAVERSION ?=")) | 1067 | "EXTRAVERSION ?=")) |
| 1064 | (setenv "EXTRAVERSION" | 1068 | (setenv "EXTRAVERSION" |
| 1065 | #$(and extra-version | 1069 | #$(and extra-version |
| 1066 | (string-append "-" extra-version))))) | 1070 | (string-append "-" extra-version))) |
| 1071 | ;; Use the maximum compression available for Zstd-compressed | ||
| 1072 | ;; modules. | ||
| 1073 | (setenv "ZSTD_CLEVEL" "19"))) | ||
| 1067 | (replace 'configure | 1074 | (replace 'configure |
| 1068 | (lambda _ | 1075 | (lambda _ |
| 1069 | (let ((config | 1076 | (let ((config |
| @@ -1157,7 +1164,9 @@ ARCH and optionally VARIANT, or #f if there is no such configuration." | |||
| 1157 | ;; support. | 1164 | ;; support. |
| 1158 | dwarves ;for pahole | 1165 | dwarves ;for pahole |
| 1159 | python-wrapper | 1166 | python-wrapper |
| 1160 | zlib)) | 1167 | zlib |
| 1168 | ;; For Zstd compression of kernel modules. | ||
| 1169 | zstd)) | ||
| 1161 | (home-page "https://www.gnu.org/software/linux-libre/") | 1170 | (home-page "https://www.gnu.org/software/linux-libre/") |
| 1162 | (synopsis "100% free redistribution of a cleaned Linux kernel") | 1171 | (synopsis "100% free redistribution of a cleaned Linux kernel") |
| 1163 | (description "GNU Linux-Libre is a free (as in freedom) variant of the | 1172 | (description "GNU Linux-Libre is a free (as in freedom) variant of the |
diff --git a/gnu/system/linux-initrd.scm b/gnu/system/linux-initrd.scm index d448c789181..f902637e484 100644 --- a/gnu/system/linux-initrd.scm +++ b/gnu/system/linux-initrd.scm | |||
| @@ -128,7 +128,7 @@ MODULES and taken from LINUX." | |||
| 128 | 128 | ||
| 129 | (define build-exp | 129 | (define build-exp |
| 130 | (with-imported-modules imported-modules | 130 | (with-imported-modules imported-modules |
| 131 | (with-extensions (list guile-zlib) | 131 | (with-extensions (list guile-zlib guile-zstd) |
| 132 | #~(begin | 132 | #~(begin |
| 133 | (use-modules (gnu build linux-modules) | 133 | (use-modules (gnu build linux-modules) |
| 134 | (guix build utils) | 134 | (guix build utils) |
| @@ -168,7 +168,9 @@ MODULES and taken from LINUX." | |||
| 168 | ;; is already gzipped as a whole. | 168 | ;; is already gzipped as a whole. |
| 169 | (cond | 169 | (cond |
| 170 | ((string-contains file ".ko.gz") | 170 | ((string-contains file ".ko.gz") |
| 171 | (invoke #+(file-append gzip "/bin/gunzip") file)))) | 171 | (invoke #+(file-append gzip "/bin/gunzip") file)) |
| 172 | ((string-contains file ".ko.zst") | ||
| 173 | (invoke #+(file-append zstd "/bin/zstd") "-d" file)))) | ||
| 172 | 174 | ||
| 173 | (mkdir #$output) | 175 | (mkdir #$output) |
| 174 | (for-each (lambda (module) | 176 | (for-each (lambda (module) |
diff --git a/guix/profiles.scm b/guix/profiles.scm index d41802422bc..864ed02b6de 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | ;;; Copyright © 2016, 2017, 2018, 2019, 2021, 2022 Ricardo Wurmus <rekado@elephly.net> | 7 | ;;; Copyright © 2016, 2017, 2018, 2019, 2021, 2022 Ricardo Wurmus <rekado@elephly.net> |
| 8 | ;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com> | 8 | ;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com> |
| 9 | ;;; Copyright © 2017 Huang Ying <huang.ying.caritas@gmail.com> | 9 | ;;; Copyright © 2017 Huang Ying <huang.ying.caritas@gmail.com> |
| 10 | ;;; Copyright © 2017, 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com> | 10 | ;;; Copyright © 2017, 2021, 2024 Maxim Cournoyer <maxim.cournoyer@gmail.com> |
| 11 | ;;; Copyright © 2019 Kyle Meyer <kyle@kyleam.com> | 11 | ;;; Copyright © 2019 Kyle Meyer <kyle@kyleam.com> |
| 12 | ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@gmail.com> | 12 | ;;; Copyright © 2019 Mathieu Othacehe <m.othacehe@gmail.com> |
| 13 | ;;; Copyright © 2020 Danny Milosavljevic <dannym@scratchpost.org> | 13 | ;;; Copyright © 2020 Danny Milosavljevic <dannym@scratchpost.org> |
| @@ -1487,11 +1487,14 @@ This is meant to be used as a profile hook." | |||
| 1487 | (define guile-zlib | 1487 | (define guile-zlib |
| 1488 | (module-ref (resolve-interface '(gnu packages guile)) 'guile-zlib)) | 1488 | (module-ref (resolve-interface '(gnu packages guile)) 'guile-zlib)) |
| 1489 | 1489 | ||
| 1490 | (define guile-zstd | ||
| 1491 | (module-ref (resolve-interface '(gnu packages guile)) 'guile-zstd)) | ||
| 1492 | |||
| 1490 | (define build | 1493 | (define build |
| 1491 | (with-imported-modules (source-module-closure | 1494 | (with-imported-modules (source-module-closure |
| 1492 | '((guix build utils) | 1495 | '((guix build utils) |
| 1493 | (gnu build linux-modules))) | 1496 | (gnu build linux-modules))) |
| 1494 | (with-extensions (list guile-zlib) | 1497 | (with-extensions (list guile-zlib guile-zstd) |
| 1495 | #~(begin | 1498 | #~(begin |
| 1496 | (use-modules (ice-9 ftw) | 1499 | (use-modules (ice-9 ftw) |
| 1497 | (ice-9 match) | 1500 | (ice-9 match) |
