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

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