summaryrefslogtreecommitdiff
path: root/Monitor.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-11-25 18:58:27 +1100
committerNeilBrown <neilb@suse.de>2010-11-25 18:58:27 +1100
commit5739e0d007a3eea80f5108d73d444751dbbde1ef (patch)
treeb436fa7134053e0edcc0999f5f86f89a9fed1fb8 /Monitor.c
parent0fa21e85227ed207881f7636a00223c2397b0a37 (diff)
Monitor: choose spare correctly for external metadata.
When metadata is managed externally - probably as a container - we need to examine that metadata to see which devices are spares. So use the getinfo_super_disk message and use the info returned. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'Monitor.c')
-rw-r--r--Monitor.c63
1 files changed, 62 insertions, 1 deletions
diff --git a/Monitor.c b/Monitor.c
index 5fc18d11..9ba49f25 100644
--- a/Monitor.c
+++ b/Monitor.c
@@ -798,6 +798,63 @@ static int choose_spare(struct state *from, struct state *to,
return dev;
}
+static int container_choose_spare(struct state *from, struct state *to,
+ struct domainlist *domlist)
+{
+ /* This is similar to choose_spare, but we cannot trust devstate,
+ * so we need to read the metadata instead
+ */
+
+ struct supertype *st = from->metadata;
+ int fd = open(st->devname, O_RDONLY);
+ int err;
+ struct mdinfo *disks, *d;
+ unsigned long long min_size
+ = min_spare_size_required(to);
+ int dev;
+
+ if (fd < 0)
+ return 0;
+ if (!st->ss->getinfo_super_disks)
+ return 0;
+
+ err = st->ss->load_container(st, fd, NULL);
+ close(fd);
+ if (err)
+ return 0;
+
+ disks = st->ss->getinfo_super_disks(st);
+ st->ss->free_super(st);
+
+ if (!disks)
+ return 0;
+
+ for (d = disks->devs ; d && !dev ; d = d->next) {
+ if (d->disk.state == 0) {
+ struct dev_policy *pol;
+ unsigned long long dev_size;
+ dev = makedev(d->disk.major,d->disk.minor);
+
+ if (min_size &&
+ dev_size_from_id(dev, &dev_size) &&
+ dev_size < min_size)
+ continue;
+
+ pol = devnum_policy(dev);
+ if (from->spare_group)
+ pol_add(&pol, pol_domain,
+ from->spare_group, NULL);
+ if (!domain_test(domlist, pol, to->metadata->ss->name))
+ dev = 0;
+
+ dev_policy_free(pol);
+ }
+ }
+ sysfs_free(disks);
+ return dev;
+}
+
+
static void try_spare_migration(struct state *statelist, struct alert_info *info)
{
struct state *from;
@@ -827,7 +884,11 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
int devid;
if (!check_donor(from, to, domlist))
continue;
- devid = choose_spare(from, to, domlist);
+ if (from->metadata->ss->external)
+ devid = container_choose_spare(
+ from, to, domlist);
+ else
+ devid = choose_spare(from, to, domlist);
if (devid > 0
&& move_spare(from, to, devid, info))
break;