diff --git a/Assemble.c b/Assemble.c index d6beb23..a9442c8 100644 --- a/Assemble.c +++ b/Assemble.c @@ -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 11ba12f..665d906 100644 --- 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; diff --git a/Create.c b/Create.c index 6ca0924..df1bc20 100644 --- 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)); diff --git a/Incremental.c b/Incremental.c index 66c5b03..4789e36 100644 --- a/Incremental.c +++ b/Incremental.c @@ -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; diff --git a/Makefile b/Makefile index 6850696..021d3ad 100644 --- 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 b640634..7e44b1f 100644 --- 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 1bbacfe..6a382a7 100644 --- 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); diff --git a/mdopen.c b/mdopen.c index 82b97fc..099efa0 100644 --- 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; + udev_unblock(); + } } - 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; - } - 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 index 0000000..2be466b --- /dev/null +++ b/udev-md-raid-creating.rules @@ -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"