diff options
author | Neil Brown <neilb@suse.de> | 2001-06-08 02:36:23 +0000 |
---|---|---|
committer | Neil Brown <neilb@suse.de> | 2001-06-08 02:36:23 +0000 |
commit | 64c4757e27fe7d688685e9a86ff87a3331a88979 (patch) | |
tree | 2c9a30b670f8d5c839bdd27db660f0d781f666e4 /Assemble.c | |
download | mdadm-64c4757e27fe7d688685e9a86ff87a3331a88979.tar.gz mdadm-64c4757e27fe7d688685e9a86ff87a3331a88979.tar.xz mdadm-64c4757e27fe7d688685e9a86ff87a3331a88979.zip |
mdctl-v0.2mdctl-v0.2
Diffstat (limited to 'Assemble.c')
-rw-r--r-- | Assemble.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/Assemble.c b/Assemble.c new file mode 100644 index 0000000..504bde7 --- /dev/null +++ b/Assemble.c @@ -0,0 +1,366 @@ +/* + * mdctl - manage Linux "md" devices aka RAID arrays. + * + * Copyright (C) 2001 Neil Brown <neilb@cse.unsw.edu.au> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Neil Brown + * Email: <neilb@cse.unsw.edu.au> + * Paper: Neil Brown + * School of Computer Science and Engineering + * The University of New South Wales + * Sydney, 2052 + * Australia + */ + +#include "mdctl.h" +#include "md_p.h" +#include "md_u.h" + +int Assemble(char *mddev, int mdfd, + int uuid[4], int uuidset, + char *conffile, int scan, + int subdevs, char **subdev, + int readonly, int runstop, + int verbose, int force) +{ + /* + * The task of Assemble is to submit 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 + * the array. Finally RUN_ARRAY might + * be submitted to start the array. + * + * Much of the work of Assemble is in finding and/or + * checking the disks to make sure they look right. + * + * If mddev is not set, then scan must be and we + * read through the config file for dev+uuid mapping + * We recurse, setting mddev, for each device that + * - isn't running + * - has a valid uuid (or any uuid if !uuidset + * + * If mddev is set, we try to determine state of md. + * check version - must be at least 0.90.0 + * check kernel version. must be at least 2.4. + * If not, we can possibly fall back on START_ARRAY + * Try to GET_ARRAY_INFO. + * If possible, give up + * If not, try to STOP_ARRAY just to make sure + * + * If !uuidset and scan, look in conf-file for uuid + * If not found, give up + * If !subdevs and scan and uuidset, get list of devs from conf-file + * + * 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 + * 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 + * + * Count disks with recent enough event count + * While force && !enough disks + * Choose newest rejected disks, update event count + * mark clean and rewrite superblock + * If recent kernel: + * SET_ARRAY_INFO + * foreach device with recent events : ADD_NEW_DISK + * if runstop == 1 || "enough" disks and runstop==0 -> RUN_ARRAY + * If old kernel: + * Check the device numbers in superblock are right + * update superblock if any changes + * START_ARRAY + * + */ + int old_linux = 0; + int vers; + mdu_array_info_t array; + mddev_dev_t devlist = NULL; + mdp_super_t first_super, super; + struct { + char *devname; + int major, minor; + long long events; + time_t utime; + int uptodate; + } devices[MD_SB_DISKS]; + int best[MD_SB_DISKS]; /* indexed by raid_disk */ + int devcnt = 0, okcnt; + int i; + int most_recent = 0; + + if (!mddev && !scan) { + fputs("mdctl: internal error - Assemble called with no devie 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, "mdctl: No devices found in config file\n"); + return 1; + } + while (device_list) { + if (!uuidset || same_uuid(device_list->uuid,uuid)) { + mdfd = open(device_list->devname, O_RDONLY, 0); + if (mdfd < 0) { + fprintf(stderr, + "mdctl: 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); + } + device_list = device_list->next; + } + if (found) + return 0; + fprintf(stderr,"mdctl: Did not successful Assemble any devices\n"); + return 1; + } + + /* + * Ok, we have an mddev, check it out + */ + vers = md_get_version(mdfd); + if (vers <= 0) { + fprintf(stderr, "mdctl: %s appears not to be an md device.\n"); + return 1; + } + if (vers < (90<<8)) { + fprintf(stderr, "mdctl: Assemble requires driver version 0.90.0 or later.\n" + " Upgrade your kernel or try --Build\n"); + return 1; + } + if (get_linux_version() < 0x020400) + old_linux = 1; + + if (ioctl(mdfd, GET_ARRAY_INFO, &array)>=0) { + fprintf(stderr, "mdctl: device %s already active - cannot assemble it\n", + mddev); + return 1; + } + ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */ + + /* + * We have a valid mddev, check out uuid + */ + 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, "mdctl: --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; + } + + /* 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) + devlist = conf_get_devs(conffile); + + if (subdevs == 0 && devlist == NULL) { + fprintf(stderr, "mdctl: 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; + + while (subdevs || devlist) { + char *devname; + int this_uuid[4]; + int dfd; + struct stat stb; + int inargv; + if (subdevs) { + devname = *subdev++; + subdevs--; + inargv=1; + } else { + devname = devlist->devname; + devlist = devlist->next; + inargv=0; + } + + dfd = open(devname, O_RDONLY, 0); + if (dfd < 0) { + if (inargv || verbose) + fprintf(stderr, "mdctl: cannot open device %s: %s\n", + devname, strerror(errno)); + continue; + } + if (fstat(dfd, &stb)< 0) { + /* Impossible! */ + fprintf(stderr, "mdctl: fstat failed for %s: %s\n", + devname, strerror(errno)); + close(dfd); + continue; + } + if ((stb.st_mode & S_IFMT) != S_IFBLK) { + fprintf(stderr, "mdctl: %d is not a block device.\n", + devname); + close(dfd); + continue; + } + if (load_super(dfd, &super)) { + if (inargv || verbose) + fprintf( stderr, "mdctl: no RAID superblock on %s\n", + devname); + close(dfd); + continue; + } + close(dfd); + if (compare_super(&first_super, &super)) { + if (inargv || verbose) + fprintf(stderr, "mdctl: superblock on %s doesn't match\n", + devname); + continue; + } + if (uuidset) { + uuid_from_super(this_uuid, &first_super); + if (!same_uuid(this_uuid, uuid)) { + if (inargv || verbose) + fprintf(stderr, "mdctl: %s has wrong uuid.\n", + devname); + continue; + } + } else { + uuid_from_super(uuid, &first_super); + uuidset = 1; + } + + /* Ok, this one is at least worth considering */ + if (devcnt >= MD_SB_DISKS) { + fprintf(stderr, "mdctl: ouch - too many devices appear to be in this array. Ignoring %s\n", + devname); + continue; + } + devices[devcnt].devname = devname; + devices[devcnt].major = MAJOR(stb.st_rdev); + devices[devcnt].minor = MINOR(stb.st_rdev); + devices[devcnt].events = md_event(&super); + devices[devcnt].utime = super.utime; + 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; + } + devcnt++; + } + + if (devcnt == 0) { + fprintf(stderr, "mdctl: no devices found for %s\n", + mddev); + return 1; + } + /* now we have some devices that might be suitable. + * I wonder how many + */ + okcnt = 0; + for (i=0; i< first_super.raid_disks;i++) { + int j = best[i]; + if (j < 0) continue; + if (devices[j].events+1 >= + devices[most_recent].events) { + devices[j].uptodate = 1; + okcnt++; + } + } + while (force && !enough(first_super.level, first_super.raid_disks, okcnt)) { + /* Choose the newest best drive which is + * not up-to-date, update the superblock + * and add it. + */ + fprintf(stderr,"NoImplementedYet\n"); + /* FIXME */ + exit(2); + } + /* Almost ready to actually *do* something */ + if (!old_linux) { + if (ioctl(mdfd, SET_ARRAY_INFO, NULL) != 0) { + fprintf(stderr, "mdctl: SET_ARRAY_INFO failed for %s: %s\n", + mddev, strerror(errno)); + return 1; + } + /* First, add the raid disks */ + for (i=0; i<first_super.raid_disks; i++) { + int j = best[i]; + if (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, "mdctl: failed to add %s to %s: %s\n", + devices[j].devname, + mddev, + strerror(errno)); + } else + okcnt--; + } else if (verbose) + fprintf(stderr, "mdctl: 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) + return 0; + fprintf(stderr, "mdctl: failed to RUN_ARRAY %s: %s\n", + mddev, strerror(errno)); + return 1; + } + if (runstop == -1) + return 0; + else return 1; + } else { + /* FIXME */ + return 1; + } +} |