summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-11-22 20:58:07 +1100
committerNeilBrown <neilb@suse.de>2010-11-22 20:58:07 +1100
commite78dda3bf5ff840b65e85dbd7fc24ec4ccd291a5 (patch)
treeda8f35e89c6ea9ee90ca54674a416fdfa67dd044
parent2feb22efbc216e53486cc20c05df13f8340a9d49 (diff)
Monitor: policy based spare migration.
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>
-rw-r--r--Monitor.c62
-rw-r--r--mdadm.h6
-rw-r--r--policy.c36
3 files changed, 73 insertions, 31 deletions
diff --git a/Monitor.c b/Monitor.c
index 38dad640..ba6735c4 100644
--- 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 3b0cad18..83152f7d 100644
--- 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);
diff --git a/policy.c b/policy.c
index cc126949..ad5850bd 100644
--- 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) {