diff options
-rw-r--r-- | Assemble.c | 1 | ||||
-rw-r--r-- | Create.c | 2 | ||||
-rw-r--r-- | Incremental.c | 55 | ||||
-rw-r--r-- | Manage.c | 214 | ||||
-rw-r--r-- | Monitor.c | 6 | ||||
-rw-r--r-- | ReadMe.c | 28 | ||||
-rw-r--r-- | mdadm.8.in | 54 | ||||
-rw-r--r-- | mdadm.c | 17 | ||||
-rw-r--r-- | mdadm.conf-example | 2 | ||||
-rw-r--r-- | mdadm.h | 9 | ||||
-rw-r--r-- | mdstat.c | 69 | ||||
-rw-r--r-- | udev-md-raid.rules | 12 |
12 files changed, 387 insertions, 82 deletions
@@ -271,6 +271,7 @@ int Assemble(struct supertype *st, char *mddev, fprintf(stderr, Name ": %s has metadata type %s for which " "auto-assembly is disabled\n", devname, tst->ss->name); + tst->ss->free_super(tst); tmpdev->used = 2; } else { content = &info; @@ -43,7 +43,7 @@ static int default_layout(struct supertype *st, int level, int verbose) layout = 0x102; /* near=2, far=1 */ if (verbose > 0) fprintf(stderr, - Name ": layout defaults to n1\n"); + Name ": layout defaults to n2\n"); break; case 5: case 6: diff --git a/Incremental.c b/Incremental.c index 8062e2b..96bfcec 100644 --- a/Incremental.c +++ b/Incremental.c @@ -368,6 +368,22 @@ int Incremental(char *devname, int verbose, int runstop, else strcpy(chosen_name, devnum2devname(mp->devnum)); + /* It is generally not OK to add drives to a running array + * as they are probably missing because they failed. + * However if runstop is 1, then the array was possibly + * started early and our best be is to add this anyway. + * It would probably be good to allow explicit policy + * statement about this. + */ + if (runstop < 1) { + if (ioctl(mdfd, GET_ARRAY_INFO, &ainf) == 0) { + fprintf(stderr, Name + ": not adding %s to active array (without --run) %s\n", + devname, chosen_name); + close(mdfd); + return 2; + } + } sra = sysfs_read(mdfd, fd2devnum(mdfd), (GET_DEVS | GET_STATE)); if (!sra) return 2; @@ -854,3 +870,42 @@ int Incremental_container(struct supertype *st, char *devname, int verbose, map_unlock(&map); return 0; } + +/* + * IncrementalRemove - Attempt to see if the passed in device belongs to any + * raid arrays, and if so first fail (if needed) and then remove the device. + * + * @devname - The device we want to remove + * + * Note: the device name must be a kernel name like "sda", so + * that we can find it in /proc/mdstat + */ +int IncrementalRemove(char *devname, int verbose) +{ + int mdfd; + struct mdstat_ent *ent; + struct mddev_dev_s devlist; + + if (strchr(devname, '/')) { + fprintf(stderr, Name ": incremental removal requires a " + "kernel device name, not a file: %s\n", devname); + return 1; + } + ent = mdstat_by_component(devname); + if (!ent) { + fprintf(stderr, Name ": %s does not appear to be a component " + "of any array\n", devname); + return 1; + } + mdfd = open_dev(ent->devnum); + if (mdfd < 0) { + fprintf(stderr, Name ": Cannot open array %s!!\n", ent->dev); + return 1; + } + memset(&devlist, 0, sizeof(devlist)); + devlist.devname = devname; + devlist.disposition = 'f'; + Manage_subdevs(ent->dev, mdfd, &devlist, verbose, 0); + devlist.disposition = 'r'; + return Manage_subdevs(ent->dev, mdfd, &devlist, verbose, 0); +} @@ -326,7 +326,7 @@ int Manage_resize(char *devname, int fd, long long size, int raid_disks) } int Manage_subdevs(char *devname, int fd, - mddev_dev_t devlist, int verbose) + mddev_dev_t devlist, int verbose, int test) { /* do something to each dev. * devmode can be @@ -339,7 +339,10 @@ int Manage_subdevs(char *devname, int fd, * 'f' - set the device faulty SET_DISK_FAULTY * device can be 'detached' in which case any device that * is inaccessible will be marked faulty. + * For 'f' and 'r', the device can also be a kernel-internal + * name such as 'sdb'. */ + mddev_dev_t add_devlist = NULL; mdu_array_info_t array; mdu_disk_info_t disc; unsigned long long array_size; @@ -351,6 +354,8 @@ int Manage_subdevs(char *devname, int fd, int duuid[4]; int ouuid[4]; int lfd = -1; + int sysfd = -1; + int count = 0; /* number of actions taken */ if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": cannot get array info for %s\n", @@ -373,10 +378,12 @@ int Manage_subdevs(char *devname, int fd, return 1; } + stb.st_rdev = 0; for (dv = devlist, j=0 ; dv; dv = next, j = jnext) { unsigned long long ldsize; char dvname[20]; char *dnprintable = dv->devname; + char *add_dev = dv->devname; int err; next = dv->next; @@ -391,6 +398,7 @@ int Manage_subdevs(char *devname, int fd, return 1; } for (; j < array.raid_disks + array.nr_disks ; j++) { + int dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; @@ -398,9 +406,15 @@ int Manage_subdevs(char *devname, int fd, continue; if ((disc.state & 1) == 0) /* faulty */ continue; - stb.st_rdev = makedev(disc.major, disc.minor); + dev = makedev(disc.major, disc.minor); + if (stb.st_rdev == dev) + /* already did that one */ + continue; + stb.st_rdev = dev; next = dv; - jnext = j+1; + /* same slot again next time - things might + * have reshuffled */ + jnext = j; sprintf(dvname,"%d:%d", disc.major, disc.minor); dnprintable = dvname; break; @@ -416,6 +430,7 @@ int Manage_subdevs(char *devname, int fd, } for (; j < array.raid_disks + array.nr_disks; j++) { int sfd; + int dev; disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) continue; @@ -432,14 +447,72 @@ int Manage_subdevs(char *devname, int fd, continue; if (errno != ENXIO) continue; - stb.st_rdev = makedev(disc.major, disc.minor); + dev = makedev(disc.major, disc.minor); + if (stb.st_rdev == dev) + /* already did that one */ + continue; + stb.st_rdev = dev; next = dv; - jnext = j+1; + /* same slot again next time - things might + * have reshuffled */ + jnext = j; dnprintable = dvname; break; } if (jnext == 0) continue; + } else if (strcmp(dv->devname, "missing") == 0) { + if (dv->disposition != 'a' || dv->re_add == 0) { + fprintf(stderr, Name ": 'missing' only meaningful " + "with --re-add\n"); + return 1; + } + if (add_devlist == NULL) + add_devlist = conf_get_devs(); + if (add_devlist == NULL) { + fprintf(stderr, Name ": no devices to scan for missing members."); + continue; + } + add_dev = add_devlist->devname; + add_devlist = add_devlist->next; + if (add_devlist != NULL) + next = dv; + if (stat(add_dev, &stb) < 0) + continue; + } else if (strchr(dv->devname, '/') == NULL && + strlen(dv->devname) < 50) { + /* Assume this is a kernel-internal name like 'sda1' */ + int found = 0; + char dname[55]; + if (dv->disposition != 'r' && dv->disposition != 'f') { + fprintf(stderr, Name ": %s only meaningful " + "with -r of -f, not -%c\n", + dv->devname, dv->disposition); + return 1; + } + + sprintf(dname, "dev-%s", dv->devname); + sysfd = sysfs_open(fd2devnum(fd), dname, "block/dev"); + if (sysfd >= 0) { + char dn[20]; + int mj,mn; + if (sysfs_fd_get_str(sysfd, dn, 20) > 0 && + sscanf(dn, "%d:%d", &mj,&mn) == 2) { + stb.st_rdev = makedev(mj,mn); + found = 1; + } + close(sysfd); + sysfd = -1; + } + if (!found) { + sysfd = sysfs_open(fd2devnum(fd), dname, "state"); + if (sysfd < 0) { + fprintf(stderr, Name ": %s does not appear " + "to be a component of %s\n", + dv->devname, devname); + return 1; + } + } } else { j = 0; @@ -481,39 +554,44 @@ int Manage_subdevs(char *devname, int fd, return 1; } /* Make sure it isn't in use (in 2.6 or later) */ - tfd = dev_open(dv->devname, O_RDONLY|O_EXCL|O_DIRECT); + tfd = dev_open(add_dev, O_RDONLY|O_EXCL|O_DIRECT); + if (tfd < 0 && add_dev != dv->devname) + continue; if (tfd < 0) { fprintf(stderr, Name ": Cannot open %s: %s\n", dv->devname, strerror(errno)); return 1; } - remove_partitions(tfd); st = dup_super(tst); if (array.not_persistent==0) st->ss->load_super(st, tfd, NULL); - if (!get_dev_size(tfd, dv->devname, &ldsize)) { + if (add_dev == dv->devname) { + if (!get_dev_size(tfd, dv->devname, &ldsize)) { + close(tfd); + return 1; + } + } else if (!get_dev_size(tfd, NULL, &ldsize)) { close(tfd); - return 1; + continue; } - close(tfd); - if (!tst->ss->external && array.major_version == 0 && md_get_version(fd)%100 < 2) { + close(tfd); if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) { if (verbose >= 0) fprintf(stderr, Name ": hot added %s\n", - dv->devname); + add_dev); continue; } fprintf(stderr, Name ": hot add failed for %s: %s\n", - dv->devname, strerror(errno)); + add_dev, strerror(errno)); return 1; } @@ -524,7 +602,9 @@ int Manage_subdevs(char *devname, int fd, * For 'external' array (well, container based), * We can just load the metadata for the array. */ - if (tst->ss->external) { + if (tst->sb) + /* already loaded */; + else if (tst->ss->external) { tst->ss->load_super(tst, fd, NULL); } else for (j = 0; j < tst->max_devs; j++) { char *dev; @@ -550,6 +630,7 @@ int Manage_subdevs(char *devname, int fd, } /* FIXME this is a bad test to be using */ if (!tst->sb) { + close(tfd); fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n"); return 1; } @@ -557,6 +638,9 @@ int Manage_subdevs(char *devname, int fd, /* Make sure device is large enough */ if (tst->ss->avail_size(tst, ldsize/512) < array_size) { + close(tfd); + if (add_dev != dv->devname) + continue; fprintf(stderr, Name ": %s not large enough to join array\n", dv->devname); return 1; @@ -592,23 +676,41 @@ int Manage_subdevs(char *devname, int fd, disc.state |= 1 << MD_DISK_WRITEMOSTLY; if (dv->writemostly == 2) disc.state &= ~(1 << MD_DISK_WRITEMOSTLY); + remove_partitions(tfd); + close(tfd); + tfd = -1; /* don't even try if disk is marked as faulty */ errno = 0; if ((disc.state & 1) == 0 && ioctl(fd, ADD_NEW_DISK, &disc) == 0) { if (verbose >= 0) - fprintf(stderr, Name ": re-added %s\n", dv->devname); + fprintf(stderr, Name ": re-added %s\n", add_dev); + count++; continue; } if (errno == ENOMEM || errno == EROFS) { + close(tfd); fprintf(stderr, Name ": add new device failed for %s: %s\n", - dv->devname, strerror(errno)); + add_dev, strerror(errno)); + if (add_dev != dv->devname) + continue; return 1; } /* fall back on normal-add */ } } + if (add_dev != dv->devname) { + if (verbose > 0) + fprintf(stderr, Name + ": --re-add for %s to %s is not possible\n", + add_dev, devname); + if (tfd >= 0) + close(tfd); + continue; + } if (dv->re_add) { + if (tfd >= 0) + close(tfd); fprintf(stderr, Name ": --re-add for %s to %s is not possible\n", dv->devname, devname); @@ -624,6 +726,11 @@ int Manage_subdevs(char *devname, int fd, return 1; } } + /* committed to really trying this device now*/ + if (tfd >= 0) { + remove_partitions(tfd); + close(tfd); + } /* in 2.6.17 and earlier, version-1 superblocks won't * use the number we write, but will choose a free number. * we must choose the same free number, which requires @@ -751,6 +858,8 @@ int Manage_subdevs(char *devname, int fd, fprintf(stderr, Name ": Cannot remove disks from a" " \'member\' array, perform this" " operation on the parent container\n"); + if (sysfd >= 0) + close(sysfd); return 1; } if (tst->ss->external) { @@ -769,6 +878,8 @@ int Manage_subdevs(char *devname, int fd, fprintf(stderr, Name ": Cannot get exclusive access " " to container - odd\n"); + if (sysfd >= 0) + close(sysfd); return 1; } /* in the detached case it is not possible to @@ -776,6 +887,7 @@ int Manage_subdevs(char *devname, int fd, * rely on the 'detached' checks */ if (strcmp(dv->devname, "detached") == 0 || + sysfd >= 0 || sysfs_unique_holder(dnum, stb.st_rdev)) /* pass */; else { @@ -789,25 +901,38 @@ int Manage_subdevs(char *devname, int fd, } } /* FIXME check that it is a current member */ - err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev); - if (err && errno == ENODEV) { - /* Old kernels rejected this if no personality - * registered */ - struct mdinfo *sra = sysfs_read(fd, 0, GET_DEVS); - struct mdinfo *dv = NULL; - if (sra) - dv = sra->devs; - for ( ; dv ; dv=dv->next) - if (dv->disk.major == major(stb.st_rdev) && - dv->disk.minor == minor(stb.st_rdev)) - break; - if (dv) - err = sysfs_set_str(sra, dv, - "state", "remove"); - else + if (sysfd >= 0) { + /* device has been removed and we don't know + * the major:minor number + */ + int n = write(sysfd, "remove", 6); + if (n != 6) err = -1; - if (sra) - sysfs_free(sra); + else + err = 0; + close(sysfd); + sysfd = -1; + } else { + err = ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev); + if (err && errno == ENODEV) { + /* Old kernels rejected this if no personality + * registered */ + struct mdinfo *sra = sysfs_read(fd, 0, GET_DEVS); + struct mdinfo *dv = NULL; + if (sra) + dv = sra->devs; + for ( ; dv ; dv=dv->next) + if (dv->disk.major == major(stb.st_rdev) && + dv->disk.minor == minor(stb.st_rdev)) + break; + if (dv) + err = sysfs_set_str(sra, dv, + "state", "remove"); + else + err = -1; + if (sra) + sysfs_free(sra); + } } if (err) { fprintf(stderr, Name ": hot remove failed " @@ -834,27 +959,38 @@ int Manage_subdevs(char *devname, int fd, ping_manager(name); free(name); } - close(lfd); + if (lfd >= 0) + close(lfd); + count++; if (verbose >= 0) - fprintf(stderr, Name ": hot removed %s\n", - dnprintable); + fprintf(stderr, Name ": hot removed %s from %s\n", + dnprintable, devname); break; case 'f': /* set faulty */ /* FIXME check current member */ - if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) { + if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) || + (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY, + (unsigned long) stb.st_rdev))) { fprintf(stderr, Name ": set device faulty failed for %s: %s\n", dnprintable, strerror(errno)); + if (sysfd >= 0) + close(sysfd); return 1; } + if (sysfd >= 0) + close(sysfd); + sysfd = -1; + count++; if (verbose >= 0) fprintf(stderr, Name ": set %s faulty in %s\n", dnprintable, devname); break; } } + if (test && count == 0) + return 2; return 0; - } int autodetect(void) @@ -491,15 +491,15 @@ int Monitor(mddev_dev_t devlist, sprintf(devname, "%d:%d", major(dev), minor(dev)); devlist.disposition = 'r'; - if (Manage_subdevs(st2->devname, fd2, &devlist, -1) == 0) { + if (Manage_subdevs(st2->devname, fd2, &devlist, -1, 0) == 0) { devlist.disposition = 'a'; - if (Manage_subdevs(st->devname, fd1, &devlist, -1) == 0) { + if (Manage_subdevs(st->devname, fd1, &devlist, -1, 0) == 0) { alert("MoveSpare", st->devname, st2->devname, mailaddr, mailfrom, alert_cmd, dosyslog); close(fd1); close(fd2); break; } - else Manage_subdevs(st2->devname, fd2, &devlist, -1); + else Manage_subdevs(st2->devname, fd2, &devlist, -1, 0); } } close(fd1); @@ -215,7 +215,7 @@ char Help[] = " mdadm --grow options device\n" " resize/reshape an active array\n" " mdadm --incremental device\n" -" add a device to an array as appropriate\n" +" add/remove a device to/from an array as appropriate\n" " mdadm --monitor options...\n" " Monitor one or more array for significant changes.\n" " mdadm device options...\n" @@ -258,7 +258,7 @@ char OptionHelp[] = " --examine-bitmap -X: Display the detail of a bitmap file\n" " --monitor -F : monitor (follow) some arrays\n" " --grow -G : resize/ reshape and array\n" -" --incremental -I : add a single device to an array as appropriate\n" +" --incremental -I : add/remove a single device to/from an array as appropriate\n" " --query -Q : Display general information about how a\n" " device relates to the md driver\n" " --auto-detect : Start arrays auto-detected by the kernel\n" @@ -537,20 +537,26 @@ char Help_grow[] = ; char Help_incr[] = -"Usage: mdadm --incremental [-Rqrs] device\n" +"Usage: mdadm --incremental [-Rqrsf] device\n" "\n" "This usage allows for incremental assembly of md arrays. Devices can be\n" "added one at a time as they are discovered. Once an array has all expected\n" "devices, it will be started.\n" "\n" -"Options that are valid with incremental assembly (-I --incremental) more are:\n" -" --run -R : run arrays as soon as a minimal number of devices are\n" -" : present rather than waiting for all expected.\n" -" --quiet -q : Don't print any information messages, just errors.\n" -" --rebuild -r : Rebuild the 'map' file that mdadm uses for tracking\n" -" : partial arrays.\n" -" --scan -s : Use with -R to start any arrays that have the minimal\n" -" : required number of devices, but are not yet started.\n" +"Optionally, the process can be reversed by using the fail option.\n" +"When fail mode is invoked, mdadm will see if the device belongs to an array\n" +"and then both fail (if needed) and remove the device from that array.\n" +"\n" +"Options that are valid with incremental assembly (-I --incremental) are:\n" +" --run -R : Run arrays as soon as a minimal number of devices are\n" +" : present rather than waiting for all expected.\n" +" --quiet -q : Don't print any information messages, just errors.\n" +" --rebuild-map -r : Rebuild the 'map' file that mdadm uses for tracking\n" +" : partial arrays.\n" +" --scan -s : Use with -R to start any arrays that have the minimal\n" +" : required number of devices, but are not yet started.\n" +" --fail -f : First fail (if needed) and then remove device from\n" +" : any array that it is a member of.\n" ; char Help_config[] = @@ -136,6 +136,10 @@ This provides a convenient interface to a system. As each device is detected, .I mdadm has a chance to include it in some array as appropriate. +Optionally, when the +.I \-\-fail +flag is passed in we will remove the device from any active array +instead of adding it. If a .B CONTAINER @@ -189,7 +193,7 @@ Change the size or shape of an active array. .TP .BR \-I ", " \-\-incremental -Add a single device into an appropriate array, and possibly start the array. +Add/remove a single device to/from an appropriate array, and possibly start the array. .TP .B \-\-auto-detect @@ -1014,16 +1018,24 @@ immediately start recovering data on to one of these spares. .TP .BR \-\-re\-add -re-add a device that was recently removed from an array. This is only -needed for arrays that have be built (i.e. with +re\-add a device that was recently removed from an array. This is +normally only needed for arrays that have be built (i.e. with .BR --build ). -For created arrays, devices are always re-added if that is possible. -When re-adding a device, if nothing has changed on the array since the +For created arrays, devices are always re\-added if that is possible, +however using \-\-re\-add will ensure the device isn't made into a +spare if the \-\-re\-add failed. + +When re\-adding a device, if nothing has changed on the array since the device was removed, no recovery is performed. Also, if the array has -a write-intent bitmap, then the recovery performed after a re-add will +a write-intent bitmap, then the recovery performed after a re\-add will be limited to those blocks which, according to the bitmap, might have changed since the device was removed. +If the device name given is +.B missing +then mdadm will try to find any device that looks like it should be +part of the array but isn't and will try to re\-add all such devices. + .TP .BR \-r ", " \-\-remove remove listed devices. They must not be active. i.e. they should @@ -1058,12 +1070,12 @@ same as .TP .BR \-\-write\-mostly -Subsequent devices that are added or re-added will have the 'write-mostly' +Subsequent devices that are added or re\-added will have the 'write-mostly' flag set. This is only valid for RAID1 and means that the 'md' driver will avoid reading from these devices if possible. .TP .BR \-\-readwrite -Subsequent devices that are added or re-added will have the 'write-mostly' +Subsequent devices that are added or re\-added will have the 'write-mostly' flag cleared. .P @@ -1078,7 +1090,7 @@ Each operation applies to all devices listed until the next operation. If an array is using a write-intent bitmap, then devices which have -been removed can be re-added in a way that avoids a full +been removed can be re\-added in a way that avoids a full reconstruction but instead just updates the blocks that have changed since the device was removed. For arrays with persistent metadata (superblocks) this is done automatically. For arrays created with @@ -1254,6 +1266,15 @@ in .B mdadm.conf as requiring an external bitmap, that bitmap will be attached first. +.TP +.BR \-\-fail ", " \-f +This allows the hot-plug system to remove devices that have fully disappeared +from the kernel. It will first fail and then remove the device from any +array it belongs to. +The device name given should be a kernel device name such as "sda", +not a name in +.IR /dev . + .SH For Monitor mode: .TP .BR \-m ", " \-\-mail @@ -1693,7 +1714,7 @@ command. When a device is added to an active array, mdadm checks to see if it has metadata on it which suggests that it was recently a member of the -array. If it does, it tried to "re-add" the device. If there have +array. If it does, it tries to "re\-add" the device. If there have been no changes since the device was removed, or if the array has a write-intent bitmap which has recorded whatever changes there were, then the device will immediately become a full member of the array and @@ -2182,7 +2203,11 @@ Usage: .I component-device .HP 12 Usage: -.B mdadm \-\-incremental \-\-rebuild +.B mdadm \-\-incremental \-\-fail +.I component-device +.HP 12 +Usage: +.B mdadm \-\-incremental \-\-rebuild\-map .HP 12 Usage: .B mdadm \-\-incremental \-\-run \-\-scan @@ -2194,6 +2219,11 @@ passed to .B "mdadm \-\-incremental" to be conditionally added to an appropriate array. +Conversely, it can also be used with the +.B \-\-fail +flag to do just the opposite and find whatever array a particular device +is part of and remove the device from that array. + If the device passed is a .B CONTAINER device created by a previous call to @@ -2428,7 +2458,7 @@ pid of mdadm daemon to Try to incorporate newly discovered device into some array as appropriate. -.B " mdadm \-\-incremental \-\-rebuild \-\-run \-\-scan" +.B " mdadm \-\-incremental \-\-rebuild\-map \-\-run \-\-scan" .br Rebuild the array map from any current arrays, and then start any that can be started. @@ -793,6 +793,9 @@ int main(int argc, char *argv[]) devmode = 'r'; continue; case O(MANAGE,'f'): /* set faulty */ + case O(INCREMENTAL,'f'): /* r for incremental is taken, use f + * even though we will both fail and + * remove the device */ devmode = 'f'; continue; case O(INCREMENTAL,'R'): @@ -813,6 +816,9 @@ int main(int argc, char *argv[]) } runstop = -1; continue; + case O(MANAGE,'t'): + test = 1; + continue; case O(MISC,'Q'): case O(MISC,'D'): @@ -1092,7 +1098,7 @@ int main(int argc, char *argv[]) rv = Manage_ro(devlist->devname, mdfd, readonly); if (!rv && devs_found>1) rv = Manage_subdevs(devlist->devname, mdfd, - devlist->next, verbose-quiet); + devlist->next, verbose-quiet, test); if (!rv && readonly < 0) rv = Manage_ro(devlist->devname, mdfd, readonly); if (!rv && runstop) @@ -1559,6 +1565,11 @@ int main(int argc, char *argv[]) ": --incremental --scan meaningless without --run.\n"); break; } + if (devmode == 'f') { + fprintf(stderr, Name + ": --incremental --scan --fail not supported.\n"); + break; + } rv = IncrementalScan(verbose); } if (!devlist) { @@ -1575,6 +1586,10 @@ int main(int argc, char *argv[]) rv = 1; break; } + if (devmode == 'f') { + rv = IncrementalRemove(devlist->devname, verbose-quiet); + break; + } rv = Incremental(devlist->devname, verbose-quiet, runstop, ss, homehost, require_homehost, autof); break; diff --git a/mdadm.conf-example b/mdadm.conf-example index 9250f23..7bdff67 100644 --- a/mdadm.conf-example +++ b/mdadm.conf-example @@ -34,7 +34,7 @@ # If you want to ignore all DDF arrays (maybe they are managed by dmraid), # and only assemble 1.x arrays if which are marked for 'this' homehost, # but assemble all others, then use -#AUTH -ddf hosthost -1.x +all +#AUTO -ddf homehost -1.x +all # # ARRAY lines specify an array to assemble and a method of identification. # Arrays can currently be identified by using a UUID, superblock minor number, @@ -358,6 +358,10 @@ struct mdstat_ent { int raid_disks; int chunk_size; char * metadata_version; + struct dev_member { + char *name; + struct dev_member *next; + } *members; struct mdstat_ent *next; }; @@ -366,6 +370,7 @@ extern void free_mdstat(struct mdstat_ent *ms); extern void mdstat_wait(int seconds); extern void mdstat_wait_fd(int fd, const sigset_t *sigmask); extern int mddev_busy(int devnum); +extern struct mdstat_ent *mdstat_by_component(char *name); struct map_ent { struct map_ent *next; @@ -772,7 +777,7 @@ extern int Manage_ro(char *devname, int fd, int readonly); extern int Manage_runstop(char *devname, int fd, int runstop, int quiet); extern int Manage_resize(char *devname, int fd, long long size, int raid_disks); extern int Manage_subdevs(char *devname, int fd, - mddev_dev_t devlist, int verbose); + mddev_dev_t devlist, int verbose, int test); extern int autodetect(void); extern int Grow_Add_device(char *devname, int fd, char *newdev); extern int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int write_behind, int force); @@ -828,7 +833,7 @@ extern int Incremental_container(struct supertype *st, char *devname, int trustworthy); extern void RebuildMap(void); extern int IncrementalScan(int verbose); - +extern int IncrementalRemove(char *devname, int verbose); extern int CreateBitmap(char *filename, int force, char uuid[16], unsigned long chunksize, unsigned long daemon_sleep, unsigned long write_behind, @@ -83,14 +83,41 @@ #include <sys/select.h> #include <ctype.h> +static void free_member_devnames(struct dev_member *m) +{ + while(m) { + struct dev_member *t = m; + + m = m->next; + free(t->name); + free(t); + } +} + +static void add_member_devname(struct dev_member **m, char *name) +{ + struct dev_member *new; + char *t; + + if ((t = strchr(name, '[')) == NULL) + /* not a device */ + return; + + new = malloc(sizeof(*new)); + new->name = strndup(name, t - name); + new->next = *m; + *m = new; +} + void free_mdstat(struct mdstat_ent *ms) { while (ms) { struct mdstat_ent *t; - if (ms->dev) free(ms->dev); - if (ms->level) free(ms->level); - if (ms->pattern) free(ms->pattern); - if (ms->metadata_version) free(ms->metadata_version); + free(ms->dev); + free(ms->level); + free(ms->pattern); + free(ms->metadata_version); + free_member_devnames(ms->members); t = ms; ms = ms->next; free(t); @@ -159,6 +186,7 @@ struct mdstat_ent *mdstat_read(int hold, int start) ent->raid_disks = 0; ent->chunk_size = 0; ent->devcnt = 0; + ent->members = NULL; ent->dev = strdup(line); ent->devnum = devnum; @@ -168,9 +196,10 @@ struct mdstat_ent *mdstat_read(int hold, int start) char *eq; if (strcmp(w, "active")==0) ent->active = 1; - else if (strcmp(w, "inactive")==0) + else if (strcmp(w, "inactive")==0) { ent->active = 0; - else if (ent->active >=0 && + in_devs = 1; + } else if (ent->active > 0 && ent->level == NULL && w[0] != '(' /*readonly*/) { ent->level = strdup(w); @@ -179,6 +208,7 @@ struct mdstat_ent *mdstat_read(int hold, int start) in_devs = 0; else if (in_devs) { ent->devcnt++; + add_member_devname(&ent->members, w); if (strncmp(w, "md", 2)==0) { /* This has an md device as a component. * If that device is already in the @@ -310,3 +340,30 @@ int mddev_busy(int devnum) free_mdstat(mdstat); return me != NULL; } + +struct mdstat_ent *mdstat_by_component(char *name) +{ + struct mdstat_ent *mdstat = mdstat_read(0, 0); + + while (mdstat) { + struct dev_member *m; + struct mdstat_ent *ent; + if (mdstat->metadata_version && + strncmp(mdstat->metadata_version, "external:", 9) == 0 && + is_subarray(mdstat->metadata_version+9)) + /* don't return subarrays, only containers */ + ; + else for (m = mdstat->members; m; m = m->next) { + if (strcmp(m->name, name) == 0) { + free_mdstat(mdstat->next); + mdstat->next = NULL; + return mdstat; + } + } + ent = mdstat; + mdstat = mdstat->next; + ent->next = NULL; + free_mdstat(ent); + } + return NULL; +} diff --git a/udev-md-raid.rules b/udev-md-raid.rules index c9a4f0e..da52058 100644 --- a/udev-md-raid.rules +++ b/udev-md-raid.rules @@ -1,13 +1,13 @@ # do not edit this file, it will be overwritten on update SUBSYSTEM!="block", GOTO="md_end" -ACTION!="add|change", GOTO="md_end" -ACTION=="change", GOTO="md_no_incr" -# import data from a raid member and activate it -#ENV{ID_FS_TYPE}=="linux_raid_member", IMPORT{program}="/sbin/mdadm --examine --export $tempnode", RUN+="/sbin/mdadm --incremental $env{DEVNAME}" -# import data from a raid set -LABEL="md_no_incr" +# handle potential components of arrays +ENV{ID_FS_TYPE}=="linux_raid_member", ACTION=="remove", RUN+="/sbin/mdadm -If $name" +ENV{ID_FS_TYPE}=="linux_raid_member", ACTION=="add", RUN+="/sbin/mdadm --incremental $env{DEVNAME}" + +# handle md arrays +ACTION!="add|change", GOTO="md_end" KERNEL!="md*", GOTO="md_end" # partitions have no md/{array_state,metadata_version}, but should not |