X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=util.c;h=26254c086881fa21c6e9d930fde04f11f68c242b;hp=fab01929caf0d8bf461543fba518668b16360e47;hb=881990a2e440d58d2c1d070e9005225f56d21260;hpb=8f23b0b3fa61cb112a974a711fe3c424482fe11d diff --git a/util.c b/util.c index fab01929..26254c08 100644 --- a/util.c +++ b/util.c @@ -118,10 +118,31 @@ int get_linux_version() return (a*1000000)+(b*1000)+c; } -int enough(int level, int raid_disks, int avail_disks) +int enough(int level, int raid_disks, int layout, + char *avail, int avail_disks) { + int copies, first; switch (level) { - case 10: return 1; /* a lie, but it is hard to tell */ + case 10: + /* This is the tricky one - we need to check + * which actual disks are present. + */ + copies = (layout&255)* (layout>>8); + first=0; + do { + /* there must be one of the 'copies' form 'first' */ + int n = copies; + int cnt=0; + while (n--) { + if (avail[first]) + cnt++; + first = (first+1) % raid_disks; + } + if (cnt == 0) + return 0; + + } while (first != 0); + return 1; case -4: return avail_disks>= 1; @@ -140,14 +161,32 @@ int enough(int level, int raid_disks, int avail_disks) } } -int same_uuid(int a[4], int b[4]) +int same_uuid(int a[4], int b[4], int swapuuid) { - if (a[0]==b[0] && - a[1]==b[1] && - a[2]==b[2] && - a[3]==b[3]) - return 1; - return 0; + if (swapuuid) { + /* parse uuids are hostendian. + * uuid's from some superblocks are big-ending + * if there is a difference, we need to swap.. + */ + unsigned char *ac = (unsigned char *)a; + unsigned char *bc = (unsigned char *)b; + int i; + for (i=0; i<16; i+= 4) { + if (ac[i+0] != bc[i+3] || + ac[i+1] != bc[i+2] || + ac[i+2] != bc[i+1] || + ac[i+3] != bc[i+0]) + return 0; + } + return 1; + } else { + if (a[0]==b[0] && + a[1]==b[1] && + a[2]==b[2] && + a[3]==b[3]) + return 1; + return 0; + } } int check_ext2(int fd, char *name) @@ -190,7 +229,7 @@ int check_reiser(int fd, char *name) * */ unsigned char sb[1024]; - int size; + unsigned long size; if (lseek(fd, 64*1024, 0) != 64*1024) return 0; if (read(fd, sb, 1024) != 1024) @@ -200,7 +239,7 @@ int check_reiser(int fd, char *name) return 0; fprintf(stderr, Name ": %s appears to contain a reiserfs file system\n",name); size = sb[0]|(sb[1]|(sb[2]|sb[3]<<8)<<8)<<8; - fprintf(stderr, " size = %dK\n", size*4); + fprintf(stderr, " size = %luK\n", size*4); return 1; } @@ -209,7 +248,9 @@ int check_raid(int fd, char *name) { void *super; struct mdinfo info; + struct mddev_ident_s ident; time_t crtime; + char *level; struct supertype *st = guess_super(fd); if (!st) return 0; @@ -217,11 +258,13 @@ int check_raid(int fd, char *name) /* Looks like a raid array .. */ fprintf(stderr, Name ": %s appears to be part of a raid array:\n", name); - st->ss->getinfo_super(&info, super); + st->ss->getinfo_super(&info, &ident, super); free(super); crtime = info.array.ctime; - fprintf(stderr, " level=%d devices=%d ctime=%s", - info.array.level, info.array.raid_disks, ctime(&crtime)); + level = map_num(pers, info.array.level); + if (!level) level = "-unknown-"; + fprintf(stderr, " level=%s devices=%d ctime=%s", + level, info.array.raid_disks, ctime(&crtime)); return 1; } @@ -546,8 +589,28 @@ void put_md_name(char *name) unlink(name); } - - +int dev_open(char *dev, int flags) +{ + /* like 'open', but if 'dev' matches %d:%d, create a temp + * block device and open that + */ + char *e; + int fd = -1; + char devname[32]; + int major = strtoul(dev, &e, 0); + int minor; + if (e > dev && *e == ':' && e[1] && + (minor = strtoul(e+1, &e, 0)) >= 0 && + *e == 0) { + snprintf(devname, sizeof(devname), "/dev/.tmp.md.%d:%d", major, minor); + if (mknod(devname, S_IFBLK|0600, makedev(major, minor))==0) { + fd = open(devname, flags); + unlink(devname); + } + } else + fd = open(dev, flags); + return fd; +} struct superswitch *superlist[] = { &super0, &super1, NULL }; @@ -586,21 +649,23 @@ struct supertype *guess_super(int fd) for (i=0 ; superlist[i]; i++) { int rv; ss = superlist[i]; + st->ss = NULL; rv = ss->load_super(st, fd, &sbp, NULL); if (rv == 0) { struct mdinfo info; - ss->getinfo_super(&info, sbp); + struct mddev_ident_s ident; + ss->getinfo_super(&info, &ident, sbp); if (bestsuper == -1 || besttime < info.array.ctime) { bestsuper = i; besttime = info.array.ctime; } - st->ss = NULL; free(sbp); } } if (bestsuper != -1) { int rv; + st->ss = NULL; rv = superlist[bestsuper]->load_super(st, fd, &sbp, NULL); if (rv == 0) { free(sbp); @@ -610,3 +675,38 @@ struct supertype *guess_super(int fd) free(st); return NULL; } + +unsigned long long get_component_size(int fd) +{ + /* Find out the component size of the array. + * We cannot trust GET_ARRAY_INFO ioctl as it's + * size field is only 32bits. + * So look in /sys/block/mdXXX/md/component_size + */ + struct stat stb; + char fname[50]; + int n; + if (fstat(fd, &stb)) return 0; + if (major(stb.st_rdev) == 9) + sprintf(fname, "/sys/block/md%d/md/component_size", + minor(stb.st_rdev)); + else + sprintf(fname, "/sys/block/md_d%d/md/component_size", + minor(stb.st_rdev)/16); + fd = open(fname, O_RDONLY); + if (fd < 0) + return 0; + n = read(fd, fname, sizeof(fname)); + close(fd); + if (n == sizeof(fname)) + return 0; + fname[n] = 0; + return strtoull(fname, NULL, 10); +} + + +#ifdef __TINYC__ +/* tinyc doesn't optimize this check in ioctl.h out ... */ +unsigned int __invalid_size_argument_for_IOC = 0; +#endif +