X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=Assemble.c;h=4003e06a547bd89b257840c2bf1171270c64530b;hp=53c09d61e110cdb468f0c69fba19e4fcb1b792f3;hb=0df46c2ad8872a9d6e5832f3098d12a7e0d2eb01;hpb=9a9dab3670110c2db7fe6f716977b72adedbf855 diff --git a/Assemble.c b/Assemble.c index 53c09d61..4003e06a 100644 --- a/Assemble.c +++ b/Assemble.c @@ -35,6 +35,7 @@ int Assemble(char *mddev, int mdfd, mddev_ident_t ident, char *conffile, mddev_dev_t devlist, int readonly, int runstop, + char *update, int verbose, int force) { /* @@ -72,7 +73,7 @@ int Assemble(char *mddev, int mdfd, * For each device: * Check superblock - discard if bad * Check uuid (set if we don't have one) - discard if no match - * Check superblock similarity if we have a superbloc - discard if different + * Check superblock similarity if we have a superblock - discard if different * Record events, devicenum, utime * This should give us a list of devices for the array * We should collect the most recent event and utime numbers @@ -97,24 +98,31 @@ int Assemble(char *mddev, int mdfd, mdp_super_t first_super, super; struct { char *devname; - int major, minor; + unsigned int major, minor; + unsigned int oldmajor, oldminor; long long events; time_t utime; int uptodate; + int state; int raid_disk; - } devices[MD_SB_DISKS]; - int best[MD_SB_DISKS]; /* indexed by raid_disk */ - int devcnt = 0, okcnt, sparecnt; - int i; + } *devices; + int *best = NULL; /* indexed by raid_disk */ + unsigned int bestcnt = 0; + int devcnt = 0; + unsigned int okcnt, sparecnt; + unsigned int req_cnt; + unsigned int i; int most_recent = 0; int chosen_drive; int change = 0; int inargv = 0; int start_partial_ok = force || devlist==NULL; + unsigned int num_devs; + mddev_dev_t tmpdev; vers = md_get_version(mdfd); if (vers <= 0) { - fprintf(stderr, Name ": %s appears not to be an md device.\n"); + fprintf(stderr, Name ": %s appears not to be an md device.\n", mddev); return 1; } if (vers < 9000) { @@ -152,8 +160,16 @@ int Assemble(char *mddev, int mdfd, devlist = conf_get_devs(conffile); else inargv = 1; + tmpdev = devlist; num_devs = 0; + while (tmpdev) { + num_devs++; + tmpdev = tmpdev->next; + } + best = malloc(num_devs * sizeof(*best)); + devices = malloc(num_devs * sizeof(*devices)); + first_super.md_magic = 0; - for (i=0; inext; if (ident->devices && - !match_oneof(ident->devices, devname)) + !match_oneof(ident->devices, devname)) { + if (inargv || verbose) + fprintf(stderr, Name ": %s is not one of %s\n", devname, ident->devices); continue; + } dfd = open(devname, O_RDONLY, 0); if (dfd < 0) { @@ -206,21 +225,21 @@ int Assemble(char *mddev, int mdfd, devname); continue; } - if (ident->super_minor >= 0 && + if (ident->super_minor != UnSet && (!havesuper || ident->super_minor != super.md_minor)) { if (inargv || verbose) fprintf(stderr, Name ": %s has wrong super-minor.\n", devname); continue; } - if (ident->level != -10 && - (!havesuper|| ident->level != super.level)) { + if (ident->level != UnSet && + (!havesuper|| ident->level != (int)super.level)) { if (inargv || verbose) fprintf(stderr, Name ": %s has wrong raid level.\n", devname); continue; } - if (ident->raid_disks != -1 && + if (ident->raid_disks != UnSet && (!havesuper || ident->raid_disks!= super.raid_disks)) { if (inargv || verbose) fprintf(stderr, Name ": %s requires wrong number of drives.\n", @@ -244,32 +263,121 @@ int Assemble(char *mddev, int mdfd, return 1; } + + /* this is needed until we get a more relaxed super block format */ if (devcnt >= MD_SB_DISKS) { fprintf(stderr, Name ": ouch - too many devices appear to be in this array. Ignoring %s\n", devname); continue; } + + /* looks like a good enough match to update the super block if needed */ + if (update) { + if (strcmp(update, "sparc2.2")==0 ) { + /* 2.2 sparc put the events in the wrong place + * So we copy the tail of the superblock + * up 4 bytes before continuing + */ + __u32 *sb32 = (__u32*)&super; + memcpy(sb32+MD_SB_GENERIC_CONSTANT_WORDS+7, + sb32+MD_SB_GENERIC_CONSTANT_WORDS+7+1, + (MD_SB_WORDS - (MD_SB_GENERIC_CONSTANT_WORDS+7+1))*4); + fprintf (stderr, Name ": adjusting superblock of %s for 2.2/sparc compatability.\n", + devname); + } + if (strcmp(update, "super-minor") ==0) { + struct stat stb2; + fstat(mdfd, &stb2); + super.md_minor = minor(stb2.st_rdev); + if (verbose) + fprintf(stderr, Name ": updating superblock of %s with minor number %d\n", + devname, super.md_minor); + } + if (strcmp(update, "summaries") == 0) { + /* set nr_disks, active_disks, working_disks, + * failed_disks, spare_disks based on disks[] + * array in superblock. + * Also make sure extra slots aren't 'failed' + */ + super.nr_disks = super.active_disks = + super.working_disks = super.failed_disks = + super.spare_disks = 0; + for (i=0; i < MD_SB_DISKS ; i++) + if (super.disks[i].major || + super.disks[i].minor) { + int state = super.disks[i].state; + if (state & (1<= super.raid_disks && super.disks[i].number == 0) + super.disks[i].state = 0; + } + if (strcmp(update, "resync") == 0) { + /* make sure resync happens */ + super.state &= ~(1<= 0) + close(dfd); + } + if (verbose) fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n", devname, mddev, super.this_disk.raid_disk); devices[devcnt].devname = devname; - devices[devcnt].major = MAJOR(stb.st_rdev); - devices[devcnt].minor = MINOR(stb.st_rdev); + devices[devcnt].major = major(stb.st_rdev); + devices[devcnt].minor = minor(stb.st_rdev); + devices[devcnt].oldmajor = super.this_disk.major; + devices[devcnt].oldminor = super.this_disk.minor; devices[devcnt].events = md_event(&super); devices[devcnt].utime = super.utime; devices[devcnt].raid_disk = super.this_disk.raid_disk; devices[devcnt].uptodate = 0; + devices[devcnt].state = super.this_disk.state; if (most_recent < devcnt) { if (devices[devcnt].events > devices[most_recent].events) most_recent = devcnt; } - i = devices[devcnt].raid_disk; - if (i>=0 && i < MD_SB_DISKS) + if ((int)super.level == -4) + /* with multipath, the raid_disk from the superblock is meaningless */ + i = devcnt; + else + i = devices[devcnt].raid_disk; + if (i < 10000) { + if (i >= bestcnt) { + unsigned int newbestcnt = i+10; + int *newbest = malloc(sizeof(int)*newbestcnt); + unsigned int c; + for (c=0; c < newbestcnt; c++) + if (c < bestcnt) + newbest[c] = best[c]; + else + newbest[c] = -1; + if (best)free(best); + best = newbest; + bestcnt = newbestcnt; + } if (best[i] == -1 || devices[best[i]].events < devices[devcnt].events) best[i] = devcnt; - + } devcnt++; } @@ -283,10 +391,19 @@ int Assemble(char *mddev, int mdfd, */ okcnt = 0; sparecnt=0; - for (i=0; i< MD_SB_DISKS;i++) { + for (i=0; i< bestcnt ;i++) { int j = best[i]; int event_margin = !force; if (j < 0) continue; + /* note: we ignore error flags in multipath arrays + * as they don't make sense + */ + if ((int)first_super.level != -4) + if (!(devices[j].state & (1<= devices[most_recent].events) { devices[j].uptodate = 1; @@ -303,7 +420,7 @@ int Assemble(char *mddev, int mdfd, */ int fd; chosen_drive = -1; - for (i=0; i=0 && !devices[j].uptodate && @@ -334,6 +451,10 @@ int Assemble(char *mddev, int mdfd, } super.events_hi = (devices[most_recent].events>>32)&0xFFFFFFFF; super.events_lo = (devices[most_recent].events)&0xFFFFFFFF; + if (super.level == 5 || super.level == 4) { + /* need to force clean */ + super.state = (1<= 0 && devices[j].uptodate) { + if (j >= 0 /* && devices[j].uptodate */) { mdu_disk_info_t disk; memset(&disk, 0, sizeof(disk)); disk.major = devices[j].major; @@ -472,12 +624,14 @@ int Assemble(char *mddev, int mdfd, if (runstop == 1 || (runstop == 0 && - ( first_super.raid_disks == okcnt - || start_partial_ok && enough(first_super.level, first_super.raid_disks, okcnt)) - )) { + ( enough(first_super.level, first_super.raid_disks, okcnt) && + (okcnt >= req_cnt || start_partial_ok) + ))) { if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { fprintf(stderr, Name ": %s has been started with %d drive%s", mddev, okcnt, okcnt==1?"":"s"); + if (okcnt < first_super.raid_disks) + fprintf(stderr, " (out of %d)", first_super.raid_disks); if (sparecnt) fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); fprintf(stderr, ".\n"); @@ -492,8 +646,18 @@ int Assemble(char *mddev, int mdfd, mddev, okcnt, okcnt==1?"":"s"); return 0; } - fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it (use --run to insist).\n", - mddev, okcnt, okcnt==1?"":"s"); + fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s"); + if (sparecnt) + fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); + if (!enough(first_super.level, first_super.raid_disks, okcnt)) + fprintf(stderr, " - not enough to start the array.\n"); + else { + if (req_cnt == first_super.raid_disks) + fprintf(stderr, " - need all %d to start it", req_cnt); + else + fprintf(stderr, " - need %d of %d to start", req_cnt, first_super.raid_disks); + fprintf(stderr, " (use --run to insist).\n"); + } return 1; } else { /* The "chosen_drive" is a good choice, and if necessary, the superblock has @@ -501,7 +665,7 @@ int Assemble(char *mddev, int mdfd, * so we can just start the array */ unsigned long dev; - dev = MKDEV(devices[chosen_drive].major, + dev = makedev(devices[chosen_drive].major, devices[chosen_drive].minor); if (ioctl(mdfd, START_ARRAY, dev)) { fprintf(stderr, Name ": Cannot start array: %s\n", @@ -509,4 +673,5 @@ int Assemble(char *mddev, int mdfd, } } + return 0; }