diff --git a/Incremental.c b/Incremental.c index 36f79ef..1b7ebfa 100644 --- a/Incremental.c +++ b/Incremental.c @@ -1578,9 +1578,11 @@ static int Incremental_container(struct supertype *st, char *devname, int IncrementalRemove(char *devname, char *id_path, int verbose) { int mdfd; - int rv; + int rv = 0; struct mdstat_ent *ent; struct mddev_dev devlist; + struct mdinfo mdi; + char buf[32]; if (!id_path) dprintf(Name ": incremental removal without --path " @@ -1598,6 +1600,14 @@ int IncrementalRemove(char *devname, char *id_path, int verbose) "of any array\n", devname); return 1; } + sysfs_init(&mdi, -1, ent->devnm); + if (sysfs_get_str(&mdi, NULL, "array_state", + buf, sizeof(buf)) > 0) { + if (strncmp(buf, "active", 6) == 0 || + strncmp(buf, "clean", 5) == 0) + sysfs_set_str(&mdi, NULL, + "array_state", "read-auto"); + } mdfd = open_dev(ent->devnm); if (mdfd < 0) { pr_err("Cannot open array %s!!\n", ent->dev); @@ -1625,17 +1635,30 @@ int IncrementalRemove(char *devname, char *id_path, int verbose) if (is_container_member(memb, ent->dev)) { int subfd = open_dev(memb->devnm); if (subfd >= 0) { - Manage_subdevs(memb->dev, subfd, - &devlist, verbose, 0, - NULL, 0); + rv |= Manage_subdevs( + memb->dev, subfd, + &devlist, verbose, 0, + NULL, 0); close(subfd); } } free_mdstat(mdstat); } else - Manage_subdevs(ent->dev, mdfd, &devlist, verbose, 0, NULL, 0); - devlist.disposition = 'r'; - rv = Manage_subdevs(ent->dev, mdfd, &devlist, verbose, 0, NULL, 0); + rv |= Manage_subdevs(ent->dev, mdfd, &devlist, + verbose, 0, NULL, 0); + if (rv & 2) { + /* Failed due to EBUSY, try to stop the array + */ + rv = Manage_runstop(ent->dev, mdfd, -1, + verbose, 1); + if (rv) + /* At least we can try to trigger a 'remove' */ + sysfs_uevent(&mdi, "remove"); + } else { + devlist.disposition = 'r'; + rv = Manage_subdevs(ent->dev, mdfd, &devlist, + verbose, 0, NULL, 0); + } close(mdfd); free_mdstat(ent); return rv; diff --git a/Manage.c b/Manage.c index 6267c0c..c7738e1 100644 --- a/Manage.c +++ b/Manage.c @@ -222,7 +222,10 @@ int Manage_runstop(char *devname, int fd, int runstop, * to stop is probably a bad idea. */ close(fd); - fd = open(devname, O_RDONLY|O_EXCL); + if (devnm[0] == '/') + fd = open(devname, O_RDONLY|O_EXCL); + else + fd = open_dev_flags(devnm, O_RDONLY|O_EXCL); if (fd < 0 || strcmp(fd2devnm(fd), devnm) != 0) { if (fd >= 0) close(fd); @@ -1100,6 +1103,7 @@ int Manage_subdevs(char *devname, int fd, int count = 0; /* number of actions taken */ struct mdinfo info; int frozen = 0; + int busy = 0; if (ioctl(fd, GET_ARRAY_INFO, &array)) { pr_err("Cannot get array info for %s\n", @@ -1320,6 +1324,8 @@ int Manage_subdevs(char *devname, int fd, if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) || (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev))) { + if (errno == EBUSY) + busy = 1; pr_err("set device faulty failed for %s: %s\n", dv->devname, strerror(errno)); if (sysfd >= 0) @@ -1377,7 +1383,7 @@ int Manage_subdevs(char *devname, int fd, abort: if (frozen > 0) sysfs_set_str(&info, NULL, "sync_action","idle"); - return 1; + return !test && busy ? 2 : 1; } int autodetect(void)