Manage: simplify device searches in Manage_subdevs

We currently have rather hard-to-follow loop to iterate
through all the matches for 'missing' or 'faulty' or 'detached'.

Simplify it by creating a list of possible devices for each
of those and splicing the new list into the device list.

This removes the need for 'jnext' and 'next' and various other hacks.

Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
NeilBrown 2012-07-09 17:22:16 +10:00
parent 50f01ba5a1
commit 1d9976430c
1 changed files with 133 additions and 113 deletions

246
Manage.c
View File

@ -378,6 +378,80 @@ int Manage_resize(char *devname, int fd, long long size, int raid_disks)
return 0;
}
static void add_faulty(struct mddev_dev *dv, int fd, char disp)
{
mdu_array_info_t array;
mdu_disk_info_t disk;
int remaining_disks;
int i;
if (ioctl(fd, GET_ARRAY_INFO, &array) != 0)
return;
remaining_disks = array.nr_disks;
for (i = 0; i < MAX_DISKS && remaining_disks > 0; i++) {
struct mddev_dev *new;
char buf[40];
disk.number = i;
if (ioctl(fd, GET_DISK_INFO, &disk) != 0)
continue;
if (disk.major == 0 && disk.minor == 0)
continue;
remaining_disks--;
if ((disk.state & 1) == 0) /* not faulty */
continue;
sprintf(buf, "%d:%d", disk.major, disk.minor);
new = xmalloc(sizeof(*new));
new->devname = xstrdup(buf);
new->disposition = disp;
new->next = dv->next;
dv->next = new;
dv = new;
}
}
static void add_detached(struct mddev_dev *dv, int fd, char disp)
{
mdu_array_info_t array;
mdu_disk_info_t disk;
int remaining_disks;
int i;
if (ioctl(fd, GET_ARRAY_INFO, &array) != 0)
return;
remaining_disks = array.nr_disks;
for (i = 0; i < MAX_DISKS && remaining_disks > 0; i++) {
struct mddev_dev *new;
char buf[40];
int sfd;
disk.number = i;
if (ioctl(fd, GET_DISK_INFO, &disk) != 0)
continue;
if (disk.major == 0 && disk.minor == 0)
continue;
remaining_disks--;
if (disp == 'f' && (disk.state & 1) != 0) /* already faulty */
continue;
sprintf(buf, "%d:%d", disk.major, disk.minor);
sfd = dev_open(buf, O_RDONLY);
if (sfd >= 0) {
/* Not detached */
close(sfd);
continue;
}
if (errno != ENXIO)
/* Probably not detached */
continue;
new = xmalloc(sizeof(*new));
new->devname = xstrdup(buf);
new->disposition = disp;
new->next = dv->next;
dv->next = new;
dv = new;
}
}
int Manage_subdevs(char *devname, int fd,
struct mddev_dev *devlist, int verbose, int test,
char *update, int force)
@ -396,13 +470,12 @@ int Manage_subdevs(char *devname, int fd,
* For 'f' and 'r', the device can also be a kernel-internal
* name such as 'sdb'.
*/
struct mddev_dev *add_devlist = NULL;
mdu_array_info_t array;
mdu_disk_info_t disc;
unsigned long long array_size;
struct mddev_dev *dv, *next = NULL;
struct mddev_dev *dv;
struct stat stb;
int j, jnext = 0;
int j;
int tfd = -1;
struct supertype *st, *tst;
char *subarray = NULL;
@ -437,112 +510,55 @@ int Manage_subdevs(char *devname, int fd,
}
stb.st_rdev = 0;
for (dv = devlist, j=0 ; dv; dv = next, j = jnext) {
for (dv = devlist, j=0 ; dv; dv = dv->next) {
unsigned long long ldsize;
char dvname[20];
char *dnprintable = dv->devname;
char *add_dev = dv->devname;
int err;
int array_failed;
next = dv->next;
jnext = 0;
if (strcmp(dv->devname, "failed")==0 ||
strcmp(dv->devname, "faulty")==0) {
int remaining_disks = array.nr_disks;
if (strcmp(dv->devname, "failed") == 0 ||
strcmp(dv->devname, "faulty") == 0) {
if (dv->disposition != 'r') {
pr_err("%s only meaningful "
"with -r, not -%c\n",
dv->devname, dv->disposition);
goto abort;
}
for (; j < MAX_DISKS && 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);
if (stb.st_rdev == dev)
/* already did that one */
continue;
stb.st_rdev = dev;
next = dv;
/* same slot again next time - things might
* have reshuffled */
jnext = j;
sprintf(dvname,"%d:%d", disc.major, disc.minor);
dnprintable = dvname;
break;
}
if (next != dv)
continue;
} else if (strcmp(dv->devname, "detached") == 0) {
int remaining_disks = array.nr_disks;
add_faulty(dv, fd, 'r');
continue;
}
if (strcmp(dv->devname, "detached") == 0) {
if (dv->disposition != 'r' && dv->disposition != 'f') {
pr_err("%s only meaningful "
"with -r of -f, not -%c\n",
dv->devname, dv->disposition);
goto abort;
}
for (; j < MAX_DISKS && remaining_disks > 0; j++) {
int sfd;
unsigned dev;
disc.number = j;
if (ioctl(fd, GET_DISK_INFO, &disc))
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) {
close(sfd);
continue;
}
if (dv->disposition == 'f' &&
(disc.state & 1) == 1) /* already faulty */
continue;
if (errno != ENXIO)
continue;
dev = makedev(disc.major, disc.minor);
if (stb.st_rdev == dev)
/* already did that one */
continue;
stb.st_rdev = dev;
next = dv;
/* same slot again next time - things might
* have reshuffled */
jnext = j;
dnprintable = dvname;
break;
}
if (next != dv)
continue;
} else if (strcmp(dv->devname, "missing") == 0) {
add_detached(dv, fd, dv->disposition);
continue;
}
if (strcmp(dv->devname, "missing") == 0) {
struct mddev_dev *add_devlist = NULL;
struct mddev_dev **dp;
if (dv->disposition != 'A') {
pr_err("'missing' only meaningful "
"with --re-add\n");
goto abort;
}
if (add_devlist == NULL)
add_devlist = conf_get_devs();
add_devlist = conf_get_devs();
if (add_devlist == NULL) {
pr_err("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 &&
for (dp = &add_devlist; *dp; dp = & (*dp)->next)
/* 'M' is like 'A' without errors */
(*dp)->disposition = 'M';
*dp = dv->next;
dv->next = add_devlist;
continue;
}
if (strchr(dv->devname, '/') == NULL &&
strchr(dv->devname, ':') == NULL &&
strlen(dv->devname) < 50) {
/* Assume this is a kernel-internal name like 'sda1' */
@ -589,16 +605,22 @@ int Manage_subdevs(char *devname, int fd,
;
else {
if (tfd < 0 || fstat(tfd, &stb) != 0) {
pr_err("cannot find %s: %s\n",
dv->devname, strerror(errno));
if (tfd >= 0)
close(tfd);
if (dv->disposition == 'M')
/* non-fatal */
continue;
pr_err("cannot find %s: %s\n",
dv->devname, strerror(errno));
goto abort;
}
close(tfd);
tfd = -1;
}
if ((stb.st_mode & S_IFMT) != S_IFBLK) {
if (dv->disposition == 'M')
/* non-fatal. Also improbable */
continue;
pr_err("%s is not a "
"block device.\n",
dv->devname);
@ -612,6 +634,7 @@ int Manage_subdevs(char *devname, int fd,
goto abort;
case 'a':
case 'A':
case 'M':
/* add the device */
if (subarray) {
pr_err("Cannot add disks to a"
@ -620,10 +643,10 @@ int Manage_subdevs(char *devname, int fd,
goto abort;
}
/* Make sure it isn't in use (in 2.6 or later) */
tfd = dev_open(add_dev, O_RDONLY|O_EXCL|O_DIRECT);
if (tfd < 0 && add_dev != dv->devname)
continue;
tfd = dev_open(dv->devname, O_RDONLY|O_EXCL);
if (tfd < 0) {
if (dv->disposition == 'M')
continue;
pr_err("Cannot open %s: %s\n",
dv->devname, strerror(errno));
goto abort;
@ -640,17 +663,14 @@ int Manage_subdevs(char *devname, int fd,
if (array.not_persistent==0)
st->ss->load_super(st, tfd, NULL);
if (add_dev == dv->devname) {
if (!get_dev_size(tfd, dv->devname, &ldsize)) {
st->ss->free_super(st);
close(tfd);
goto abort;
}
} else if (!get_dev_size(tfd, NULL, &ldsize)) {
if (!get_dev_size(tfd, dv->devname, &ldsize)) {
st->ss->free_super(st);
close(tfd);
tfd = -1;
continue;
if (dv->disposition == 'M')
continue;
else
goto abort;
}
if (tst->ss->validate_geometry(
@ -662,7 +682,7 @@ int Manage_subdevs(char *devname, int fd,
"effectively use.\n"
" Add --force is you "
"really want to add this device.\n",
add_dev, devname);
dv->devname, devname);
st->ss->free_super(st);
close(tfd);
goto abort;
@ -671,7 +691,7 @@ int Manage_subdevs(char *devname, int fd,
"effectively use.\n"
" Adding anyway as --force "
"was given.\n",
add_dev, devname);
dv->devname, devname);
}
if (!tst->ss->external &&
array.major_version == 0 &&
@ -683,12 +703,12 @@ int Manage_subdevs(char *devname, int fd,
(unsigned long)stb.st_rdev)==0) {
if (verbose >= 0)
pr_err("hot added %s\n",
add_dev);
dv->devname);
continue;
}
pr_err("hot add failed for %s: %s\n",
add_dev, strerror(errno));
dv->devname, strerror(errno));
goto abort;
}
@ -726,7 +746,7 @@ int Manage_subdevs(char *devname, int fd,
break;
}
/* FIXME this is a bad test to be using */
if (!tst->sb && dv->disposition == 'A') {
if (!tst->sb && dv->disposition != 'a') {
/* we are re-adding a device to a
* completely dead array - have to depend
* on kernel to check
@ -744,7 +764,7 @@ int Manage_subdevs(char *devname, int fd,
close(tfd);
tfd = -1;
st->ss->free_super(st);
if (add_dev != dv->devname)
if (dv->disposition == 'M')
continue;
pr_err("%s not large enough to join array\n",
dv->devname);
@ -831,16 +851,16 @@ int Manage_subdevs(char *devname, int fd,
errno = 0;
if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) {
if (verbose >= 0)
pr_err("re-added %s\n", add_dev);
pr_err("re-added %s\n", dv->devname);
count++;
st->ss->free_super(st);
continue;
}
if (errno == ENOMEM || errno == EROFS) {
pr_err("add new device failed for %s: %s\n",
add_dev, strerror(errno));
dv->devname, strerror(errno));
st->ss->free_super(st);
if (add_dev != dv->devname)
if (dv->disposition == 'M')
continue;
goto abort;
}
@ -848,10 +868,10 @@ int Manage_subdevs(char *devname, int fd,
skip_re_add:
st->ss->free_super(st);
}
if (add_dev != dv->devname) {
if (dv->disposition == 'M') {
if (verbose > 0)
pr_err("--re-add for %s to %s is not possible\n",
add_dev, devname);
dv->devname, devname);
if (tfd >= 0) {
close(tfd);
tfd = -1;
@ -1085,7 +1105,7 @@ int Manage_subdevs(char *devname, int fd,
/* pass */;
else {
pr_err("%s is %s, cannot remove.\n",
dnprintable,
dv->devname,
errno == EEXIST ? "still in use":
"not a member");
close(lfd);
@ -1128,7 +1148,7 @@ int Manage_subdevs(char *devname, int fd,
}
if (err) {
pr_err("hot remove failed "
"for %s: %s\n", dnprintable,
"for %s: %s\n", dv->devname,
strerror(errno));
if (lfd >= 0)
close(lfd);
@ -1156,7 +1176,7 @@ int Manage_subdevs(char *devname, int fd,
count++;
if (verbose >= 0)
pr_err("hot removed %s from %s\n",
dnprintable, devname);
dv->devname, devname);
break;
case 'f': /* set faulty */
@ -1165,7 +1185,7 @@ int Manage_subdevs(char *devname, int fd,
(sysfd < 0 && ioctl(fd, SET_DISK_FAULTY,
(unsigned long) stb.st_rdev))) {
pr_err("set device faulty failed for %s: %s\n",
dnprintable, strerror(errno));
dv->devname, strerror(errno));
if (sysfd >= 0)
close(sysfd);
goto abort;
@ -1176,7 +1196,7 @@ int Manage_subdevs(char *devname, int fd,
count++;
if (verbose >= 0)
pr_err("set %s faulty in %s\n",
dnprintable, devname);
dv->devname, devname);
break;
}
}