]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Monitor.c
Allow more spare selection criteria
[thirdparty/mdadm.git] / Monitor.c
index 1f15377c6444e6b0a4cbd5b694b716612eb6171b..9a2baad02e1193c11228eedf0293b9d587af7e51 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -454,7 +454,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
        mdu_array_info_t array;
        struct mdstat_ent *mse = NULL, *mse2;
        char *dev = st->devname;
-       int fd = -1;
+       int fd;
        int i;
        int remaining_disks;
        int last_disk;
@@ -462,33 +462,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
 
        if (test)
                alert("TestMessage", dev, NULL, ainfo);
-       if (st->devnm[0])
-               fd = open("/sys/block", O_RDONLY|O_DIRECTORY);
-       if (fd >= 0) {
-               /* Don't open the device unless it is present and
-                * active in sysfs.
-                */
-               char buf[10];
-               close(fd);
-               fd = sysfs_open(st->devnm, NULL, "array_state");
-               if (fd < 0 ||
-                   read(fd, buf, 10) < 5 ||
-                   strncmp(buf,"clear",5) == 0 ||
-                   strncmp(buf,"inact",5) == 0) {
-                       if (fd >= 0)
-                               close(fd);
-                       fd = sysfs_open(st->devnm, NULL, "level");
-                       if (fd < 0 || read(fd, buf, 10) != 0) {
-                               if (fd >= 0)
-                                       close(fd);
-                               if (!st->err)
-                                       alert("DeviceDisappeared", dev, NULL, ainfo);
-                               st->err++;
-                               return 0;
-                       }
-               }
-               close(fd);
-       }
+
        fd = open(dev, O_RDONLY);
        if (fd < 0) {
                if (!st->err)
@@ -496,6 +470,15 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                st->err++;
                return 0;
        }
+
+       if (!md_array_active(fd)) {
+               close(fd);
+               if (!st->err)
+                       alert("DeviceDisappeared", dev, NULL, ainfo);
+               st->err++;
+               return 0;
+       }
+
        fcntl(fd, F_SETFD, FD_CLOEXEC);
        if (md_get_array_info(fd, &array) < 0) {
                if (!st->err)
@@ -544,13 +527,10 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                alert("NewArray", st->devname, NULL, ainfo);
        }
 
-       if (st->utime == array.utime &&
-           st->failed == array.failed_disks &&
+       if (st->utime == array.utime && st->failed == array.failed_disks &&
            st->working == array.working_disks &&
            st->spare == array.spare_disks &&
-           (mse == NULL  || (
-                   mse->percent == st->percent
-                   ))) {
+           (mse == NULL  || (mse->percent == st->percent))) {
                close(fd);
                if ((st->active < st->raid) && st->spare == 0)
                        return 1;
@@ -558,32 +538,33 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                        return 0;
        }
        if (st->utime == 0 && /* new array */
-           mse->pattern && strchr(mse->pattern, '_') /* degraded */
-               )
+           mse->pattern && strchr(mse->pattern, '_') /* degraded */)
                alert("DegradedArray", dev, NULL, ainfo);
 
        if (st->utime == 0 && /* new array */
-           st->expected_spares > 0 &&
-           array.spare_disks < st->expected_spares)
+           st->expected_spares > 0 && array.spare_disks < st->expected_spares)
                alert("SparesMissing", dev, NULL, ainfo);
        if (st->percent < 0 && st->percent != RESYNC_UNKNOWN &&
            mse->percent >= 0)
                alert("RebuildStarted", dev, NULL, ainfo);
-       if (st->percent >= 0 &&
-           mse->percent >= 0 &&
+       if (st->percent >= 0 && mse->percent >= 0 &&
            (mse->percent / increments) > (st->percent / increments)) {
-               char percentalert[15]; // "RebuildNN" (10 chars) or "RebuildStarted" (15 chars)
+               char percentalert[15];
+               /*
+                * "RebuildNN" (10 chars) or "RebuildStarted" (15 chars)
+                */
 
                if((mse->percent / increments) == 0)
-                       snprintf(percentalert, sizeof(percentalert), "RebuildStarted");
+                       snprintf(percentalert, sizeof(percentalert),
+                                "RebuildStarted");
                else
-                       snprintf(percentalert, sizeof(percentalert), "Rebuild%02d", mse->percent);
+                       snprintf(percentalert, sizeof(percentalert),
+                                "Rebuild%02d", mse->percent);
 
                alert(percentalert, dev, NULL, ainfo);
        }
 
-       if (mse->percent == RESYNC_NONE &&
-           st->percent >= 0) {
+       if (mse->percent == RESYNC_NONE && st->percent >= 0) {
                /* Rebuild/sync/whatever just finished.
                 * If there is a number in /mismatch_cnt,
                 * we should report that.
@@ -604,8 +585,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
        st->percent = mse->percent;
 
        remaining_disks = array.nr_disks;
-       for (i=0; i<MAX_DISKS && remaining_disks > 0;
-            i++) {
+       for (i = 0; i < MAX_DISKS && remaining_disks > 0; i++) {
                mdu_disk_info_t disc;
                disc.number = i;
                if (md_get_disk_info(fd, &disc) >= 0) {
@@ -623,15 +603,13 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
            strncmp(mse->metadata_version, "external:", 9) == 0 &&
            is_subarray(mse->metadata_version+9)) {
                char *sl;
-               strcpy(st->parent_devnm,
-                      mse->metadata_version+10);
+               strcpy(st->parent_devnm, mse->metadata_version+10);
                sl = strchr(st->parent_devnm, '/');
                if (sl)
                        *sl = 0;
        } else
                st->parent_devnm[0] = 0;
-       if (st->metadata == NULL &&
-           st->parent_devnm[0] == 0)
+       if (st->metadata == NULL && st->parent_devnm[0] == 0)
                st->metadata = super_by_fd(fd, NULL);
 
        close(fd);
@@ -642,12 +620,10 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                int change;
                char *dv = NULL;
                disc.number = i;
-               if (i < last_disk &&
-                   (info[i].major || info[i].minor)) {
+               if (i < last_disk && (info[i].major || info[i].minor)) {
                        newstate = info[i].state;
-                       dv = map_dev_preferred(
-                               info[i].major, info[i].minor, 1,
-                               prefer);
+                       dv = map_dev_preferred(info[i].major, info[i].minor, 1,
+                                              prefer);
                        disc.state = newstate;
                        disc.major = info[i].major;
                        disc.minor = info[i].minor;
@@ -655,18 +631,18 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
                        newstate = (1 << MD_DISK_REMOVED);
 
                if (dv == NULL && st->devid[i])
-                       dv = map_dev_preferred(
-                               major(st->devid[i]),
-                               minor(st->devid[i]), 1, prefer);
+                       dv = map_dev_preferred(major(st->devid[i]),
+                                              minor(st->devid[i]), 1, prefer);
                change = newstate ^ st->devstate[i];
                if (st->utime && change && !st->err && !new_array) {
-                       if ((st->devstate[i]&change)&(1<<MD_DISK_SYNC))
+                       if ((st->devstate[i]&change) & (1 << MD_DISK_SYNC))
                                alert("Fail", dev, dv, ainfo);
-                       else if ((newstate & (1<<MD_DISK_FAULTY)) &&
+                       else if ((newstate & (1 << MD_DISK_FAULTY)) &&
                                 (disc.major || disc.minor) &&
-                                st->devid[i] == makedev(disc.major, disc.minor))
+                                st->devid[i] == makedev(disc.major,
+                                                        disc.minor))
                                alert("FailSpare", dev, dv, ainfo);
-                       else if ((newstate&change)&(1<<MD_DISK_SYNC))
+                       else if ((newstate&change) & (1 << MD_DISK_SYNC))
                                alert("SpareActive", dev, dv, ainfo);
                }
                st->devstate[i] = newstate;
@@ -747,13 +723,14 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
        return new_found;
 }
 
-static int get_min_spare_size_required(struct state *st, unsigned long long *sizep)
+static int get_required_spare_criteria(struct state *st,
+                                      struct spare_criteria *sc)
 {
        int fd;
 
        if (!st->metadata ||
-           !st->metadata->ss->min_acceptable_spare_size) {
-               *sizep = 0;
+           !st->metadata->ss->get_spare_criteria) {
+               sc->min_size = 0;
                return 0;
        }
 
@@ -767,7 +744,8 @@ static int get_min_spare_size_required(struct state *st, unsigned long long *siz
        close(fd);
        if (!st->metadata->sb)
                return 1;
-       *sizep = st->metadata->ss->min_acceptable_spare_size(st->metadata);
+
+       st->metadata->ss->get_spare_criteria(st->metadata, sc);
        st->metadata->ss->free_super(st->metadata);
 
        return 0;
@@ -799,7 +777,7 @@ static int check_donor(struct state *from, struct state *to)
 }
 
 static dev_t choose_spare(struct state *from, struct state *to,
-                       struct domainlist *domlist, unsigned long long min_size)
+                       struct domainlist *domlist, struct spare_criteria *sc)
 {
        int d;
        dev_t dev = 0;
@@ -814,9 +792,9 @@ static dev_t choose_spare(struct state *from, struct state *to,
                            test_partition_from_id(from->devid[d]))
                                continue;
 
-                       if (min_size &&
+                       if (sc->min_size &&
                            dev_size_from_id(from->devid[d], &dev_size) &&
-                           dev_size < min_size)
+                           dev_size < sc->min_size)
                                continue;
 
                        pol = devid_policy(from->devid[d]);
@@ -833,7 +811,7 @@ static dev_t choose_spare(struct state *from, struct state *to,
 
 static dev_t container_choose_spare(struct state *from, struct state *to,
                                    struct domainlist *domlist,
-                                   unsigned long long min_size, int active)
+                                   struct spare_criteria *sc, int active)
 {
        /* This is similar to choose_spare, but we cannot trust devstate,
         * so we need to read the metadata instead
@@ -884,7 +862,7 @@ static dev_t container_choose_spare(struct state *from, struct state *to,
        }
 
        /* We only need one spare so full list not needed */
-       list = container_choose_spares(st, min_size, domlist, from->spare_group,
+       list = container_choose_spares(st, sc, domlist, from->spare_group,
                                       to->metadata->ss->name, 1);
        if (list) {
                struct mdinfo *disks = list->devs;
@@ -900,6 +878,7 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
 {
        struct state *from;
        struct state *st;
+       struct spare_criteria sc;
 
        link_containers_with_subarrays(statelist);
        for (st = statelist; st; st = st->next)
@@ -908,7 +887,6 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
                        struct domainlist *domlist = NULL;
                        int d;
                        struct state *to = st;
-                       unsigned long long min_size;
 
                        if (to->parent_devnm[0] && !to->parent)
                                /* subarray monitored without parent container
@@ -919,14 +897,14 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
                                /* member of a container */
                                to = to->parent;
 
-                       if (get_min_spare_size_required(to, &min_size))
+                       if (get_required_spare_criteria(to, &sc))
                                continue;
                        if (to->metadata->ss->external) {
                                /* We must make sure there is
                                 * no suitable spare in container already.
                                 * If there is we don't add more */
                                dev_t devid = container_choose_spare(
-                                       to, to, NULL, min_size, st->active);
+                                       to, to, NULL, &sc, st->active);
                                if (devid > 0)
                                        continue;
                        }
@@ -949,10 +927,10 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
                                        continue;
                                if (from->metadata->ss->external)
                                        devid = container_choose_spare(
-                                               from, to, domlist, min_size, 0);
+                                               from, to, domlist, &sc, 0);
                                else
                                        devid = choose_spare(from, to, domlist,
-                                                            min_size);
+                                                            &sc);
                                if (devid > 0
                                    && move_spare(from->devname, to->devname, devid)) {
                                        alert("MoveSpare", to->devname, from->devname, info);
@@ -993,23 +971,13 @@ static void link_containers_with_subarrays(struct state *list)
 /* Not really Monitor but ... */
 int Wait(char *dev)
 {
-       struct stat stb;
        char devnm[32];
-       char *tmp;
        int rv = 1;
        int frozen_remaining = 3;
 
-       if (stat(dev, &stb) != 0) {
-               pr_err("Cannot find %s: %s\n", dev,
-                       strerror(errno));
-               return 2;
-       }
-       tmp = stat2devnm(&stb);
-       if (!tmp) {
-               pr_err("%s is not a block device.\n", dev);
+       if (!stat_is_blkdev(dev, NULL))
                return 2;
-       }
-       strcpy(devnm, tmp);
+       strcpy(devnm, dev);
 
        while(1) {
                struct mdstat_ent *ms = mdstat_read(1, 0);
@@ -1068,6 +1036,8 @@ int WaitClean(char *dev, int sock, int verbose)
        int rv = 1;
        char devnm[32];
 
+       if (!stat_is_blkdev(dev, NULL))
+               return 2;
        fd = open(dev, O_RDONLY);
        if (fd < 0) {
                if (verbose)