diff --git a/Assemble.c b/Assemble.c index c7563ab2..2d1ff448 100644 --- a/Assemble.c +++ b/Assemble.c @@ -2221,8 +2221,8 @@ int assemble_container_content(struct supertype *st, int mdfd, set_array_assembly_status(c, result, INCR_NO, &array); else { set_array_assembly_status(c, result, INCR_YES, &array); - wait_for(chosen_name, mdfd); sysfs_rules_apply(chosen_name, content, st); + wait_for(chosen_name, mdfd); } return err; diff --git a/Create.c b/Create.c index 3a4eff77..acf75aba 100644 --- a/Create.c +++ b/Create.c @@ -523,6 +523,7 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, int container_fd = -1; int need_mdmon = 0; unsigned long long bitmapsize; + bool udev_blocked; struct mdinfo info; int did_default = 0; int do_default_layout = 0; @@ -1029,7 +1030,8 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, /* We need to create the device */ map_lock(&map); - mdfd = create_mddev(ident->devname, ident->name, LOCAL, chosen_name, 1); + udev_blocked = udev_is_available(); + mdfd = create_mddev(ident->devname, ident->name, LOCAL, chosen_name, udev_blocked); if (mdfd < 0) { map_unlock(&map); return 1; @@ -1043,7 +1045,8 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, pr_err("Array name %s is in use already.\n", chosen_name); close(mdfd); map_unlock(&map); - udev_unblock(); + if (udev_blocked) + udev_unblock(); return 1; } @@ -1331,14 +1334,15 @@ int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, pr_err("not starting array - not enough devices.\n"); } close(mdfd); - udev_unblock(); - sysfs_uevent(&info, "change"); + if (udev_blocked) + udev_ready(&info); dev_policy_free(custom_pols); return 0; abort: - udev_unblock(); + if (udev_blocked) + udev_unblock(); map_lock(&map); abort_locked: map_remove(&map, fd2devnm(mdfd)); diff --git a/Incremental.c b/Incremental.c index f717c9c3..2cf625ef 100644 --- a/Incremental.c +++ b/Incremental.c @@ -107,6 +107,8 @@ int Incremental(struct mddev_dev *devlist, struct context *c, int have_target; char *devname = devlist->devname; int journal_device_missing = 0; + bool array_started = false; + bool udev_blocked = false; if (!stat_is_blkdev(devname, &rdev)) return rv; @@ -286,8 +288,9 @@ int Incremental(struct mddev_dev *devlist, struct context *c, goto out_unlock; /* Couldn't find an existing array, maybe make a new one */ + udev_blocked = udev_is_available(); mdfd = create_mddev(match ? match->devname : NULL, name_to_use, trustworthy, - chosen_name, 1); + chosen_name, udev_blocked); if (mdfd < 0) goto out_unlock; @@ -469,14 +472,12 @@ int Incremental(struct mddev_dev *devlist, struct context *c, chosen_name, info.array.working_disks, info.array.working_disks == 1?"":"s"); sysfs_rules_apply(chosen_name, &info, st); - wait_for(chosen_name, mdfd); if (st->ss->external) strcpy(devnm, fd2devnm(mdfd)); if (st->ss->load_container) rv = st->ss->load_container(st, mdfd, NULL); - close(mdfd); - udev_unblock(); - sysfs_uevent(sra, "change"); + if (udev_blocked) + udev_ready(sra); sysfs_free(sra); if (!rv) rv = Incremental_container(st, chosen_name, c, NULL); @@ -485,7 +486,8 @@ int Incremental(struct mddev_dev *devlist, struct context *c, * so that it can eg. try to rebuild degraded array */ if (st->ss->external) ping_monitor(devnm); - udev_unblock(); + wait_for(chosen_name, mdfd); + close(mdfd); return rv; } @@ -604,8 +606,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c, } else if (c->verbose >= 0) pr_err("%s attached to %s, which has been started.\n", devname, chosen_name); - rv = 0; - wait_for(chosen_name, mdfd); + array_started = true; /* We just started the array, so some devices * might have been evicted from the array * because their event counts were too old. @@ -638,15 +639,19 @@ int Incremental(struct mddev_dev *devlist, struct context *c, free(avail); if (dfd >= 0) close(dfd); - if (mdfd >= 0) - close(mdfd); if (policy) dev_policy_free(policy); - udev_unblock(); - if (sra) { - sysfs_uevent(sra, "change"); - sysfs_free(sra); + if (udev_blocked) { + if (sra) + udev_ready(sra); + else + udev_unblock(); } + sysfs_free(sra); + if (array_started) + wait_for(chosen_name, mdfd); + if (mdfd >= 0) + close(mdfd); return rv; out_unlock: map_unlock(&map); @@ -1531,6 +1536,7 @@ static int Incremental_container(struct supertype *st, char *devname, char *sysname; struct map_ent *mp; struct mddev_ident *match = NULL; + bool udev_blocked = false; /* do not activate arrays blocked by metadata handler */ if (ra->array.state & (1 << MD_SB_BLOCK_VOLUME)) { @@ -1601,8 +1607,9 @@ static int Incremental_container(struct supertype *st, char *devname, if (match) trustworthy = LOCAL; + udev_blocked = udev_is_available(); mdfd = create_mddev(match ? match->devname : NULL, ra->name, trustworthy, - chosen_name, 1); + chosen_name, udev_blocked); if (!is_fd_valid(mdfd)) { pr_err("create_mddev failed with chosen name %s: %s.\n", @@ -1613,6 +1620,8 @@ static int Incremental_container(struct supertype *st, char *devname, } if (only && (!mp || strcmp(mp->devnm, only) != 0)) { + if (udev_blocked) + udev_unblock(); close_fd(&mdfd); continue; } @@ -1624,8 +1633,8 @@ static int Incremental_container(struct supertype *st, char *devname, sysname = fd2devnm(mdfd); strncpy(info.sys_name, sysname, sizeof(sysname) - 1); close_fd(&mdfd); - udev_unblock(); - sysfs_uevent(&info, "change"); + if (udev_blocked) + udev_ready(&info); } if (c->export && result) { char sep = '='; @@ -1652,8 +1661,6 @@ static int Incremental_container(struct supertype *st, char *devname, release: map_free(map); sysfs_free(list); - udev_unblock(); - sysfs_uevent(&info, "change"); return rv; } diff --git a/mdopen.c b/mdopen.c index 9af0284b..f0e344d5 100644 --- a/mdopen.c +++ b/mdopen.c @@ -135,9 +135,6 @@ int create_mddev(char *dev, char *name, int trustworthy, return -1; } - if (!udev_is_available()) - block_udev = 0; - if (chosen == NULL) chosen = cbuf; @@ -273,7 +270,8 @@ int create_mddev(char *dev, char *name, int trustworthy, return -1; if (!create_named_array(devnm)) { devnm[0] = 0; - udev_unblock(); + if (block_udev) + udev_unblock(); } } if (num >= 0) { @@ -282,7 +280,8 @@ int create_mddev(char *dev, char *name, int trustworthy, return -1; if (!create_named_array(devnm)) { devnm[0] = 0; - udev_unblock(); + if (block_udev) + udev_unblock(); } } if (devnm[0] == 0) { @@ -327,14 +326,14 @@ int create_mddev(char *dev, char *name, int trustworthy, stb.st_rdev != devnm2devid(devnm)) { pr_err("%s exists but looks wrong, please fix\n", devname); - return -1; + goto error; } } else { if (mknod(devname, S_IFBLK|0600, devnm2devid(devnm)) != 0) { pr_err("failed to create %s\n", devname); - return -1; + goto error; } if (chown(devname, ci->uid, ci->gid)) perror("chown"); @@ -343,7 +342,7 @@ int create_mddev(char *dev, char *name, int trustworthy, if (stat(devname, &stb) < 0) { pr_err("failed to stat %s\n", devname); - return -1; + goto error; } add_dev(devname, &stb, 0, NULL); } @@ -379,10 +378,17 @@ int create_mddev(char *dev, char *name, int trustworthy, } } mdfd = open_dev_excl(devnm); - if (mdfd < 0) + if (mdfd < 0) { pr_err("unexpected failure opening %s\n", devname); + goto error; + } return mdfd; + +error: + if (block_udev) + udev_unblock(); + return -1; } /* Open this and check that it is an md device. diff --git a/udev.c b/udev.c index f857c723..ce2d4850 100644 --- a/udev.c +++ b/udev.c @@ -197,8 +197,24 @@ enum udev_status udev_block(char *devnm) */ void udev_unblock(void) { - if (unblock_path) - unlink(unblock_path); + if (!unblock_path) { + pr_err("Called without prior udev block.\n"); + return; + } + + unlink(unblock_path); free(unblock_path); unblock_path = NULL; } + +/* + * udev_ready() - Unblock udev and signal that the device is ready. + * + * Removes the blocking file and sends a synthetic change uevent + * so udev re-evaluates the device in its final state. + */ +void udev_ready(struct mdinfo *sra) +{ + udev_unblock(); + sysfs_uevent(sra, "change"); +} diff --git a/udev.h b/udev.h index ae0a3617..db2ef1d3 100644 --- a/udev.h +++ b/udev.h @@ -36,5 +36,6 @@ enum udev_status udev_wait_for_events(int seconds); enum udev_status udev_block(char *devnm); void udev_unblock(void); +void udev_ready(struct mdinfo *sra); #endif