X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=util.c;h=8febfd2c0ab6e0ff5a3aa23b7ac4d0c912b22221;hp=05eb9c901112b45fb5eb9818e608c497ea6d5940;hb=5a6d1148cccc50532ae6a96e04226522b7996850;hpb=0df46c2ad8872a9d6e5832f3098d12a7e0d2eb01 diff --git a/util.c b/util.c index 05eb9c90..8febfd2c 100644 --- a/util.c +++ b/util.c @@ -150,139 +150,6 @@ int same_uuid(int a[4], int b[4]) return 0; } -void uuid_from_super(int uuid[4], mdp_super_t *super) -{ - uuid[0] = super->set_uuid0; - if (super->minor_version >= 90) { - uuid[1] = super->set_uuid1; - uuid[2] = super->set_uuid2; - uuid[3] = super->set_uuid3; - } else { - uuid[1] = 0; - uuid[2] = 0; - uuid[3] = 0; - } -} - -int compare_super(mdp_super_t *first, mdp_super_t *second) -{ - /* - * return: - * 0 same, or first was empty, and second was copied - * 1 second had wrong number - * 2 wrong uuid - * 3 wrong other info - */ - int uuid1[4], uuid2[4]; - if (second->md_magic != MD_SB_MAGIC) - return 1; - if (first-> md_magic != MD_SB_MAGIC) { - memcpy(first, second, sizeof(*first)); - return 0; - } - - uuid_from_super(uuid1, first); - uuid_from_super(uuid2, second); - if (!same_uuid(uuid1, uuid2)) - return 2; - if (first->major_version != second->major_version || - first->minor_version != second->minor_version || - first->patch_version != second->patch_version || - first->gvalid_words != second->gvalid_words || - first->ctime != second->ctime || - first->level != second->level || - first->size != second->size || - first->raid_disks != second->raid_disks ) - return 3; - - return 0; -} - -int load_super(int fd, mdp_super_t *super) -{ - /* try to read in the superblock - * - * return - * 0 - success - * 1 - no block size - * 2 - too small - * 3 - no seek - * 4 - no read - * 5 - no magic - * 6 - wrong major version - */ - unsigned long size; - unsigned long long dsize; - unsigned long long offset; - -#ifdef BLKGETSIZE64 - if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) -#endif - { - if (ioctl(fd, BLKGETSIZE, &size)) - return 1; - else - dsize = size << 9; - } - - if (dsize < MD_RESERVED_SECTORS*2) - return 2; - - offset = MD_NEW_SIZE_SECTORS(dsize>>9); - - offset *= 512; - - ioctl(fd, BLKFLSBUF, 0); /* make sure we read current data */ - - if (lseek64(fd, offset, 0)< 0LL) - return 3; - - if (read(fd, super, sizeof(*super)) != sizeof(*super)) - return 4; - - if (super->md_magic != MD_SB_MAGIC) - return 5; - - if (super->major_version != 0) - return 6; - return 0; -} - -int store_super(int fd, mdp_super_t *super) -{ - unsigned long size; - unsigned long long dsize; - - long long offset; - -#ifdef BLKGETSIZE64 - if (ioctl(fd, BLKGETSIZE64, &dsize) != 0) -#endif - { - if (ioctl(fd, BLKGETSIZE, &size)) - return 1; - else - dsize = ((unsigned long long)size) << 9; - } - - if (dsize < MD_RESERVED_SECTORS*2) - return 2; - - offset = MD_NEW_SIZE_SECTORS(dsize>>9); - - offset *= 512; - - if (lseek64(fd, offset, 0)< 0LL) - return 3; - - if (write(fd, super, sizeof(*super)) != sizeof(*super)) - return 4; - - return 0; -} - - - int check_ext2(int fd, char *name) { /* @@ -328,8 +195,8 @@ int check_reiser(int fd, char *name) return 0; if (read(fd, sb, 1024) != 1024) return 0; - if (strncmp(sb+52, "ReIsErFs",8)!=0 && - strncmp(sb+52, "ReIsEr2Fs",9)!=0) + if (strncmp((char*)sb+52, "ReIsErFs",8)!=0 && + strncmp((char*)sb+52, "ReIsEr2Fs",9)!=0) 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; @@ -340,20 +207,24 @@ int check_reiser(int fd, char *name) int check_raid(int fd, char *name) { - mdp_super_t super; + void *super; + struct mdinfo info; time_t crtime; - if (load_super(fd, &super)) - return 0; + struct supertype *st = guess_super(fd); + + if (!st) return 0; + st->ss->load_super(st, fd, &super, name); /* Looks like a raid array .. */ fprintf(stderr, Name ": %s appears to be part of a raid array:\n", name); - crtime = super.ctime; + st->ss->getinfo_super(&info, super); + free(super); + crtime = info.array.ctime; fprintf(stderr, " level=%d devices=%d ctime=%s", - super.level, super.raid_disks, ctime(&crtime)); + info.array.level, info.array.raid_disks, ctime(&crtime)); return 1; } - int ask(char *mesg) { char *add = ""; @@ -413,7 +284,7 @@ int is_standard(char *dev, int *nump) else if (strncmp(d, "/md", 3)==0) d += 3, type=-1; /* /dev/mdN */ else if (d-dev > 3 && strncmp(d-2, "md/", 3)==0) - type = -1; /* /dev/md/N */ + d += 1, type=-1; /* /dev/md/N */ else return 0; if (!*d) @@ -505,19 +376,25 @@ char *map_dev(int major, int minor) #endif -unsigned long calc_sb_csum(mdp_super_t *super) +unsigned long calc_csum(void *super, int bytes) { - unsigned int oldcsum = super->sb_csum; unsigned long long newcsum = 0; - unsigned long csum; int i; - unsigned int *superc = (int*) super; - super->sb_csum = 0; + unsigned int csum; + unsigned int *superc = (unsigned int*) super; - for(i=0; i>32); - super->sb_csum = oldcsum; +#ifdef __alpha__ +/* The in-kernel checksum calculation is always 16bit on + * the alpha, though it is 32 bit on i386... + * I wonder what it is elsewhere... (it uses and API in + * a way that it shouldn't). + */ + csum = (csum & 0xffff) + (csum >> 16); + csum = (csum & 0xffff) + (csum >> 16); +#endif return csum; } @@ -650,3 +527,68 @@ void put_md_name(char *name) if (strncmp(name, "/dev/.tmp.md", 12)==0) unlink(name); } + + + + +struct superswitch *superlist[] = { &super0, &super1, NULL }; + +struct supertype *super_by_version(int vers, int minor) +{ + struct supertype *st = malloc(sizeof(*st)); + if (!st) return st; + if (vers == 0) { + st->ss = &super0; + st->max_devs = MD_SB_DISKS; + } + + if (vers == 1) { + st->ss = &super1; + st->max_devs = 384; + } + st->minor_version = minor; + return st; +} + +struct supertype *guess_super(int fd) +{ + /* try each load_super to find the best match, + * and return the best superswitch + */ + struct superswitch *ss; + struct supertype *st; + unsigned long besttime = 0; + int bestsuper = -1; + + void *sbp = NULL; + int i; + + st = malloc(sizeof(*st)); + memset(st, 0, sizeof(*st)); + for (i=0 ; superlist[i]; i++) { + int rv; + ss = superlist[i]; + rv = ss->load_super(st, fd, &sbp, NULL); + if (rv == 0) { + struct mdinfo info; + ss->getinfo_super(&info, sbp); + if (bestsuper == -1 || + besttime < info.array.ctime) { + bestsuper = i; + besttime = info.array.ctime; + } + st->ss = NULL; + free(sbp); + } + } + if (bestsuper != -1) { + int rv; + rv = superlist[bestsuper]->load_super(st, fd, &sbp, NULL); + if (rv == 0) { + free(sbp); + return st; + } + } + free(st); + return NULL; +}