X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=Assemble.c;h=210bfa004c55ffe732381fd79bf7d939ffd120ed;hb=eec3f887856664e224cdd97d3e4d609766f26a8a;hp=ac489e8741c82af3c3f7fe36361a1cc81a3161ef;hpb=f80c8614b0014fde1220591fcc4a1365c9cde0c4;p=thirdparty%2Fmdadm.git diff --git a/Assemble.c b/Assemble.c index ac489e87..210bfa00 100644 --- a/Assemble.c +++ b/Assemble.c @@ -78,38 +78,37 @@ static int ident_matches(struct mddev_ident *ident, { if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) && - same_uuid(content->uuid, ident->uuid, tst->ss->swapuuid)==0) { + same_uuid(content->uuid, ident->uuid, tst->ss->swapuuid)==0 && + memcmp(content->uuid, uuid_zero, sizeof(int[4])) != 0) { if (devname) - fprintf(stderr, Name ": %s has wrong uuid.\n", - devname); + pr_err("%s has wrong uuid.\n", devname); return 0; } if (ident->name[0] && (!update || strcmp(update, "name")!= 0) && name_matches(content->name, ident->name, homehost)==0) { if (devname) - fprintf(stderr, Name ": %s has wrong name.\n", - devname); + pr_err("%s has wrong name.\n", devname); return 0; } if (ident->super_minor != UnSet && ident->super_minor != content->array.md_minor) { if (devname) - fprintf(stderr, Name ": %s has wrong super-minor.\n", - devname); + pr_err("%s has wrong super-minor.\n", + devname); return 0; } if (ident->level != UnSet && ident->level != content->array.level) { if (devname) - fprintf(stderr, Name ": %s has wrong raid level.\n", - devname); + pr_err("%s has wrong raid level.\n", + devname); return 0; } if (ident->raid_disks != UnSet && ident->raid_disks!= content->array.raid_disks) { if (devname) - fprintf(stderr, Name ": %s requires wrong number of drives.\n", - devname); + pr_err("%s requires wrong number of drives.\n", + devname); return 0; } if (ident->member && ident->member[0]) { @@ -117,13 +116,13 @@ static int ident_matches(struct mddev_ident *ident, char *s = strchr(content->text_version+1, '/'); if (s == NULL) { if (devname) - fprintf(stderr, Name ": %s is not a container and one is required.\n", - devname); + pr_err("%s is not a container and one is required.\n", + devname); return 0; } else if (strcmp(ident->member, s+1) != 0) { if (devname) - fprintf(stderr, Name ": skipping wrong member %s is %s\n", - content->text_version, devname); + pr_err("skipping wrong member %s is %s\n", + content->text_version, devname); return 0; } } @@ -134,10 +133,7 @@ static int ident_matches(struct mddev_ident *ident, int Assemble(struct supertype *st, char *mddev, struct mddev_ident *ident, struct mddev_dev *devlist, - char *backup_file, int invalid_backup, - int readonly, int runstop, - char *update, char *homehost, int require_homehost, - int verbose, int force) + struct context *c) { /* * The task of Assemble is to find a collection of @@ -219,9 +215,11 @@ int Assemble(struct supertype *st, char *mddev, int change = 0; int inargv = 0; int report_missmatch; +#ifndef MDASSEMBLE int bitmap_done; - int start_partial_ok = (runstop >= 0) && - (force || devlist==NULL || auto_assem); +#endif + int start_partial_ok = (c->runstop >= 0) && + (c->force || devlist==NULL || auto_assem); unsigned int num_devs; struct mddev_dev *tmpdev; struct mdinfo info; @@ -231,6 +229,7 @@ int Assemble(struct supertype *st, char *mddev, char *name = NULL; int trustworthy; char chosen_name[1024]; + struct domainlist *domains = NULL; if (get_linux_version() < 2004000) old_linux = 1; @@ -249,8 +248,8 @@ int Assemble(struct supertype *st, char *mddev, ident->name[0] == 0 && (ident->container == NULL || ident->member == NULL) && ident->devices == NULL) { - fprintf(stderr, Name ": No identity information available for %s - cannot assemble.\n", - mddev ? mddev : "further assembly"); + pr_err("No identity information available for %s - cannot assemble.\n", + mddev ? mddev : "further assembly"); return 1; } @@ -259,7 +258,7 @@ int Assemble(struct supertype *st, char *mddev, else if (mddev) inargv = 1; - report_missmatch = ((inargv && verbose >= 0) || verbose > 0); + report_missmatch = ((inargv && c->verbose >= 0) || c->verbose > 0); try_again: /* We come back here when doing auto-assembly and attempting some * set of devices failed. Those are now marked as ->used==2 and @@ -277,9 +276,9 @@ int Assemble(struct supertype *st, char *mddev, if (!st && ident->st) st = ident->st; - if (verbose>0) - fprintf(stderr, Name ": looking for devices for %s\n", - mddev ? mddev : "further assembly"); + if (c->verbose>0) + pr_err("looking for devices for %s\n", + mddev ? mddev : "further assembly"); /* first walk the list of devices to find a consistent set * that match the criterea, if that is possible. @@ -291,7 +290,7 @@ int Assemble(struct supertype *st, char *mddev, char *devname = tmpdev->devname; int dfd; struct stat stb; - struct supertype *tst = dup_super(st); + struct supertype *tst; struct dev_policy *pol = NULL; int found_container = 0; @@ -300,24 +299,26 @@ int Assemble(struct supertype *st, char *mddev, if (ident->devices && !match_oneof(ident->devices, devname)) { if (report_missmatch) - fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices); + pr_err("%s is not one of %s\n", devname, ident->devices); continue; } - dfd = dev_open(devname, O_RDONLY|O_EXCL); + tst = dup_super(st); + + dfd = dev_open(devname, O_RDONLY); if (dfd < 0) { if (report_missmatch) - fprintf(stderr, Name ": cannot open device %s: %s\n", - devname, strerror(errno)); + pr_err("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)); + pr_err("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); + pr_err("%s is not a block device.\n", + devname); tmpdev->used = 2; } else if (must_be_container(dfd)) { if (st) { @@ -325,59 +326,61 @@ int Assemble(struct supertype *st, char *mddev, * be another one. */ if (report_missmatch) - fprintf(stderr, Name ": %s is a container, but we are looking for components\n", - devname); + pr_err("%s is a container, but we are looking for components\n", + devname); tmpdev->used = 2; +#if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO) } if (!tst && (tst = super_by_fd(dfd, NULL)) == NULL) { if (report_missmatch) - fprintf(stderr, Name ": not a recognisable container: %s\n", - devname); + pr_err("not a recognisable container: %s\n", + devname); tmpdev->used = 2; +#endif } else if (!tst->ss->load_container || tst->ss->load_container(tst, dfd, NULL)) { if (report_missmatch) - fprintf(stderr, Name ": no correct container type: %s\n", - devname); + pr_err("no correct container type: %s\n", + devname); tmpdev->used = 2; } else if (auto_assem && !conf_test_metadata(tst->ss->name, (pol = devnum_policy(stb.st_rdev)), - tst->ss->match_home(tst, homehost) == 1)) { + tst->ss->match_home(tst, c->homehost) == 1)) { if (report_missmatch) - fprintf(stderr, Name ": %s has metadata type %s for which " - "auto-assembly is disabled\n", - devname, tst->ss->name); + pr_err("%s has metadata type %s for which " + "auto-assembly is disabled\n", + devname, tst->ss->name); tmpdev->used = 2; } else found_container = 1; } else { if (!tst && (tst = guess_super(dfd)) == NULL) { if (report_missmatch) - fprintf(stderr, Name ": no recogniseable superblock on %s\n", - devname); + pr_err("no recogniseable superblock on %s\n", + devname); tmpdev->used = 2; } else if (tst->ss->load_super(tst,dfd, NULL)) { if (report_missmatch) - fprintf(stderr, Name ": no RAID superblock on %s\n", - devname); + pr_err("no RAID superblock on %s\n", + devname); tmpdev->used = 2; } else if (tst->ss->compare_super == NULL) { if (report_missmatch) - fprintf(stderr, Name ": Cannot assemble %s metadata on %s\n", - tst->ss->name, devname); + pr_err("Cannot assemble %s metadata on %s\n", + tst->ss->name, devname); tmpdev->used = 2; } else if (auto_assem && st == NULL && !conf_test_metadata(tst->ss->name, (pol = devnum_policy(stb.st_rdev)), - tst->ss->match_home(tst, homehost) == 1)) { + tst->ss->match_home(tst, c->homehost) == 1)) { if (report_missmatch) - fprintf(stderr, Name ": %s has metadata type %s for which " - "auto-assembly is disabled\n", - devname, tst->ss->name); + pr_err("%s has metadata type %s for which " + "auto-assembly is disabled\n", + devname, tst->ss->name); tmpdev->used = 2; } } if (dfd >= 0) close(dfd); if (tmpdev->used == 2) { - if (auto_assem) + if (auto_assem || !inargv) /* Ignore unrecognised devices during auto-assembly */ goto loop; if (ident->uuid_set || ident->name[0] || @@ -387,11 +390,12 @@ int Assemble(struct supertype *st, char *mddev, goto loop; - fprintf(stderr, Name ": %s has no superblock - assembly aborted\n", + pr_err("%s has no superblock - assembly aborted\n", devname); if (st) st->ss->free_super(st); dev_policy_free(pol); + domain_free(domains); return 1; } @@ -399,12 +403,23 @@ int Assemble(struct supertype *st, char *mddev, /* tmpdev is a container. We need to be either * looking for a member, or auto-assembling */ + /* should be safe to try an exclusive open now, we + * have rejected anything that some other mdadm might + * be looking at + */ + dfd = dev_open(devname, O_RDONLY | O_EXCL); + if (dfd < 0) { + if (report_missmatch) + pr_err("%s is busy - skipping\n", devname); + goto loop; + } + close(dfd); if (ident->container) { if (ident->container[0] == '/' && !same_dev(ident->container, devname)) { if (report_missmatch) - fprintf(stderr, Name ": %s is not the container required (%s)\n", + pr_err("%s is not the container required (%s)\n", devname, ident->container); goto loop; } @@ -413,13 +428,12 @@ int Assemble(struct supertype *st, char *mddev, int uuid[4]; content = &info; - memset(content, 0, sizeof(*content)); tst->ss->getinfo_super(tst, content, NULL); if (!parse_uuid(ident->container, uuid) || !same_uuid(content->uuid, uuid, tst->ss->swapuuid)) { if (report_missmatch) - fprintf(stderr, Name ": %s has wrong UUID to be required container\n", + pr_err("%s has wrong UUID to be required container\n", devname); goto loop; } @@ -427,8 +441,8 @@ int Assemble(struct supertype *st, char *mddev, } /* It is worth looking inside this container. */ - if (verbose > 0) - fprintf(stderr, Name ": looking in container %s\n", + if (c->verbose > 0) + pr_err("looking in container %s\n", devname); for (content = tst->ss->container_content(tst, NULL); @@ -436,14 +450,19 @@ int Assemble(struct supertype *st, char *mddev, content = content->next) { if (!ident_matches(ident, content, tst, - homehost, update, + c->homehost, c->update, report_missmatch ? devname : NULL)) /* message already printed */; else if (is_member_busy(content->text_version)) { if (report_missmatch) - fprintf(stderr, Name ": member %s in %s is already assembled\n", + pr_err("member %s in %s is already assembled\n", content->text_version, devname); + } else if (content->array.state & (1<text_version, + devname); } else break; } @@ -454,15 +473,16 @@ int Assemble(struct supertype *st, char *mddev, st = tst; tst = NULL; if (!auto_assem && inargv && tmpdev->next != NULL) { - fprintf(stderr, Name ": %s is a container, but is not " + pr_err("%s is a container, but is not " "only device given: confused and aborting\n", devname); st->ss->free_super(st); dev_policy_free(pol); + domain_free(domains); return 1; } - if (verbose > 0) - fprintf(stderr, Name ": found match on member %s in %s\n", + if (c->verbose > 0) + pr_err("found match on member %s in %s\n", content->text_version, devname); /* make sure we finished the loop */ @@ -471,18 +491,41 @@ int Assemble(struct supertype *st, char *mddev, } else { content = &info; - memset(content, 0, sizeof(*content)); tst->ss->getinfo_super(tst, content, NULL); if (!ident_matches(ident, content, tst, - homehost, update, + c->homehost, c->update, report_missmatch ? devname : NULL)) goto loop; + + /* should be safe to try an exclusive open now, we + * have rejected anything that some other mdadm might + * be looking at + */ + dfd = dev_open(devname, O_RDONLY | O_EXCL); + if (dfd < 0) { + if (report_missmatch) + pr_err("%s is busy - skipping\n", devname); + goto loop; + } + close(dfd); if (st == NULL) st = dup_super(tst); if (st->minor_version == -1) st->minor_version = tst->minor_version; + + if (memcmp(content->uuid, uuid_zero, + sizeof(int[4])) == 0) { + /* this is a floating spare. It cannot define + * an array unless there are no more arrays of + * this type to be found. It can be included + * in an array of this type though. + */ + tmpdev->used = 3; + goto loop; + } + if (st->ss != tst->ss || st->minor_version != tst->minor_version || st->ss->compare_super(st, tst) != 0) { @@ -493,21 +536,21 @@ int Assemble(struct supertype *st, char *mddev, */ if (auto_assem) goto loop; - if (homehost) { - int first = st->ss->match_home(st, homehost); - int last = tst->ss->match_home(tst, homehost); + if (c->homehost) { + int first = st->ss->match_home(st, c->homehost); + int last = tst->ss->match_home(tst, c->homehost); if (first != last && (first == 1 || last == 1)) { /* We can do something */ if (first) {/* just ignore this one */ if (report_missmatch) - fprintf(stderr, Name ": %s misses out due to wrong homehost\n", + pr_err("%s misses out due to wrong homehost\n", devname); goto loop; } else { /* reject all those sofar */ struct mddev_dev *td; if (report_missmatch) - fprintf(stderr, Name ": %s overrides previous devices due to good homehost\n", + pr_err("%s overrides previous devices due to good homehost\n", devname); for (td=devlist; td != tmpdev; td=td->next) if (td->used == 1) @@ -517,22 +560,79 @@ int Assemble(struct supertype *st, char *mddev, } } } - fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", + pr_err("superblock on %s doesn't match others - assembly aborted\n", devname); tst->ss->free_super(tst); st->ss->free_super(st); dev_policy_free(pol); + domain_free(domains); return 1; } tmpdev->used = 1; } loop: + /* Collect domain information from members only */ + if (tmpdev && tmpdev->used == 1) { + if (!pol) + pol = devnum_policy(stb.st_rdev); + domain_merge(&domains, pol, tst?tst->ss->name:NULL); + } dev_policy_free(pol); pol = NULL; if (tst) tst->ss->free_super(tst); } + /* Check if we found some imsm spares but no members */ + if ((auto_assem || + (ident->uuid_set && + memcmp(uuid_zero, ident->uuid,sizeof(uuid_zero)) == 0)) && + (!st || !st->sb)) + for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) { + if (tmpdev->used != 3) + continue; + tmpdev->used = 1; + content = &info; + + if (!st->sb) { + /* we need sb from one of the spares */ + int dfd = dev_open(tmpdev->devname, O_RDONLY); + if (dfd < 0 || + st->ss->load_super(st, dfd, NULL)) + tmpdev->used = 2; + if (dfd > 0) + close(dfd); + } + } + + /* Now reject spares that don't match domains of identified members */ + for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) { + struct stat stb; + if (tmpdev->used != 3) + continue; + if (stat(tmpdev->devname, &stb)< 0) { + pr_err("fstat failed for %s: %s\n", + tmpdev->devname, strerror(errno)); + tmpdev->used = 2; + } else { + struct dev_policy *pol = devnum_policy(stb.st_rdev); + int dt = domain_test(domains, pol, NULL); + if (inargv && dt != 0) + /* take this spare as domains match + * if there are any */ + tmpdev->used = 1; + else if (!inargv && dt == 1) + /* device wasn't explicitly listed, so need + * explicit domain match - which we have */ + tmpdev->used = 1; + else + /* if domains don't match mark as unused */ + tmpdev->used = 0; + dev_policy_free(pol); + } + } + domain_free(domains); + if (!st || !st->sb || !content) return 2; @@ -542,7 +642,7 @@ int Assemble(struct supertype *st, char *mddev, trustworthy = FOREIGN; name = content->name; - switch (st->ss->match_home(st, homehost) + switch (st->ss->match_home(st, c->homehost) ?: st->ss->match_home(st, "any")) { case 1: trustworthy = LOCAL; @@ -567,7 +667,7 @@ int Assemble(struct supertype *st, char *mddev, } if (name[0] && trustworthy != LOCAL && - ! require_homehost && + ! c->require_homehost && conf_name_is_free(name)) trustworthy = LOCAL; @@ -587,20 +687,20 @@ int Assemble(struct supertype *st, char *mddev, mddev = chosen_name; vers = md_get_version(mdfd); if (vers < 9000) { - fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n" + pr_err("Assemble requires driver version 0.90.0 or later.\n" " Upgrade your kernel or try --build\n"); close(mdfd); return 1; } if (mddev_busy(fd2devnum(mdfd))) { - fprintf(stderr, Name ": %s already active, cannot restart it!\n", + pr_err("%s already active, cannot restart it!\n", mddev); for (tmpdev = devlist ; tmpdev && tmpdev->used != 1; tmpdev = tmpdev->next) ; if (tmpdev && auto_assem) - fprintf(stderr, Name ": %s needed for %s...\n", + pr_err("%s needed for %s...\n", mddev, tmpdev->devname); close(mdfd); mdfd = -3; @@ -614,21 +714,25 @@ int Assemble(struct supertype *st, char *mddev, #ifndef MDASSEMBLE if (content != &info) { /* This is a member of a container. Try starting the array. */ - return assemble_container_content(st, mdfd, content, runstop, - chosen_name, verbose); + int err; + err = assemble_container_content(st, mdfd, content, c->runstop, + c->readonly, + chosen_name, c->verbose, + c->backup_file, c->freeze_reshape); + close(mdfd); + return err; } + bitmap_done = 0; #endif /* Ok, no bad inconsistancy, we can try updating etc */ - bitmap_done = 0; - content->update_private = NULL; - devices = malloc(num_devs * sizeof(*devices)); - devmap = calloc(num_devs * content->array.raid_disks, 1); + devices = xcalloc(num_devs, sizeof(*devices)); + devmap = xcalloc(num_devs, content->array.raid_disks); 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 */ #ifndef MDASSEMBLE - if (update) { + if (c->update) { int dfd; /* prepare useful information in info structures */ struct stat stb2; @@ -636,7 +740,7 @@ int Assemble(struct supertype *st, char *mddev, int err; fstat(mdfd, &stb2); - if (strcmp(update, "uuid")==0 && + if (strcmp(c->update, "uuid")==0 && !ident->uuid_set) { int rfd; if ((rfd = open("/dev/urandom", O_RDONLY)) < 0 || @@ -652,7 +756,7 @@ int Assemble(struct supertype *st, char *mddev, tst = dup_super(st); if (dfd < 0 || tst->ss->load_super(tst, dfd, NULL) != 0) { - fprintf(stderr, Name ": cannot re-read metadata from %s - aborting\n", + pr_err("cannot re-read metadata from %s - aborting\n", devname); if (dfd >= 0) close(dfd); @@ -667,18 +771,17 @@ int Assemble(struct supertype *st, char *mddev, strcpy(content->name, ident->name); content->array.md_minor = minor(stb2.st_rdev); - if (strcmp(update, "byteorder") == 0) + if (strcmp(c->update, "byteorder") == 0) err = 0; else - err = tst->ss->update_super(tst, content, update, - devname, verbose, + err = tst->ss->update_super(tst, content, c->update, + devname, c->verbose, ident->uuid_set, - homehost); + c->homehost); if (err < 0) { - fprintf(stderr, - Name ": --update=%s not understood" - " for %s metadata\n", - update, tst->ss->name); + pr_err("--update=%s not understood" + " for %s metadata\n", + c->update, tst->ss->name); tst->ss->free_super(tst); free(tst); close(mdfd); @@ -687,22 +790,22 @@ int Assemble(struct supertype *st, char *mddev, free(devmap); return 1; } - if (strcmp(update, "uuid")==0 && + if (strcmp(c->update, "uuid")==0 && !ident->uuid_set) { ident->uuid_set = 1; memcpy(ident->uuid, content->uuid, 16); } if (tst->ss->store_super(tst, dfd)) - fprintf(stderr, Name ": Could not re-write superblock on %s.\n", + pr_err("Could not re-write superblock on %s.\n", devname); close(dfd); - if (strcmp(update, "uuid")==0 && + if (strcmp(c->update, "uuid")==0 && ident->bitmap_fd >= 0 && !bitmap_done) { if (bitmap_update_uuid(ident->bitmap_fd, content->uuid, tst->ss->swapuuid) != 0) - fprintf(stderr, Name ": Could not update uuid on external bitmap.\n"); + pr_err("Could not update uuid on external bitmap.\n"); else bitmap_done = 1; } @@ -715,7 +818,7 @@ int Assemble(struct supertype *st, char *mddev, dfd = dev_open(devname, O_RDWR|O_EXCL); if (dfd < 0 || tst->ss->load_super(tst, dfd, NULL) != 0) { - fprintf(stderr, Name ": cannot re-read metadata from %s - aborting\n", + pr_err("cannot re-read metadata from %s - aborting\n", devname); if (dfd >= 0) close(dfd); @@ -731,8 +834,8 @@ int Assemble(struct supertype *st, char *mddev, stat(devname, &stb); - if (verbose > 0) - fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n", + if (c->verbose > 0) + pr_err("%s is identified as a member of %s, slot %d.\n", devname, mddev, content->disk.raid_disk); devices[devcnt].devname = devname; devices[devcnt].uptodate = 0; @@ -761,7 +864,7 @@ int Assemble(struct supertype *st, char *mddev, if (i < 10000) { if (i >= bestcnt) { int newbestcnt = i+10; - int *newbest = malloc(sizeof(int)*newbestcnt); + int *newbest = xmalloc(sizeof(int)*newbestcnt); int c; for (c=0; c < newbestcnt; c++) if (c < bestcnt) @@ -783,7 +886,7 @@ int Assemble(struct supertype *st, char *mddev, * Could be a mis-detection caused by overlapping * partitions. fail-safe. */ - fprintf(stderr, Name ": WARNING %s and %s appear" + pr_err("WARNING %s and %s appear" " to have very similar superblocks.\n" " If they are really different, " "please --zero the superblock on one\n" @@ -805,11 +908,9 @@ int Assemble(struct supertype *st, char *mddev, } devcnt++; } - free(content->update_private); - content->update_private = NULL; if (devcnt == 0) { - fprintf(stderr, Name ": no devices found for %s\n", + pr_err("no devices found for %s\n", mddev); if (st) st->ss->free_super(st); @@ -819,7 +920,7 @@ int Assemble(struct supertype *st, char *mddev, return 1; } - if (update && strcmp(update, "byteorder")==0) + if (c->update && strcmp(c->update, "byteorder")==0) st->minor_version = 90; st->ss->getinfo_super(st, content, NULL); @@ -828,8 +929,7 @@ int Assemble(struct supertype *st, char *mddev, /* now we have some devices that might be suitable. * I wonder how many */ - avail = malloc(content->array.raid_disks); - memset(avail, 0, content->array.raid_disks); + avail = xcalloc(content->array.raid_disks, 1); okcnt = 0; sparecnt=0; rebuilding_cnt=0; @@ -845,19 +945,21 @@ int Assemble(struct supertype *st, char *mddev, if (content->array.level != LEVEL_MULTIPATH) if (!(devices[j].i.disk.state & (1<array.raid_disks > 0 && devices[most_recent].i.disk.raid_disk >= 0 && devmap[j * content->array.raid_disks + devices[most_recent].i.disk.raid_disk] == 0) { - if (verbose > -1) - fprintf(stderr, Name ": ignoring %s as it reports %s as failed\n", + if (c->verbose > -1) + pr_err("ignoring %s as it reports %s as failed\n", devices[j].devname, devices[most_recent].devname); best[i] = -1; continue; @@ -868,7 +970,9 @@ int Assemble(struct supertype *st, char *mddev, if (i < content->array.raid_disks) { if (devices[j].i.recovery_start == MaxSector || (content->reshape_active && - j >= content->array.raid_disks - content->delta_disks)) { + ((i >= content->array.raid_disks - content->delta_disks) || + (i >= content->array.raid_disks - content->delta_disks - 1 + && content->array.level == 4)))) { okcnt++; avail[i]=1; } else @@ -878,9 +982,17 @@ int Assemble(struct supertype *st, char *mddev, } } free(devmap); - while (force && !enough(content->array.level, content->array.raid_disks, - content->array.layout, 1, - avail, okcnt)) { + while (c->force && + (!enough(content->array.level, content->array.raid_disks, + content->array.layout, 1, + avail) + || + (content->reshape_active && content->delta_disks > 0 && + !enough(content->array.level, (content->array.raid_disks + - content->delta_disks), + content->new_layout, 1, + avail) + ))) { /* Choose the newest best drive which is * not up-to-date, update the superblock * and add it. @@ -903,15 +1015,15 @@ int Assemble(struct supertype *st, char *mddev, break; current_events = devices[chosen_drive].i.events; add_another: - if (verbose >= 0) - fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n", + if (c->verbose >= 0) + pr_err("forcing event count in %s(%d) from %d upto %d\n", devices[chosen_drive].devname, devices[chosen_drive].i.disk.raid_disk, (int)(devices[chosen_drive].i.events), (int)(devices[most_recent].i.events)); fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); if (fd < 0) { - fprintf(stderr, Name ": Couldn't open %s for write - not updating\n", + pr_err("Couldn't open %s for write - not updating\n", devices[chosen_drive].devname); devices[chosen_drive].i.events = 0; continue; @@ -919,19 +1031,19 @@ int Assemble(struct supertype *st, char *mddev, tst = dup_super(st); if (tst->ss->load_super(tst,fd, NULL)) { close(fd); - fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", + pr_err("RAID superblock disappeared from %s - not updating.\n", devices[chosen_drive].devname); devices[chosen_drive].i.events = 0; continue; } content->events = devices[most_recent].i.events; tst->ss->update_super(tst, content, "force-one", - devices[chosen_drive].devname, verbose, + devices[chosen_drive].devname, c->verbose, 0, NULL); if (tst->ss->store_super(tst, fd)) { close(fd); - fprintf(stderr, Name ": Could not re-write superblock on %s\n", + pr_err("Could not re-write superblock on %s\n", devices[chosen_drive].devname); devices[chosen_drive].i.events = 0; tst->ss->free_super(tst); @@ -951,6 +1063,7 @@ int Assemble(struct supertype *st, char *mddev, int j = best[i]; if (j >= 0 && !devices[j].uptodate && + devices[j].i.recovery_start == MaxSector && devices[j].i.events == current_events) { chosen_drive = j; goto add_another; @@ -974,9 +1087,11 @@ int Assemble(struct supertype *st, char *mddev, continue; if (!devices[j].uptodate) continue; + if (devices[j].i.events < devices[most_recent].i.events) + continue; chosen_drive = j; if ((fd=dev_open(devices[j].devname, O_RDONLY|O_EXCL))< 0) { - fprintf(stderr, Name ": Cannot open %s: %s\n", + pr_err("Cannot open %s: %s\n", devices[j].devname, strerror(errno)); close(mdfd); free(devices); @@ -984,7 +1099,7 @@ int Assemble(struct supertype *st, char *mddev, } if (st->ss->load_super(st,fd, NULL)) { close(fd); - fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", + pr_err("RAID superblock has disappeared from %s\n", devices[j].devname); close(mdfd); free(devices); @@ -993,7 +1108,7 @@ int Assemble(struct supertype *st, char *mddev, close(fd); } if (st->sb == NULL) { - fprintf(stderr, Name ": No suitable drives found for %s\n", mddev); + pr_err("No suitable drives found for %s\n", mddev); close(mdfd); free(devices); return 1; @@ -1021,33 +1136,31 @@ int Assemble(struct supertype *st, char *mddev, clean = 0; if (st->ss->update_super(st, &devices[j].i, "assemble", NULL, - verbose, 0, NULL)) { - if (force) { - if (verbose >= 0) - fprintf(stderr, Name ": " - "clearing FAULTY flag for device %d in %s for %s\n", + c->verbose, 0, NULL)) { + if (c->force) { + if (c->verbose >= 0) + pr_err("clearing FAULTY flag for device %d in %s for %s\n", j, mddev, devices[j].devname); change = 1; } else { - if (verbose >= -1) - fprintf(stderr, Name ": " - "device %d in %s has wrong state in superblock, but %s seems ok\n", + if (c->verbose >= -1) + pr_err("device %d in %s has wrong state in superblock, but %s seems ok\n", i, mddev, devices[j].devname); } } #if 0 if (!(super.disks[i].i.disk.state & (1 << MD_DISK_FAULTY))) { - fprintf(stderr, Name ": devices %d of %s is not marked FAULTY in superblock, but cannot be found\n", + pr_err("devices %d of %s is not marked FAULTY in superblock, but cannot be found\n", i, mddev); } #endif } - if (force && !clean && + if (c->force && !clean && !enough(content->array.level, content->array.raid_disks, content->array.layout, clean, - avail, okcnt)) { + avail)) { change += st->ss->update_super(st, content, "force-array", - devices[chosen_drive].devname, verbose, + devices[chosen_drive].devname, c->verbose, 0, NULL); clean = 1; } @@ -1056,7 +1169,7 @@ int Assemble(struct supertype *st, char *mddev, int fd; fd = dev_open(devices[chosen_drive].devname, O_RDWR|O_EXCL); if (fd < 0) { - fprintf(stderr, Name ": Could not open %s for write - cannot Assemble array.\n", + pr_err("Could not open %s for write - cannot Assemble array.\n", devices[chosen_drive].devname); close(mdfd); free(devices); @@ -1064,12 +1177,15 @@ int Assemble(struct supertype *st, char *mddev, } if (st->ss->store_super(st, fd)) { close(fd); - fprintf(stderr, Name ": Could not re-write superblock on %s\n", + pr_err("Could not re-write superblock on %s\n", devices[chosen_drive].devname); close(mdfd); free(devices); return 1; } + if (c->verbose >= 0) + pr_err("Marking array %s as 'clean'\n", + mddev); close(fd); } @@ -1080,9 +1196,9 @@ int Assemble(struct supertype *st, char *mddev, #ifndef MDASSEMBLE if (content->reshape_active) { int err = 0; - int *fdlist = malloc(sizeof(int)* bestcnt); - if (verbose > 0) - fprintf(stderr, Name ":%s has an active reshape - checking " + int *fdlist = xmalloc(sizeof(int)* bestcnt); + if (c->verbose > 0) + pr_err(":%s has an active reshape - checking " "if critical section needs to be restored\n", chosen_name); for (i=0; i= 0) { fdlist[i] = dev_open(devices[j].devname, O_RDWR|O_EXCL); if (fdlist[i] < 0) { - fprintf(stderr, Name ": Could not open %s for write - cannot Assemble array.\n", + pr_err("Could not open %s for write - cannot Assemble array.\n", devices[j].devname); err = 1; break; @@ -1099,11 +1215,14 @@ int Assemble(struct supertype *st, char *mddev, fdlist[i] = -1; } if (!err) { - err = Grow_restart(st, content, fdlist, bestcnt, - backup_file, verbose > 0); - if (err && invalid_backup) { - if (verbose > 0) - fprintf(stderr, Name ": continuing" + if (st->ss->external && st->ss->recover_backup) + err = st->ss->recover_backup(st, content); + else + err = Grow_restart(st, content, fdlist, bestcnt, + c->backup_file, c->verbose > 0); + if (err && c->invalid_backup) { + if (c->verbose > 0) + pr_err("continuing" " without restoring backup\n"); err = 0; } @@ -1113,9 +1232,9 @@ int Assemble(struct supertype *st, char *mddev, if (fdlist[i]>=0) close(fdlist[i]); } if (err) { - fprintf(stderr, Name ": Failed to restore critical section for reshape, sorry.\n"); - if (backup_file == NULL) - fprintf(stderr," Possibly you needed to specify the --backup-file\n"); + pr_err("Failed to restore critical section for reshape, sorry.\n"); + if (c->backup_file == NULL) + cont_err("Possibly you needed to specify the --backup-file\n"); close(mdfd); free(devices); return err; @@ -1139,7 +1258,7 @@ int Assemble(struct supertype *st, char *mddev, rv = set_array_info(mdfd, st, content); if (rv) { - fprintf(stderr, Name ": failed to set array info for %s: %s\n", + pr_err("failed to set array info for %s: %s\n", mddev, strerror(errno)); ioctl(mdfd, STOP_ARRAY, NULL); close(mdfd); @@ -1148,7 +1267,7 @@ int Assemble(struct supertype *st, char *mddev, } if (ident->bitmap_fd >= 0) { if (ioctl(mdfd, SET_BITMAP_FILE, ident->bitmap_fd) != 0) { - fprintf(stderr, Name ": SET_BITMAP_FILE failed.\n"); + pr_err("SET_BITMAP_FILE failed.\n"); ioctl(mdfd, STOP_ARRAY, NULL); close(mdfd); free(devices); @@ -1158,7 +1277,7 @@ int Assemble(struct supertype *st, char *mddev, /* From config file */ int bmfd = open(ident->bitmap_file, O_RDWR); if (bmfd < 0) { - fprintf(stderr, Name ": Could not open bitmap file %s\n", + pr_err("Could not open bitmap file %s\n", ident->bitmap_file); ioctl(mdfd, STOP_ARRAY, NULL); close(mdfd); @@ -1166,7 +1285,7 @@ int Assemble(struct supertype *st, char *mddev, return 1; } if (ioctl(mdfd, SET_BITMAP_FILE, bmfd) != 0) { - fprintf(stderr, Name ": Failed to set bitmapfile for %s\n", mddev); + pr_err("Failed to set bitmapfile for %s\n", mddev); close(bmfd); ioctl(mdfd, STOP_ARRAY, NULL); close(mdfd); @@ -1196,30 +1315,31 @@ int Assemble(struct supertype *st, char *mddev, rv = add_disk(mdfd, st, content, &devices[j].i); if (rv) { - fprintf(stderr, Name ": failed to add " - "%s to %s: %s\n", - devices[j].devname, - mddev, - strerror(errno)); + pr_err("failed to add " + "%s to %s: %s\n", + devices[j].devname, + mddev, + strerror(errno)); if (i < content->array.raid_disks || i == bestcnt) okcnt--; else sparecnt--; - } else if (verbose > 0) - fprintf(stderr, Name ": added %s " - "to %s as %d\n", - devices[j].devname, mddev, - devices[j].i.disk.raid_disk); - } else if (verbose > 0 && i < content->array.raid_disks) - fprintf(stderr, Name ": no uptodate device for " + } else if (c->verbose > 0) + pr_err("added %s to %s as %d%s\n", + devices[j].devname, mddev, + devices[j].i.disk.raid_disk, + devices[j].uptodate?"": + " (possibly out of date)"); + } else if (c->verbose > 0 && i < content->array.raid_disks) + pr_err("no uptodate device for " "slot %d of %s\n", i, mddev); } if (content->array.level == LEVEL_CONTAINER) { - if (verbose >= 0) { - fprintf(stderr, Name ": Container %s has been " + if (c->verbose >= 0) { + pr_err("Container %s has been " "assembled with %d drive%s", mddev, okcnt+sparecnt, okcnt+sparecnt==1?"":"s"); if (okcnt < (unsigned)content->array.raid_disks) @@ -1227,6 +1347,7 @@ int Assemble(struct supertype *st, char *mddev, content->array.raid_disks); fprintf(stderr, "\n"); } + st->ss->free_super(st); sysfs_uevent(content, "change"); wait_for(chosen_name, mdfd); close(mdfd); @@ -1234,10 +1355,10 @@ int Assemble(struct supertype *st, char *mddev, return 0; } - if (runstop == 1 || - (runstop <= 0 && + if (c->runstop == 1 || + (c->runstop <= 0 && ( enough(content->array.level, content->array.raid_disks, - content->array.layout, clean, avail, okcnt) && + content->array.layout, clean, avail) && (okcnt + rebuilding_cnt >= req_cnt || start_partial_ok) ))) { /* This array is good-to-go. @@ -1248,14 +1369,24 @@ int Assemble(struct supertype *st, char *mddev, int rv; #ifndef MDASSEMBLE if (content->reshape_active && - content->delta_disks <= 0) - rv = Grow_continue(mdfd, st, content, backup_file); - else + content->delta_disks <= 0) { + rv = sysfs_set_str(content, NULL, + "array_state", "readonly"); + if (rv == 0) + rv = Grow_continue(mdfd, st, content, + c->backup_file, + c->freeze_reshape); + } else if (c->readonly && + sysfs_attribute_available( + content, NULL, "array_state")) { + rv = sysfs_set_str(content, NULL, + "array_state", "readonly"); + } else #endif rv = ioctl(mdfd, RUN_ARRAY, NULL); if (rv == 0) { - if (verbose >= 0) { - fprintf(stderr, Name ": %s has been started with %d drive%s", + if (c->verbose >= 0) { + pr_err("%s has been started with %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (okcnt < (unsigned)content->array.raid_disks) fprintf(stderr, " (out of %d)", content->array.raid_disks); @@ -1277,6 +1408,7 @@ int Assemble(struct supertype *st, char *mddev, sysfs_set_num(sra, NULL, "stripe_cache_size", (4 * content->array.chunk_size / 4096) + 1); + sysfs_free(sra); } } if (okcnt < (unsigned)content->array.raid_disks) { @@ -1288,17 +1420,16 @@ int Assemble(struct supertype *st, char *mddev, * might allow them to be included, or * they will become spares. */ - for (i = 0; i <= bestcnt; i++) { + for (i = 0; i < bestcnt; i++) { int j = best[i]; if (j >= 0 && !devices[j].uptodate) { if (!disk_action_allows(&devices[j].i, st->ss->name, act_re_add)) continue; rv = add_disk(mdfd, st, content, &devices[j].i); - if (rv == 0 && verbose >= 0) - fprintf(stderr, - Name ": %s has been re-added.\n", - devices[j].devname); + if (rv == 0 && c->verbose >= 0) + pr_err("%s has been re-added.\n", + devices[j].devname); } } } @@ -1333,18 +1464,18 @@ int Assemble(struct supertype *st, char *mddev, free(devices); return 0; } - fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n", + pr_err("failed to RUN_ARRAY %s: %s\n", mddev, strerror(errno)); if (!enough(content->array.level, content->array.raid_disks, - content->array.layout, 1, avail, okcnt)) - fprintf(stderr, Name ": Not enough devices to " + content->array.layout, 1, avail)) + pr_err("Not enough devices to " "start the array.\n"); else if (!enough(content->array.level, content->array.raid_disks, content->array.layout, clean, - avail, okcnt)) - fprintf(stderr, Name ": Not enough devices to " + avail)) + pr_err("Not enough devices to " "start the array while not clean " "- consider --force.\n"); @@ -1354,9 +1485,9 @@ int Assemble(struct supertype *st, char *mddev, free(devices); return 1; } - if (runstop == -1) { - fprintf(stderr, Name ": %s assembled from %d drive%s", - mddev, okcnt, okcnt==1?"":"s"); + if (c->runstop == -1) { + pr_err("%s assembled from %d drive%s", + mddev, okcnt, okcnt==1?"":"s"); if (okcnt != (unsigned)content->array.raid_disks) fprintf(stderr, " (out of %d)", content->array.raid_disks); fprintf(stderr, ", but not started.\n"); @@ -1364,19 +1495,19 @@ int Assemble(struct supertype *st, char *mddev, free(devices); return 0; } - if (verbose >= -1) { - fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); + if (c->verbose >= -1) { + pr_err("%s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); if (rebuilding_cnt) fprintf(stderr, "%s %d rebuilding", sparecnt?", ":" and ", rebuilding_cnt); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); if (!enough(content->array.level, content->array.raid_disks, - content->array.layout, 1, avail, okcnt)) + content->array.layout, 1, avail)) fprintf(stderr, " - not enough to start the array.\n"); else if (!enough(content->array.level, content->array.raid_disks, content->array.layout, clean, - avail, okcnt)) + avail)) fprintf(stderr, " - not enough to start the " "array while not clean - consider " "--force.\n"); @@ -1402,7 +1533,7 @@ int Assemble(struct supertype *st, char *mddev, dev = makedev(devices[chosen_drive].i.disk.major, devices[chosen_drive].i.disk.minor); if (ioctl(mdfd, START_ARRAY, dev)) { - fprintf(stderr, Name ": Cannot start array: %s\n", + pr_err("Cannot start array: %s\n", strerror(errno)); } @@ -1415,47 +1546,99 @@ int Assemble(struct supertype *st, char *mddev, #ifndef MDASSEMBLE int assemble_container_content(struct supertype *st, int mdfd, struct mdinfo *content, int runstop, - char *chosen_name, int verbose) + int readonly, + char *chosen_name, int verbose, + char *backup_file, int freeze_reshape) { struct mdinfo *dev, *sra; int working = 0, preexist = 0; + int expansion = 0; struct map_ent *map = NULL; + int old_raid_disks; + int start_reshape; sysfs_init(content, mdfd, 0); sra = sysfs_read(mdfd, 0, GET_VERSION); - if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0) + if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0) { + if (content->array.major_version == -1 && + content->array.minor_version == -2 && + readonly && + content->text_version[0] == '/') + content->text_version[0] = '-'; if (sysfs_set_array(content, md_get_version(mdfd)) != 0) { - close(mdfd); + if (sra) + sysfs_free(sra); return 1; } + } + + /* There are two types of reshape: container wide or sub-array specific + * Check if metadata requests blocking container wide reshapes + */ + start_reshape = (content->reshape_active && + !((content->reshape_active == CONTAINER_RESHAPE) && + (content->array.state & (1<ss->external && content->recovery_blocked && start_reshape) + block_subarray(content); + if (sra) sysfs_free(sra); - + old_raid_disks = content->array.raid_disks - content->delta_disks; for (dev = content->devs; dev; dev = dev->next) - if (sysfs_add_disk(content, dev, 1) == 0) - working++; - else if (errno == EEXIST) + if (sysfs_add_disk(content, dev, 1) == 0) { + if (dev->disk.raid_disk >= old_raid_disks && + content->reshape_active) + expansion++; + else + working++; + } else if (errno == EEXIST) preexist++; - if (working == 0) { - close(mdfd); + if (working + expansion == 0) return 1;/* Nothing new, don't try to start */ - } - + map_update(&map, fd2devnum(mdfd), content->text_version, content->uuid, chosen_name); if (runstop > 0 || - (working + preexist) >= content->array.working_disks) { + (working + preexist + expansion) >= + content->array.working_disks) { int err; - switch(content->array.level) { + if (start_reshape) { + int spare = content->array.raid_disks + expansion; + if (restore_backup(st, content, + working, + spare, backup_file, verbose) == 1) + return 1; + + err = sysfs_set_str(content, NULL, + "array_state", "readonly"); + if (err) + return 1; + + if (st->ss->external) { + if (!mdmon_running(st->container_dev)) + start_mdmon(st->container_dev); + ping_monitor_by_id(st->container_dev); + if (mdmon_running(st->container_dev) && + st->update_tail == NULL) + st->update_tail = &st->updates; + } + + err = Grow_continue(mdfd, st, content, backup_file, + freeze_reshape); + } else switch(content->array.level) { case LEVEL_LINEAR: case LEVEL_MULTIPATH: case 0: err = sysfs_set_str(content, NULL, "array_state", - "active"); + readonly ? "readonly" : "active"); break; default: err = sysfs_set_str(content, NULL, "array_state", @@ -1464,37 +1647,50 @@ int assemble_container_content(struct supertype *st, int mdfd, if (!err) { if (!mdmon_running(st->container_dev)) start_mdmon(st->container_dev); - ping_monitor(devnum2devname(st->container_dev)); + ping_monitor_by_id(st->container_dev); } break; } if (!err) sysfs_set_safemode(content, content->safe_mode_delay); + + /* Block subarray here if it is not reshaped now + * It has be blocked a little later to allow mdmon to switch in + * in to R/W state + */ + if (st->ss->external && content->recovery_blocked && + !start_reshape) + block_subarray(content); + if (verbose >= 0) { if (err) - fprintf(stderr, Name - ": array %s now has %d devices", - chosen_name, working + preexist); + pr_err("array %s now has %d device%s", + chosen_name, working + preexist, + working + preexist == 1 ? "":"s"); else - fprintf(stderr, Name - ": Started %s with %d devices", - chosen_name, working + preexist); + pr_err("Started %s with %d device%s", + chosen_name, working + preexist, + working + preexist == 1 ? "":"s"); if (preexist) fprintf(stderr, " (%d new)", working); + if (expansion) + fprintf(stderr, " ( + %d for expansion)", + expansion); fprintf(stderr, "\n"); } if (!err) wait_for(chosen_name, mdfd); - close(mdfd); - return 0; + return err; /* FIXME should have an O_EXCL and wait for read-auto */ } else { - if (verbose >= 0) - fprintf(stderr, Name - ": %s assembled with %d devices but " - "not started\n", - chosen_name, working); - close(mdfd); + if (verbose >= 0) { + pr_err("%s assembled with %d device%s", + chosen_name, preexist + working, + preexist + working == 1 ? "":"s"); + if (preexist) + fprintf(stderr, " (%d new)", working); + fprintf(stderr, " but not started\n"); + } return 1; } }