Check all member devices in enough_fd
authorNeilBrown <neilb@suse.de>
Mon, 23 May 2011 07:21:35 +0000 (17:21 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 23 May 2011 07:21:35 +0000 (17:21 +1000)
The loop over all member devices in enough_fd could easily stop
before it had found all devices.  This would cause --re-add to
fail incorrectly.

So change the loop to be based on the reported number of devices
in the device - with a safe-guard limit of 1024.

Change some other loops to be more careful too.

Reported-by: "Schmidt, Annemarie" <Annemarie.Schmidt@stratus.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Manage.c
Monitor.c
util.c

index 0e54bc7..66d6978 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -438,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);
@@ -469,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;
@@ -483,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) {
index 55aebeb..101bca4 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -449,6 +449,8 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
        char *dev = st->devname;
        int fd;
        int i;
+       int remaining_disks;
+       int last_disk;
 
        if (test)
                alert("TestMessage", dev, NULL, ainfo);
@@ -565,7 +567,8 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
        }
        st->percent = mse->percent;
 
-       for (i=0; i<MaxDisks && i <= array.raid_disks + array.nr_disks;
+       remaining_disks = array.nr_disks;
+       for (i=0; i<MaxDisks && remaining_disks > 0;
             i++) {
                mdu_disk_info_t disc;
                disc.number = i;
@@ -573,9 +576,12 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                        info[i].state = disc.state;
                        info[i].major = disc.major;
                        info[i].minor = disc.minor;
+                       if (disc.major || disc.minor)
+                               remaining_disks --;
                } else
                        info[i].major = info[i].minor = 0;
        }
+       last_disk = i;
 
        if (mse->metadata_version &&
            strncmp(mse->metadata_version, "external:", 9) == 0 &&
@@ -596,7 +602,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                int change;
                char *dv = NULL;
                disc.number = i;
-               if (i > array.raid_disks + array.nr_disks) {
+               if (i >= last_disk) {
                        newstate = 0;
                        disc.major = disc.minor = 0;
                } else if (info[i].major || info[i].minor) {
diff --git a/util.c b/util.c
index 1056ae4..e92be4f 100644 (file)
--- a/util.c
+++ b/util.c
@@ -370,10 +370,14 @@ int enough_fd(int fd)
            array.raid_disks <= 0)
                return 0;
        avail = calloc(array.raid_disks, 1);
-       for (i=0; i<array.raid_disks + array.nr_disks; i++) {
+       for (i=0; i < 1024 && array.nr_disks > 0; i++) {
                disk.number = i;
                if (ioctl(fd, GET_DISK_INFO, &disk) != 0)
                        continue;
+               if (disk.major == 0 && disk.minor == 0)
+                       continue;
+               array.nr_disks--;
+
                if (! (disk.state & (1<<MD_DISK_SYNC)))
                        continue;
                if (disk.raid_disk < 0 || disk.raid_disk >= array.raid_disks)
@@ -1256,10 +1260,13 @@ int check_partitions(int fd, char *dname, unsigned long long freesize,
 void get_one_disk(int mdfd, mdu_array_info_t *ainf, mdu_disk_info_t *disk)
 {
        int d;
+
        ioctl(mdfd, GET_ARRAY_INFO, ainf);
-       for (d = 0 ; d < ainf->raid_disks + ainf->nr_disks ; d++)
-               if (ioctl(mdfd, GET_DISK_INFO, disk) == 0)
+       for (d = 0 ; d < 1024 ; d++) {
+               if (ioctl(mdfd, GET_DISK_INFO, disk) == 0 &&
+                   (disk->major || disk->minor))
                        return;
+       }
 }
 
 int open_container(int fd)