|
|
3c4af5 |
From ff6bb131a46e1bac84a26e5b2c4bf408c0e56926 Mon Sep 17 00:00:00 2001
|
|
|
3c4af5 |
From: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
|
|
|
3c4af5 |
Date: Wed, 4 Nov 2020 10:02:36 +0100
|
|
|
3c4af5 |
Subject: [PATCH 103/108] mdadm: Unify forks behaviour
|
|
|
3c4af5 |
|
|
|
3c4af5 |
If mdadm is run by udev or systemd, it gets a pipe as each stream.
|
|
|
3c4af5 |
Forks in the background may run after an event or service has been
|
|
|
3c4af5 |
processed when udev is detached from pipe. As a result process
|
|
|
3c4af5 |
fails quietly if any message is written.
|
|
|
3c4af5 |
To prevent from it, each fork has to close all parent streams. Leave
|
|
|
3c4af5 |
stderr and stdout opened only for debug purposes.
|
|
|
3c4af5 |
Unify it across all forks. Introduce other descriptors detection by
|
|
|
3c4af5 |
scanning /proc/self/fd directory. Add generic method for
|
|
|
3c4af5 |
managing systemd services.
|
|
|
3c4af5 |
|
|
|
3c4af5 |
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
|
|
|
3c4af5 |
---
|
|
|
3c4af5 |
Grow.c | 52 ++++--------------------
|
|
|
3c4af5 |
Incremental.c | 1 +
|
|
|
3c4af5 |
Monitor.c | 5 +--
|
|
|
3c4af5 |
mdadm.h | 10 +++++
|
|
|
3c4af5 |
mdmon.c | 9 +----
|
|
|
3c4af5 |
util.c | 124 +++++++++++++++++++++++++++++++++++++---------------------
|
|
|
3c4af5 |
6 files changed, 100 insertions(+), 101 deletions(-)
|
|
|
3c4af5 |
|
|
|
3c4af5 |
diff --git a/Grow.c b/Grow.c
|
|
|
3c4af5 |
index 57db7d4..6b8321c 100644
|
|
|
3c4af5 |
--- a/Grow.c
|
|
|
3c4af5 |
+++ b/Grow.c
|
|
|
3c4af5 |
@@ -2982,47 +2982,6 @@ static void catch_term(int sig)
|
|
|
3c4af5 |
sigterm = 1;
|
|
|
3c4af5 |
}
|
|
|
3c4af5 |
|
|
|
3c4af5 |
-static int continue_via_systemd(char *devnm)
|
|
|
3c4af5 |
-{
|
|
|
3c4af5 |
- int skipped, i, pid, status;
|
|
|
3c4af5 |
- char pathbuf[1024];
|
|
|
3c4af5 |
- /* In a systemd/udev world, it is best to get systemd to
|
|
|
3c4af5 |
- * run "mdadm --grow --continue" rather than running in the
|
|
|
3c4af5 |
- * background.
|
|
|
3c4af5 |
- */
|
|
|
3c4af5 |
- switch(fork()) {
|
|
|
3c4af5 |
- case 0:
|
|
|
3c4af5 |
- /* FIXME yuk. CLOSE_EXEC?? */
|
|
|
3c4af5 |
- skipped = 0;
|
|
|
3c4af5 |
- for (i = 3; skipped < 20; i++)
|
|
|
3c4af5 |
- if (close(i) < 0)
|
|
|
3c4af5 |
- skipped++;
|
|
|
3c4af5 |
- else
|
|
|
3c4af5 |
- skipped = 0;
|
|
|
3c4af5 |
-
|
|
|
3c4af5 |
- /* Don't want to see error messages from
|
|
|
3c4af5 |
- * systemctl. If the service doesn't exist,
|
|
|
3c4af5 |
- * we fork ourselves.
|
|
|
3c4af5 |
- */
|
|
|
3c4af5 |
- close(2);
|
|
|
3c4af5 |
- open("/dev/null", O_WRONLY);
|
|
|
3c4af5 |
- snprintf(pathbuf, sizeof(pathbuf),
|
|
|
3c4af5 |
- "mdadm-grow-continue@%s.service", devnm);
|
|
|
3c4af5 |
- status = execl("/usr/bin/systemctl", "systemctl", "restart",
|
|
|
3c4af5 |
- pathbuf, NULL);
|
|
|
3c4af5 |
- status = execl("/bin/systemctl", "systemctl", "restart",
|
|
|
3c4af5 |
- pathbuf, NULL);
|
|
|
3c4af5 |
- exit(1);
|
|
|
3c4af5 |
- case -1: /* Just do it ourselves. */
|
|
|
3c4af5 |
- break;
|
|
|
3c4af5 |
- default: /* parent - good */
|
|
|
3c4af5 |
- pid = wait(&status);
|
|
|
3c4af5 |
- if (pid >= 0 && status == 0)
|
|
|
3c4af5 |
- return 1;
|
|
|
3c4af5 |
- }
|
|
|
3c4af5 |
- return 0;
|
|
|
3c4af5 |
-}
|
|
|
3c4af5 |
-
|
|
|
3c4af5 |
static int reshape_array(char *container, int fd, char *devname,
|
|
|
3c4af5 |
struct supertype *st, struct mdinfo *info,
|
|
|
3c4af5 |
int force, struct mddev_dev *devlist,
|
|
|
3c4af5 |
@@ -3401,6 +3360,7 @@ static int reshape_array(char *container, int fd, char *devname,
|
|
|
3c4af5 |
default: /* parent */
|
|
|
3c4af5 |
return 0;
|
|
|
3c4af5 |
case 0:
|
|
|
3c4af5 |
+ manage_fork_fds(0);
|
|
|
3c4af5 |
map_fork();
|
|
|
3c4af5 |
break;
|
|
|
3c4af5 |
}
|
|
|
3c4af5 |
@@ -3509,8 +3469,9 @@ started:
|
|
|
3c4af5 |
return 1;
|
|
|
3c4af5 |
}
|
|
|
3c4af5 |
|
|
|
3c4af5 |
- if (!forked && !check_env("MDADM_NO_SYSTEMCTL"))
|
|
|
3c4af5 |
- if (continue_via_systemd(container ?: sra->sys_name)) {
|
|
|
3c4af5 |
+ if (!forked)
|
|
|
3c4af5 |
+ if (continue_via_systemd(container ?: sra->sys_name,
|
|
|
3c4af5 |
+ GROW_SERVICE)) {
|
|
|
3c4af5 |
free(fdlist);
|
|
|
3c4af5 |
free(offsets);
|
|
|
3c4af5 |
sysfs_free(sra);
|
|
|
3c4af5 |
@@ -3704,8 +3665,8 @@ int reshape_container(char *container, char *devname,
|
|
|
3c4af5 |
*/
|
|
|
3c4af5 |
ping_monitor(container);
|
|
|
3c4af5 |
|
|
|
3c4af5 |
- if (!forked && !freeze_reshape && !check_env("MDADM_NO_SYSTEMCTL"))
|
|
|
3c4af5 |
- if (continue_via_systemd(container))
|
|
|
3c4af5 |
+ if (!forked && !freeze_reshape)
|
|
|
3c4af5 |
+ if (continue_via_systemd(container, GROW_SERVICE))
|
|
|
3c4af5 |
return 0;
|
|
|
3c4af5 |
|
|
|
3c4af5 |
switch (forked ? 0 : fork()) {
|
|
|
3c4af5 |
@@ -3718,6 +3679,7 @@ int reshape_container(char *container, char *devname,
|
|
|
3c4af5 |
printf("%s: multi-array reshape continues in background\n", Name);
|
|
|
3c4af5 |
return 0;
|
|
|
3c4af5 |
case 0: /* child */
|
|
|
3c4af5 |
+ manage_fork_fds(0);
|
|
|
3c4af5 |
map_fork();
|
|
|
3c4af5 |
break;
|
|
|
3c4af5 |
}
|
|
|
3c4af5 |
diff --git a/Incremental.c b/Incremental.c
|
|
|
3c4af5 |
index 98dbcd9..ad9ec1c 100644
|
|
|
3c4af5 |
--- a/Incremental.c
|
|
|
3c4af5 |
+++ b/Incremental.c
|
|
|
3c4af5 |
@@ -1679,6 +1679,7 @@ static void run_udisks(char *arg1, char *arg2)
|
|
|
3c4af5 |
int pid = fork();
|
|
|
3c4af5 |
int status;
|
|
|
3c4af5 |
if (pid == 0) {
|
|
|
3c4af5 |
+ manage_fork_fds(1);
|
|
|
3c4af5 |
execl("/usr/bin/udisks", "udisks", arg1, arg2, NULL);
|
|
|
3c4af5 |
execl("/bin/udisks", "udisks", arg1, arg2, NULL);
|
|
|
3c4af5 |
exit(1);
|
|
|
3c4af5 |
diff --git a/Monitor.c b/Monitor.c
|
|
|
3c4af5 |
index a82e99d..3f3005b 100644
|
|
|
3c4af5 |
--- a/Monitor.c
|
|
|
3c4af5 |
+++ b/Monitor.c
|
|
|
3c4af5 |
@@ -323,10 +323,7 @@ static int make_daemon(char *pidfile)
|
|
|
3c4af5 |
perror("daemonise");
|
|
|
3c4af5 |
return 1;
|
|
|
3c4af5 |
}
|
|
|
3c4af5 |
- close(0);
|
|
|
3c4af5 |
- open("/dev/null", O_RDWR);
|
|
|
3c4af5 |
- dup2(0, 1);
|
|
|
3c4af5 |
- dup2(0, 2);
|
|
|
3c4af5 |
+ manage_fork_fds(0);
|
|
|
3c4af5 |
setsid();
|
|
|
3c4af5 |
return -1;
|
|
|
3c4af5 |
}
|
|
|
3c4af5 |
diff --git a/mdadm.h b/mdadm.h
|
|
|
3c4af5 |
index 4961c0f..56b1b19 100644
|
|
|
3c4af5 |
--- a/mdadm.h
|
|
|
3c4af5 |
+++ b/mdadm.h
|
|
|
3c4af5 |
@@ -129,6 +129,14 @@ struct dlm_lksb {
|
|
|
3c4af5 |
#define FAILED_SLOTS_DIR "/run/mdadm/failed-slots"
|
|
|
3c4af5 |
#endif /* FAILED_SLOTS */
|
|
|
3c4af5 |
|
|
|
3c4af5 |
+#ifndef MDMON_SERVICE
|
|
|
3c4af5 |
+#define MDMON_SERVICE "mdmon"
|
|
|
3c4af5 |
+#endif /* MDMON_SERVICE */
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+#ifndef GROW_SERVICE
|
|
|
3c4af5 |
+#define GROW_SERVICE "mdadm-grow-continue"
|
|
|
3c4af5 |
+#endif /* GROW_SERVICE */
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
#include "md_u.h"
|
|
|
3c4af5 |
#include "md_p.h"
|
|
|
3c4af5 |
#include "bitmap.h"
|
|
|
3c4af5 |
@@ -1497,6 +1505,8 @@ extern int is_standard(char *dev, int *nump);
|
|
|
3c4af5 |
extern int same_dev(char *one, char *two);
|
|
|
3c4af5 |
extern int compare_paths (char* path1,char* path2);
|
|
|
3c4af5 |
extern void enable_fds(int devices);
|
|
|
3c4af5 |
+extern void manage_fork_fds(int close_all);
|
|
|
3c4af5 |
+extern int continue_via_systemd(char *devnm, char *service_name);
|
|
|
3c4af5 |
|
|
|
3c4af5 |
extern int parse_auto(char *str, char *msg, int config);
|
|
|
3c4af5 |
extern struct mddev_ident *conf_get_ident(char *dev);
|
|
|
3c4af5 |
diff --git a/mdmon.c b/mdmon.c
|
|
|
3c4af5 |
index ff985d2..c71e62c 100644
|
|
|
3c4af5 |
--- a/mdmon.c
|
|
|
3c4af5 |
+++ b/mdmon.c
|
|
|
3c4af5 |
@@ -546,14 +546,7 @@ static int mdmon(char *devnm, int must_fork, int takeover)
|
|
|
3c4af5 |
}
|
|
|
3c4af5 |
|
|
|
3c4af5 |
setsid();
|
|
|
3c4af5 |
- close(0);
|
|
|
3c4af5 |
- open("/dev/null", O_RDWR);
|
|
|
3c4af5 |
- close(1);
|
|
|
3c4af5 |
- ignore = dup(0);
|
|
|
3c4af5 |
-#ifndef DEBUG
|
|
|
3c4af5 |
- close(2);
|
|
|
3c4af5 |
- ignore = dup(0);
|
|
|
3c4af5 |
-#endif
|
|
|
3c4af5 |
+ manage_fork_fds(0);
|
|
|
3c4af5 |
|
|
|
3c4af5 |
/* This silliness is to stop the compiler complaining
|
|
|
3c4af5 |
* that we ignore 'ignore'
|
|
|
3c4af5 |
diff --git a/util.c b/util.c
|
|
|
3c4af5 |
index 579dd42..5879694 100644
|
|
|
3c4af5 |
--- a/util.c
|
|
|
3c4af5 |
+++ b/util.c
|
|
|
3c4af5 |
@@ -1915,7 +1915,7 @@ int mdmon_running(char *devnm)
|
|
|
3c4af5 |
|
|
|
3c4af5 |
int start_mdmon(char *devnm)
|
|
|
3c4af5 |
{
|
|
|
3c4af5 |
- int i, skipped;
|
|
|
3c4af5 |
+ int i;
|
|
|
3c4af5 |
int len;
|
|
|
3c4af5 |
pid_t pid;
|
|
|
3c4af5 |
int status;
|
|
|
3c4af5 |
@@ -1929,7 +1929,10 @@ int start_mdmon(char *devnm)
|
|
|
3c4af5 |
|
|
|
3c4af5 |
if (check_env("MDADM_NO_MDMON"))
|
|
|
3c4af5 |
return 0;
|
|
|
3c4af5 |
+ if (continue_via_systemd(devnm, MDMON_SERVICE))
|
|
|
3c4af5 |
+ return 0;
|
|
|
3c4af5 |
|
|
|
3c4af5 |
+ /* That failed, try running mdmon directly */
|
|
|
3c4af5 |
len = readlink("/proc/self/exe", pathbuf, sizeof(pathbuf)-1);
|
|
|
3c4af5 |
if (len > 0) {
|
|
|
3c4af5 |
char *sl;
|
|
|
3c4af5 |
@@ -1943,51 +1946,9 @@ int start_mdmon(char *devnm)
|
|
|
3c4af5 |
} else
|
|
|
3c4af5 |
pathbuf[0] = '\0';
|
|
|
3c4af5 |
|
|
|
3c4af5 |
- /* First try to run systemctl */
|
|
|
3c4af5 |
- if (!check_env("MDADM_NO_SYSTEMCTL"))
|
|
|
3c4af5 |
- switch(fork()) {
|
|
|
3c4af5 |
- case 0:
|
|
|
3c4af5 |
- /* FIXME yuk. CLOSE_EXEC?? */
|
|
|
3c4af5 |
- skipped = 0;
|
|
|
3c4af5 |
- for (i = 3; skipped < 20; i++)
|
|
|
3c4af5 |
- if (close(i) < 0)
|
|
|
3c4af5 |
- skipped++;
|
|
|
3c4af5 |
- else
|
|
|
3c4af5 |
- skipped = 0;
|
|
|
3c4af5 |
-
|
|
|
3c4af5 |
- /* Don't want to see error messages from
|
|
|
3c4af5 |
- * systemctl. If the service doesn't exist,
|
|
|
3c4af5 |
- * we start mdmon ourselves.
|
|
|
3c4af5 |
- */
|
|
|
3c4af5 |
- close(2);
|
|
|
3c4af5 |
- open("/dev/null", O_WRONLY);
|
|
|
3c4af5 |
- snprintf(pathbuf, sizeof(pathbuf), "mdmon@%s.service",
|
|
|
3c4af5 |
- devnm);
|
|
|
3c4af5 |
- status = execl("/usr/bin/systemctl", "systemctl",
|
|
|
3c4af5 |
- "start",
|
|
|
3c4af5 |
- pathbuf, NULL);
|
|
|
3c4af5 |
- status = execl("/bin/systemctl", "systemctl", "start",
|
|
|
3c4af5 |
- pathbuf, NULL);
|
|
|
3c4af5 |
- exit(1);
|
|
|
3c4af5 |
- case -1: pr_err("cannot run mdmon. Array remains readonly\n");
|
|
|
3c4af5 |
- return -1;
|
|
|
3c4af5 |
- default: /* parent - good */
|
|
|
3c4af5 |
- pid = wait(&status);
|
|
|
3c4af5 |
- if (pid >= 0 && status == 0)
|
|
|
3c4af5 |
- return 0;
|
|
|
3c4af5 |
- }
|
|
|
3c4af5 |
-
|
|
|
3c4af5 |
- /* That failed, try running mdmon directly */
|
|
|
3c4af5 |
switch(fork()) {
|
|
|
3c4af5 |
case 0:
|
|
|
3c4af5 |
- /* FIXME yuk. CLOSE_EXEC?? */
|
|
|
3c4af5 |
- skipped = 0;
|
|
|
3c4af5 |
- for (i = 3; skipped < 20; i++)
|
|
|
3c4af5 |
- if (close(i) < 0)
|
|
|
3c4af5 |
- skipped++;
|
|
|
3c4af5 |
- else
|
|
|
3c4af5 |
- skipped = 0;
|
|
|
3c4af5 |
-
|
|
|
3c4af5 |
+ manage_fork_fds(1);
|
|
|
3c4af5 |
for (i = 0; paths[i]; i++)
|
|
|
3c4af5 |
if (paths[i][0]) {
|
|
|
3c4af5 |
execl(paths[i], paths[i],
|
|
|
3c4af5 |
@@ -2192,6 +2153,81 @@ void enable_fds(int devices)
|
|
|
3c4af5 |
setrlimit(RLIMIT_NOFILE, &lim);
|
|
|
3c4af5 |
}
|
|
|
3c4af5 |
|
|
|
3c4af5 |
+/* Close all opened descriptors if needed and redirect
|
|
|
3c4af5 |
+ * streams to /dev/null.
|
|
|
3c4af5 |
+ * For debug purposed, leave STDOUT and STDERR untouched
|
|
|
3c4af5 |
+ * Returns:
|
|
|
3c4af5 |
+ * 1- if any error occurred
|
|
|
3c4af5 |
+ * 0- otherwise
|
|
|
3c4af5 |
+ */
|
|
|
3c4af5 |
+void manage_fork_fds(int close_all)
|
|
|
3c4af5 |
+{
|
|
|
3c4af5 |
+ DIR *dir;
|
|
|
3c4af5 |
+ struct dirent *dirent;
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+ close(0);
|
|
|
3c4af5 |
+ open("/dev/null", O_RDWR);
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+#ifndef DEBUG
|
|
|
3c4af5 |
+ dup2(0, 1);
|
|
|
3c4af5 |
+ dup2(0, 2);
|
|
|
3c4af5 |
+#endif
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+ if (close_all == 0)
|
|
|
3c4af5 |
+ return;
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+ dir = opendir("/proc/self/fd");
|
|
|
3c4af5 |
+ if (!dir) {
|
|
|
3c4af5 |
+ pr_err("Cannot open /proc/self/fd directory.\n");
|
|
|
3c4af5 |
+ return;
|
|
|
3c4af5 |
+ }
|
|
|
3c4af5 |
+ for (dirent = readdir(dir); dirent; dirent = readdir(dir)) {
|
|
|
3c4af5 |
+ int fd = -1;
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+ if ((strcmp(dirent->d_name, ".") == 0) ||
|
|
|
3c4af5 |
+ (strcmp(dirent->d_name, "..")) == 0)
|
|
|
3c4af5 |
+ continue;
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+ fd = strtol(dirent->d_name, NULL, 10);
|
|
|
3c4af5 |
+ if (fd > 2)
|
|
|
3c4af5 |
+ close(fd);
|
|
|
3c4af5 |
+ }
|
|
|
3c4af5 |
+}
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+/* In a systemd/udev world, it is best to get systemd to
|
|
|
3c4af5 |
+ * run daemon rather than running in the background.
|
|
|
3c4af5 |
+ * Returns:
|
|
|
3c4af5 |
+ * 1- if systemd service has been started
|
|
|
3c4af5 |
+ * 0- otherwise
|
|
|
3c4af5 |
+ */
|
|
|
3c4af5 |
+int continue_via_systemd(char *devnm, char *service_name)
|
|
|
3c4af5 |
+{
|
|
|
3c4af5 |
+ int pid, status;
|
|
|
3c4af5 |
+ char pathbuf[1024];
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
+ /* Simply return that service cannot be started */
|
|
|
3c4af5 |
+ if (check_env("MDADM_NO_SYSTEMCTL"))
|
|
|
3c4af5 |
+ return 0;
|
|
|
3c4af5 |
+ switch (fork()) {
|
|
|
3c4af5 |
+ case 0:
|
|
|
3c4af5 |
+ manage_fork_fds(1);
|
|
|
3c4af5 |
+ snprintf(pathbuf, sizeof(pathbuf),
|
|
|
3c4af5 |
+ "%s@%s.service", service_name, devnm);
|
|
|
3c4af5 |
+ status = execl("/usr/bin/systemctl", "systemctl", "restart",
|
|
|
3c4af5 |
+ pathbuf, NULL);
|
|
|
3c4af5 |
+ status = execl("/bin/systemctl", "systemctl", "restart",
|
|
|
3c4af5 |
+ pathbuf, NULL);
|
|
|
3c4af5 |
+ exit(1);
|
|
|
3c4af5 |
+ case -1: /* Just do it ourselves. */
|
|
|
3c4af5 |
+ break;
|
|
|
3c4af5 |
+ default: /* parent - good */
|
|
|
3c4af5 |
+ pid = wait(&status);
|
|
|
3c4af5 |
+ if (pid >= 0 && status == 0)
|
|
|
3c4af5 |
+ return 1;
|
|
|
3c4af5 |
+ }
|
|
|
3c4af5 |
+ return 0;
|
|
|
3c4af5 |
+}
|
|
|
3c4af5 |
+
|
|
|
3c4af5 |
int in_initrd(void)
|
|
|
3c4af5 |
{
|
|
|
3c4af5 |
/* This is based on similar function in systemd. */
|
|
|
3c4af5 |
--
|
|
|
3c4af5 |
2.7.5
|
|
|
3c4af5 |
|