]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Create: tell udev md device is not ready when first created.
authorNeilBrown <neilb@suse.com>
Fri, 28 Apr 2017 05:05:50 +0000 (15:05 +1000)
committerJes Sorensen <jsorensen@fb.com>
Tue, 2 May 2017 13:41:39 +0000 (09:41 -0400)
When an array is created the content is not initialized,
so it could have remnants of an old filesystem or md array
etc on it.
udev will see this and might try to activate it, which is almost
certainly not what is wanted.

So create a mechanism for mdadm to communicate with udev to tell
it that the device isn't ready.  This mechanism is the existance
of a file /run/mdadm/created-mdXXX where mdXXX is the md device name.

When creating an array, mdadm will create the file.
A new udev rule file, 01-md-raid-creating.rules, will detect the
precense of thst file and set ENV{SYSTEMD_READY}="0".
This is fairly uniformly used to suppress actions based on the
contents of the device.

Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
Assemble.c
Build.c
Create.c
Incremental.c
Makefile
lib.c
mdadm.h
mdopen.c
udev-md-raid-creating.rules [new file with mode: 0644]

index d6beb23da9c5218adbea829522a6eea6776cae1b..a9442c8ce73b13f0a7c334acdcbe02a8a9522e5b 100644 (file)
@@ -1478,7 +1478,7 @@ try_again:
                        name = strchr(name, ':')+1;
 
                mdfd = create_mddev(mddev, name, ident->autof, trustworthy,
-                                   chosen_name);
+                                   chosen_name, 0);
        }
        if (mdfd < 0) {
                st->ss->free_super(st);
diff --git a/Build.c b/Build.c
index 11ba12f4ae7d73000faa9ba3fda07e3dec32c464..665d9067b8d6c34ccb0abb9e7e2bf5f46281e4e0 100644 (file)
--- a/Build.c
+++ b/Build.c
@@ -109,7 +109,7 @@ int Build(char *mddev, struct mddev_dev *devlist,
        /* We need to create the device.  It can have no name. */
        map_lock(&map);
        mdfd = create_mddev(mddev, NULL, c->autof, LOCAL,
-                           chosen_name);
+                           chosen_name, 0);
        if (mdfd < 0) {
                map_unlock(&map);
                return 1;
index 6ca0924498809770d6f5898ea6f8c151090a0573..df1bc20c635b53e5c80ae774b9b03bab16b78e38 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -605,7 +605,7 @@ int Create(struct supertype *st, char *mddev,
 
        /* We need to create the device */
        map_lock(&map);
-       mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name);
+       mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name, 1);
        if (mdfd < 0) {
                map_unlock(&map);
                return 1;
@@ -620,6 +620,7 @@ int Create(struct supertype *st, char *mddev,
                        chosen_name);
                close(mdfd);
                map_unlock(&map);
+               udev_unblock();
                return 1;
        }
        mddev = chosen_name;
@@ -1053,9 +1054,15 @@ int Create(struct supertype *st, char *mddev,
                pr_err("not starting array - not enough devices.\n");
        }
        close(mdfd);
+       /* Give udev a moment to process the Change event caused
+        * by the close.
+        */
+       usleep(100*1000);
+       udev_unblock();
        return 0;
 
  abort:
+       udev_unblock();
        map_lock(&map);
  abort_locked:
        map_remove(&map, fd2devnm(mdfd));
index 66c5b037b10a704381692e24993f62af6168053f..4789e36ce8a7d5f5b126efb9a94eefd7fcf2892d 100644 (file)
@@ -320,7 +320,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
 
                /* Couldn't find an existing array, maybe make a new one */
                mdfd = create_mddev(match ? match->devname : NULL,
-                                   name_to_use, c->autof, trustworthy, chosen_name);
+                                   name_to_use, c->autof, trustworthy, chosen_name, 0);
 
                if (mdfd < 0)
                        goto out_unlock;
@@ -1596,7 +1596,7 @@ static int Incremental_container(struct supertype *st, char *devname,
                                            ra->name,
                                            c->autof,
                                            trustworthy,
-                                           chosen_name);
+                                           chosen_name, 0);
                }
                if (only && (!mp || strcmp(mp->devnm, only) != 0))
                        continue;
index 685069612617bd405c30efbd5d6658005e17410b..021d3adf3ed1d4f1564da387ea5fc1c32a08b576 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -256,8 +256,8 @@ install-man: mdadm.8 md.4 mdadm.conf.5 mdmon.8
        $(INSTALL) -D -m 644 md.4 $(DESTDIR)$(MAN4DIR)/md.4
        $(INSTALL) -D -m 644 mdadm.conf.5 $(DESTDIR)$(MAN5DIR)/mdadm.conf.5
 
-install-udev: udev-md-raid-arrays.rules udev-md-raid-assembly.rules
-       @for file in 63-md-raid-arrays.rules 64-md-raid-assembly.rules ; \
+install-udev: udev-md-raid-arrays.rules udev-md-raid-assembly.rules udev-md-raid-creating.rules
+       @for file in 01-md-raid-creating.rules 63-md-raid-arrays.rules 64-md-raid-assembly.rules ; \
        do sed -e 's,BINDIR,$(BINDIR),g' udev-$${file#??-} > .install.tmp.1 && \
           $(ECHO) $(INSTALL) -D -m 644 udev-$${file#??-} $(DESTDIR)$(UDEVDIR)/rules.d/$$file ; \
           $(INSTALL) -D -m 644 .install.tmp.1 $(DESTDIR)$(UDEVDIR)/rules.d/$$file ; \
diff --git a/lib.c b/lib.c
index b640634ef6f2e7cff7c5512cc2706f59c0d0ac0f..7e44b1f27fcc23e65f287d4fdacaa8f3ecc02c7c 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -163,6 +163,35 @@ char *fd2devnm(int fd)
        return NULL;
 }
 
+/* When we create a new array, we don't want the content to
+ * be immediately examined by udev - it is probably meaningless.
+ * So create /run/mdadm/creating-FOO and expect that a udev
+ * rule will noticed this and act accordingly.
+ */
+static char block_path[] = "/run/mdadm/creating-%s";
+static char *unblock_path = NULL;
+void udev_block(char *devnm)
+{
+       int fd;
+       char *path = NULL;
+
+       xasprintf(&path, block_path, devnm);
+       fd = open(path, O_CREAT|O_RDWR, 0600);
+       if (fd >= 0) {
+               close(fd);
+               unblock_path = path;
+       } else
+               free(path);
+}
+
+void udev_unblock(void)
+{
+       if (unblock_path)
+               unlink(unblock_path);
+       free(unblock_path);
+       unblock_path = NULL;
+}
+
 /*
  * convert a major/minor pair for a block device into a name in /dev, if possible.
  * On the first call, walk /dev collecting name.
diff --git a/mdadm.h b/mdadm.h
index 1bbacfe9e9161d278a1107f1b402ba2cec6f8089..6a382a7c1b904431ef748626b47688289096d2a5 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -1533,7 +1533,7 @@ extern char *get_md_name(char *devnm);
 extern char DefaultConfFile[];
 
 extern int create_mddev(char *dev, char *name, int autof, int trustworthy,
-                       char *chosen);
+                       char *chosen, int block_udev);
 /* values for 'trustworthy' */
 #define        LOCAL   1
 #define        LOCAL_ANY 10
@@ -1567,6 +1567,8 @@ extern char *stat2kname(struct stat *st);
 extern char *fd2kname(int fd);
 extern char *stat2devnm(struct stat *st);
 extern char *fd2devnm(int fd);
+extern void udev_block(char *devnm);
+extern void udev_unblock(void);
 
 extern int in_initrd(void);
 
index 82b97fc903394d432f4de982ffbe2e7ed30c38a4..099efa0aa2e5cfaf5512054cd568a5005b393161 100644 (file)
--- a/mdopen.c
+++ b/mdopen.c
@@ -135,7 +135,7 @@ void make_parts(char *dev, int cnt)
  */
 
 int create_mddev(char *dev, char *name, int autof, int trustworthy,
-                char *chosen)
+                char *chosen, int block_udev)
 {
        int mdfd;
        struct stat stb;
@@ -147,6 +147,10 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy,
        char devname[37];
        char devnm[32];
        char cbuf[400];
+
+       if (!use_udev())
+               block_udev = 0;
+
        if (chosen == NULL)
                chosen = cbuf;
 
@@ -305,43 +309,53 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy,
                int fd;
                int n = -1;
                sprintf(devnm, "md_%s", cname);
+               if (block_udev)
+                       udev_block(devnm);
                fd = open("/sys/module/md_mod/parameters/new_array", O_WRONLY);
                if (fd >= 0) {
                        n = write(fd, devnm, strlen(devnm));
                        close(fd);
                }
-               if (n < 0)
+               if (n < 0) {
                        devnm[0] = 0;
+                       udev_unblock();
+               }
        }
        if (num >= 0) {
                int fd;
                int n = -1;
                sprintf(devnm, "md%d", num);
+               if (block_udev)
+                       udev_block(devnm);
                fd = open("/sys/module/md_mod/parameters/new_array", O_WRONLY);
                if (fd >= 0) {
                        n = write(fd, devnm, strlen(devnm));
                        close(fd);
                }
-               if (n < 0)
+               if (n < 0) {
                        devnm[0] = 0;
-       }
-       if (devnm[0])
-               ;
-       else if (num < 0) {
-               /* need to choose a free number. */
-               char *_devnm = find_free_devnm(use_mdp);
-               if (_devnm == NULL) {
-                       pr_err("No avail md devices - aborting\n");
-                       return -1;
+                       udev_unblock();
                }
-               strcpy(devnm, _devnm);
-       } else {
-               sprintf(devnm, "%s%d", use_mdp?"md_d":"md", num);
-               if (mddev_busy(devnm)) {
-                       pr_err("%s is already in use.\n",
-                               dev);
-                       return -1;
+       }
+       if (devnm[0] == 0) {
+               if (num < 0) {
+                       /* need to choose a free number. */
+                       char *_devnm = find_free_devnm(use_mdp);
+                       if (_devnm == NULL) {
+                               pr_err("No avail md devices - aborting\n");
+                               return -1;
+                       }
+                       strcpy(devnm, _devnm);
+               } else {
+                       sprintf(devnm, "%s%d", use_mdp?"md_d":"md", num);
+                       if (mddev_busy(devnm)) {
+                               pr_err("%s is already in use.\n",
+                                      dev);
+                               return -1;
+                       }
                }
+               if (block_udev)
+                       udev_block(devnm);
        }
 
        sprintf(devname, "/dev/%s", devnm);
diff --git a/udev-md-raid-creating.rules b/udev-md-raid-creating.rules
new file mode 100644 (file)
index 0000000..2be466b
--- /dev/null
@@ -0,0 +1,7 @@
+# do not edit this file, it will be overwritten on update
+# While mdadm is creating an array, it creates a file
+# /run/mdadm/creating-mdXXX.  If that file exists, then
+# the array is not "ready" and we should make sure the
+# content is ignored.
+
+KERNEL=="md*", TEST="/run/mdadm/creating-$kernel", ENV{SYSTEMD_READY}="0"