X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=Manage.c;h=7afd89b7ce7b56c81aa6871ed8c149961cf02382;hb=fdb482f99b9ad2ef8cd1724902fdfeedaa8796a1;hp=98f9fb7684e3b13e54b14f7af92bb40f0a756047;hpb=43dad3d6fb475bfefd2028e9dea1c15a83bb2d03;p=thirdparty%2Fmdadm.git diff --git a/Manage.c b/Manage.c index 98f9fb76..7afd89b7 100644 --- a/Manage.c +++ b/Manage.c @@ -30,6 +30,7 @@ #include "mdadm.h" #include "md_u.h" #include "md_p.h" +#include #define REGISTER_DEV _IO (MD_MAJOR, 1) #define START_MD _IO (MD_MAJOR, 2) @@ -45,11 +46,57 @@ int Manage_ro(char *devname, int fd, int readonly) * */ mdu_array_info_t array; +#ifndef MDASSEMBLE + struct mdinfo *mdi; +#endif if (md_get_version(fd) < 9000) { fprintf(stderr, Name ": need md driver version 0.90.0 or later\n"); return 1; } +#ifndef MDASSEMBLE + /* If this is an externally-manage array, we need to modify the + * metadata_version so that mdmon doesn't undo our change. + */ + mdi = sysfs_read(fd, -1, GET_LEVEL|GET_VERSION); + if (mdi && + mdi->array.major_version == -1 && + mdi->array.level > 0 && + is_subarray(mdi->text_version)) { + char vers[64]; + strcpy(vers, "external:"); + strcat(vers, mdi->text_version); + if (readonly > 0) { + int rv; + /* We set readonly ourselves. */ + vers[9] = '-'; + sysfs_set_str(mdi, NULL, "metadata_version", vers); + + close(fd); + rv = sysfs_set_str(mdi, NULL, "array_state", "readonly"); + + if (rv < 0) { + fprintf(stderr, Name ": failed to set readonly for %s: %s\n", + devname, strerror(errno)); + + vers[9] = mdi->text_version[0]; + sysfs_set_str(mdi, NULL, "metadata_version", vers); + return 1; + } + } else { + char *cp; + /* We cannot set read/write - must signal mdmon */ + vers[9] = '/'; + sysfs_set_str(mdi, NULL, "metadata_version", vers); + + cp = strchr(vers+10, '/'); + if (*cp) + *cp = 0; + ping_monitor(vers+10); + } + return 0; + } +#endif if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": %s does not appear to be active.\n", devname); @@ -74,6 +121,54 @@ int Manage_ro(char *devname, int fd, int readonly) #ifndef MDASSEMBLE +static void remove_devices(int devnum, char *path) +{ + /* Remove all 'standard' devices for 'devnum', including + * partitions. Also remove names at 'path' - possibly with + * partition suffixes - which link to those names. + */ + char base[40]; + char *path2; + char link[1024]; + int n; + int part; + char *be; + char *pe; + + if (devnum >= 0) + sprintf(base, "/dev/md%d", devnum); + else + sprintf(base, "/dev/md_d%d", -1-devnum); + be = base + strlen(base); + if (path) { + path2 = malloc(strlen(path)+20); + strcpy(path2, path); + pe = path2 + strlen(path2); + } else + path = NULL; + + for (part = 0; part < 16; part++) { + if (part) { + sprintf(be, "p%d", part); + if (path) { + if (isdigit(pe[-1])) + sprintf(pe, "p%d", part); + else + sprintf(pe, "%d", part); + } + } + /* FIXME test if really is md device ?? */ + unlink(base); + if (path) { + n = readlink(path2, link, sizeof(link)); + if (n && strlen(base) == n && + strncmp(link, base, n) == 0) + unlink(path2); + } + } +} + + int Manage_runstop(char *devname, int fd, int runstop, int quiet) { /* Run or stop the array. array must already be configured @@ -117,15 +212,15 @@ int Manage_runstop(char *devname, int fd, int runstop, int quiet) struct map_ent *map = NULL; struct stat stb; struct mdinfo *mdi; + int devnum; /* If this is an mdmon managed array, just write 'inactive' * to the array state and let mdmon clear up. */ + devnum = fd2devnum(fd); mdi = sysfs_read(fd, -1, GET_LEVEL|GET_VERSION); if (mdi && mdi->array.level > 0 && - mdi->text_version[0] == '/') { - char *cp; - + is_subarray(mdi->text_version)) { /* This is mdmon managed. */ close(fd); if (sysfs_set_str(mdi, NULL, @@ -138,24 +233,19 @@ int Manage_runstop(char *devname, int fd, int runstop, int quiet) } /* Give monitor a chance to act */ - cp = strchr(mdi->text_version+1, '/'); - if (*cp) - *cp = 0; - ping_monitor(mdi->text_version+1); + ping_monitor(mdi->text_version); fd = open(devname, O_RDONLY); } else if (mdi && mdi->array.major_version == -1 && mdi->array.minor_version == -2 && - mdi->text_version[0] != '/') { + !is_subarray(mdi->text_version)) { /* container, possibly mdmon-managed. * Make sure mdmon isn't opening it, which * would interfere with the 'stop' */ ping_monitor(mdi->sys_name); } - if (mdi) - sysfs_free(mdi); if (fd >= 0 && ioctl(fd, STOP_ARRAY, NULL)) { if (quiet == 0) { @@ -167,17 +257,31 @@ int Manage_runstop(char *devname, int fd, int runstop, int quiet) "process, mounted filesystem " "or active volume group?\n"); } + if (mdi) + sysfs_free(mdi); return 1; } + /* prior to 2.6.28, KOBJ_CHANGE was not sent when an md array + * was stopped, so We'll do it here just to be sure. Drop any + * partitions as well... + */ + if (fd >= 0) + ioctl(fd, BLKRRPART, 0); + if (mdi) + sysfs_uevent(mdi, "change"); + + + if (devnum != NoMdDev && + (stat("/dev/.udev", &stb) != 0 || + check_env("MDADM_NO_UDEV"))) { + struct map_ent *mp = map_by_devnum(&map, devnum); + remove_devices(devnum, mp ? mp->path : NULL); + } + if (quiet <= 0) fprintf(stderr, Name ": stopped %s\n", devname); - if (fd >= 0 && fstat(fd, &stb) == 0) { - int devnum; - if (major(stb.st_rdev) == MD_MAJOR) - devnum = minor(stb.st_rdev); - else - devnum = -1-(minor(stb.st_rdev)>>6); + if (devnum != NoMdDev) { map_delete(&map, devnum); map_write(map); map_free(map); @@ -405,13 +509,6 @@ int Manage_subdevs(char *devname, int fd, } if (array.not_persistent == 0 || tst->ss->external) { - /* Make sure device is large enough */ - if (tst->ss->avail_size(tst, ldsize/512) < - array_size) { - fprintf(stderr, Name ": %s not large enough to join array\n", - dv->devname); - return 1; - } /* need to find a sample superblock to copy, and * a spare slot to use. @@ -447,6 +544,15 @@ int Manage_subdevs(char *devname, int fd, fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n"); return 1; } + + /* Make sure device is large enough */ + if (tst->ss->avail_size(tst, ldsize/512) < + array_size) { + fprintf(stderr, Name ": %s not large enough to join array\n", + dv->devname); + return 1; + } + /* Possibly this device was recently part of the array * and was temporarily removed, and is now being re-added. * If so, we can simply re-add it. @@ -473,8 +579,10 @@ int Manage_subdevs(char *devname, int fd, disc.number = mdi.disk.number; disc.raid_disk = mdi.disk.raid_disk; disc.state = mdi.disk.state; - if (dv->writemostly) + if (dv->writemostly == 1) disc.state |= 1 << MD_DISK_WRITEMOSTLY; + if (dv->writemostly == 2) + disc.state &= ~(1 << MD_DISK_WRITEMOSTLY); if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) { if (verbose >= 0) fprintf(stderr, Name ": re-added %s\n", dv->devname); @@ -513,11 +621,14 @@ int Manage_subdevs(char *devname, int fd, disc.state = 0; if (array.not_persistent==0 || tst->ss->external) { int dfd; - if (dv->writemostly) + if (dv->writemostly == 1) disc.state |= 1 << MD_DISK_WRITEMOSTLY; dfd = open(dv->devname, O_RDWR | O_EXCL|O_DIRECT); - tst->ss->add_to_super(tst, &disc, dfd, - dv->devname); + if (tst->ss->add_to_super(tst, &disc, dfd, + dv->devname)) { + close(dfd); + return 1; + } /* write_init_super will close 'dfd' */ if (tst->ss->external) /* mdmon will write the metadata */ @@ -553,7 +664,7 @@ int Manage_subdevs(char *devname, int fd, break; } } - if (dv->writemostly) + if (dv->writemostly == 1) disc.state |= (1 << MD_DISK_WRITEMOSTLY); if (tst->ss->external) { /* add a disk to an external metadata container @@ -635,7 +746,14 @@ int Manage_subdevs(char *devname, int fd, " to container - odd\n"); return 1; } - if (!sysfs_unique_holder(dnum, stb.st_rdev)) { + /* in the detached case it is not possible to + * check if we are the unique holder, so just + * rely on the 'detached' checks + */ + if (strcmp(dv->devname, "detached") == 0 || + sysfs_unique_holder(dnum, stb.st_rdev)) + /* pass */; + else { fprintf(stderr, Name ": %s is %s, cannot remove.\n", dnprintable, @@ -674,6 +792,23 @@ int Manage_subdevs(char *devname, int fd, close(lfd); return 1; } + if (tst->ss->external) { + /* + * Before dropping our exclusive open we make an + * attempt at preventing mdmon from seeing an + * 'add' event before reconciling this 'remove' + * event. + */ + char *name = devnum2devname(fd2devnum(fd)); + + if (!name) { + fprintf(stderr, Name ": unable to get container name\n"); + return 1; + } + + ping_manager(name); + free(name); + } close(lfd); if (verbose >= 0) fprintf(stderr, Name ": hot removed %s\n",