Create: tell udev md device is not ready when first created.

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>
This commit is contained in:
NeilBrown 2017-04-28 15:05:50 +10:00 committed by Jes Sorensen
parent f8c432bfc9
commit cd6cbb08c4
9 changed files with 86 additions and 27 deletions

View 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);

View File

@ -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;

View File

@ -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));

View 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;

View File

@ -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 ; \

29
lib.c
View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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"