X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=Manage.c;h=66d697803e2866923897e7a3af27b70749631432;hb=42de2ac27d632236909f88bd5309161a32379327;hp=8c86a5328abf5750b8b3b69422164010f74b1a0a;hpb=5b660791b4afb9b24b13cbf4877ea62e4e832537;p=thirdparty%2Fmdadm.git diff --git a/Manage.c b/Manage.c index 8c86a532..66d69780 100644 --- a/Manage.c +++ b/Manage.c @@ -208,29 +208,63 @@ int Manage_runstop(char *devname, int fd, int runstop, int quiet) struct stat stb; struct mdinfo *mdi; int devnum; + int err; + int count; /* If this is an mdmon managed array, just write 'inactive' * to the array state and let mdmon clear up. */ devnum = fd2devnum(fd); + /* Get EXCL access first. If this fails, then attempting + * to stop is probably a bad idea. + */ + close(fd); + fd = open(devname, O_RDONLY|O_EXCL); + if (fd < 0 || fd2devnum(fd) != devnum) { + if (fd >= 0) + close(fd); + fprintf(stderr, + Name ": Cannot get exclusive access to %s:" + "Perhaps a running " + "process, mounted filesystem " + "or active volume group?\n", + devname); + return 1; + } mdi = sysfs_read(fd, -1, GET_LEVEL|GET_VERSION); if (mdi && mdi->array.level > 0 && is_subarray(mdi->text_version)) { + int err; /* This is mdmon managed. */ close(fd); - if (sysfs_set_str(mdi, NULL, - "array_state", "inactive") < 0) { - if (quiet == 0) - fprintf(stderr, Name - ": failed to stop array %s: %s\n", - devname, strerror(errno)); + + count = 25; + while (count && + (err = sysfs_set_str(mdi, NULL, + "array_state", + "inactive")) < 0 + && errno == EBUSY) { + usleep(200000); + count--; + } + if (err && !quiet) { + fprintf(stderr, Name + ": failed to stop array %s: %s\n", + devname, strerror(errno)); return 1; } /* Give monitor a chance to act */ ping_monitor(mdi->text_version); - fd = open(devname, O_RDONLY); + fd = open_dev_excl(devnum); + if (fd < 0) { + fprintf(stderr, Name + ": failed to completely stop %s" + ": Device is busy\n", + devname); + return 1; + } } else if (mdi && mdi->array.major_version == -1 && mdi->array.minor_version == -2 && @@ -263,7 +297,18 @@ int Manage_runstop(char *devname, int fd, int runstop, int quiet) } } - if (fd >= 0 && ioctl(fd, STOP_ARRAY, NULL)) { + /* As we have an O_EXCL open, any use of the device + * which blocks STOP_ARRAY is probably a transient use, + * so it is reasonable to retry for a while - 5 seconds. + */ + count = 25; err = 0; + while (count && fd >= 0 + && (err = ioctl(fd, STOP_ARRAY, NULL)) < 0 + && errno == EBUSY) { + usleep(200000); + count --; + } + if (fd >= 0 && err) { if (quiet == 0) { fprintf(stderr, Name ": failed to stop array %s: %s\n", @@ -393,19 +438,21 @@ int Manage_subdevs(char *devname, int fd, if (strcmp(dv->devname, "failed")==0 || strcmp(dv->devname, "faulty")==0) { + int remaining_disks = array.nr_disks; if (dv->disposition != 'r') { fprintf(stderr, Name ": %s only meaningful " "with -r, not -%c\n", dv->devname, dv->disposition); return 1; } - for (; j < array.raid_disks + array.nr_disks ; j++) { + for (; j < 1024 && remaining_disks > 0; j++) { unsigned dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; if (disc.major == 0 && disc.minor == 0) continue; + remaining_disks --; if ((disc.state & 1) == 0) /* faulty */ continue; dev = makedev(disc.major, disc.minor); @@ -424,13 +471,14 @@ int Manage_subdevs(char *devname, int fd, if (next != dv) continue; } else if (strcmp(dv->devname, "detached") == 0) { + int remaining_disks = array.nr_disks; if (dv->disposition != 'r' && dv->disposition != 'f') { fprintf(stderr, Name ": %s only meaningful " "with -r of -f, not -%c\n", dv->devname, dv->disposition); return 1; } - for (; j < array.raid_disks + array.nr_disks; j++) { + for (; j < 1024 && remaining_disks > 0; j++) { int sfd; unsigned dev; disc.number = j; @@ -438,6 +486,7 @@ int Manage_subdevs(char *devname, int fd, continue; if (disc.major == 0 && disc.minor == 0) continue; + remaining_disks --; sprintf(dvname,"%d:%d", disc.major, disc.minor); sfd = dev_open(dvname, O_RDONLY); if (sfd >= 0) { @@ -637,7 +686,7 @@ int Manage_subdevs(char *devname, int fd, /* FIXME this is a bad test to be using */ if (!tst->sb) { close(tfd); - fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n"); + fprintf(stderr, Name ": cannot load array metadata from %s\n", devname); return 1; } @@ -659,13 +708,7 @@ int Manage_subdevs(char *devname, int fd, */ tst->ss->uuid_from_super(tst, duuid); - /* re-add doesn't work for version-1 superblocks - * before 2.6.18 :-( - */ - if (array.major_version == 1 && - get_linux_version() <= 2006018) - ; - else if (st->sb) { + if (st->sb) { struct mdinfo mdi; st->ss->getinfo_super(st, &mdi, NULL); st->ss->uuid_from_super(st, ouuid); @@ -675,6 +718,12 @@ int Manage_subdevs(char *devname, int fd, /* look like it is worth a try. Need to * make sure kernel will accept it though. */ + /* re-add doesn't work for version-1 superblocks + * before 2.6.18 :-( + */ + if (array.major_version == 1 && + get_linux_version() <= 2006018) + goto skip_re_add; disc.number = mdi.disk.number; if (ioctl(fd, GET_DISK_INFO, &disc) != 0 || disc.major != 0 || disc.minor != 0 @@ -701,7 +750,7 @@ int Manage_subdevs(char *devname, int fd, st, NULL, update, devname, verbose, 0, NULL); if (rv == 0) - rv = tst->ss->store_super(st, tfd); + rv = st->ss->store_super(st, tfd); close(tfd); tfd = -1; if (rv != 0) { @@ -796,14 +845,11 @@ int Manage_subdevs(char *devname, int fd, disc.minor = minor(stb.st_rdev); disc.number =j; disc.state = 0; - if (array.not_persistent==0 || tst->ss->external) { + if (array.not_persistent==0) { int dfd; if (dv->writemostly == 1) disc.state |= 1 << MD_DISK_WRITEMOSTLY; dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT); - if (tst->ss->external && - mdmon_running(tst->container_dev)) - tst->update_tail = &tst->updates; if (tst->ss->add_to_super(tst, &disc, dfd, dv->devname)) { close(dfd); @@ -852,6 +898,7 @@ int Manage_subdevs(char *devname, int fd, struct mdinfo *sra; int container_fd; int devnum = fd2devnum(fd); + int dfd; container_fd = open_dev_excl(devnum); if (container_fd < 0) { @@ -862,6 +909,20 @@ int Manage_subdevs(char *devname, int fd, return 1; } + dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT); + if (mdmon_running(tst->container_dev)) + tst->update_tail = &tst->updates; + if (tst->ss->add_to_super(tst, &disc, dfd, + dv->devname)) { + close(dfd); + close(container_fd); + return 1; + } + if (tst->update_tail) + flush_metadata_updates(tst); + else + tst->ss->sync_metadata(tst); + sra = sysfs_read(container_fd, -1, 0); if (!sra) { fprintf(stderr, Name ": add failed for %s: sysfs_read failed\n", @@ -886,7 +947,7 @@ int Manage_subdevs(char *devname, int fd, sysfs_free(sra); return 1; } - ping_monitor(devnum2devname(devnum)); + ping_monitor_by_id(devnum); sysfs_free(sra); close(container_fd); } else {