dcavalca / rpms / mdadm

Forked from rpms/mdadm 3 years ago
Clone

Blame SOURCES/0103-mdadm-Unify-forks-behaviour.patch

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