bug-guix
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#38359: Guix 1.0.1-10.41b4b71 test fails on armhf


From: Mathieu Othacehe
Subject: bug#38359: Guix 1.0.1-10.41b4b71 test fails on armhf
Date: Mon, 02 Dec 2019 14:33:36 +0100
User-agent: mu4e 1.2.0; emacs 26.3

> Mmmh, I get what's going on in tests/processes.scm. It's an issue in
> (guix scripts processes) where argv0 is checked for "guix-daemon".
>
> When using --system my-system, argv0 is "qemu-my-system". So we need to
> check both argv0 and argv1 for "guix-daemon".
>
> I'll propose a patch.

Here it is. Please tell me what you think. Another solution would be to
accept that (guix process) is broken when guix-daemon is run via binfmt
and disable the tests in that case. However, I don't know how to detect
it properly for the test suite.

WDYT?

Mathieu
>From 3b6f5708043a29343275fadf0b0e0e651bb6971e Mon Sep 17 00:00:00 2001
From: Mathieu Othacehe <address@hidden>
Date: Fri, 29 Nov 2019 10:37:12 +0100
Subject: [PATCH] process: Fix binfmt support.

Guix-daemon does fork itself for each client process. The pid of the client is
hardcoded into the clone argv[1] field. (guix process) uses this debugging
feature to detect guix-daemon clients.

This does not work when the guix-daemon is run by binfmt. In that case two
problem occurs:

* Command line parsing fails because guix-daemon command line looks like
/gnu/store/xxx-qemu-arm /gnu/store/yyy-guix-daemon ... instead of just
/gnu/store/yyy-guix-daemon ...

* The pid stuffing mechanism does not work because the memory location of argv
differs when the forked process is in reality run by qemu-arm through binfmt.

The first problem is solved by reading /proc/pid/comm instead of parsing
/proc/pid/cmdline to detect if a process is a guix-daemon.

The second problem is solved by renaming guix-daemon forked process to
"guix/<client-pid>" using PR_SET_NAME. Then, (guix process) can parse the
process name instead of the cmdline to find client pids.

* nix/nix-daemon/nix-daemon.cc (acceptConnection): Change the forked process
name to "guix/<client-pid>" with PR_SET_NAME.
* guix/scripts/processes.scm (<process>): "command" field now contains the
content of /proc/pid/comm. Add a new field "command-line" to store the process
command line.
(read-command): New procedure.
(processes): Fill "command" field with /proc/pid/comm content and
"command-line" field with /proc/pid/cmdline content. Adapt "process"
construction accordingly.
(daemon-sessions): Identify guix-daemon main processes by filtering process
with "command" field set to "guix-daemon" and guix-daemon children by
filtering process with "command" field set to "guix/...".
In "child-process->session", parse children "command" field to extract client
pids.
(daemon-session->recutils): Adapt accordingly.
* tests/processes.scm (client): Guix-daemon client process command is now
"guix/...". Adapt accordingly.
---
 guix/scripts/processes.scm   | 78 +++++++++++++++++++-----------------
 nix/nix-daemon/nix-daemon.cc | 15 +++++++
 tests/processes.scm          |  2 +-
 3 files changed, 58 insertions(+), 37 deletions(-)

diff --git a/guix/scripts/processes.scm b/guix/scripts/processes.scm
index a2ab017490..6586da5996 100644
--- a/guix/scripts/processes.scm
+++ b/guix/scripts/processes.scm
@@ -32,6 +32,7 @@
             process-id
             process-parent-id
             process-command
+            process-command-line
             processes
 
             daemon-session?
@@ -45,11 +46,12 @@
 
 ;; Process as can be found in /proc on GNU/Linux.
 (define-record-type <process>
-  (process id parent command)
+  (process id parent command command-line)
   process?
-  (id       process-id)                           ;integer
-  (parent   process-parent-id)                    ;integer | #f
-  (command  process-command))                     ;list of strings
+  (id            process-id)               ;integer
+  (parent        process-parent-id)        ;integer | #f
+  (command       process-command)          ;string
+  (command-line  process-command-line))    ;list of strings
 
 (define (write-process process port)
   (format port "#<process ~a>" (process-id process)))
@@ -67,6 +69,9 @@
            (string->number (string-trim-both (string-drop line 5)))
            (loop))))))
 
+(define (read-command port)
+  (string-trim-right (read-string port) #\newline))
+
 (define %not-nul
   (char-set-complement (char-set #\nul)))
 
@@ -89,9 +94,12 @@ processes."
                       (call-with-input-file (string-append "/proc/" pid 
"/status")
                         read-status-ppid))
                     (define command
+                      (call-with-input-file (string-append "/proc/" pid 
"/comm")
+                        read-command))
+                    (define command-line
                       (call-with-input-file (string-append "/proc/" pid 
"/cmdline")
                         read-command-line))
-                    (process (string->number pid) ppid command))
+                    (process (string->number pid) ppid command command-line))
                   (lambda args
                     (if (= ENOENT (system-error-errno args))
                         #f
@@ -131,21 +139,17 @@ active sessions, and the master 'guix-daemon' process."
          (string-suffix? ".lock" file)))
 
   (let* ((processes (processes))
-         (daemons   (filter (lambda (process)
-                              (match (process-command process)
-                                ((argv0 _ ...)
-                                 (string=? (basename argv0) "guix-daemon"))
-                                (_ #f)))
-                            processes))
-         (children  (filter (lambda (process)
-                              (match (process-command process)
-                                ((argv0 (= string->number argv1) _ ...)
-                                 (integer? argv1))
-                                (_ #f)))
-                            daemons))
-         (master    (remove (lambda (process)
-                              (memq process children))
-                            daemons)))
+         (daemons   (filter
+                     (lambda (process)
+                       (string=? (process-command process) "guix-daemon"))
+                     processes))
+         ;; Guix-daemon children have their command set to
+         ;; "guix/<client-pid>".
+         (children  (filter
+                     (lambda (process)
+                       (string-prefix? "guix/" (process-command process)))
+                     processes)))
+
     (define (lookup-process pid)
       (find (lambda (process)
               (and (process-id process)
@@ -159,22 +163,24 @@ active sessions, and the master 'guix-daemon' process."
               processes))
 
     (define (child-process->session process)
-      (match (process-command process)
-        ((argv0 (= string->number client) _ ...)
-         (let ((files  (process-open-files process))
-               (client (lookup-process client)))
-           ;; After a client has died, there's a window during which its
-           ;; corresponding 'guix-daemon' process is still alive, in which
-           ;; case 'lookup-process' returns #f.  In that case ignore the
-           ;; session.
-           (and client
-                (daemon-session process client
-                                (lookup-children
-                                 (process-id process))
-                                (filter lock-file? files)))))))
+      (let* ((command (process-command process))
+             (client (string->number
+                      (substring command
+                                 (1+ (string-index command #\/)))))
+             (files  (process-open-files process))
+             (client (lookup-process client)))
+        ;; After a client has died, there's a window during which its
+        ;; corresponding 'guix-daemon' process is still alive, in which
+        ;; case 'lookup-process' returns #f.  In that case ignore the
+        ;; session.
+        (and client
+             (daemon-session process client
+                             (lookup-children
+                              (process-id process))
+                             (filter lock-file? files)))))
 
     (values (filter-map child-process->session children)
-            master)))
+            daemons)))
 
 (define (daemon-session->recutils session port)
   "Display SESSION information in recutils format on PORT."
@@ -183,14 +189,14 @@ active sessions, and the master 'guix-daemon' process."
   (format port "ClientPID: ~a~%"
           (process-id (daemon-session-client session)))
   (format port "ClientCommand:~{ ~a~}~%"
-          (process-command (daemon-session-client session)))
+          (process-command-line (daemon-session-client session)))
   (for-each (lambda (lock)
               (format port "LockHeld: ~a~%" lock))
             (daemon-session-locks-held session))
   (for-each (lambda (process)
               (format port "ChildProcess: ~a:~{ ~a~}~%"
                       (process-id process)
-                      (process-command process)))
+                      (process-command-line process)))
             (daemon-session-children session)))
 
 
diff --git a/nix/nix-daemon/nix-daemon.cc b/nix/nix-daemon/nix-daemon.cc
index 3dd156ba77..467439bb56 100644
--- a/nix/nix-daemon/nix-daemon.cc
+++ b/nix/nix-daemon/nix-daemon.cc
@@ -16,6 +16,7 @@
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -967,9 +968,23 @@ static void acceptConnection(int fdSocket)
                 /* Restore normal handling of SIGCHLD. */
                 setSigChldAction(false);
 
+
                 /* For debugging, stuff the pid into argv[1]. */
                 if (clientPid != -1 && argvSaved[1]) {
                     string processName = std::to_string(clientPid);
+                    string new_pr_name =
+                        "guix/" + processName;
+                    /*
+                     * Stuffing the pid into argv[1] does not work if
+                     * guix-daemon in run with binfmt. Change the process name
+                     * to guix/pid, so that there is another way to find the
+                     * client pid.
+                     */
+                    prctl(PR_SET_NAME,
+                          new_pr_name.c_str(),
+                          NULL,
+                          NULL,
+                          NULL);
                     strncpy(argvSaved[1], processName.c_str(), 
strlen(argvSaved[1]));
                 }
 
diff --git a/tests/processes.scm b/tests/processes.scm
index 40454bcbc7..ffb9f507f4 100644
--- a/tests/processes.scm
+++ b/tests/processes.scm
@@ -48,7 +48,7 @@
                           (daemon-sessions)))
            (daemon  (daemon-session-process session)))
       (and (kill (process-id daemon) 0)
-           (string-suffix? "guix-daemon" (first (process-command daemon)))))))
+           (string-prefix? "guix/" (process-command daemon))))))
 
 (test-assert "client + lock"
   (with-store store
-- 
2.24.0


reply via email to

[Prev in Thread] Current Thread [Next in Thread]