X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=mdopen.c;h=f818fdf339eb9314eae07fd24b96c5229d0baf43;hp=61eda8120a3b670e4d628fa0aad6e3ffc20eaddf;hb=36138e4e4b6c3f9db21e65ac8962bf22d4b2c274;hpb=7103b9b88d8c27989e17c80d7296eda97370dc1e diff --git a/mdopen.c b/mdopen.c index 61eda812..f818fdf3 100644 --- a/mdopen.c +++ b/mdopen.c @@ -1,7 +1,7 @@ /* * mdadm - manage Linux "md" devices aka RAID arrays. * - * Copyright (C) 2001-2012 Neil Brown + * Copyright (C) 2001-2013 Neil Brown * * * This program is free software; you can redistribute it and/or modify @@ -126,7 +126,7 @@ void make_parts(char *dev, int cnt) * * If udev is configured, we create a temporary device, open it, and * unlink it. - * If not, we create the /dev/mdXX device, and is name is usable, + * If not, we create the /dev/mdXX device, and if name is usable, * /dev/md/name * In any case we return /dev/md/name or (if that isn't available) * /dev/mdXX in 'chosen'. @@ -145,6 +145,7 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, int parts; char *cname; char devname[20]; + char devnm[32]; char cbuf[400]; if (chosen == NULL) chosen = cbuf; @@ -172,8 +173,7 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, /* name *must* be mdXX or md_dXX in this context */ if (num < 0 || (strcmp(cname, "md") != 0 && strcmp(cname, "md_d") != 0)) { - pr_err("%s is an invalid name " - "for an md device. Try /dev/md/%s\n", + pr_err("%s is an invalid name for an md device. Try /dev/md/%s\n", dev, dev+5); return -1; } @@ -190,13 +190,11 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, * empty. */ if (strchr(cname, '/') != NULL) { - pr_err("%s is an invalid name " - "for an md device.\n", dev); + pr_err("%s is an invalid name for an md device.\n", dev); return -1; } if (cname[0] == 0) { - pr_err("%s is an invalid name " - "for an md device (empty!).", dev); + pr_err("%s is an invalid name for an md device (empty!).", dev); return -1; } if (num < 0) { @@ -207,7 +205,10 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, char *ep; if (cname[0] == 'd') sp++; - num = strtoul(sp, &ep, 10); + if (isdigit(sp[0])) + num = strtoul(sp, &ep, 10); + else + ep = sp; if (ep == sp || *ep || num < 0) num = -1; else if (cname[0] == 'd') @@ -222,8 +223,7 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, if (name && name[0] == 0) name = NULL; if (name && trustworthy == METADATA && use_mdp == 1) { - pr_err("%s is not allowed for a %s container. " - "Consider /dev/md%d.\n", dev, name, num); + pr_err("%s is not allowed for a %s container. Consider /dev/md%d.\n", dev, name, num); return -1; } if (name && trustworthy == METADATA) @@ -249,31 +249,13 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, num = strtoul(n2, &ep, 10); if (ep == n2 || *ep) num = -1; - else if (mddev_busy(use_mdp ? (-1-num) : num)) - num = -1; - } - - if (num < 0) { - /* need to choose a free number. */ - num = find_free_devnum(use_mdp); - if (num == NoMdDev) { - pr_err("No avail md devices - aborting\n"); - return -1; - } - } else { - num = use_mdp ? (-1-num) : num; - if (mddev_busy(num)) { - pr_err("%s is already in use.\n", - dev); - return -1; + else { + sprintf(devnm, "md%s%d", use_mdp ? "_d":"", num); + if (mddev_busy(devnm)) + num = -1; } } - if (num < 0) - sprintf(devname, "/dev/md_d%d", -1-num); - else - sprintf(devname, "/dev/md%d", num); - if (cname[0] == 0 && name) { /* Need to find a name if we can * We don't completely trust 'name'. Truncate to @@ -318,6 +300,40 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, } } + devnm[0] = 0; + if (num < 0 && cname && ci->names) { + int fd; + int n = -1; + sprintf(devnm, "md_%s", cname); + 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) + 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; + } + 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; + } + } + + sprintf(devname, "/dev/%s", devnm); + if (dev && dev[0] == '/') strcpy(chosen, dev); else if (cname[0] == 0) @@ -327,20 +343,19 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, * If we cannot detect udev, we need to make * devices and links ourselves. */ - if ((stat("/dev/.udev", &stb) != 0 && stat("/run/udev", &stb) != 0) || - check_env("MDADM_NO_UDEV")) { + if (!use_udev()) { /* Make sure 'devname' exists and 'chosen' is a symlink to it */ if (lstat(devname, &stb) == 0) { /* Must be the correct device, else error */ if ((stb.st_mode&S_IFMT) != S_IFBLK || - stb.st_rdev != makedev(dev2major(num),dev2minor(num))) { + stb.st_rdev != devnm2devid(devnm)) { pr_err("%s exists but looks wrong, please fix\n", devname); return -1; } } else { if (mknod(devname, S_IFBLK|0600, - makedev(dev2major(num),dev2minor(num))) != 0) { + devnm2devid(devnm)) != 0) { pr_err("failed to create %s\n", devname); return -1; @@ -387,7 +402,7 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, make_parts(chosen, parts); } } - mdfd = open_dev_excl(num); + mdfd = open_dev_excl(devnm); if (mdfd < 0) pr_err("unexpected failure opening %s\n", devname); @@ -413,9 +428,41 @@ int open_mddev(char *dev, int report_errors) if (md_get_version(mdfd) <= 0) { close(mdfd); if (report_errors) - pr_err("%s does not appear to be " - "an md device\n", dev); + pr_err("%s does not appear to be an md device\n", dev); return -2; } return mdfd; } + +char *find_free_devnm(int use_partitions) +{ + static char devnm[32]; + int devnum; + for (devnum = 127; devnum != 128; + devnum = devnum ? devnum-1 : (1<<9)-1) { + + if (use_partitions) + sprintf(devnm, "md_d%d", devnum); + else + sprintf(devnm, "md%d", devnum); + if (mddev_busy(devnm)) + continue; + if (!conf_name_is_free(devnm)) + continue; + if (!use_udev()) { + /* make sure it is new to /dev too, at least as a + * non-standard */ + dev_t devid = devnm2devid(devnm); + if (devid) { + char *dn = map_dev(major(devid), + minor(devid), 0); + if (dn && ! is_standard(dn, NULL)) + continue; + } + } + break; + } + if (devnum == 128) + return NULL; + return devnm; +}