]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Monitor: policy based spare migration.
authorNeilBrown <neilb@suse.de>
Mon, 22 Nov 2010 09:58:07 +0000 (20:58 +1100)
committerNeilBrown <neilb@suse.de>
Mon, 22 Nov 2010 09:58:07 +0000 (20:58 +1100)
Rather than only migrating between arrays with the same spare_group,
we now migrate based on domains set in the policy.

In order for spare_group to continue to work, we treat it as a domain
of the destination array, and a domain of any device we might remove
from a source array.

Signed-off-by: NeilBrown <neilb@suse.de>
Monitor.c
mdadm.h
policy.c

index 38dad640321301ddfe071c559656770034b7513a..ba6735c4b139eece19ec0d95fb028b43cbf3e101 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
@@ -681,15 +681,16 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state *statelist,
        return new_found;
 }
 
-static int move_spare(struct state *st2, struct state *st,
+static int move_spare(struct state *from, struct state *to,
+                     struct domainlist *domlist,
                      struct alert_info *info)
 {
        struct mddev_dev devlist;
        char devname[20];
 
        /* try to remove and add */
-       int fd1 = open(st->devname, O_RDONLY);
-       int fd2 = open(st2->devname, O_RDONLY);
+       int fd1 = open(to->devname, O_RDONLY);
+       int fd2 = open(from->devname, O_RDONLY);
        int dev = -1;
        int d;
        if (fd1 < 0 || fd2 < 0) {
@@ -697,11 +698,14 @@ static int move_spare(struct state *st2, struct state *st,
                if (fd2>=0) close(fd2);
                return 0;
        }
-       for (d=st2->raid; d < MaxDisks; d++) {
-               if (st2->devid[d] > 0 &&
-                   st2->devstate[d] == 0) {
-                       dev = st2->devid[d];
-                       break;
+       for (d = from->raid; dev < 0 && d < MaxDisks; d++) {
+               if (from->devid[d] > 0 &&
+                   from->devstate[d] == 0) {
+                       struct dev_policy *pol = devnum_policy(from->devid[d]);
+                       pol_add(&pol, pol_domain, from->spare_group, NULL);
+                       if (domain_test(domlist, pol, to->metadata->ss->name))
+                           dev = from->devid[d];
+                       dev_policy_free(pol);
                }
        }
        if (dev < 0) {
@@ -718,22 +722,23 @@ static int move_spare(struct state *st2, struct state *st,
        sprintf(devname, "%d:%d", major(dev), minor(dev));
 
        devlist.disposition = 'r';
-       if (Manage_subdevs(st2->devname, fd2, &devlist, -1, 0) == 0) {
+       if (Manage_subdevs(from->devname, fd2, &devlist, -1, 0) == 0) {
                devlist.disposition = 'a';
-               if (Manage_subdevs(st->devname, fd1, &devlist, -1, 0) == 0) {
-                       alert("MoveSpare", st->devname, st2->devname, info);
+               if (Manage_subdevs(to->devname, fd1, &devlist, -1, 0) == 0) {
+                       alert("MoveSpare", to->devname, from->devname, info);
                        close(fd1);
                        close(fd2);
                        return 1;
                }
-               else Manage_subdevs(st2->devname, fd2, &devlist, -1, 0);
+               else Manage_subdevs(from->devname, fd2, &devlist, -1, 0);
        }
        close(fd1);
        close(fd2);
        return 0;
 }
 
-static int check_donor(struct state *from, struct state *to)
+static int check_donor(struct state *from, struct state *to,
+                      struct domainlist *domlist)
 {
        if (from == to)
                return 0;
@@ -741,24 +746,35 @@ static int check_donor(struct state *from, struct state *to)
                return 0;
        if (from->spare <= 0)
                return 0;
-       if (!from->spare_group || !to->spare_group)
+       if (domlist == NULL)
                return 0;
-       return (strcmp(from->spare_group, to->spare_group) == 0);
+       return 1;
 }
 
 static void try_spare_migration(struct state *statelist, struct alert_info *info)
 {
-       struct state *st;
+       struct state *from, *to;
 
        link_containers_with_subarrays(statelist);
-       for (st = statelist; st; st=st->next)
-               if (st->active < st->raid &&
-                   st->spare == 0) {
-                       struct state *st2;
-                       for (st2=statelist ; st2 ; st2=st2->next)
-                               if (check_donor(st2, st)
-                                   && move_spare(st2, st, info))
+       for (to = statelist; to; to = to->next)
+               if (to->active < to->raid &&
+                   to->spare == 0) {
+                       struct domainlist *domlist = NULL;
+                       int d;
+
+                       for (d = 0; d < MaxDisks; d++)
+                               if (to->devid[d])
+                                       domainlist_add_dev(&domlist,
+                                                          to->devid[d],
+                                                          to->metadata->ss->name);
+                       if (to->spare_group)
+                               domain_add(&domlist, to->spare_group);
+
+                       for (from=statelist ; from ; from=from->next)
+                               if (check_donor(from, to, domlist)
+                                   && move_spare(from, to, domlist, info))
                                                break;
+                       domain_free(domlist);
                }
 }
 
diff --git a/mdadm.h b/mdadm.h
index 3b0cad1818bc72c8c2080ae5301b821e861a4e12..83152f7df87586fe3f75a01db47a4fcfe2508fe0 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -811,7 +811,8 @@ extern struct dev_policy *disk_policy(struct mdinfo *disk);
 extern struct dev_policy *devnum_policy(int dev);
 extern void dev_policy_free(struct dev_policy *p);
 
-extern void pol_new(struct dev_policy **pol, char *name, char *val, char *metadata);
+//extern void pol_new(struct dev_policy **pol, char *name, char *val, char *metadata);
+extern void pol_add(struct dev_policy **pol, char *name, char *val, char *metadata);
 extern struct dev_policy *pol_find(struct dev_policy *pol, char *name);
 
 enum policy_action {
@@ -839,9 +840,12 @@ extern int domain_test(struct domainlist *dom, struct dev_policy *pol,
                       const char *metadata);
 extern struct domainlist *domain_from_array(struct mdinfo *mdi,
                                            const char *metadata);
+extern void domainlist_add_dev(struct domainlist **dom, int devnum,
+                              const char *metadata);
 extern void domain_free(struct domainlist *dl);
 extern void domain_merge(struct domainlist **domp, struct dev_policy *pol,
                         const char *metadata);
+void domain_add(struct domainlist **domp, char *domain);
 
 extern void policy_save_path(char *id_path, struct map_ent *array);
 extern int policy_check_path(struct mdinfo *disk, struct map_ent *array);
index cc126949a7f98ae8c675b773028c222c9c3fd5d1..ad5850bd8244a8a1eae9a07595d3ad826355f7b0 100644 (file)
--- a/policy.c
+++ b/policy.c
@@ -40,7 +40,7 @@
  * particularly from a set of policy rules in mdadm.conf
  */
 
-void pol_new(struct dev_policy **pol, char *name, char *val, char *metadata)
+static void pol_new(struct dev_policy **pol, char *name, char *val, char *metadata)
 {
        struct dev_policy *n = malloc(sizeof(*n));
        const char *real_metadata = NULL;
@@ -365,6 +365,16 @@ struct dev_policy *path_policy(char *path, char *type)
        return pol;
 }
 
+void pol_add(struct dev_policy **pol,
+                   char *name, char *val,
+                   char *metadata)
+{
+       pol_new(pol, name, val, metadata);
+       pol_sort(pol);
+       pol_dedup(*pol);
+}
+
+
 /*
  * disk_policy() gathers policy information for the
  * disk described in the given mdinfo (disk.{major,minor}).
@@ -600,7 +610,7 @@ void domain_merge(struct domainlist **domp, struct dev_policy *pollist,
        struct dev_policy *pol;
        pollist = pol_find(pollist, pol_domain);
        pol_for_each(pol, pollist, metadata)
-               domp = domain_merge_one(domp, pol->value);
+               domain_merge_one(domp, pol->value);
 }
 
 int domain_test(struct domainlist *dom, struct dev_policy *pol,
@@ -625,19 +635,31 @@ int domain_test(struct domainlist *dom, struct dev_policy *pol,
        return found_any;
 }
 
+void domainlist_add_dev(struct domainlist **dom, int devnum, const char *metadata)
+{
+       struct dev_policy *pol = devnum_policy(devnum);
+       domain_merge(dom, pol, metadata);
+       dev_policy_free(pol);
+}
+
 struct domainlist *domain_from_array(struct mdinfo *mdi, const char *metadata)
 {
        struct domainlist *domlist = NULL;
 
-       for (mdi = mdi->devs ; mdi ; mdi = mdi->next) {
-               struct dev_policy *pol = disk_policy(mdi);
+       for (mdi = mdi->devs ; mdi ; mdi = mdi->next)
+               domainlist_add_dev(&domlist, makedev(mdi->disk.major,
+                                                    mdi->disk.minor),
+                                  metadata);
 
-               domain_merge(&domlist, pol, metadata);
-               dev_policy_free(pol);
-       }
        return domlist;
 }
 
+void domain_add(struct domainlist **domp, char *domain)
+{
+       domain_merge_one(domp, domain);
+}
+
+
 void domain_free(struct domainlist *dl)
 {
        while (dl) {