diff options
| author | Mathieu Othacehe <othacehe@gnu.org> | 2020-07-05 12:23:21 +0200 |
|---|---|---|
| committer | Mathieu Othacehe <othacehe@gnu.org> | 2020-08-25 11:53:20 +0200 |
| commit | 755f365b02b42a5d1e8ef3000dadef069553a478 (patch) | |
| tree | 57ce759104439219c2c6076aa3c1af875487c5c1 /gnu/build | |
| parent | 46ef674b34fd63f6bcd5bd07348d5c66eb8bdf29 (diff) | |
linux-libre: Support module compression.
This commit adds support for GZIP compression for linux-libre kernel
modules. The initrd modules are kept uncompressed as the initrd is already
compressed as a whole.
The linux-libre kernel also supports XZ compression, but as Guix does not have
any available bindings for now, and the compression time is far more
significant, GZIP seems to be a better option.
* gnu/build/linux-modules.scm (modinfo-section-contents): Use
'call-with-gzip-input-port' to read from a module file using '.gz' extension,
(strip-extension): new procedure,
(dot-ko): adapt to support compression,
(ensure-dot-ko): ditto,
(file-name->module-name): ditto,
(find-module-file): ditto,
(load-linux-module*): ditto,
(module-name->file-name/guess): ditto,
(module-name-lookup): ditto,
(write-module-name-database): ditto,
(write-module-alias-database): ditto,
(write-module-device-database): ditto.
* gnu/installer.scm (installer-program): Add "guile-zlib" to the extensions.
* gnu/machine/ssh.scm (machine-check-initrd-modules): Ditto.
* gnu/services.scm (activation-script): Ditto.
* gnu/services/base.scm (default-serial-port): Ditto,
(agetty-shepherd-service): ditto,
(udev-service-type): ditto.
* gnu/system/image.scm (gcrypt-sqlite3&co): Ditto.
* gnu/system/linux-initrd.scm (flat-linux-module-directory): Add "guile-zlib"
to the extensions and make sure that the initrd only contains
uncompressed module files.
* gnu/system/shadow.scm (account-shepherd-service): Add "guile-zlib" to the
extensions.
* guix/profiles.scm (linux-module-database): Ditto.
Diffstat (limited to 'gnu/build')
| -rw-r--r-- | gnu/build/linux-modules.scm | 115 |
1 files changed, 79 insertions, 36 deletions
diff --git a/gnu/build/linux-modules.scm b/gnu/build/linux-modules.scm index aa1c7cfeae2..3a473220655 100644 --- a/gnu/build/linux-modules.scm +++ b/gnu/build/linux-modules.scm | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #:use-module (guix build syscalls) | 24 | #:use-module (guix build syscalls) |
| 25 | #:use-module ((guix build utils) #:select (find-files invoke)) | 25 | #:use-module ((guix build utils) #:select (find-files invoke)) |
| 26 | #:use-module (guix build union) | 26 | #:use-module (guix build union) |
| 27 | #:autoload (zlib) (call-with-gzip-input-port) | ||
| 27 | #:use-module (rnrs io ports) | 28 | #:use-module (rnrs io ports) |
| 28 | #:use-module (rnrs bytevectors) | 29 | #:use-module (rnrs bytevectors) |
| 29 | #:use-module (srfi srfi-1) | 30 | #:use-module (srfi srfi-1) |
| @@ -94,10 +95,28 @@ string list." | |||
| 94 | (cons (string->symbol (string-take str =)) | 95 | (cons (string->symbol (string-take str =)) |
| 95 | (string-drop str (+ 1 =))))) | 96 | (string-drop str (+ 1 =))))) |
| 96 | 97 | ||
| 98 | ;; Matches kernel modules, without compression, with GZIP compression or with | ||
| 99 | ;; XZ compression. | ||
| 100 | (define module-regex "\\.ko(\\.gz|\\.xz)?$") | ||
| 101 | |||
| 97 | (define (modinfo-section-contents file) | 102 | (define (modinfo-section-contents file) |
| 98 | "Return the contents of the '.modinfo' section of FILE as a list of | 103 | "Return the contents of the '.modinfo' section of FILE as a list of |
| 99 | key/value pairs.." | 104 | key/value pairs.." |
| 100 | (let* ((bv (call-with-input-file file get-bytevector-all)) | 105 | (define (get-bytevector file) |
| 106 | (cond | ||
| 107 | ((string-suffix? ".ko.gz" file) | ||
| 108 | (let ((port (open-file file "r0"))) | ||
| 109 | (dynamic-wind | ||
| 110 | (lambda () | ||
| 111 | #t) | ||
| 112 | (lambda () | ||
| 113 | (call-with-gzip-input-port port get-bytevector-all)) | ||
| 114 | (lambda () | ||
| 115 | (close-port port))))) | ||
| 116 | (else | ||
| 117 | (call-with-input-file file get-bytevector-all)))) | ||
| 118 | |||
| 119 | (let* ((bv (get-bytevector file)) | ||
| 101 | (elf (parse-elf bv)) | 120 | (elf (parse-elf bv)) |
| 102 | (section (elf-section-by-name elf ".modinfo")) | 121 | (section (elf-section-by-name elf ".modinfo")) |
| 103 | (modinfo (section-contents elf section))) | 122 | (modinfo (section-contents elf section))) |
| @@ -110,7 +129,7 @@ key/value pairs.." | |||
| 110 | (define (module-formal-name file) | 129 | (define (module-formal-name file) |
| 111 | "Return the module name of FILE as it appears in its info section. Usually | 130 | "Return the module name of FILE as it appears in its info section. Usually |
| 112 | the module name is the same as the base name of FILE, modulo hyphens and minus | 131 | the module name is the same as the base name of FILE, modulo hyphens and minus |
| 113 | the \".ko\" extension." | 132 | the \".ko[.gz|.xz]\" extension." |
| 114 | (match (assq 'name (modinfo-section-contents file)) | 133 | (match (assq 'name (modinfo-section-contents file)) |
| 115 | (('name . name) name) | 134 | (('name . name) name) |
| 116 | (#f #f))) | 135 | (#f #f))) |
| @@ -171,14 +190,25 @@ modules that can be postloaded, of the soft dependencies of module FILE." | |||
| 171 | (_ #f)) | 190 | (_ #f)) |
| 172 | (modinfo-section-contents file)))) | 191 | (modinfo-section-contents file)))) |
| 173 | 192 | ||
| 174 | (define dot-ko | 193 | (define (strip-extension filename) |
| 175 | (cut string-append <> ".ko")) | 194 | (let ((extension (string-index filename #\.))) |
| 176 | 195 | (if extension | |
| 177 | (define (ensure-dot-ko name) | 196 | (string-take filename extension) |
| 178 | "Return NAME with a '.ko' prefix appended, unless it already has it." | 197 | filename))) |
| 179 | (if (string-suffix? ".ko" name) | 198 | |
| 199 | (define (dot-ko name compression) | ||
| 200 | (let ((suffix (match compression | ||
| 201 | ('xz ".ko.xz") | ||
| 202 | ('gzip ".ko.gz") | ||
| 203 | (else ".ko")))) | ||
| 204 | (string-append name suffix))) | ||
| 205 | |||
| 206 | (define (ensure-dot-ko name compression) | ||
| 207 | "Return NAME with a '.ko[.gz|.xz]' suffix appended, unless it already has | ||
| 208 | it." | ||
| 209 | (if (string-contains name ".ko") | ||
| 180 | name | 210 | name |
| 181 | (dot-ko name))) | 211 | (dot-ko name compression))) |
| 182 | 212 | ||
| 183 | (define (normalize-module-name module) | 213 | (define (normalize-module-name module) |
| 184 | "Return the \"canonical\" name for MODULE, replacing hyphens with | 214 | "Return the \"canonical\" name for MODULE, replacing hyphens with |
| @@ -191,9 +221,9 @@ underscores." | |||
| 191 | module)) | 221 | module)) |
| 192 | 222 | ||
| 193 | (define (file-name->module-name file) | 223 | (define (file-name->module-name file) |
| 194 | "Return the module name corresponding to FILE, stripping the trailing '.ko' | 224 | "Return the module name corresponding to FILE, stripping the trailing |
| 195 | and normalizing it." | 225 | '.ko[.gz|.xz]' and normalizing it." |
| 196 | (normalize-module-name (basename file ".ko"))) | 226 | (normalize-module-name (strip-extension (basename file)))) |
| 197 | 227 | ||
| 198 | (define (find-module-file directory module) | 228 | (define (find-module-file directory module) |
| 199 | "Lookup module NAME under DIRECTORY, and return its absolute file name. | 229 | "Lookup module NAME under DIRECTORY, and return its absolute file name. |
| @@ -208,19 +238,19 @@ whereas file names often, but not always, use hyphens. Examples: | |||
| 208 | ;; List of possible file names. XXX: It would of course be cleaner to | 238 | ;; List of possible file names. XXX: It would of course be cleaner to |
| 209 | ;; have a database that maps module names to file names and vice versa, | 239 | ;; have a database that maps module names to file names and vice versa, |
| 210 | ;; but everyone seems to be doing hacks like this one. Oh well! | 240 | ;; but everyone seems to be doing hacks like this one. Oh well! |
| 211 | (map ensure-dot-ko | 241 | (delete-duplicates |
| 212 | (delete-duplicates | 242 | (list module |
| 213 | (list module | 243 | (normalize-module-name module) |
| 214 | (normalize-module-name module) | 244 | (string-map (lambda (chr) ;converse of 'normalize-module-name' |
| 215 | (string-map (lambda (chr) ;converse of 'normalize-module-name' | 245 | (case chr |
| 216 | (case chr | 246 | ((#\_) #\-) |
| 217 | ((#\_) #\-) | 247 | (else chr))) |
| 218 | (else chr))) | 248 | module)))) |
| 219 | module))))) | ||
| 220 | 249 | ||
| 221 | (match (find-files directory | 250 | (match (find-files directory |
| 222 | (lambda (file stat) | 251 | (lambda (file stat) |
| 223 | (member (basename file) names))) | 252 | (member (strip-extension |
| 253 | (basename file)) names))) | ||
| 224 | ((file) | 254 | ((file) |
| 225 | file) | 255 | file) |
| 226 | (() | 256 | (() |
| @@ -290,8 +320,8 @@ not a file name." | |||
| 290 | (recursive? #t) | 320 | (recursive? #t) |
| 291 | (lookup-module dot-ko) | 321 | (lookup-module dot-ko) |
| 292 | (black-list (module-black-list))) | 322 | (black-list (module-black-list))) |
| 293 | "Load Linux module from FILE, the name of a '.ko' file; return true on | 323 | "Load Linux module from FILE, the name of a '.ko[.gz|.xz]' file; return true |
| 294 | success, false otherwise. When RECURSIVE? is true, load its dependencies | 324 | on success, false otherwise. When RECURSIVE? is true, load its dependencies |
| 295 | first (à la 'modprobe'.) The actual files containing modules depended on are | 325 | first (à la 'modprobe'.) The actual files containing modules depended on are |
| 296 | obtained by calling LOOKUP-MODULE with the module name. Modules whose name | 326 | obtained by calling LOOKUP-MODULE with the module name. Modules whose name |
| 297 | appears in BLACK-LIST are not loaded." | 327 | appears in BLACK-LIST are not loaded." |
| @@ -523,16 +553,29 @@ are required to access DEVICE." | |||
| 523 | ;;; Module databases. | 553 | ;;; Module databases. |
| 524 | ;;; | 554 | ;;; |
| 525 | 555 | ||
| 526 | (define (module-name->file-name/guess directory name) | 556 | (define* (module-name->file-name/guess directory name |
| 557 | #:key compression) | ||
| 527 | "Guess the file name corresponding to NAME, a module name. That doesn't | 558 | "Guess the file name corresponding to NAME, a module name. That doesn't |
| 528 | always work because sometimes underscores in NAME map to hyphens (e.g., | 559 | always work because sometimes underscores in NAME map to hyphens (e.g., |
| 529 | \"input-leds.ko\"), sometimes not (e.g., \"mac_hid.ko\")." | 560 | \"input-leds.ko\"), sometimes not (e.g., \"mac_hid.ko\"). If the module is |
| 530 | (string-append directory "/" (ensure-dot-ko name))) | 561 | compressed then COMPRESSED can be set to 'xz or 'gzip, depending on the |
| 562 | compression type." | ||
| 563 | (string-append directory "/" (ensure-dot-ko name compression))) | ||
| 531 | 564 | ||
| 532 | (define (module-name-lookup directory) | 565 | (define (module-name-lookup directory) |
| 533 | "Return a one argument procedure that takes a module name (e.g., | 566 | "Return a one argument procedure that takes a module name (e.g., |
| 534 | \"input_leds\") and returns its absolute file name (e.g., | 567 | \"input_leds\") and returns its absolute file name (e.g., |
| 535 | \"/.../input-leds.ko\")." | 568 | \"/.../input-leds.ko\")." |
| 569 | (define (guess-file-name name) | ||
| 570 | (let ((names (list | ||
| 571 | (module-name->file-name/guess directory name) | ||
| 572 | (module-name->file-name/guess directory name | ||
| 573 | #:compression 'xz) | ||
| 574 | (module-name->file-name/guess directory name | ||
| 575 | #:compression 'gzip)))) | ||
| 576 | (or (find file-exists? names) | ||
| 577 | (first names)))) | ||
| 578 | |||
| 536 | (catch 'system-error | 579 | (catch 'system-error |
| 537 | (lambda () | 580 | (lambda () |
| 538 | (define mapping | 581 | (define mapping |
| @@ -541,23 +584,23 @@ always work because sometimes underscores in NAME map to hyphens (e.g., | |||
| 541 | 584 | ||
| 542 | (lambda (name) | 585 | (lambda (name) |
| 543 | (or (assoc-ref mapping name) | 586 | (or (assoc-ref mapping name) |
| 544 | (module-name->file-name/guess directory name)))) | 587 | (guess-file-name name)))) |
| 545 | (lambda args | 588 | (lambda args |
| 546 | (if (= ENOENT (system-error-errno args)) | 589 | (if (= ENOENT (system-error-errno args)) |
| 547 | (cut module-name->file-name/guess directory <>) | 590 | (cut guess-file-name <>) |
| 548 | (apply throw args))))) | 591 | (apply throw args))))) |
| 549 | 592 | ||
| 550 | (define (write-module-name-database directory) | 593 | (define (write-module-name-database directory) |
| 551 | "Write a database that maps \"module names\" as they appear in the relevant | 594 | "Write a database that maps \"module names\" as they appear in the relevant |
| 552 | ELF section of '.ko' files, to actual file names. This format is | 595 | ELF section of '.ko[.gz|.xz]' files, to actual file names. This format is |
| 553 | Guix-specific. It aims to deal with inconsistent naming, in particular | 596 | Guix-specific. It aims to deal with inconsistent naming, in particular |
| 554 | hyphens vs. underscores." | 597 | hyphens vs. underscores." |
| 555 | (define mapping | 598 | (define mapping |
| 556 | (map (lambda (file) | 599 | (map (lambda (file) |
| 557 | (match (module-formal-name file) | 600 | (match (module-formal-name file) |
| 558 | (#f (cons (basename file ".ko") file)) | 601 | (#f (cons (strip-extension (basename file)) file)) |
| 559 | (name (cons name file)))) | 602 | (name (cons name file)))) |
| 560 | (find-files directory "\\.ko$"))) | 603 | (find-files directory module-regex))) |
| 561 | 604 | ||
| 562 | (call-with-output-file (string-append directory "/modules.name") | 605 | (call-with-output-file (string-append directory "/modules.name") |
| 563 | (lambda (port) | 606 | (lambda (port) |
| @@ -569,12 +612,12 @@ hyphens vs. underscores." | |||
| 569 | (pretty-print mapping port)))) | 612 | (pretty-print mapping port)))) |
| 570 | 613 | ||
| 571 | (define (write-module-alias-database directory) | 614 | (define (write-module-alias-database directory) |
| 572 | "Traverse the '.ko' files in DIRECTORY and create the corresponding | 615 | "Traverse the '.ko[.gz|.xz]' files in DIRECTORY and create the corresponding |
| 573 | 'modules.alias' file." | 616 | 'modules.alias' file." |
| 574 | (define aliases | 617 | (define aliases |
| 575 | (map (lambda (file) | 618 | (map (lambda (file) |
| 576 | (cons (file-name->module-name file) (module-aliases file))) | 619 | (cons (file-name->module-name file) (module-aliases file))) |
| 577 | (find-files directory "\\.ko$"))) | 620 | (find-files directory module-regex))) |
| 578 | 621 | ||
| 579 | (call-with-output-file (string-append directory "/modules.alias") | 622 | (call-with-output-file (string-append directory "/modules.alias") |
| 580 | (lambda (port) | 623 | (lambda (port) |
| @@ -616,7 +659,7 @@ are found, return a tuple (DEVNAME TYPE MAJOR MINOR), otherwise return #f." | |||
| 616 | (char-set-complement (char-set #\-))) | 659 | (char-set-complement (char-set #\-))) |
| 617 | 660 | ||
| 618 | (define (write-module-device-database directory) | 661 | (define (write-module-device-database directory) |
| 619 | "Traverse the '.ko' files in DIRECTORY and create the corresponding | 662 | "Traverse the '.ko[.gz|.xz]' files in DIRECTORY and create the corresponding |
| 620 | 'modules.devname' file. This file contains information about modules that can | 663 | 'modules.devname' file. This file contains information about modules that can |
| 621 | be loaded on-demand, such as file system modules." | 664 | be loaded on-demand, such as file system modules." |
| 622 | (define aliases | 665 | (define aliases |
| @@ -624,7 +667,7 @@ be loaded on-demand, such as file system modules." | |||
| 624 | (match (aliases->device-tuple (module-aliases file)) | 667 | (match (aliases->device-tuple (module-aliases file)) |
| 625 | (#f #f) | 668 | (#f #f) |
| 626 | (tuple (cons (file-name->module-name file) tuple)))) | 669 | (tuple (cons (file-name->module-name file) tuple)))) |
| 627 | (find-files directory "\\.ko$"))) | 670 | (find-files directory module-regex))) |
| 628 | 671 | ||
| 629 | (call-with-output-file (string-append directory "/modules.devname") | 672 | (call-with-output-file (string-append directory "/modules.devname") |
| 630 | (lambda (port) | 673 | (lambda (port) |
