diff options
Diffstat (limited to 'Manage.c')
-rw-r--r-- | Manage.c | 187 |
1 files changed, 83 insertions, 104 deletions
@@ -26,6 +26,8 @@ #include "md_u.h" #include "md_p.h" #include "udev.h" +#include "xmalloc.h" + #include <ctype.h> int Manage_ro(char *devname, int fd, int readonly) @@ -238,13 +240,14 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) "array_state", "inactive")) < 0 && errno == EBUSY) { + err = errno; sleep_for(0, MSEC_TO_NSEC(200), true); count--; } if (err) { if (verbose >= 0) pr_err("failed to stop array %s: %s\n", - devname, strerror(errno)); + devname, strerror(err)); rv = 1; goto out; } @@ -276,10 +279,8 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) */ mds = mdstat_read(0, 0); for (m = mds; m; m = m->next) - if (m->metadata_version && - strncmp(m->metadata_version, "external:", 9)==0 && - metadata_container_matches(m->metadata_version+9, - devnm)) { + if (is_mdstat_ent_external(m) && + metadata_container_matches(m->metadata_version + 9, devnm)) { if (verbose >= 0) pr_err("Cannot stop container %s: member %s still active\n", devname, m->devnm); @@ -440,14 +441,15 @@ done: count = 25; err = 0; while (count && fd >= 0 && (err = ioctl(fd, STOP_ARRAY, NULL)) < 0 && errno == EBUSY) { + err = errno; sleep_for(0, MSEC_TO_NSEC(200), true); count --; } if (fd >= 0 && err) { if (verbose >= 0) { pr_err("failed to stop array %s: %s\n", - devname, strerror(errno)); - if (errno == EBUSY) + devname, strerror(err)); + if (err == EBUSY) cont_err("Perhaps a running process, mounted filesystem or active volume group?\n"); } rv = 1; @@ -791,6 +793,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, int j; mdu_disk_info_t disc; struct map_ent *map = NULL; + bool add_new_super = false; if (!get_dev_size(tfd, dv->devname, &ldsize)) { if (dv->disposition == 'M') @@ -1009,6 +1012,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, goto unlock; if (tst->ss->write_init_super(tst)) goto unlock; + add_new_super = true; } else if (dv->disposition == 'A') { /* this had better be raid1. * As we are "--re-add"ing we must find a spare slot @@ -1076,6 +1080,8 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, map_unlock(&map); return 1; unlock: + if (add_new_super) + Kill(dv->devname, tst, 0, -1, 0); map_unlock(&map); return -1; } @@ -1439,29 +1445,25 @@ int Manage_subdevs(char *devname, int fd, for (dv = devlist; dv; dv = dv->next) { dev_t rdev = 0; /* device to add/remove etc */ - int rv; - int mj,mn; + int rv, err = 0; + int mj, mn; raid_slot = -1; if (dv->disposition == 'c') { - rv = parse_cluster_confirm_arg(dv->devname, - &dv->devname, - &raid_slot); + rv = parse_cluster_confirm_arg(dv->devname, &dv->devname, &raid_slot); if (rv) { pr_err("Could not get the devname of cluster\n"); goto abort; } } - if (strcmp(dv->devname, "failed") == 0 || - strcmp(dv->devname, "faulty") == 0) { + if (strcmp(dv->devname, "failed") == 0 || strcmp(dv->devname, "faulty") == 0) { if (dv->disposition != 'A' && dv->disposition != 'r') { pr_err("%s only meaningful with -r or --re-add, not -%c\n", dv->devname, dv->disposition); goto abort; } - add_faulty(dv, fd, (dv->disposition == 'A' - ? 'F' : 'r')); + add_faulty(dv, fd, (dv->disposition == 'A' ? 'F' : 'r')); continue; } if (strcmp(dv->devname, "detached") == 0) { @@ -1477,6 +1479,7 @@ int Manage_subdevs(char *devname, int fd, if (strcmp(dv->devname, "missing") == 0) { struct mddev_dev *add_devlist; struct mddev_dev **dp; + if (dv->disposition == 'c') { rv = ioctl(fd, CLUSTERED_DISK_NACK, NULL); break; @@ -1491,7 +1494,7 @@ int Manage_subdevs(char *devname, int fd, pr_err("no devices to scan for missing members.\n"); continue; } - for (dp = &add_devlist; *dp; dp = & (*dp)->next) + for (dp = &add_devlist; *dp; dp = &(*dp)->next) /* 'M' (for 'missing') is like 'A' without errors */ (*dp)->disposition = 'M'; *dp = dv->next; @@ -1499,74 +1502,50 @@ int Manage_subdevs(char *devname, int fd, continue; } - if (strncmp(dv->devname, "set-", 4) == 0 && - strlen(dv->devname) == 5) { + if (strncmp(dv->devname, "set-", 4) == 0 && strlen(dv->devname) == 5) { int copies; - if (dv->disposition != 'r' && - dv->disposition != 'f') { - pr_err("'%s' only meaningful with -r or -f\n", - dv->devname); + if (dv->disposition != 'r' && dv->disposition != 'f') { + pr_err("'%s' only meaningful with -r or -f\n", dv->devname); goto abort; } + if (array.level != 10) { - pr_err("'%s' only meaningful with RAID10 arrays\n", - dv->devname); + pr_err("'%s' only meaningful with RAID10 arrays\n", dv->devname); goto abort; } - copies = ((array.layout & 0xff) * - ((array.layout >> 8) & 0xff)); - if (array.raid_disks % copies != 0 || - dv->devname[4] < 'A' || - dv->devname[4] >= 'A' + copies || - copies > 26) { - pr_err("'%s' not meaningful with this array\n", - dv->devname); + + copies = ((array.layout & 0xff) * ((array.layout >> 8) & 0xff)); + + if (array.raid_disks % copies != 0 || dv->devname[4] < 'A' || + dv->devname[4] >= 'A' + copies || copies > 26) { + pr_err("'%s' not meaningful with this array\n", dv->devname); goto abort; } add_set(dv, fd, dv->devname[4]); continue; } - if (strchr(dv->devname, '/') == NULL && - strchr(dv->devname, ':') == NULL && + if (!strchr(dv->devname, '/') && !strchr(dv->devname, ':') && 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' && - dv->disposition != 'I') { + char *array_devnm = fd2devnm(fd); + + /* This is a kernel-internal name like 'sda1' */ + + if (!strchr("rfI", dv->disposition)) { pr_err("%s only meaningful with -r, -f or -I, not -%c\n", dv->devname, dv->disposition); goto abort; } - sprintf(dname, "dev-%s", dv->devname); - sysfd = sysfs_open(fd2devnm(fd), dname, "block/dev"); - if (sysfd >= 0) { - char dn[SYSFS_MAX_BUF_SIZE]; - if (sysfs_fd_get_str(sysfd, dn, sizeof(dn)) > 0 && - sscanf(dn, "%d:%d", &mj,&mn) == 2) { - rdev = makedev(mj,mn); - found = 1; - } - close_fd(&sysfd); - sysfd = -1; - } - if (!found) { - sysfd = sysfs_open(fd2devnm(fd), dname, "state"); - if (sysfd < 0) { - pr_err("%s does not appear to be a component of %s\n", - dv->devname, devname); + sysfd = sysfs_open_memb_attr(array_devnm, dv->devname, "state", O_RDWR); + if (!is_fd_valid(sysfd)) { + pr_err("%s does not appear to be a component of %s\n", dv->devname, + devname); goto abort; } - } - } else if ((dv->disposition == 'r' || - dv->disposition == 'f') && - get_maj_min(dv->devname, &mj, &mn)) { - /* for 'fail' and 'remove', the device might - * not exist. - */ + } else if (strchr("rf", dv->disposition) && get_maj_min(dv->devname, &mj, &mn)) { + /* for 'fail' and 'remove', the device might not exist. */ rdev = makedev(mj, mn); } else { tfd = dev_open(dv->devname, O_RDONLY); @@ -1575,6 +1554,7 @@ int Manage_subdevs(char *devname, int fd, close_fd(&tfd); } else { int open_err = errno; + if (!stat_is_blkdev(dv->devname, &rdev)) { if (dv->disposition == 'M') /* non-fatal. Also improbable */ @@ -1590,16 +1570,15 @@ int Manage_subdevs(char *devname, int fd, if (dv->disposition == 'M') /* non-fatal */ continue; - pr_err("Cannot open %s: %s\n", - dv->devname, strerror(open_err)); + pr_err("Cannot open %s: %s\n", dv->devname, + strerror(open_err)); goto abort; } } } - switch(dv->disposition){ + switch (dv->disposition) { default: - pr_err("internal error - devmode[%s]=%d\n", - dv->devname, dv->disposition); + pr_err("internal error - devmode[%s]=%d\n", dv->devname, dv->disposition); goto abort; case 'a': case 'S': /* --add-spare */ @@ -1615,12 +1594,11 @@ int Manage_subdevs(char *devname, int fd, } /* Let's first try to write re-add to sysfs */ - if (rdev != 0 && - (dv->disposition == 'A' || dv->disposition == 'F')) { + if (rdev != 0 && (dv->disposition == 'A' || dv->disposition == 'F')) { sysfs_init_dev(&devinfo, rdev); if (sysfs_set_str(&info, &devinfo, "state", "re-add") == 0) { - pr_err("re-add %s to %s succeed\n", - dv->devname, info.sys_name); + pr_err("re-add %s to %s succeed\n", dv->devname, + info.sys_name); break; } } @@ -1651,8 +1629,7 @@ int Manage_subdevs(char *devname, int fd, else frozen = -1; } - rv = Manage_add(fd, tfd, dv, tst, &array, - force, verbose, devname, update, + rv = Manage_add(fd, tfd, dv, tst, &array, force, verbose, devname, update, rdev, array_size, raid_slot); close_fd(&tfd); if (rv < 0) @@ -1667,12 +1644,10 @@ int Manage_subdevs(char *devname, int fd, pr_err("Cannot remove disks from a \'member\' array, perform this operation on the parent container\n"); rv = -1; } else - rv = Manage_remove(tst, fd, dv, sysfd, - rdev, verbose, force, + rv = Manage_remove(tst, fd, dv, sysfd, rdev, verbose, force, devname); - if (sysfd >= 0) - close_fd(&sysfd); - sysfd = -1; + close_fd(&sysfd); + if (rv < 0) goto abort; if (rv > 0) @@ -1686,23 +1661,31 @@ int Manage_subdevs(char *devname, int fd, close_fd(&sysfd); goto abort; } - case 'I': /* incremental fail */ - if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) || - (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY, - rdev))) { - if (errno == EBUSY) - busy = 1; - pr_err("set device faulty failed for %s: %s\n", - dv->devname, strerror(errno)); - close_fd(&sysfd); - goto abort; + case 'I': + if (is_fd_valid(sysfd)) { + static const char val[] = "faulty"; + + rv = sysfs_write_descriptor(sysfd, val, strlen(val), &err); + } else { + rv = ioctl(fd, SET_DISK_FAULTY, rdev); + if (rv) + err = errno; } + close_fd(&sysfd); - count++; - if (verbose >= 0) - pr_err("set %s faulty in %s\n", - dv->devname, devname); - break; + + if (rv == MDADM_STATUS_SUCCESS) { + count++; + + pr_vrb("set %s faulty in %s\n", dv->devname, devname); + break; + } + + if (err == EBUSY) + busy = 1; + + pr_err("set device faulty failed for %s: %s\n", dv->devname, strerror(err)); + goto abort; case 'R': /* Mark as replaceable */ if (subarray) { pr_err("Cannot replace disks in a \'member\' array, perform this operation on the parent container\n"); @@ -1714,9 +1697,7 @@ int Manage_subdevs(char *devname, int fd, else frozen = -1; } - rv = Manage_replace(tst, fd, dv, - rdev, verbose, - devname); + rv = Manage_replace(tst, fd, dv, rdev, verbose, devname); } if (rv < 0) goto abort; @@ -1724,12 +1705,10 @@ int Manage_subdevs(char *devname, int fd, count++; break; case 'W': /* --with device that doesn't match */ - pr_err("No matching --replace device for --with %s\n", - dv->devname); + pr_err("No matching --replace device for --with %s\n", dv->devname); goto abort; case 'w': /* --with device which was matched */ - rv = Manage_with(tst, fd, dv, - rdev, verbose, devname); + rv = Manage_with(tst, fd, dv, rdev, verbose, devname); if (rv < 0) goto abort; break; @@ -1737,7 +1716,7 @@ int Manage_subdevs(char *devname, int fd, } free(tst); if (frozen > 0) - sysfs_set_str(&info, NULL, "sync_action","idle"); + sysfs_set_str(&info, NULL, "sync_action", "idle"); if (test && count == 0) return 2; return 0; @@ -1745,7 +1724,7 @@ int Manage_subdevs(char *devname, int fd, abort: free(tst); if (frozen > 0) - sysfs_set_str(&info, NULL, "sync_action","idle"); + sysfs_set_str(&info, NULL, "sync_action", "idle"); return !test && busy ? 2 : 1; } |