]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
fix load_super/free_super mismatch in util.c
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index 811627e874d498eb723a913c570d29dd57b0aec5..dbe46404c89ae1d00d649b6ecb02292709e5b879 100644 (file)
--- a/util.c
+++ b/util.c
@@ -723,29 +723,65 @@ int dev_open(char *dev, int flags)
 
 struct superswitch *superlist[] = { &super0, &super1, NULL };
 
-struct supertype *super_by_version(int vers, int minor)
+struct supertype *super_by_fd(int fd)
 {
-       struct supertype *st = malloc(sizeof(*st));
-       if (!st) return st;
-       if (vers == 0) {
-               st->ss = &super0;
-               st->max_devs = MD_SB_DISKS;
+       mdu_array_info_t array;
+       int vers;
+       int minor;
+       struct supertype *st = NULL;
+       struct mdinfo *sra;
+       char *verstr;
+       char version[20];
+       int i;
+
+       sra = sysfs_read(fd, 0, GET_VERSION);
+
+       if (sra) {
+               vers = sra->array.major_version;
+               minor = sra->array.minor_version;
+               verstr = sra->text_version;
+       } else {
+               if (ioctl(fd, GET_ARRAY_INFO, &array))
+                       array.major_version = array.minor_version = 0;
+               vers = array.major_version;
+               minor = array.minor_version;
+               verstr = "";
        }
 
-       if (vers == 1) {
-               st->ss = &super1;
-               st->max_devs = 384;
+       if (vers != -1) {
+               sprintf(version, "%d.%d", vers, minor);
+               verstr = version;
        }
-       st->minor_version = minor;
+       for (i = 0; st == NULL && superlist[i] ; i++)
+               st = superlist[i]->match_metadata_desc(verstr);
+
+       if (sra)
+               sysfs_free(sra);
        st->sb = NULL;
        return st;
 }
 
 struct supertype *dup_super(struct supertype *st)
 {
+       struct supertype *stnew = NULL;
+       char *verstr = NULL;
+       char version[20];
+       int i;
+
        if (!st)
                return st;
-       return super_by_version(st->ss->major, st->minor_version);
+
+       if (st->minor_version == -1)
+               sprintf(version, "%d", st->ss->major);
+       else
+               sprintf(version, "%d.%d", st->ss->major, st->minor_version);
+       verstr = version;
+
+       for (i = 0; stnew == NULL && superlist[i] ; i++)
+               stnew = superlist[i]->match_metadata_desc(verstr);
+
+       stnew->sb = NULL;
+       return stnew;
 }
 
 struct supertype *guess_super(int fd)
@@ -782,7 +818,7 @@ struct supertype *guess_super(int fd)
                st->ss = NULL;
                rv = superlist[bestsuper]->load_super(st, fd, NULL);
                if (rv == 0) {
-                       ss->free_super(st);
+                       superlist[bestsuper]->free_super(st);
                        return st;
                }
        }
@@ -794,6 +830,11 @@ struct supertype *guess_super(int fd)
 int get_dev_size(int fd, char *dname, unsigned long long *sizep)
 {
        unsigned long long ldsize;
+       struct stat st;
+
+       if (fstat(fd, &st) != -1 && S_ISREG(st.st_mode))
+               ldsize = (unsigned long long)st.st_size;
+       else
 #ifdef BLKGETSIZE64
        if (ioctl(fd, BLKGETSIZE64, &ldsize) != 0)
 #endif