From de6ae75015c1f277327a78bbf19bbf531659c134 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 29 Nov 2010 09:40:15 +1100 Subject: [PATCH] Incremental - avoid including wayward devices. If a devices - typically in a mirrored set - is assembled independently of the other devices, and then attempted to be brought back into the set, it could contain inconsistent data. It should not be included. So detect this situation by ensuring that the 'most recent' device is believed to be active by every other device. If a device is wayward, it will only consider fellow wayward devices to be active and will think all others are failed or missing. This patches fixes --incremental, --assemble was done in an earlier patch. Signed-off-by: NeilBrown --- Incremental.c | 80 +++++++++++++++++++++++++++++++++++++++------------ mdadm.h | 2 ++ util.c | 15 ++++++++++ 3 files changed, 79 insertions(+), 18 deletions(-) diff --git a/Incremental.c b/Incremental.c index c6abf00e..8cae1ee5 100644 --- a/Incremental.c +++ b/Incremental.c @@ -94,13 +94,13 @@ int Incremental(char *devname, int verbose, int runstop, */ struct stat stb; struct mdinfo info, dinfo; - struct mdinfo *sra = NULL; + struct mdinfo *sra = NULL, *d; struct mddev_ident *match; char chosen_name[1024]; int rv = 1; struct map_ent *mp, *map = NULL; int dfd = -1, mdfd = -1; - char *avail; + char *avail = NULL; int active_disks; int trustworthy; char *name_to_use; @@ -462,7 +462,7 @@ int Incremental(char *devname, int verbose, int runstop, rv = 0; return rv; } - avail = NULL; + /* We have added something to the array, so need to re-read the * state. Eventually this state should be kept up-to-date as * things change. @@ -474,7 +474,6 @@ int Incremental(char *devname, int verbose, int runstop, if (enough(info.array.level, info.array.raid_disks, info.array.layout, info.array.state & 1, avail, active_disks) == 0) { - free(avail); if (verbose >= 0) fprintf(stderr, Name ": %s attached to %s, not enough to start (%d).\n", @@ -483,7 +482,6 @@ int Incremental(char *devname, int verbose, int runstop, rv = 0; goto out; } - free(avail); /* 7b/ if yes, */ /* - if number of OK devices match expected, or -R and there */ @@ -522,6 +520,12 @@ int Incremental(char *devname, int verbose, int runstop, } close(bmfd); } + /* Need to remove from the array any devices which + * 'count_active' discerned were too old or inappropriate + */ + for (d = sra ? sra->devs : NULL ; d ; d = d->next) + if (d->disk.state & (1<= info.array.working_disks) && trustworthy != FOREIGN) @@ -563,6 +567,7 @@ int Incremental(char *devname, int verbose, int runstop, rv = 0; } out: + free(avail); if (dfd >= 0) close(dfd); if (mdfd >= 0) @@ -697,14 +702,22 @@ static int count_active(struct supertype *st, struct mdinfo *sra, { /* count how many devices in sra think they are active */ struct mdinfo *d; - int cnt = 0, cnt1 = 0; + int cnt = 0; __u64 max_events = 0; char *avail = NULL; + int *best; + char *devmap = NULL; + int numdevs = 0; + int devnum; + int b, i; + int raid_disks = 0; if (!sra) return 0; - for (d = sra->devs ; d ; d = d->next) { + for (d = sra->devs ; d ; d = d->next) + numdevs++; + for (d = sra->devs, devnum=0 ; d ; d = d->next, devnum++) { char dn[30]; int dfd; int ok; @@ -718,15 +731,21 @@ static int count_active(struct supertype *st, struct mdinfo *sra, close(dfd); if (ok != 0) continue; - st->ss->getinfo_super(st, &info, NULL); + info.array.raid_disks = raid_disks; + st->ss->getinfo_super(st, &info, devmap + raid_disks * devnum); if (!avail) { - avail = malloc(info.array.raid_disks); + raid_disks = info.array.raid_disks; + avail = calloc(raid_disks, 1); if (!avail) { fprintf(stderr, Name ": out of memory.\n"); exit(1); } - memset(avail, 0, info.array.raid_disks); *availp = avail; + + best = calloc(raid_disks, sizeof(int)); + devmap = calloc(raid_disks * numdevs, 1); + + st->ss->getinfo_super(st, &info, devmap); } if (info.disk.state & (1<ss->getinfo_super(st, bestinfo, NULL); } else if (info.events == max_events) { - cnt++; avail[info.disk.raid_disk] = 2; + best[info.disk.raid_disk] = devnum; } else if (info.events == max_events-1) { - cnt1++; - avail[info.disk.raid_disk] = 1; + if (avail[info.disk.raid_disk] == 0) { + avail[info.disk.raid_disk] = 1; + best[info.disk.raid_disk] = devnum; + } } else if (info.events < max_events - 1) ; else if (info.events == max_events+1) { int i; - cnt1 = cnt; - cnt = 1; max_events = info.events; - for (i=0; iss->getinfo_super(st, bestinfo, NULL); } else { /* info.events much bigger */ - cnt = 1; cnt1 = 0; memset(avail, 0, info.disk.raid_disk); max_events = info.events; avail[info.disk.raid_disk] = 2; @@ -764,7 +784,31 @@ static int count_active(struct supertype *st, struct mdinfo *sra, } st->ss->free_super(st); } - return cnt + cnt1; + if (!avail) + return 0; + /* We need to reject any device that thinks the best device is + * failed or missing */ + for (b = 0; b < raid_disks; b++) + if (avail[b] == 2) + break; + cnt = 0; + for (i = 0 ; i < raid_disks ; i++) { + if (i != b && avail[i]) + if (devmap[raid_disks * best[i] + b] == 0) { + /* This device thinks 'b' is failed - + * don't use it */ + devnum = best[i]; + for (d=sra->devs ; devnum; d = d->next) + devnum--; + d->disk.state |= (1 << MD_DISK_REMOVED); + avail[i] = 0; + } + if (avail[i]) + cnt++; + } + free(best); + free(devmap); + return cnt; } static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol, diff --git a/mdadm.h b/mdadm.h index ff9c72f7..f9a53fe4 100644 --- a/mdadm.h +++ b/mdadm.h @@ -1068,6 +1068,8 @@ extern int assemble_container_content(struct supertype *st, int mdfd, extern int add_disk(int mdfd, struct supertype *st, struct mdinfo *sra, struct mdinfo *info); +extern int remove_disk(int mdfd, struct supertype *st, + struct mdinfo *sra, struct mdinfo *info); extern int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info); unsigned long long min_recovery_start(struct mdinfo *array); diff --git a/util.c b/util.c index b018d299..2a206448 100644 --- a/util.c +++ b/util.c @@ -1626,6 +1626,21 @@ int add_disk(int mdfd, struct supertype *st, return rv; } +int remove_disk(int mdfd, struct supertype *st, + struct mdinfo *sra, struct mdinfo *info) +{ + int rv; + /* Remove the disk given by 'info' from the array */ +#ifndef MDASSEMBLE + if (st->ss->external) + rv = sysfs_set_str(sra, info, "slot", "none"); + else +#endif + rv = ioctl(mdfd, HOT_REMOVE_DISK, makedev(info->disk.major, + info->disk.minor)); + return rv; +} + int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info) { /* Initialise kernel's knowledge of array. -- 2.39.2