diff options
Diffstat (limited to 'Manage.c')
-rw-r--r-- | Manage.c | 214 |
1 files changed, 175 insertions, 39 deletions
@@ -326,7 +326,7 @@ int Manage_resize(char *devname, int fd, long long size, int raid_disks) } int Manage_subdevs(char *devname, int fd, - mddev_dev_t devlist, int verbose) + mddev_dev_t devlist, int verbose, int test) { /* do something to each dev. * devmode can be @@ -339,7 +339,10 @@ int Manage_subdevs(char *devname, int fd, * 'f' - set the device faulty SET_DISK_FAULTY * device can be 'detached' in which case any device that * is inaccessible will be marked faulty. + * For 'f' and 'r', the device can also be a kernel-internal + * name such as 'sdb'. */ + mddev_dev_t add_devlist = NULL; mdu_array_info_t array; mdu_disk_info_t disc; unsigned long long array_size; @@ -351,6 +354,8 @@ int Manage_subdevs(char *devname, int fd, int duuid[4]; int ouuid[4]; int lfd = -1; + int sysfd = -1; + int count = 0; /* number of actions taken */ if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": cannot get array info for %s\n", @@ -373,10 +378,12 @@ int Manage_subdevs(char *devname, int fd, return 1; } + stb.st_rdev = 0; for (dv = devlist, j=0 ; dv; dv = next, j = jnext) { unsigned long long ldsize; char dvname[20]; char *dnprintable = dv->devname; + char *add_dev = dv->devname; int err; next = dv->next; @@ -391,6 +398,7 @@ int Manage_subdevs(char *devname, int fd, return 1; } for (; j < array.raid_disks + array.nr_disks ; j++) { + int dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; @@ -398,9 +406,15 @@ int Manage_subdevs(char *devname, int fd, continue; if ((disc.state & 1) == 0) /* faulty */ continue; - stb.st_rdev = makedev(disc.major, disc.minor); + dev = makedev(disc.major, disc.minor); + if (stb.st_rdev == dev) + /* already did that one */ + continue; + stb.st_rdev = dev; next = dv; - jnext = j+1; + /* same slot again next time - things might + * have reshuffled */ + jnext = j; sprintf(dvname,"%d:%d", disc.major, disc.minor); dnprintable = dvname; break; @@ -416,6 +430,7 @@ int Manage_subdevs(char *devname, int fd, } for (; j < array.raid_disks + array.nr_disks; j++) { int sfd; + int dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; @@ -432,14 +447,72 @@ int Manage_subdevs(char *devname, int fd, continue; if (errno != ENXIO) continue; - stb.st_rdev = makedev(disc.major, disc.minor); + dev = makedev(disc.major, disc.minor); + if (stb.st_rdev == dev) + /* already did that one */ + continue; + stb.st_rdev = dev; next = dv; - jnext = j+1; + /* same slot again next time - things might + * have reshuffled */ + jnext = j; dnprintable = dvname; break; } if (jnext == 0) continue; + } else if (strcmp(dv->devname, "missing") == 0) { + if (dv->disposition != 'a' || dv->re_add == 0) { + fprintf(stderr, Name ": 'missing' only meaningful " + "with --re-add\n"); + return 1; + } + if (add_devlist == NULL) + add_devlist = conf_get_devs(); + if (add_devlist == NULL) { + fprintf(stderr, Name ": no devices to scan for missing members."); + continue; + } + add_dev = add_devlist->devname; + add_devlist = add_devlist->next; + if (add_devlist != NULL) + next = dv; + if (stat(add_dev, &stb) < 0) + continue; + } else if (strchr(dv->devname, '/') == NULL && + strlen(dv->devname) < 50) { + /* Assume this is a kernel-internal name like 'sda1' */ + int found = 0; + char dname[55]; + 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; + } + + sprintf(dname, "dev-%s", dv->devname); + sysfd = sysfs_open(fd2devnum(fd), dname, "block/dev"); + if (sysfd >= 0) { + char dn[20]; + int mj,mn; + if (sysfs_fd_get_str(sysfd, dn, 20) > 0 && + sscanf(dn, "%d:%d", &mj,&mn) == 2) { + stb.st_rdev = makedev(mj,mn); + found = 1; + } + close(sysfd); + sysfd = -1; + } + if (!found) { + sysfd = sysfs_open(fd2devnum(fd), dname, "state"); + if (sysfd < 0) { + fprintf(stderr, Name ": %s does not appear " + "to be a component of %s\n", + dv->devname, devname); + return 1; + } + } } else { j = 0; @@ -481,39 +554,44 @@ int Manage_subdevs(char *devname, int fd, return 1; } /* Make sure it isn't in use (in 2.6 or later) */ - tfd = dev_open(dv->devname, O_RDONLY|O_EXCL|O_DIRECT); + tfd = dev_open(add_dev, O_RDONLY|O_EXCL|O_DIRECT); + if (tfd < 0 && add_dev != dv->devname) + continue; if (tfd < 0) { fprintf(stderr, Name ": Cannot open %s: %s\n", dv->devname, strerror(errno)); return 1; } - remove_partitions(tfd); st = dup_super(tst); if (array.not_persistent==0) st->ss->load_super(st, tfd, NULL); - if (!get_dev_size(tfd, dv->devname, &ldsize)) { + if (add_dev == dv->devname) { + if (!get_dev_size(tfd, dv->devname, &ldsize)) { + close(tfd); + return 1; + } + } else if (!get_dev_size(tfd, NULL, &ldsize)) { close(tfd); - return 1; + continue; } - close(tfd); - if (!tst->ss->external && array.major_version == 0 && md_get_version(fd)%100 < 2) { + close(tfd); if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) { if (verbose >= 0) fprintf(stderr, Name ": hot added %s\n", - dv->devname); + add_dev); continue; } fprintf(stderr, Name ": hot add failed for %s: %s\n", - dv->devname, strerror(errno)); + add_dev, strerror(errno)); return 1; } @@ -524,7 +602,9 @@ int Manage_subdevs(char *devname, int fd, * For 'external' array (well, container based), * We can just load the metadata for the array. */ - if (tst->ss->external) { + if (tst->sb) + /* already loaded */; + else if (tst->ss->external) { tst->ss->load_super(tst, fd, NULL); } else for (j = 0; j < tst->max_devs; j++) { char *dev; @@ -550,6 +630,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"); return 1; } @@ -557,6 +638,9 @@ int Manage_subdevs(char *devname, int fd, /* Make sure device is large enough */ if (tst->ss->avail_size(tst, ldsize/512) < array_size) { + close(tfd); + if (add_dev != dv->devname) + continue; fprintf(stderr, Name ": %s not large enough to join array\n", dv->devname); return 1; @@ -592,23 +676,41 @@ int Manage_subdevs(char *devname, int fd, disc.state |= 1 << MD_DISK_WRITEMOSTLY; if (dv->writemostly == 2) disc.state &= ~(1 << MD_DISK_WRITEMOSTLY); + remove_partitions(tfd); + close(tfd); + tfd = -1; /* don't even try if disk is marked as faulty */ errno = 0; if ((disc.state & 1) == 0 && ioctl(fd, ADD_NEW_DISK, &disc) == 0) { if (verbose >= 0) - fprintf(stderr, Name ": re-added %s\n", dv->devname); + fprintf(stderr, Name ": re-added %s\n", add_dev); + count++; continue; } if (errno == ENOMEM || errno == EROFS) { + close(tfd); fprintf(stderr, Name ": add new device failed for %s: %s\n", - dv->devname, strerror(errno)); + add_dev, strerror(errno)); + if (add_dev != dv->devname) + continue; return 1; } /* fall back on normal-add */ } } + if (add_dev != dv->devname) { + if (verbose > 0) + fprintf(stderr, Name + ": --re-add for %s to %s is not possible\n", + add_dev, devname); + if (tfd >= 0) + close(tfd); + continue; + } if (dv->re_add) { + if (tfd >= 0) + close(tfd); fprintf(stderr, Name ": --re-add for %s to %s is not possible\n", dv->devname, devname); @@ -624,6 +726,11 @@ int Manage_subdevs(char *devname, int fd, return 1; } } + /* committed to really trying this device now*/ + if (tfd >= 0) { + remove_partitions(tfd); + close(tfd); + } /* in 2.6.17 and earlier, version-1 superblocks won't * use the number we write, but will choose a free number. * we must choose the same free number, which requires @@ -751,6 +858,8 @@ int Manage_subdevs(char *devname, int fd, fprintf(stderr, Name ": Cannot remove disks from a" " \'member\' array, perform this" " operation on the parent container\n"); + if (sysfd >= 0) + close(sysfd); return 1; } if (tst->ss->external) { @@ -769,6 +878,8 @@ int Manage_subdevs(char *devname, int fd, fprintf(stderr, Name ": Cannot get exclusive access " " to container - odd\n"); + if (sysfd >= 0) + close(sysfd); return 1; } /* in the detached case it is not possible to @@ -776,6 +887,7 @@ int Manage_subdevs(char *devname, int fd, * rely on the 'detached' checks */ if (strcmp(dv->devname, "detached") == 0 || + sysfd >= 0 || sysfs_unique_holder(dnum, stb.st_rdev)) /* pass */; else { @@ -789,25 +901,38 @@ int Manage_subdevs(char *devname, int fd, } } /* FIXME check that it is a current member */ - err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev); - if (err && errno == ENODEV) { - /* Old kernels rejected this if no personality - * registered */ - struct mdinfo *sra = sysfs_read(fd, 0, GET_DEVS); - struct mdinfo *dv = NULL; - if (sra) - dv = sra->devs; - for ( ; dv ; dv=dv->next) - if (dv->disk.major == major(stb.st_rdev) && - dv->disk.minor == minor(stb.st_rdev)) - break; - if (dv) - err = sysfs_set_str(sra, dv, - "state", "remove"); - else + if (sysfd >= 0) { + /* device has been removed and we don't know + * the major:minor number + */ + int n = write(sysfd, "remove", 6); + if (n != 6) err = -1; - if (sra) - sysfs_free(sra); + else + err = 0; + close(sysfd); + sysfd = -1; + } else { + err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev); + if (err && errno == ENODEV) { + /* Old kernels rejected this if no personality + * registered */ + struct mdinfo *sra = sysfs_read(fd, 0, GET_DEVS); + struct mdinfo *dv = NULL; + if (sra) + dv = sra->devs; + for ( ; dv ; dv=dv->next) + if (dv->disk.major == major(stb.st_rdev) && + dv->disk.minor == minor(stb.st_rdev)) + break; + if (dv) + err = sysfs_set_str(sra, dv, + "state", "remove"); + else + err = -1; + if (sra) + sysfs_free(sra); + } } if (err) { fprintf(stderr, Name ": hot remove failed " @@ -834,27 +959,38 @@ int Manage_subdevs(char *devname, int fd, ping_manager(name); free(name); } - close(lfd); + if (lfd >= 0) + close(lfd); + count++; if (verbose >= 0) - fprintf(stderr, Name ": hot removed %s\n", - dnprintable); + fprintf(stderr, Name ": hot removed %s from %s\n", + dnprintable, devname); break; case 'f': /* set faulty */ /* FIXME check current member */ - if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) { + if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) || + (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY, + (unsigned long) stb.st_rdev))) { fprintf(stderr, Name ": set device faulty failed for %s: %s\n", dnprintable, strerror(errno)); + if (sysfd >= 0) + close(sysfd); return 1; } + if (sysfd >= 0) + close(sysfd); + sysfd = -1; + count++; if (verbose >= 0) fprintf(stderr, Name ": set %s faulty in %s\n", dnprintable, devname); break; } } + if (test && count == 0) + return 2; return 0; - } int autodetect(void) |