From da6b5ca9bd6962ea70dfa750f3d85ac1657fb9cf Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Fri, 26 May 2006 00:50:15 +0000 Subject: [PATCH] Initial implementation of auto-assembly This basically works, but needs various improvements and some tests. Signed-off-by: Neil Brown --- Assemble.c | 68 +++++++++++++++++++++++++++++++++++++------ config.c | 2 ++ mdadm.c | 84 ++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 118 insertions(+), 36 deletions(-) diff --git a/Assemble.c b/Assemble.c index 46ec9bc..6d89a24 100644 --- a/Assemble.c +++ b/Assemble.c @@ -180,11 +180,15 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, } if (devlist == NULL) devlist = conf_get_devs(conffile); - else inargv = 1; + else if (mdfd >= 0) + inargv = 1; tmpdev = devlist; num_devs = 0; while (tmpdev) { - num_devs++; + if (tmpdev->used) + tmpdev->used = 2; + else + num_devs++; tmpdev = tmpdev->next; } devices = malloc(num_devs * sizeof(*devices)); @@ -207,6 +211,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, struct stat stb; struct supertype *tst = st; + if (tmpdev->used > 1) continue; + if (ident->devices && !match_oneof(ident->devices, devname)) { if ((inargv && verbose>=0) || verbose > 0) @@ -224,16 +230,21 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": cannot open device %s: %s\n", devname, strerror(errno)); + tmpdev->used = 2; } else if (fstat(dfd, &stb)< 0) { /* Impossible! */ fprintf(stderr, Name ": fstat failed for %s: %s\n", devname, strerror(errno)); + tmpdev->used = 2; } else if ((stb.st_mode & S_IFMT) != S_IFBLK) { fprintf(stderr, Name ": %s is not a block device.\n", devname); + tmpdev->used = 2; } else if (!tst && (tst = guess_super(dfd)) == NULL) { if ((inargv && verbose >= 0) || verbose > 0) - fprintf(stderr, Name ": no recogniseable superblock\n"); + fprintf(stderr, Name ": no recogniseable superblock on %s\n", + devname); + tmpdev->used = 2; } else if (tst->ss->load_super(tst,dfd, &super, NULL)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf( stderr, Name ": no RAID superblock on %s\n", @@ -278,7 +289,17 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, devname); continue; } - + if (mdfd < 0) { + if (tst == NULL || super == NULL) + continue; + if (tst->ss->match_home(super, homehost)==0) { + if ((inargv && verbose >= 0) || verbose > 0) + fprintf(stderr, Name ": %s is not built for host %s.\n", + devname, homehost); + /* Auto-assemble, and this is not a usable host */ + continue; + } + } /* If we are this far, then we are nearly commited to this device. * If the super_block doesn't exist, or doesn't match others, * then we probably cannot continue @@ -299,8 +320,12 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, st->minor_version != tst->minor_version || st->ss->compare_super(&first_super, super) != 0) { /* Some mismatch. If exactly one array matches this host, - * we can resolve on that one + * we can resolve on that one. + * Or, if we are auto assembling, we just ignore the second + * for now. */ + if (mdfd < 0) + continue; if (homehost) { int first = st->ss->match_home(first_super, homehost); int last = tst->ss->match_home(super, homehost); @@ -339,14 +364,29 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, * We create a name '/dev/md/XXX' based on the info in the * superblock, and call open_mddev on that */ - asprintf(&mddev, "/dev/md/%s", info.name); - mdfd = open_mddev(mddev, 0); + mdu_array_info_t inf; + char *c; + if (!first_super) { + return 1; + } + st->ss->getinfo_super(&info, first_super); + c = strchr(info.name, ':'); + if (c) c++; else c= info.name; + asprintf(&mddev, "/dev/md/%s", c); + mdfd = open_mddev(mddev, ident->autof); if (mdfd < 0) return mdfd; + vers = md_get_version(mdfd); + if (ioctl(mdfd, GET_ARRAY_INFO, &inf)==0) { + fprintf(stderr, Name ": %s already active, cannot restart it!\n", mddev); + close(mdfd); + free(first_super); + return 1; + } } /* Ok, no bad inconsistancy, we can try updating etc */ - for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used) { + for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used == 1) { char *devname = tmpdev->devname; struct stat stb; /* looks like a good enough match to update the super block if needed */ @@ -401,6 +441,18 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, if (strcmp(update, "uuid")==0 && ident->bitmap_fd) bitmap_update_uuid(ident->bitmap_fd, info.uuid); + } else { + int dfd; + dfd = dev_open(devname, O_RDWR|O_EXCL); + + if (super) { + free(super); + super = NULL; + } + + st->ss->load_super(st, dfd, &super, NULL); + st->ss->getinfo_super(&info, super); + close(dfd); } stat(devname, &stb); diff --git a/config.c b/config.c index 8382cdf..d753f54 100644 --- a/config.c +++ b/config.c @@ -246,6 +246,7 @@ mddev_dev_t load_partitions(void) d = malloc(sizeof(*d)); d->devname = strdup(name); d->next = rv; + d->used = 0; rv = d; } fclose(f); @@ -716,6 +717,7 @@ mddev_dev_t conf_get_devs(char *conffile) mddev_dev_t t = malloc(sizeof(*t)); t->devname = strdup(globbuf.gl_pathv[i]); t->next = dlist; + t->used = 0; dlist = t; /* printf("one dev is %s\n", t->devname);*/ } diff --git a/mdadm.c b/mdadm.c index 0df7369..6c30058 100644 --- a/mdadm.c +++ b/mdadm.c @@ -237,6 +237,7 @@ int main(int argc, char *argv[]) dv->disposition = devmode; dv->writemostly = writemostly; dv->re_add = re_add; + dv->used = 0; dv->next = NULL; *devlistend = dv; devlistend = &dv->next; @@ -981,36 +982,63 @@ int main(int argc, char *argv[]) } } else { mddev_ident_t array_list = conf_get_ident(configfile, NULL); - if (!array_list) { + mddev_dev_t devlist = conf_get_devs(configfile); + int cnt = 0; + if (devlist == NULL) { + fprintf(stderr, Name ": No devices listed in conf file were found.\n"); + exit(1); + } + if (update) { + fprintf(stderr, Name ": --update not meaningful with a --scan assembly.\n"); + exit(1); + } + if (backup_file) { + fprintf(stderr, Name ": --backup_file not meaningful with a --scan assembly.\n"); + exit(1); + } + for (; array_list; array_list = array_list->next) { + mdu_array_info_t array; + mdfd = open_mddev(array_list->devname, + array_list->autof ? array_list->autof : autof); + if (mdfd < 0) { + rv |= 1; + continue; + } + if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0) + /* already assembled, skip */ + ; + else { + rv |= Assemble(ss, array_list->devname, mdfd, + array_list, configfile, + devlist, NULL, + readonly, runstop, NULL, homehost, verbose-quiet, force); + if (rv == 0) cnt++; + } + close(mdfd); + } + if (homehost) { + /* Maybe we can auto-assemble something. + * Repeatedly call Assemble in auto-assmble mode + * until it fails + */ + int rv2; + do { + ident.autof = autof; + rv2 = Assemble(ss, NULL, -1, + &ident, configfile, + devlist, NULL, + readonly, runstop, NULL, homehost, verbose-quiet, force); + if (rv2==0) + cnt++; + } while (rv2==0); + if (cnt == 0 && rv == 0) { + fprintf(stderr, Name ": No arrays found in config file or automatically\n"); + rv = 1; + } + } else if (cnt == 0 && rv == 0) { fprintf(stderr, Name ": No arrays found in config file\n"); rv = 1; - } else - if (update) { - fprintf(stderr, Name ": --update not meaningful with a --scan assembly.\n"); - exit(1); - } - if (backup_file) { - fprintf(stderr, Name ": --backup_file not meaningful with a --scan assembly.\n"); - exit(1); - } - for (; array_list; array_list = array_list->next) { - mdu_array_info_t array; - mdfd = open_mddev(array_list->devname, - array_list->autof ? array_list->autof : autof); - if (mdfd < 0) { - rv |= 1; - continue; - } - if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0) - /* already assembled, skip */ - ; - else - rv |= Assemble(ss, array_list->devname, mdfd, - array_list, configfile, - NULL, NULL, - readonly, runstop, NULL, homehost, verbose-quiet, force); - close(mdfd); - } + } } break; case BUILD: