Blame SOURCES/Create-tell-udev-md-device-is-not-ready-when-first-c.patch

b7f731
From cd6cbb08c458cee07acb1d854e04532b29ec87bf Mon Sep 17 00:00:00 2001
b7f731
From: NeilBrown <neilb@suse.com>
b7f731
Date: Fri, 28 Apr 2017 15:05:50 +1000
b7f731
Subject: [RHEL7.5 PATCH 100/169] Create: tell udev md device is not ready
b7f731
 when first created.
b7f731
b7f731
When an array is created the content is not initialized,
b7f731
so it could have remnants of an old filesystem or md array
b7f731
etc on it.
b7f731
udev will see this and might try to activate it, which is almost
b7f731
certainly not what is wanted.
b7f731
b7f731
So create a mechanism for mdadm to communicate with udev to tell
b7f731
it that the device isn't ready.  This mechanism is the existance
b7f731
of a file /run/mdadm/created-mdXXX where mdXXX is the md device name.
b7f731
b7f731
When creating an array, mdadm will create the file.
b7f731
A new udev rule file, 01-md-raid-creating.rules, will detect the
b7f731
precense of thst file and set ENV{SYSTEMD_READY}="0".
b7f731
This is fairly uniformly used to suppress actions based on the
b7f731
contents of the device.
b7f731
b7f731
Signed-off-by: NeilBrown <neilb@suse.com>
b7f731
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
b7f731
---
b7f731
 Assemble.c                  |  2 +-
b7f731
 Build.c                     |  2 +-
b7f731
 Create.c                    |  9 +++++++-
b7f731
 Incremental.c               |  4 ++--
b7f731
 Makefile                    |  4 ++--
b7f731
 lib.c                       | 29 +++++++++++++++++++++++++
b7f731
 mdadm.h                     |  4 +++-
b7f731
 mdopen.c                    | 52 ++++++++++++++++++++++++++++-----------------
b7f731
 udev-md-raid-creating.rules |  7 ++++++
b7f731
 9 files changed, 86 insertions(+), 27 deletions(-)
b7f731
 create mode 100644 udev-md-raid-creating.rules
b7f731
b7f731
diff --git a/Assemble.c b/Assemble.c
b7f731
index d6beb23..a9442c8 100644
b7f731
--- a/Assemble.c
b7f731
+++ b/Assemble.c
b7f731
@@ -1478,7 +1478,7 @@ try_again:
b7f731
 			name = strchr(name, ':')+1;
b7f731
 
b7f731
 		mdfd = create_mddev(mddev, name, ident->autof, trustworthy,
b7f731
-				    chosen_name);
b7f731
+				    chosen_name, 0);
b7f731
 	}
b7f731
 	if (mdfd < 0) {
b7f731
 		st->ss->free_super(st);
b7f731
diff --git a/Build.c b/Build.c
b7f731
index 11ba12f..665d906 100644
b7f731
--- a/Build.c
b7f731
+++ b/Build.c
b7f731
@@ -109,7 +109,7 @@ int Build(char *mddev, struct mddev_dev *devlist,
b7f731
 	/* We need to create the device.  It can have no name. */
b7f731
 	map_lock(&map);
b7f731
 	mdfd = create_mddev(mddev, NULL, c->autof, LOCAL,
b7f731
-			    chosen_name);
b7f731
+			    chosen_name, 0);
b7f731
 	if (mdfd < 0) {
b7f731
 		map_unlock(&map);
b7f731
 		return 1;
b7f731
diff --git a/Create.c b/Create.c
b7f731
index 6ca0924..df1bc20 100644
b7f731
--- a/Create.c
b7f731
+++ b/Create.c
b7f731
@@ -605,7 +605,7 @@ int Create(struct supertype *st, char *mddev,
b7f731
 
b7f731
 	/* We need to create the device */
b7f731
 	map_lock(&map);
b7f731
-	mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name);
b7f731
+	mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name, 1);
b7f731
 	if (mdfd < 0) {
b7f731
 		map_unlock(&map);
b7f731
 		return 1;
b7f731
@@ -620,6 +620,7 @@ int Create(struct supertype *st, char *mddev,
b7f731
 			chosen_name);
b7f731
 		close(mdfd);
b7f731
 		map_unlock(&map);
b7f731
+		udev_unblock();
b7f731
 		return 1;
b7f731
 	}
b7f731
 	mddev = chosen_name;
b7f731
@@ -1053,9 +1054,15 @@ int Create(struct supertype *st, char *mddev,
b7f731
 		pr_err("not starting array - not enough devices.\n");
b7f731
 	}
b7f731
 	close(mdfd);
b7f731
+	/* Give udev a moment to process the Change event caused
b7f731
+	 * by the close.
b7f731
+	 */
b7f731
+	usleep(100*1000);
b7f731
+	udev_unblock();
b7f731
 	return 0;
b7f731
 
b7f731
  abort:
b7f731
+	udev_unblock();
b7f731
 	map_lock(&map);
b7f731
  abort_locked:
b7f731
 	map_remove(&map, fd2devnm(mdfd));
b7f731
diff --git a/Incremental.c b/Incremental.c
b7f731
index 66c5b03..4789e36 100644
b7f731
--- a/Incremental.c
b7f731
+++ b/Incremental.c
b7f731
@@ -320,7 +320,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
b7f731
 
b7f731
 		/* Couldn't find an existing array, maybe make a new one */
b7f731
 		mdfd = create_mddev(match ? match->devname : NULL,
b7f731
-				    name_to_use, c->autof, trustworthy, chosen_name);
b7f731
+				    name_to_use, c->autof, trustworthy, chosen_name, 0);
b7f731
 
b7f731
 		if (mdfd < 0)
b7f731
 			goto out_unlock;
b7f731
@@ -1596,7 +1596,7 @@ static int Incremental_container(struct supertype *st, char *devname,
b7f731
 					    ra->name,
b7f731
 					    c->autof,
b7f731
 					    trustworthy,
b7f731
-					    chosen_name);
b7f731
+					    chosen_name, 0);
b7f731
 		}
b7f731
 		if (only && (!mp || strcmp(mp->devnm, only) != 0))
b7f731
 			continue;
b7f731
diff --git a/Makefile b/Makefile
b7f731
index 6850696..021d3ad 100644
b7f731
--- a/Makefile
b7f731
+++ b/Makefile
b7f731
@@ -256,8 +256,8 @@ install-man: mdadm.8 md.4 mdadm.conf.5 mdmon.8
b7f731
 	$(INSTALL) -D -m 644 md.4 $(DESTDIR)$(MAN4DIR)/md.4
b7f731
 	$(INSTALL) -D -m 644 mdadm.conf.5 $(DESTDIR)$(MAN5DIR)/mdadm.conf.5
b7f731
 
b7f731
-install-udev: udev-md-raid-arrays.rules udev-md-raid-assembly.rules
b7f731
-	@for file in 63-md-raid-arrays.rules 64-md-raid-assembly.rules ; \
b7f731
+install-udev: udev-md-raid-arrays.rules udev-md-raid-assembly.rules udev-md-raid-creating.rules
b7f731
+	@for file in 01-md-raid-creating.rules 63-md-raid-arrays.rules 64-md-raid-assembly.rules ; \
b7f731
 	do sed -e 's,BINDIR,$(BINDIR),g' udev-$${file#??-} > .install.tmp.1 && \
b7f731
 	   $(ECHO) $(INSTALL) -D -m 644 udev-$${file#??-} $(DESTDIR)$(UDEVDIR)/rules.d/$$file ; \
b7f731
 	   $(INSTALL) -D -m 644 .install.tmp.1 $(DESTDIR)$(UDEVDIR)/rules.d/$$file ; \
b7f731
diff --git a/lib.c b/lib.c
b7f731
index b640634..7e44b1f 100644
b7f731
--- a/lib.c
b7f731
+++ b/lib.c
b7f731
@@ -163,6 +163,35 @@ char *fd2devnm(int fd)
b7f731
 	return NULL;
b7f731
 }
b7f731
 
b7f731
+/* When we create a new array, we don't want the content to
b7f731
+ * be immediately examined by udev - it is probably meaningless.
b7f731
+ * So create /run/mdadm/creating-FOO and expect that a udev
b7f731
+ * rule will noticed this and act accordingly.
b7f731
+ */
b7f731
+static char block_path[] = "/run/mdadm/creating-%s";
b7f731
+static char *unblock_path = NULL;
b7f731
+void udev_block(char *devnm)
b7f731
+{
b7f731
+	int fd;
b7f731
+	char *path = NULL;
b7f731
+
b7f731
+	xasprintf(&path, block_path, devnm);
b7f731
+	fd = open(path, O_CREAT|O_RDWR, 0600);
b7f731
+	if (fd >= 0) {
b7f731
+		close(fd);
b7f731
+		unblock_path = path;
b7f731
+	} else
b7f731
+		free(path);
b7f731
+}
b7f731
+
b7f731
+void udev_unblock(void)
b7f731
+{
b7f731
+	if (unblock_path)
b7f731
+		unlink(unblock_path);
b7f731
+	free(unblock_path);
b7f731
+	unblock_path = NULL;
b7f731
+}
b7f731
+
b7f731
 /*
b7f731
  * convert a major/minor pair for a block device into a name in /dev, if possible.
b7f731
  * On the first call, walk /dev collecting name.
b7f731
diff --git a/mdadm.h b/mdadm.h
b7f731
index 1bbacfe..6a382a7 100644
b7f731
--- a/mdadm.h
b7f731
+++ b/mdadm.h
b7f731
@@ -1533,7 +1533,7 @@ extern char *get_md_name(char *devnm);
b7f731
 extern char DefaultConfFile[];
b7f731
 
b7f731
 extern int create_mddev(char *dev, char *name, int autof, int trustworthy,
b7f731
-			char *chosen);
b7f731
+			char *chosen, int block_udev);
b7f731
 /* values for 'trustworthy' */
b7f731
 #define	LOCAL	1
b7f731
 #define	LOCAL_ANY 10
b7f731
@@ -1567,6 +1567,8 @@ extern char *stat2kname(struct stat *st);
b7f731
 extern char *fd2kname(int fd);
b7f731
 extern char *stat2devnm(struct stat *st);
b7f731
 extern char *fd2devnm(int fd);
b7f731
+extern void udev_block(char *devnm);
b7f731
+extern void udev_unblock(void);
b7f731
 
b7f731
 extern int in_initrd(void);
b7f731
 
b7f731
diff --git a/mdopen.c b/mdopen.c
b7f731
index 82b97fc..099efa0 100644
b7f731
--- a/mdopen.c
b7f731
+++ b/mdopen.c
b7f731
@@ -135,7 +135,7 @@ void make_parts(char *dev, int cnt)
b7f731
  */
b7f731
 
b7f731
 int create_mddev(char *dev, char *name, int autof, int trustworthy,
b7f731
-		 char *chosen)
b7f731
+		 char *chosen, int block_udev)
b7f731
 {
b7f731
 	int mdfd;
b7f731
 	struct stat stb;
b7f731
@@ -147,6 +147,10 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy,
b7f731
 	char devname[37];
b7f731
 	char devnm[32];
b7f731
 	char cbuf[400];
b7f731
+
b7f731
+	if (!use_udev())
b7f731
+		block_udev = 0;
b7f731
+
b7f731
 	if (chosen == NULL)
b7f731
 		chosen = cbuf;
b7f731
 
b7f731
@@ -305,43 +309,53 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy,
b7f731
 		int fd;
b7f731
 		int n = -1;
b7f731
 		sprintf(devnm, "md_%s", cname);
b7f731
+		if (block_udev)
b7f731
+			udev_block(devnm);
b7f731
 		fd = open("/sys/module/md_mod/parameters/new_array", O_WRONLY);
b7f731
 		if (fd >= 0) {
b7f731
 			n = write(fd, devnm, strlen(devnm));
b7f731
 			close(fd);
b7f731
 		}
b7f731
-		if (n < 0)
b7f731
+		if (n < 0) {
b7f731
 			devnm[0] = 0;
b7f731
+			udev_unblock();
b7f731
+		}
b7f731
 	}
b7f731
 	if (num >= 0) {
b7f731
 		int fd;
b7f731
 		int n = -1;
b7f731
 		sprintf(devnm, "md%d", num);
b7f731
+		if (block_udev)
b7f731
+			udev_block(devnm);
b7f731
 		fd = open("/sys/module/md_mod/parameters/new_array", O_WRONLY);
b7f731
 		if (fd >= 0) {
b7f731
 			n = write(fd, devnm, strlen(devnm));
b7f731
 			close(fd);
b7f731
 		}
b7f731
-		if (n < 0)
b7f731
+		if (n < 0) {
b7f731
 			devnm[0] = 0;
b7f731
-	}
b7f731
-	if (devnm[0])
b7f731
-		;
b7f731
-	else if (num < 0) {
b7f731
-		/* need to choose a free number. */
b7f731
-		char *_devnm = find_free_devnm(use_mdp);
b7f731
-		if (_devnm == NULL) {
b7f731
-			pr_err("No avail md devices - aborting\n");
b7f731
-			return -1;
b7f731
+			udev_unblock();
b7f731
 		}
b7f731
-		strcpy(devnm, _devnm);
b7f731
-	} else {
b7f731
-		sprintf(devnm, "%s%d", use_mdp?"md_d":"md", num);
b7f731
-		if (mddev_busy(devnm)) {
b7f731
-			pr_err("%s is already in use.\n",
b7f731
-				dev);
b7f731
-			return -1;
b7f731
+	}
b7f731
+	if (devnm[0] == 0) {
b7f731
+		if (num < 0) {
b7f731
+			/* need to choose a free number. */
b7f731
+			char *_devnm = find_free_devnm(use_mdp);
b7f731
+			if (_devnm == NULL) {
b7f731
+				pr_err("No avail md devices - aborting\n");
b7f731
+				return -1;
b7f731
+			}
b7f731
+			strcpy(devnm, _devnm);
b7f731
+		} else {
b7f731
+			sprintf(devnm, "%s%d", use_mdp?"md_d":"md", num);
b7f731
+			if (mddev_busy(devnm)) {
b7f731
+				pr_err("%s is already in use.\n",
b7f731
+				       dev);
b7f731
+				return -1;
b7f731
+			}
b7f731
 		}
b7f731
+		if (block_udev)
b7f731
+			udev_block(devnm);
b7f731
 	}
b7f731
 
b7f731
 	sprintf(devname, "/dev/%s", devnm);
b7f731
diff --git a/udev-md-raid-creating.rules b/udev-md-raid-creating.rules
b7f731
new file mode 100644
b7f731
index 0000000..2be466b
b7f731
--- /dev/null
b7f731
+++ b/udev-md-raid-creating.rules
b7f731
@@ -0,0 +1,7 @@
b7f731
+# do not edit this file, it will be overwritten on update
b7f731
+# While mdadm is creating an array, it creates a file
b7f731
+# /run/mdadm/creating-mdXXX.  If that file exists, then
b7f731
+# the array is not "ready" and we should make sure the
b7f731
+# content is ignored.
b7f731
+
b7f731
+KERNEL=="md*", TEST="/run/mdadm/creating-$kernel", ENV{SYSTEMD_READY}="0"
b7f731
-- 
b7f731
2.7.4
b7f731