X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=Assemble.c;h=f10491b63f48b2c7849aaebf7c94c13ddea3f32c;hp=7837b19bf4f2c61924eeacd3f58568cebffd1278;hb=598f0d58ac3544e25f90f2d34337e15764f4d877;hpb=68c7d6d790f856b4e8301d0afa7fc6873a0d4bb8 diff --git a/Assemble.c b/Assemble.c index 7837b19b..f10491b6 100644 --- a/Assemble.c +++ b/Assemble.c @@ -115,16 +115,12 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, int must_close = 0; int old_linux = 0; int vers = 0; /* Keep gcc quite - it really is initialised */ - void *first_super = NULL, *super = NULL; struct { char *devname; - unsigned int major, minor; - unsigned int oldmajor, oldminor; - long long events; - int uptodate; - int state; - int raid_disk; - int disk_nr; + int uptodate; /* set once we decide that this device is as + * recent as everything else in the array. + */ + struct mdinfo i; } *devices; int *best = NULL; /* indexed by raid_disk */ unsigned int bestcnt = 0; @@ -215,7 +211,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, char *devname = tmpdev->devname; int dfd; struct stat stb; - struct supertype *tst = st; + struct supertype *tst = dup_super(st); if (tmpdev->used > 1) continue; @@ -246,55 +242,60 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, fprintf(stderr, Name ": no recogniseable superblock on %s\n", devname); tmpdev->used = 2; - } else if (tst->ss->load_super(tst,dfd, &super, NULL)) { + } else if (tst->ss->load_super(tst,dfd, NULL)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf( stderr, Name ": no RAID superblock on %s\n", devname); } else { - tst->ss->getinfo_super(tst, &info, super); + tst->ss->getinfo_super(tst, &info); } if (dfd >= 0) close(dfd); if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) && - (!super || same_uuid(info.uuid, ident->uuid, tst->ss->swapuuid)==0)) { + (!tst || !tst->sb || + same_uuid(info.uuid, ident->uuid, tst->ss->swapuuid)==0)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong uuid.\n", devname); goto loop; } if (ident->name[0] && (!update || strcmp(update, "name")!= 0) && - (!super || name_matches(info.name, ident->name, homehost)==0)) { + (!tst || !tst->sb || + name_matches(info.name, ident->name, homehost)==0)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong name.\n", devname); goto loop; } if (ident->super_minor != UnSet && - (!super || ident->super_minor != info.array.md_minor)) { + (!tst || !tst->sb || + ident->super_minor != info.array.md_minor)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong super-minor.\n", devname); goto loop; } if (ident->level != UnSet && - (!super|| ident->level != info.array.level)) { + (!tst || !tst->sb || + ident->level != info.array.level)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s has wrong raid level.\n", devname); goto loop; } if (ident->raid_disks != UnSet && - (!super || ident->raid_disks!= info.array.raid_disks)) { + (!tst || !tst->sb || + ident->raid_disks!= info.array.raid_disks)) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s requires wrong number of drives.\n", devname); goto loop; } if (mdfd < 0) { - if (tst == NULL || super == NULL) + if (tst == NULL || tst->sb == NULL) continue; if (update == NULL && - tst->ss->match_home(tst, super, homehost)==0) { + tst->ss->match_home(tst, homehost)==0) { if ((inargv && verbose >= 0) || verbose > 0) fprintf(stderr, Name ": %s is not built for host %s.\n", devname, homehost); @@ -311,18 +312,21 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, * the other isn't that can disambiguate. */ - if (!super) { + if (!tst || !tst->sb) { fprintf(stderr, Name ": %s has no superblock - assembly aborted\n", devname); - st->ss->free_super(st, first_super); + if (st) + st->ss->free_super(st); return 1; } if (st == NULL) - st = tst; + st = dup_super(tst); + if (st->minor_version == -1) + st->minor_version = tst->minor_version; if (st->ss != tst->ss || st->minor_version != tst->minor_version || - st->ss->compare_super(&first_super, super) != 0) { + st->ss->compare_super(st, tst) != 0) { /* Some mismatch. If exactly one array matches this host, * we can resolve on that one. * Or, if we are auto assembling, we just ignore the second @@ -331,10 +335,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, if (mdfd < 0) goto loop; if (homehost) { - int first = st->ss->match_home(st, first_super, - homehost); - int last = tst->ss->match_home(tst, super, - homehost); + int first = st->ss->match_home(st, homehost); + int last = tst->ss->match_home(tst, homehost); if (first+last == 1) { /* We can do something */ if (first) {/* just ignore this one */ @@ -357,17 +359,15 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, } fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", devname); - tst->ss->free_super(tst, super); - st->ss->free_super(st, first_super); + tst->ss->free_super(tst); + st->ss->free_super(st); return 1; } tmpdev->used = 1; loop: - if (super) - tst->ss->free_super(tst, super); - super = NULL; + tst->ss->free_super(tst); } if (mdfd < 0) { @@ -377,10 +377,10 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, */ mdu_array_info_t inf; char *c; - if (!first_super) { + if (!st->sb) { return 2; } - st->ss->getinfo_super(st, &info, first_super); + st->ss->getinfo_super(st, &info); c = strchr(info.name, ':'); if (c) c++; else c= info.name; if (isdigit(*c) && ((ident->autof & 7)==4 || (ident->autof&7)==6)) @@ -390,9 +390,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, asprintf(&mddev, "/dev/md/%s", c); mdfd = open_mddev(mddev, ident->autof); if (mdfd < 0) { - st->ss->free_super(st, first_super); + st->ss->free_super(st); free(devices); - first_super = NULL; goto try_again; } vers = md_get_version(mdfd); @@ -407,9 +406,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, mddev, tmpdev->devname); close(mdfd); mdfd = -1; - st->ss->free_super(st, first_super); + st->ss->free_super(st); free(devices); - first_super = NULL; goto try_again; } must_close = 1; @@ -426,6 +424,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, int dfd; /* prepare useful information in info structures */ struct stat stb2; + struct supertype *tst; fstat(mdfd, &stb2); if (strcmp(update, "uuid")==0 && @@ -444,16 +443,17 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, remove_partitions(dfd); - st->ss->load_super(st, dfd, &super, NULL); - st->ss->getinfo_super(st, &info, super); + tst = dup_super(st); + tst->ss->load_super(tst, dfd, NULL); + tst->ss->getinfo_super(tst, &info); memcpy(info.uuid, ident->uuid, 16); strcpy(info.name, ident->name); info.array.md_minor = minor(stb2.st_rdev); - st->ss->update_super(st, &info, super, update, - devname, verbose, - ident->uuid_set, homehost); + tst->ss->update_super(tst, &info, update, + devname, verbose, + ident->uuid_set, homehost); if (strcmp(update, "uuid")==0 && !ident->uuid_set) { ident->uuid_set = 1; @@ -462,7 +462,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, if (dfd < 0) fprintf(stderr, Name ": Cannot open %s for superblock update\n", devname); - else if (st->ss->store_super(st, dfd, super)) + else if (tst->ss->store_super(tst, dfd)) fprintf(stderr, Name ": Could not re-write superblock on %s.\n", devname); if (dfd >= 0) @@ -470,21 +470,26 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, if (strcmp(update, "uuid")==0 && ident->bitmap_fd >= 0 && !bitmap_done) { - if (bitmap_update_uuid(ident->bitmap_fd, info.uuid, st->ss->swapuuid) != 0) + if (bitmap_update_uuid(ident->bitmap_fd, + info.uuid, + tst->ss->swapuuid) != 0) fprintf(stderr, Name ": Could not update uuid on external bitmap.\n"); else bitmap_done = 1; } + tst->ss->free_super(tst); } else #endif { + struct supertype *tst = dup_super(st);; int dfd; dfd = dev_open(devname, O_RDWR|O_EXCL); remove_partitions(dfd); - st->ss->load_super(st, dfd, &super, NULL); - st->ss->getinfo_super(st, &info, super); + tst->ss->load_super(tst, dfd, NULL); + tst->ss->getinfo_super(tst, &info); + tst->ss->free_super(tst); close(dfd); } @@ -494,25 +499,20 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n", devname, mddev, info.disk.raid_disk); devices[devcnt].devname = devname; - devices[devcnt].major = major(stb.st_rdev); - devices[devcnt].minor = minor(stb.st_rdev); - devices[devcnt].oldmajor = info.disk.major; - devices[devcnt].oldminor = info.disk.minor; - devices[devcnt].events = info.events; - devices[devcnt].raid_disk = info.disk.raid_disk; - devices[devcnt].disk_nr = info.disk.number; devices[devcnt].uptodate = 0; - devices[devcnt].state = info.disk.state; + devices[devcnt].i = info; + devices[devcnt].i.disk.major = major(stb.st_rdev); + devices[devcnt].i.disk.minor = minor(stb.st_rdev); if (most_recent < devcnt) { - if (devices[devcnt].events - > devices[most_recent].events) + if (devices[devcnt].i.events + > devices[most_recent].i.events) most_recent = devcnt; } if (info.array.level == -4) /* with multipath, the raid_disk from the superblock is meaningless */ i = devcnt; else - i = devices[devcnt].raid_disk; + i = devices[devcnt].i.disk.raid_disk; if (i+1 == 0) { if (nextspare < info.array.raid_disks) nextspare = info.array.raid_disks; @@ -537,10 +537,12 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, bestcnt = newbestcnt; } if (best[i] >=0 && - devices[best[i]].events == devices[devcnt].events && - devices[best[i]].minor != devices[devcnt].minor && - st->ss->major == 0 && - info.array.level != -4) { + devices[best[i]].i.events + == devices[devcnt].i.events + && (devices[best[i]].i.disk.minor + != devices[devcnt].i.disk.minor) + && st->ss->major == 0 + && info.array.level != -4) { /* two different devices with identical superblock. * Could be a mis-detection caused by overlapping * partitions. fail-safe. @@ -559,14 +561,11 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, return 1; } if (best[i] == -1 - || devices[best[i]].events < devices[devcnt].events) + || (devices[best[i]].i.events + < devices[devcnt].i.events)) best[i] = devcnt; } devcnt++; - - if (super) - st->ss->free_super(st, super); - super = NULL; } if (update && strcmp(update, "byteorder")==0) @@ -575,12 +574,12 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, if (devcnt == 0) { fprintf(stderr, Name ": no devices found for %s\n", mddev); - st->ss->free_super(st, first_super); + st->ss->free_super(st); if (must_close) close(mdfd); return 1; } - st->ss->getinfo_super(st, &info, first_super); + st->ss->getinfo_super(st, &info); clean = info.array.state & 1; /* now we have some devices that might be suitable. @@ -600,13 +599,14 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, * as they don't make sense */ if (info.array.level != -4) - if (!(devices[j].state & (1<= - devices[most_recent].events) { + if (devices[j].i.events+event_margin >= + devices[most_recent].i.events) { devices[j].uptodate = 1; if (i < info.array.raid_disks) { okcnt++; @@ -623,59 +623,63 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, * and add it. */ int fd; + struct supertype *tst; long long current_events; chosen_drive = -1; for (i=0; i=0 && !devices[j].uptodate && - devices[j].events > 0 && + devices[j].i.events > 0 && (chosen_drive < 0 || - devices[j].events > devices[chosen_drive].events)) + devices[j].i.events + > devices[chosen_drive].i.events)) chosen_drive = j; } if (chosen_drive < 0) break; - current_events = devices[chosen_drive].events; + 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", - devices[chosen_drive].devname, devices[chosen_drive].raid_disk, - (int)(devices[chosen_drive].events), - (int)(devices[most_recent].events)); + 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", devices[chosen_drive].devname); - devices[chosen_drive].events = 0; + devices[chosen_drive].i.events = 0; continue; } - if (st->ss->load_super(st,fd, &super, NULL)) { + tst = dup_super(st); + if (tst->ss->load_super(st,fd, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", devices[chosen_drive].devname); - devices[chosen_drive].events = 0; + devices[chosen_drive].i.events = 0; continue; } - info.events = devices[most_recent].events; - st->ss->update_super(st, &info, super, "force-one", + info.events = devices[most_recent].i.events; + tst->ss->update_super(tst, &info, "force-one", devices[chosen_drive].devname, verbose, 0, NULL); - if (st->ss->store_super(st, fd, super)) { + if (tst->ss->store_super(tst, fd)) { close(fd); fprintf(stderr, Name ": Could not re-write superblock on %s\n", devices[chosen_drive].devname); - devices[chosen_drive].events = 0; - st->ss->free_super(st, super); + devices[chosen_drive].i.events = 0; + tst->ss->free_super(tst); continue; } close(fd); - devices[chosen_drive].events = devices[most_recent].events; + devices[chosen_drive].i.events = devices[most_recent].i.events; devices[chosen_drive].uptodate = 1; avail[chosen_drive] = 1; okcnt++; - st->ss->free_super(st, super); + tst->ss->free_super(tst); /* If there are any other drives of the same vintage, * add them in as well. We can't lose and we might gain @@ -684,8 +688,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, int j = best[i]; if (j >= 0 && !devices[j].uptodate && - devices[j].events > 0 && - devices[j].events == current_events) { + devices[j].i.events > 0 && + devices[j].i.events == current_events) { chosen_drive = j; goto add_another; } @@ -699,7 +703,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, * superblock. */ chosen_drive = -1; - super = NULL; + st->ss->free_super(st); for (i=0; chosen_drive < 0 && iss->load_super(st,fd, &super, NULL)) { + if (st->ss->load_super(st,fd, NULL)) { close(fd); fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", devices[j].devname); @@ -724,12 +728,12 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, } close(fd); } - if (super == NULL) { + if (st->sb == NULL) { fprintf(stderr, Name ": No suitable drives found for %s\n", mddev); if (must_close) close(mdfd); return 1; } - st->ss->getinfo_super(st, &info, super); + st->ss->getinfo_super(st, &info); for (i=0; iss->update_super(st, &info, super, "assemble", NULL, + devices[j].i.disk.state = desired_state; + + if (st->ss->update_super(st, &devices[j].i, "assemble", NULL, verbose, 0, NULL)) { if (force) { if (verbose >= 0) @@ -764,8 +766,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, } } #if 0 - if (!devices[j].uptodate && - !(super.disks[i].state & (1 << MD_DISK_FAULTY))) { + 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", i, mddev); } @@ -775,7 +776,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, !enough(info.array.level, info.array.raid_disks, info.array.layout, clean, avail, okcnt)) { - change += st->ss->update_super(st, &info, super, "force-array", + change += st->ss->update_super(st, &info, "force-array", devices[chosen_drive].devname, verbose, 0, NULL); clean = 1; @@ -790,7 +791,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, if (must_close) close(mdfd); return 1; } - if (st->ss->store_super(st, fd, super)) { + if (st->ss->store_super(st, fd)) { close(fd); fprintf(stderr, Name ": Could not re-write superblock on %s\n", devices[chosen_drive].devname); @@ -842,6 +843,24 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, /* Almost ready to actually *do* something */ if (!old_linux) { int rv; + +#ifndef MDASSEMBLE + struct mdinfo *sra; + if (st->ss->external) { + char ver[100]; + strcat(strcpy(ver, "external:"), st->ss->text_version); + sra = sysfs_read(mdfd, 0, 0); + if ((vers % 100) < 2 || + sra == NULL || + sysfs_set_str(sra, NULL, "metadata_version", + ver) < 0) { + fprintf(stderr, Name ": This kernel does not " + "support external metadata.\n"); + return 1; + } + rv = sysfs_set_array(sra, &info); + } else +#endif if ((vers % 100) >= 1) { /* can use different versions */ mdu_array_info_t inf; memset(&inf, 0, sizeof(inf)); @@ -892,27 +911,62 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, j = chosen_drive; if (j >= 0 /* && devices[j].uptodate */) { - mdu_disk_info_t disk; - memset(&disk, 0, sizeof(disk)); - disk.major = devices[j].major; - disk.minor = devices[j].minor; - if (ioctl(mdfd, ADD_NEW_DISK, &disk)!=0) { - fprintf(stderr, Name ": failed to add %s to %s: %s\n", +#ifndef MDASSEMBLE + if (st->ss->external) { + int fd = dev_open(devices[j].devname, + O_RDONLY); + if (fd < 0) + rv = 1; + else { + devices[j].i.disk.number = + devices[j].i.disk.raid_disk; + st->ss->getinfo_super_n(st, + &devices[j].i); + rv = sysfs_add_disk(sra, fd, + &devices[j].i); + close(fd); + } + } else +#endif + rv = ioctl(mdfd, ADD_NEW_DISK, + &devices[j].i.disk); + if (rv) { + fprintf(stderr, Name ": failed to add " + "%s to %s: %s\n", devices[j].devname, mddev, strerror(errno)); - if (i < info.array.raid_disks || i == bestcnt) + if (i < info.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].raid_disk); + 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 < info.array.raid_disks) - fprintf(stderr, Name ": no uptodate device for slot %d of %s\n", + fprintf(stderr, Name ": no uptodate device for " + "slot %d of %s\n", i, mddev); } + if (info.array.level == LEVEL_CONTAINER) { + if (verbose >= 0) { + fprintf(stderr, Name ": Container %s has been " + "assembled with %d drive%s", + mddev, okcnt, okcnt==1?"":"s"); + if (okcnt < info.array.raid_disks) + fprintf(stderr, " (out of %d)", + info.array.raid_disks); + fprintf(stderr, "\n"); + } + if (must_close) + close(mdfd); + return 0; + } + if (runstop == 1 || (runstop <= 0 && ( enough(info.array.level, info.array.raid_disks, @@ -935,7 +989,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, /* There is a nasty race with 'mdadm --monitor'. * If it opens this device before we close it, * it gets an incomplete open on which IO - * doesn't work and the capacity if wrong. + * doesn't work and the capacity is + * wrong. * If we reopen (to check for layered devices) * before --monitor closes, we loose. * @@ -1014,8 +1069,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd, * so we can just start the array */ unsigned long dev; - dev = makedev(devices[chosen_drive].major, - devices[chosen_drive].minor); + 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", strerror(errno));