diff options
Diffstat (limited to 'Assemble.c')
-rw-r--r-- | Assemble.c | 429 |
1 files changed, 242 insertions, 187 deletions
@@ -28,18 +28,20 @@ */ #include "mdctl.h" -#include "md_p.h" #include "md_u.h" +#include "md_p.h" int Assemble(char *mddev, int mdfd, - int uuid[4], int uuidset, - char *conffile, int scan, + mddev_ident_t ident, char *conffile, int subdevs, char **subdev, int readonly, int runstop, int verbose, int force) { /* - * The task of Assemble is to submit a + * The task of Assemble is to find a collection of + * devices that should (according to their superblocks) + * form an array, and to give this collection to the MD driver. + * In Linux-2.4 and later, this involves submitting a * SET_ARRAY_INFO ioctl with no arg - to prepare * the array - and then submit a number of * ADD_NEW_DISK ioctls to add disks into @@ -100,52 +102,15 @@ int Assemble(char *mddev, int mdfd, long long events; time_t utime; int uptodate; + int raid_disk; } devices[MD_SB_DISKS]; int best[MD_SB_DISKS]; /* indexed by raid_disk */ - int devcnt = 0, okcnt; + int devcnt = 0, okcnt, sparecnt; int i; int most_recent = 0; + int chosen_drive = -1; + int change = 0; - if (!mddev && !scan) { - fputs(Name ": internal error - Assemble called with no device or --scan\n", stderr); - return 1; - } - if (!mddev) { - mddev_uuid_t device_list; - int found = 0; - device_list = conf_get_uuids(conffile); - if (!device_list) { - fprintf(stderr, Name ": No devices found in config file\n"); - return 1; - } - for (; device_list; device_list=device_list->next) { - if (!uuidset || same_uuid(device_list->uuid,uuid)) { - mdfd = open(device_list->devname, O_RDONLY, 0); - if (mdfd < 0) { - fprintf(stderr, - Name ": error opening %s: %s\n", - device_list->devname, - strerror(errno)); - continue; - } - if (Assemble(device_list->devname, mdfd, - device_list->uuid, 1, - conffile, 1, - subdevs, subdev, - readonly, runstop, verbose, force)==0) - found++; - close(mdfd); - } - } - if (found) - return 0; - fprintf(stderr,Name ": Did not successfully Assemble any devices\n"); - return 1; - } - - /* - * Ok, we have an mddev, check it out - */ vers = md_get_version(mdfd); if (vers <= 0) { fprintf(stderr, Name ": %s appears not to be an md device.\n"); @@ -153,7 +118,7 @@ int Assemble(char *mddev, int mdfd, } if (vers < 9000) { fprintf(stderr, Name ": Assemble requires driver version 0.90.0 or later.\n" - " Upgrade your kernel or try --Build\n"); + " Upgrade your kernel or try --build\n"); return 1; } if (get_linux_version() < 2004000) @@ -167,40 +132,24 @@ int Assemble(char *mddev, int mdfd, ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */ /* - * We have a valid mddev, check out uuid + * If any subdevs are listed, then any that don't + * match ident are discarded. Remainder must all match and + * become the array. + * If no subdevs, then we scan all devices in the config file, but + * there must be something in the identity */ - if (!uuidset && scan) { - /* device must be listed with uuid in conf file */ - mddev_uuid_t device_list; - device_list = conf_get_uuids(conffile); - while (device_list && - strcmp(device_list->devname, mddev) != 0) - device_list = device_list->next; - if (!device_list) { - fprintf(stderr, Name ": --scan set and no uuid found for %s in config file.\n", - mddev); - return 1; - } - /* the uuid is safe until next call to conf_get_uuids */ - uuid = device_list->uuid; - uuidset = 1; + if (subdevs == 0 && + ident->uuid_set == 0 && + ident->super_minor < 0 && + ident->devices == NULL) { + fprintf(stderr, Name ": No identity information available for %s - cannot assemble.\n", + mddev); + return 1; } - - /* Now to start looking at devices. - * If no devices were given, but a uuid is available and - * --scan was set, then we should scan all devices listed in the - * config file - * - */ - if (subdevs==0 && scan && uuidset) + if (subdevs==0) devlist = conf_get_devs(conffile); - if (subdevs == 0 && devlist == NULL) { - fprintf(stderr, Name ": no devices given for %s\n", mddev); - return 1; - } - /* now for each device */ first_super.md_magic = 0; for (i=0; i<MD_SB_DISKS; i++) best[i] = -1; @@ -215,6 +164,8 @@ int Assemble(char *mddev, int mdfd, int dfd; struct stat stb; int inargv; + int havesuper=0; + if (subdevs) { devname = *subdev++; subdevs--; @@ -225,61 +176,69 @@ int Assemble(char *mddev, int mdfd, inargv=0; } + if (ident->devices && + !match_oneof(ident->devices, devname)) + continue; + dfd = open(devname, O_RDONLY, 0); if (dfd < 0) { if (inargv || verbose) fprintf(stderr, Name ": cannot open device %s: %s\n", devname, strerror(errno)); - continue; - } - if (fstat(dfd, &stb)< 0) { - /* Impossible! */ - fprintf(stderr, Name ": fstat failed for %s: %s\n", - devname, strerror(errno)); - close(dfd); - continue; - } - if ((stb.st_mode & S_IFMT) != S_IFBLK) { - fprintf(stderr, Name ": %d is not a block device.\n", - devname); - close(dfd); - continue; - } - if (load_super(dfd, &super)) { + } else if (fstat(dfd, &stb)< 0) { + /* Impossible! */ + fprintf(stderr, Name ": fstat failed for %s: %s\n", + devname, strerror(errno)); + close(dfd); + } if ((stb.st_mode & S_IFMT) != S_IFBLK) { + fprintf(stderr, Name ": %d is not a block device.\n", + devname); + close(dfd); + } if (load_super(dfd, &super)) { if (inargv || verbose) fprintf( stderr, Name ": no RAID superblock on %s\n", devname); close(dfd); - continue; + } else { + havesuper =1; + uuid_from_super(this_uuid, &super); + close(dfd); } - close(dfd); - uuid_from_super(this_uuid, &super); - if (uuidset && !same_uuid(this_uuid, uuid)) { - if (inargv || verbose) - fprintf(stderr, Name ": %s has wrong uuid.\n", - devname); - continue; + + if (ident->uuid_set && + (!havesuper || same_uuid(this_uuid, ident->uuid)==0)) { + if (inargv || verbose) + fprintf(stderr, Name ": %s has wrong uuid.\n", + devname); + continue; } - if (compare_super(&first_super, &super)) { + if (ident->super_minor >= 0 && + (!havesuper || ident->super_minor != super.md_minor)) { if (inargv || verbose) - fprintf(stderr, Name ": superblock on %s doesn't match\n", + fprintf(stderr, Name ": %s has wrong super-minor.\n", devname); continue; } - if (uuidset) { - uuid_from_super(this_uuid, &first_super); - if (!same_uuid(this_uuid, uuid)) { - if (inargv || verbose) - fprintf(stderr, Name ": %s has wrong uuid.\n", - devname); - continue; - } - } else { - uuid_from_super(uuid, &first_super); - uuidset = 1; + + /* If we are this far, then we are commited to this device. + * If the super_block doesn't exist, or doesn't match others, + * then we cannot continue + */ + if (verbose) + fprintf(stderr, Name ": %s is identified as a member of %s.\n", + devname, mddev); + + if (!havesuper) { + fprintf(stderr, Name ": %s has no superblock - assembly aborted\n", + devname); + return 1; + } + if (compare_super(&first_super, &super)) { + fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n", + devname); + return 1; } - /* Ok, this one is at least worth considering */ if (devcnt >= MD_SB_DISKS) { fprintf(stderr, Name ": ouch - too many devices appear to be in this array. Ignoring %s\n", devname); @@ -290,17 +249,19 @@ int Assemble(char *mddev, int mdfd, devices[devcnt].minor = MINOR(stb.st_rdev); devices[devcnt].events = md_event(&super); devices[devcnt].utime = super.utime; + devices[devcnt].raid_disk = super.this_disk.raid_disk; devices[devcnt].uptodate = 0; if (most_recent < devcnt) { if (devices[devcnt].events > devices[most_recent].events) most_recent = devcnt; } - i = super.this_disk.raid_disk; - if (best[i] == -1 - || devices[best[i]].events < devices[devcnt].events) { - best[i] = devcnt; - } + i = devices[devcnt].raid_disk; + if (i>=0 && i < MD_SB_DISKS) + if (best[i] == -1 + || devices[best[i]].events < devices[devcnt].events) + best[i] = devcnt; + devcnt++; } @@ -313,13 +274,17 @@ int Assemble(char *mddev, int mdfd, * I wonder how many */ okcnt = 0; - for (i=0; i< first_super.raid_disks;i++) { + sparecnt=0; + for (i=0; i< MD_SB_DISKS;i++) { int j = best[i]; if (j < 0) continue; if (devices[j].events+1 >= devices[most_recent].events) { devices[j].uptodate = 1; - okcnt++; + if (i < first_super.raid_disks) + okcnt++; + else + sparecnt++; } } while (force && !enough(first_super.level, first_super.raid_disks, okcnt)) { @@ -327,10 +292,133 @@ int Assemble(char *mddev, int mdfd, * not up-to-date, update the superblock * and add it. */ - fprintf(stderr,"NotImplementedYet\n"); - /* FIXME */ - exit(2); + int fd; + for (i=0; i<first_super.raid_disks; i++) { + int j = best[i]; + if (j>=0 && + !devices[j].uptodate && + devices[j].events > 0 && + (chosen_drive < 0 || + devices[j].events > devices[chosen_drive].events)) + chosen_drive = j; + } + if (chosen_drive < 0) + break; + 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)); + fd = open(devices[chosen_drive].devname, O_RDWR); + if (fd < 0) { + fprintf(stderr, Name ": Couldn't open %s for write - not updating\n", + devices[chosen_drive].devname); + devices[chosen_drive].events = 0; + continue; + } + if (load_super(fd, &super)) { + close(fd); + fprintf(stderr, Name ": RAID superblock disappeared from %s - not updating.\n", + devices[chosen_drive].devname); + devices[chosen_drive].events = 0; + continue; + } + super.events_hi = (devices[most_recent].events>>32)&0xFFFFFFFF; + super.events_lo = (devices[most_recent].events)&0xFFFFFFFF; + super.sb_csum = calc_sb_csum(&super); +/*DRYRUN*/ if (store_super(fd, &super)) { + close(fd); + fprintf(stderr, Name ": Could not re-write superblock on %s\n", + devices[chosen_drive].devname); + devices[chosen_drive].events = 0; + continue; + } + close(fd); + devices[chosen_drive].events = devices[most_recent].events; + devices[chosen_drive].uptodate = 1; + okcnt++; } + + /* Now we want to look at the superblock which the kernel will base things on + * and compare the devices that we think are working with the devices that the + * superblock thinks are working. + * If there are differences and --force is given, then update this chosen + * superblock. + */ + for (i=0; chosen_drive < 0 && i<MD_SB_DISKS; i++) { + int j = best[i]; + int fd; + if (j<0) + continue; + if (!devices[j].uptodate) + continue; + chosen_drive = j; + if ((fd=open(devices[j].devname, O_RDONLY))< 0) { + fprintf(stderr, Name ": Cannot open %s: %s\n", + devices[j].devname, strerror(errno)); + return 1; + } + if (load_super(fd, &super)) { + close(fd); + fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", + devices[j].devname); + return 1; + } + close(fd); + } + + for (i=0; i<MD_SB_DISKS; i++) { + int j = best[i]; + if (j<0) + continue; + if (!devices[j].uptodate) + continue; + if (devices[j].major != super.disks[j].major || + devices[j].minor != super.disks[j].minor) { + change |= 1; + super.disks[j].major = devices[j].major; + super.disks[j].minor = devices[j].minor; + } + if (devices[j].uptodate && + (super.disks[i].state & (1 << MD_DISK_FAULTY))) { + if (force) { + fprintf(stderr, Name ": " + "clearing FAULT flag for device %d in %s for %s\n", + j, mddev, devices[j].devname); + super.disks[i].state &= ~(1<<MD_DISK_FAULTY); + change |= 2; + } else { + fprintf(stderr, Name ": " + "device %d in %s is marked faulty in superblock, but %s seems ok\n", + i, mddev, devices[j].devname); + } + } + if (!devices[j].uptodate && + !(super.disks[i].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); + } + } + + if ((force && (change & 2)) + || (old_linux && (change & 1))) { + int fd; + super.sb_csum = calc_sb_csum(&super); + fd = open(devices[chosen_drive].devname, O_RDWR); + if (fd < 0) { + fprintf(stderr, Name ": Could open %s for write - cannot Assemble array.\n", + devices[chosen_drive].devname); + return 1; + } + if (store_super(fd, &super)) { + close(fd); + fprintf(stderr, Name ": Could not re-write superblock on %s\n", + devices[chosen_drive].devname); + return 1; + } + close(fd); + change = 0; + } + /* Almost ready to actually *do* something */ if (!old_linux) { if (ioctl(mdfd, SET_ARRAY_INFO, NULL) != 0) { @@ -338,9 +426,16 @@ int Assemble(char *mddev, int mdfd, mddev, strerror(errno)); return 1; } - /* First, add the raid disks */ - for (i=0; i<first_super.raid_disks; i++) { - int j = best[i]; + /* First, add the raid disks, but add the chosen one last */ + for (i=0; i<=MD_SB_DISKS; i++) { + int j; + if (i < MD_SB_DISKS) { + j = best[i]; + if (j == chosen_drive) + continue; + } else + j = chosen_drive; + if (j >= 0 && devices[j].uptodate) { mdu_disk_info_t disk; memset(&disk, 0, sizeof(disk)); @@ -351,18 +446,27 @@ int Assemble(char *mddev, int mdfd, devices[j].devname, mddev, strerror(errno)); - okcnt--; - } - } else if (verbose) + if (i < first_super.raid_disks) + okcnt--; + else + sparecnt--; + } else if (verbose) + fprintf(stderr, Name ": added %s to %s as %d\n", + devices[j].devname, mddev, devices[j].raid_disk); + } else if (verbose && i < first_super.raid_disks) fprintf(stderr, Name ": no uptodate device for slot %d of %s\n", i, mddev); } + if (runstop == 1 || (runstop == 0 && enough(first_super.level, first_super.raid_disks, okcnt))) { if (ioctl(mdfd, RUN_ARRAY, NULL)==0) { - fprintf(stderr, Name ": %s has been started with %d drives\n", - mddev, okcnt); + fprintf(stderr, Name ": %s has been started with %d drive%s", + mddev, okcnt, okcnt==1?"":"s"); + if (sparecnt) + fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s"); + fprintf(stderr, ".\n"); return 0; } fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n", @@ -370,68 +474,19 @@ int Assemble(char *mddev, int mdfd, return 1; } if (runstop == -1) { - fprintf(stderr, Name ": %s assembled from %d drives, but not started.\n", - mddev, okcnt); + fprintf(stderr, Name ": %s assembled from %d drive%s, but not started.\n", + mddev, okcnt, okcnt==1?"":"s"); return 0; } - fprintf(stderr, Name ": %s assembled from %d drives - not enough to start it.\n", - mddev, okcnt); + fprintf(stderr, Name ": %s assembled from %d drive%s - not enough to start it.\n", + mddev, okcnt, okcnt==1?"":"s"); return 1; } else { - /* It maybe just a case of calling START_ARRAY, but it may not.. - * We need to pick a working device, read it's super block, and make - * sure all the device numbers and the minor number are right. - * Then we might need to re-write the super block. - * THEN we call START_ARRAY - * If the md_minor is wrong, wejust give up for now. The alternate is to - * re-write ALL super blocks. + /* The "chosen_drive" is a good choice, and if necessary, the superblock has + * been updated to point to the current locations of devices. + * so we can just start the array */ - int chosen_drive = -1; - int change = 0; int dev; - for (i=0; i<first_super.nr_disks; i++) { - if (!devices[i].uptodate) - continue; - if (chosen_drive == -1) { - int fd; - chosen_drive = i; - if (open(devices[i].devname, O_RDONLY)>= 0) { - fprintf(stderr, Name ": Cannot open %s: %s\n", - devices[i].devname, strerror(errno)); - return 1; - } - if (load_super(fd, &super)) { - close(fd); - fprintf(stderr, Name ": RAID superblock has disappeared from %s\n", - devices[i].devname); - return 1; - } - close(fd); - } - if (devices[i].major != super.disks[i].major || - devices[i].minor != super.disks[i].minor) { - change = 1; - super.disks[i].major = devices[i].major; - super.disks[i].minor = devices[i].minor; - } - } - if (change) { - int fd; - super.sb_csum = calc_sb_csum(super); - fd = open(devices[chosen_drive].devname, O_RDWR); - if (fd < 0) { - fprintf(stderr, Name ": Could open %s for write - cannot Assemble array.\n", - devices[chosen_drive].devname); - return 1; - } - if (store_super(fd, &super)) { - close(fd); - fprintf(stderr, Name ": Could not re-write superblock on %s\n", - devices[chosen_drive].devname); - return 1; - } - close(fd); - } dev = MKDEV(devices[chosen_drive].major, devices[chosen_drive].minor); if (ioctl(mdfd, START_ARRAY, dev)) { |