diff mbox series

[bug#37868] guix: Allow multiple packages to provide Linux modules in the system profile.

Message ID 20191022152238.12856-1-dannym@scratchpost.org
State Accepted
Headers show
Series [bug#37868] guix: Allow multiple packages to provide Linux modules in the system profile. | expand

Commit Message

Danny Milosavljevic Oct. 22, 2019, 3:22 p.m. UTC
* guix/profiles.scm (linux-module-database): New procedure.
(%default-profile-hooks): Add it.
* gnu/system.scm (operating-system-profile): Add kernel to what
profile-service-type gives.
* gnu/services.scm (%modprobe-wrapper): Use that profile.
* guix/build/linux-module-build-system.scm (install): Disable DEPMOD.
---
 gnu/services.scm                         |  7 ++-
 gnu/system.scm                           |  8 ++-
 guix/build/linux-module-build-system.scm |  5 +-
 guix/profiles.scm                        | 75 +++++++++++++++++++++++-
 4 files changed, 87 insertions(+), 8 deletions(-)

Comments

Danny Milosavljevic Nov. 12, 2019, 4:20 p.m. UTC | #1
Hi,

any comments about this patch?

I don't want to just push this to guix master without any discussion since it
establishes an interface that has to keep working for a long time.

Rationale of the patch:

* Make Linux more modular, allowing the user to specify a union of Guix packages
to use as "the kernel" (especially kernel modules).

Summary of the patch:

* Add a profile hook "linux-module-database" which creates the union of all
system packages that have a subdirectory "lib/modules" in their derivation,
then invokes depmod on that union and then provides the result in the system
profile.

* Adapt modprobe to check "lib/modules" inside the system profile, if available.
Fall back to "/run/booted-system/kernel/lib/modules" otherwise.

For the case where a person has just reconfigured Guix but doesn't want to reboot,
modprobe will still work, taking the modules of the old generation (which doesn't
necessarily have Linux kernel modules inside the profile yet--because it doesn't
necessarily have this patch yet.  But maybe it does).

* Adapt operating-system-profile to automatically add the Kernel's modules to
the system profile (since the system profile would be the only place searched,
not doing so would be very bad).

* Adapt linux-build-system not to invoke depmod again.  Also, its worldview
would be incomplete anyway because it wouldn't have the entire system profile.

Open questions:

* Why doesn't operating-system-profile successfully add linux-libre ?
It should.  I don't think Guix ever gets there in the first place. (adding
linux-libre to operating-system's "packages" field manually does work)

* Do we want to have this stuff in the system profile or do we want to have
a "kernel profile" instead or something?  I don't think the latter would help
us much, but if we want it, better do it now.

* Do we want to be able to add kernel modules in this fashion without requiring
a reboot?  If so, that would make the situation a lot more complicated and I
don't see a safe way to do that.
Giovanni Biscuolo Nov. 12, 2019, 5:47 p.m. UTC | #2
Hi Danny,

Danny Milosavljevic <dannym@scratchpost.org> writes:

[...]

> any comments about this patch?

I still don't understand the internals of Guix to be able to comment
yout patch, anyway...


[...]

> Rationale of the patch:
>
> * Make Linux more modular, allowing the user to specify a union of Guix packages
> to use as "the kernel" (especially kernel modules).

this would be a nice to have feature!

>
> Summary of the patch:
>
> * Add a profile hook "linux-module-database" which creates the union of all
> system packages that have a subdirectory "lib/modules" in their derivation,
> then invokes depmod on that union and then provides the result in the system
> profile.
>
> * Adapt modprobe to check "lib/modules" inside the system profile, if available.
> Fall back to "/run/booted-system/kernel/lib/modules" otherwise.
>
> For the case where a person has just reconfigured Guix but doesn't want to reboot,
> modprobe will still work, taking the modules of the old generation (which doesn't
> necessarily have Linux kernel modules inside the profile yet--because it doesn't
> necessarily have this patch yet.  But maybe it does).
>
> * Adapt operating-system-profile to automatically add the Kernel's modules to
> the system profile (since the system profile would be the only place searched,
> not doing so would be very bad).
>
> * Adapt linux-build-system not to invoke depmod again.  Also, its worldview
> would be incomplete anyway because it wouldn't have the entire system profile.
>
> Open questions:
>
> * Why doesn't operating-system-profile successfully add linux-libre ?
> It should.  I don't think Guix ever gets there in the first place. (adding
> linux-libre to operating-system's "packages" field manually does work)
>
> * Do we want to have this stuff in the system profile or do we want to have
> a "kernel profile" instead or something?  I don't think the latter would help
> us much, but if we want it, better do it now.
>
> * Do we want to be able to add kernel modules in this fashion without requiring
> a reboot?  If so, that would make the situation a lot more complicated and I
> don't see a safe way to do that.
Giovanni Biscuolo Nov. 12, 2019, 6:11 p.m. UTC | #3
[sorry for the double posting, I sent my previuos message incomplete]

Hi Danny,

Danny Milosavljevic <dannym@scratchpost.org> writes:

[...]

> any comments about this patch?

I still don't understand the internals of Guix to be able to comment
your patch, but...

[...]

> Rationale of the patch:
>
> * Make Linux more modular, allowing the user to specify a union of Guix packages
> to use as "the kernel" (especially kernel modules).

this would be a nice to have feature!

[...]

> * Do we want to be able to add kernel modules in this fashion without requiring
> a reboot?  If so, that would make the situation a lot more complicated and I
> don't see a safe way to do that.

maybe I'm asking too much... but would it be possible to load and boot
into the new (or another) kernel from the currently running kernel
without a reboot, via kexec?

something like https://wiki.archlinux.org/index.php/Kexec#Manually but
with a clean stop/restart of system services?

I know it could take some time (and maybe other things to patch) to have
this feature, but maybe it is worth thinking of it in connection with
this design change

Thanks! Gio'
Ludovic Courtès Nov. 13, 2019, 1:30 p.m. UTC | #4
Hi Danny,

Danny Milosavljevic <dannym@scratchpost.org> skribis:

> any comments about this patch?

I commented on an earlier version of this patch at
<https://lists.gnu.org/archive/html/guix-devel/2019-10/msg00514.html>.

Let me know what you think!

> I don't want to just push this to guix master without any discussion since it
> establishes an interface that has to keep working for a long time.

I agree, thanks for the heads-up.

> Open questions:
>
> * Why doesn't operating-system-profile successfully add linux-libre ?

What do you mean?  Currently ‘linux-libre’ is not added to the global
profile, and I think it’s nicer this way (we’re not clobbering the
profile).

> * Do we want to be able to add kernel modules in this fashion without requiring
> a reboot?  If so, that would make the situation a lot more complicated and I
> don't see a safe way to do that.

If we arrange for those kernel modules to show up in
/run/current-system/kernel as I suggested in the message linked above,
it should work (assuming the running kernel and the target kernel are
the same, of course).

Thanks,
Ludo’.
Danny Milosavljevic Nov. 14, 2019, 4:21 p.m. UTC | #5
Hi Ludo,

On Wed, 13 Nov 2019 14:30:56 +0100
Ludovic Courtès <ludo@gnu.org> wrote:

> > * Why doesn't operating-system-profile successfully add linux-libre ?  
> 
> What do you mean?  Currently ‘linux-libre’ is not added to the global
> profile, and I think it’s nicer this way (we’re not clobbering the
> profile).

I've modified it to automatically add linux-libre to the system profile but it
doesn't work for some reason.

> > * Do we want to be able to add kernel modules in this fashion without requiring
> > a reboot?  If so, that would make the situation a lot more complicated and I
> > don't see a safe way to do that.  
> 
> If we arrange for those kernel modules to show up in
> /run/current-system/kernel as I suggested in the message linked above,
> it should work (assuming the running kernel and the target kernel are
> the same, of course).

Hmm... I'll read it now :)
Mark H Weaver Nov. 14, 2019, 5:48 p.m. UTC | #6
Hi Danny,

Danny Milosavljevic <dannym@scratchpost.org> wrote:
> any comments about this patch?
> 
> I don't want to just push this to guix master without any discussion since it
> establishes an interface that has to keep working for a long time.

Thanks very much for bringing this to my attention.

Generally, it looks good to me, although I agree with the suggestions
that Ludovic has made, both here and in the thread on guix-devel:

  https://lists.gnu.org/archive/html/guix-devel/2019-10/msg00514.html

I'm overloaded with other tasks at the moment, so I might not comment on
this thread again, but I expect that I'll be happy with whatever you and
Ludovic can agree on.

      Thanks!
        Mark
Danny Milosavljevic Feb. 18, 2020, 9:42 a.m. UTC | #7
Danny Milosavljevic (2):
  build-system/linux-module: Disable depmod.
  system: Add kernel-module-packages to operating-system.

 gnu/system.scm                           | 26 ++++++--
 guix/build/linux-module-build-system.scm |  5 +-
 guix/profiles.scm                        | 76 +++++++++++++++++++++++-
 3 files changed, 99 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/gnu/services.scm b/gnu/services.scm
index 6ee05d4580..2a6d2bc464 100644
--- a/gnu/services.scm
+++ b/gnu/services.scm
@@ -491,7 +491,12 @@  ACTIVATION-SCRIPT-TYPE."
     (program-file "modprobe"
                   #~(begin
                       (setenv "LINUX_MODULE_DIRECTORY"
-                              "/run/booted-system/kernel/lib/modules")
+                              (if (file-exists?
+                                   "/run/booted-system/profile/lib/modules")
+                                  "/run/booted-system/profile/lib/modules"
+                                  ;; Provides compatibility with previous
+                                  ;; Guix generations.
+                                  "/run/booted-system/kernel/lib/modules"))
                       (apply execl #$modprobe
                              (cons #$modprobe (cdr (command-line))))))))
 
diff --git a/gnu/system.scm b/gnu/system.scm
index a353b1a5c8..66270b38bb 100644
--- a/gnu/system.scm
+++ b/gnu/system.scm
@@ -887,12 +887,14 @@  we're running in the final root."
 (define* (operating-system-profile os)
   "Return a derivation that builds the system profile of OS."
   (mlet* %store-monad
-      ((services -> (operating-system-services os))
+      ((kernel -> (operating-system-kernel os))
+       (services -> (operating-system-services os))
        (profile (fold-services services
-                               #:target-type profile-service-type)))
+                               #:target-type
+                               profile-service-type)))
     (match profile
       (("profile" profile)
-       (return profile)))))
+       (return (cons kernel profile)))))) ; FIXME: Doesn't work for some reason.  I don't think this place is ever reached.
 
 (define (operating-system-root-file-system os)
   "Return the root file system of OS."
diff --git a/guix/build/linux-module-build-system.scm b/guix/build/linux-module-build-system.scm
index cd76df2de7..e4e6993a49 100644
--- a/guix/build/linux-module-build-system.scm
+++ b/guix/build/linux-module-build-system.scm
@@ -60,15 +60,14 @@ 
 ;; part.
 (define* (install #:key inputs native-inputs outputs #:allow-other-keys)
   (let* ((out (assoc-ref outputs "out"))
-         (moddir (string-append out "/lib/modules"))
-         (kmod (assoc-ref (or native-inputs inputs) "kmod")))
+         (moddir (string-append out "/lib/modules")))
     ;; Install kernel modules
     (mkdir-p moddir)
     (invoke "make" "-C"
             (string-append (assoc-ref inputs "linux-module-builder")
                            "/lib/modules/build")
             (string-append "M=" (getcwd))
-            (string-append "DEPMOD=" kmod "/bin/depmod")
+            "DEPMOD=true" ; disable depmod.
             (string-append "MODULE_DIR=" moddir)
             (string-append "INSTALL_PATH=" out)
             (string-append "INSTALL_MOD_PATH=" out)
diff --git a/guix/profiles.scm b/guix/profiles.scm
index cd3b21e390..fd77392588 100644
--- a/guix/profiles.scm
+++ b/guix/profiles.scm
@@ -9,6 +9,7 @@ 
 ;;; Copyright © 2017 Huang Ying <huang.ying.caritas@gmail.com>
 ;;; Copyright © 2017 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 ;;; Copyright © 2019 Kyle Meyer <kyle@kyleam.com>
+;;; Copyright © 2019 Danny Milosavljevic <dannym@scratchpost.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -1125,6 +1126,77 @@  for both major versions of GTK+."
                               (hook . gtk-im-modules)))
           (return #f)))))
 
+(define (linux-module-database manifest)
+  (mlet %store-monad
+    ((kmod (manifest-lookup-package manifest "kmod")))
+    (define build
+      (with-imported-modules '((guix build utils)
+                               (guix build union))
+       #~(begin
+          (use-modules (srfi srfi-1)
+                       (srfi srfi-26)
+                       (guix build utils)
+                       (guix build union)
+                       (ice-9 ftw)
+                       (ice-9 match))
+          (let* ((inputs '#$(manifest-inputs manifest))
+                 (input-files (lambda (path)
+                                (filter file-exists?
+                                  (map (cut string-append <> path) inputs))))
+                 (module-directories (input-files "/lib/modules"))
+                 (System.maps (input-files "/System.map"))
+                 (Module.symverss (input-files "/Module.symvers"))
+                 (directory-entries (lambda (directory-name)
+                                       (filter (lambda (basename)
+                                                 (not (string-prefix? "."
+                                                                      basename)))
+                                               (scandir directory-name))))
+                 ;; Note: Should result in one entry.
+                 (versions (append-map directory-entries module-directories)))
+              ;; TODO: if len(module-directories) == 1: return module-directories[0]
+              (mkdir-p (string-append #$output "/lib/modules"))
+              ;; Iterate over each kernel version directory (usually one).
+              (for-each (lambda (version)
+                          (let ((destination-directory (string-append #$output "/lib/modules/" version)))
+                            (when (not (file-exists? destination-directory)) ; unique
+                              (union-build destination-directory
+                                           ;; All directories with the same version as us.
+                                           (filter-map (lambda (directory-name)
+                                                         (if (member version
+                                                                     (directory-entries directory-name))
+                                                             (string-append directory-name "/" version)
+                                                             #f))
+                                                       module-directories)
+                                           #:create-all-directories? #t)
+                              ;; Delete generated files (they will be recreated shortly).
+                              (for-each (lambda (basename)
+                                          (when (string-prefix? "modules." basename)
+                                            (false-if-file-not-found
+                                              (delete-file
+                                               (string-append
+                                                destination-directory "/"
+                                                basename)))))
+                                        (directory-entries destination-directory))
+                              (unless (zero? (system* (string-append #$kmod "/bin/depmod")
+                                                      "-e" ; Report symbols that aren't supplied
+                                                      "-w" ; Warn on duplicates
+                                                      "-b" #$output ; destination-directory
+                                                      "-F" (match System.maps
+                                                            ((x) x))
+                                                      "-E" (match Module.symverss
+                                                            ((x) x))
+                                                      version))
+                                (display "FAILED\n" (current-error-port))
+                                (exit #f)))))
+                        versions)
+              (exit #t)))))
+    (gexp->derivation "linux-module-database" build
+                      #:local-build? #t
+                      #:substitutable? #f
+                      #:properties
+                      `((type . profile-hook)
+                        (hook . linux-module-database)))))
+
 (define (xdg-desktop-database manifest)
   "Return a derivation that builds the @file{mimeinfo.cache} database from
 desktop files.  It's used to query what applications can handle a given
@@ -1425,7 +1497,8 @@  MANIFEST."
         gtk-im-modules
         texlive-configuration
         xdg-desktop-database
-        xdg-mime-database))
+        xdg-mime-database
+        linux-module-database))
 
 (define* (profile-derivation manifest
                              #:key