forked from pool/s390-tools
203 lines
6.4 KiB
Diff
203 lines
6.4 KiB
Diff
|
Subject: [PATCH] [BZ 161563] cpuplugd: Improve systemctl start error handling
|
||
|
From: Gerald Schaefer <gerald.schaefer@de.ibm.com>
|
||
|
|
||
|
Description: cpuplugd, mon_tools: Improve systemctl start error handling
|
||
|
Symptom: "systemctl start cpuplugd/mon_procd/mon_fsstatd" does not
|
||
|
report any errors in case the startup fails.
|
||
|
Problem: For type=simple, systemd forks/execs the process and if that
|
||
|
is successful, it immediately returns. There is no way to
|
||
|
find out if the initial startup fails.
|
||
|
Solution: Use type=fork and run the process in the background. In this
|
||
|
case systemd waits until the initial process returns.
|
||
|
In addition, use PIDFile and ensure that the pid file is
|
||
|
already available when the initial process returns. To
|
||
|
achieve this, use startup synchronization via pipe.
|
||
|
Reproduction: Add invalid values to the config files and start the daemons
|
||
|
with "systemctl start cpuplugd/mon_procd/mon_fsstatd".
|
||
|
Upstream-ID: 82c8148983fc09e9bfa5bf852b2d39571f8475a0
|
||
|
Problem-ID: 161563
|
||
|
|
||
|
Upstream-Description:
|
||
|
|
||
|
cpuplugd: Improve systemctl start error handling
|
||
|
|
||
|
Currently "systemctl start cpuplugd" does not report any errors in
|
||
|
case the startup fails.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
# mv /etc/cpuplugd.conf /etc/cpuplugd.conf.xxx
|
||
|
# systemctl start cpuplugd
|
||
|
|
||
|
The reason is that for type=simple systemd forks/execs cpuplugd and if
|
||
|
that is successful immediately returns. There is no way to find out
|
||
|
if the initial startup fails.
|
||
|
|
||
|
Fix this by using type=fork and running cpuplugd in the background. In
|
||
|
this case systemd waits until the initial process returns.
|
||
|
|
||
|
In addition use PIDFile and ensure that the pid file is already available
|
||
|
when the initial cpuplugd process returns. To achieve this, replace the
|
||
|
daemon() function by our own implementation that introduces startup
|
||
|
synchronization via pipe. Without that systemd would print the following
|
||
|
warning:
|
||
|
|
||
|
systemd[1]: cpuplugd.service: PID file /var/run/cpuplugd.pid not readable
|
||
|
(yet?) after start: No such file or directory
|
||
|
|
||
|
With this patch, an early startup error like in the example above, is now
|
||
|
reported correctly in "systemctl start":
|
||
|
|
||
|
# systemctl start cpuplugd
|
||
|
Job for cpuplugd.service failed because the control process exited...
|
||
|
See "systemctl status cpuplugd.service" and "journalctl -xe" for ...
|
||
|
# journalctl -ex | grep cpuplugd
|
||
|
Nov 16 15:52:27 ... cpuplugd[5096]: Opening configuration file failed:
|
||
|
No such file or directory
|
||
|
|
||
|
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
|
||
|
Acked-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
|
||
|
|
||
|
|
||
|
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
|
||
|
---
|
||
|
cpuplugd/cpuplugd.h | 2 -
|
||
|
cpuplugd/daemon.c | 60 ++++++++++++++++++++++++++++++++++++++++++--
|
||
|
cpuplugd/main.c | 4 --
|
||
|
systemd/cpuplugd.service.in | 5 ++-
|
||
|
4 files changed, 63 insertions(+), 8 deletions(-)
|
||
|
|
||
|
--- a/cpuplugd/cpuplugd.h
|
||
|
+++ b/cpuplugd/cpuplugd.h
|
||
|
@@ -197,10 +197,10 @@ int is_online(int cpuid);
|
||
|
long get_cmmpages_size();
|
||
|
void parse_options(int argc, char **argv);
|
||
|
void check_if_started_twice();
|
||
|
-void store_pid(void);
|
||
|
void handle_signals(void);
|
||
|
void handle_sighup(void);
|
||
|
void reload_daemon(void);
|
||
|
+int daemonize(void);
|
||
|
int check_cmmfiles(void);
|
||
|
void check_config();
|
||
|
void set_cmm_pages(long size);
|
||
|
--- a/cpuplugd/daemon.c
|
||
|
+++ b/cpuplugd/daemon.c
|
||
|
@@ -9,6 +9,10 @@
|
||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||
|
*/
|
||
|
|
||
|
+#include <fcntl.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <sys/types.h>
|
||
|
+
|
||
|
#include "cpuplugd.h"
|
||
|
|
||
|
const char *name = NAME;
|
||
|
@@ -49,7 +53,7 @@ void print_version()
|
||
|
/*
|
||
|
* Store daemon's pid so it can be stopped
|
||
|
*/
|
||
|
-void store_pid(void)
|
||
|
+static int store_pid(void)
|
||
|
{
|
||
|
FILE *filp;
|
||
|
|
||
|
@@ -57,10 +61,62 @@ void store_pid(void)
|
||
|
if (!filp) {
|
||
|
cpuplugd_error("cannot open pid file %s: %s\n", pid_file,
|
||
|
strerror(errno));
|
||
|
- exit(1);
|
||
|
+ return -1;
|
||
|
}
|
||
|
fprintf(filp, "%d\n", getpid());
|
||
|
fclose(filp);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Run daemon in background and write pid file
|
||
|
+ */
|
||
|
+int daemonize(void)
|
||
|
+{
|
||
|
+ int fd, pipe_fds[2], startup_rc = 1;
|
||
|
+ pid_t pid;
|
||
|
+
|
||
|
+ if (pipe(pipe_fds) == -1) {
|
||
|
+ cpuplugd_error("cannot create pipe\n");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ pid = fork();
|
||
|
+ if (pid < 0)
|
||
|
+ goto close_pipe;
|
||
|
+ if (pid != 0) {
|
||
|
+ /* Wait for startup return code from daemon */
|
||
|
+ if (read(pipe_fds[0], &startup_rc, sizeof(startup_rc)) == -1)
|
||
|
+ cpuplugd_error("cannot read from pipe\n");
|
||
|
+ /* On success daemon has written pid file at this point */
|
||
|
+ exit(startup_rc);
|
||
|
+ }
|
||
|
+ /* Create new session */
|
||
|
+ if (setsid() < 0)
|
||
|
+ goto notify_parent;
|
||
|
+ /* Redirect stdin/out/err to /dev/null */
|
||
|
+ fd = open("/dev/null", O_RDWR, 0);
|
||
|
+ if (fd == -1)
|
||
|
+ goto notify_parent;
|
||
|
+ if (dup2(fd, STDIN_FILENO) < 0)
|
||
|
+ goto notify_parent;
|
||
|
+ if (dup2(fd, STDOUT_FILENO) < 0)
|
||
|
+ goto notify_parent;
|
||
|
+ if (dup2(fd, STDERR_FILENO) < 0)
|
||
|
+ goto notify_parent;
|
||
|
+ /* Create pid file */
|
||
|
+ if (store_pid() < 0)
|
||
|
+ goto notify_parent;
|
||
|
+ startup_rc = 0;
|
||
|
+notify_parent:
|
||
|
+ /* Inform waiting parent about startup return code */
|
||
|
+ if (write(pipe_fds[1], &startup_rc, sizeof(startup_rc)) == -1) {
|
||
|
+ cpuplugd_error("cannot write to pipe\n");
|
||
|
+ startup_rc = 1;
|
||
|
+ }
|
||
|
+close_pipe:
|
||
|
+ close(pipe_fds[0]);
|
||
|
+ close(pipe_fds[1]);
|
||
|
+ return startup_rc ? -1 : 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
--- a/cpuplugd/main.c
|
||
|
+++ b/cpuplugd/main.c
|
||
|
@@ -418,13 +418,11 @@ int main(int argc, char *argv[])
|
||
|
check_config();
|
||
|
|
||
|
if (!foreground) {
|
||
|
- rc = daemon(1, 0);
|
||
|
+ rc = daemonize();
|
||
|
if (rc < 0)
|
||
|
cpuplugd_exit("Detach from terminal failed: %s\n",
|
||
|
strerror(errno));
|
||
|
}
|
||
|
- /* Store daemon pid */
|
||
|
- store_pid();
|
||
|
/* Unlock lock file */
|
||
|
flock(fd, LOCK_UN);
|
||
|
close(fd);
|
||
|
--- a/systemd/cpuplugd.service.in
|
||
|
+++ b/systemd/cpuplugd.service.in
|
||
|
@@ -13,10 +13,11 @@ Documentation=man:cpuplugd(8) man:cpuplu
|
||
|
After=remote-fs.target
|
||
|
|
||
|
[Service]
|
||
|
-ExecStart=@usrsbin_path@/cpuplugd -f -c /etc/cpuplugd.conf
|
||
|
+ExecStart=@usrsbin_path@/cpuplugd -c /etc/cpuplugd.conf
|
||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||
|
KillMode=process
|
||
|
-Type=simple
|
||
|
+Type=forking
|
||
|
+PIDFile=/var/run/cpuplugd.pid
|
||
|
|
||
|
[Install]
|
||
|
WantedBy=multi-user.target
|