]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
mdadm-1.8.0
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index bdafe66cc1afe11db6d598d62f51d6bb1350fe65..121ddbb731a28db5a4d890beaab2bf4031a22d01 100644 (file)
--- a/util.c
+++ b/util.c
@@ -121,6 +121,8 @@ int get_linux_version()
 int enough(int level, int raid_disks, int avail_disks)
 {
        switch (level) {
+       case 10: return 1; /* a lie, but it is hard to tell */
+
        case -4:
                return avail_disks>= 1;
        case -1:
@@ -210,15 +212,23 @@ int load_super(int fd, mdp_super_t *super)
         *   6 - wrong major version
         */
        unsigned long size;
+       unsigned long long dsize;
        unsigned long long offset;
     
-       if (ioctl(fd, BLKGETSIZE, &size))
-               return 1;
+#ifdef BLKGETSIZE64
+       if (ioctl(fd, BLKGETSIZE64, &dsize) != 0)
+#endif
+       {
+               if (ioctl(fd, BLKGETSIZE, &size))
+                       return 1;
+               else
+                       dsize = size << 9;
+       }
 
-       if (size < MD_RESERVED_SECTORS*2)
+       if (dsize < MD_RESERVED_SECTORS*2)
                return 2;
        
-       offset = MD_NEW_SIZE_SECTORS(size);
+       offset = MD_NEW_SIZE_SECTORS(dsize>>9);
 
        offset *= 512;
 
@@ -240,16 +250,25 @@ int load_super(int fd, mdp_super_t *super)
 
 int store_super(int fd, mdp_super_t *super)
 {
-       long size;
+       unsigned long size;
+       unsigned long long dsize;
+       
        long long offset;
     
-       if (ioctl(fd, BLKGETSIZE, &size))
-               return 1;
+#ifdef BLKGETSIZE64
+       if (ioctl(fd, BLKGETSIZE64, &dsize) != 0)
+#endif
+       {
+               if (ioctl(fd, BLKGETSIZE, &size))
+                       return 1;
+               else
+                       dsize = ((unsigned long long)size) << 9;
+       }
 
-       if (size < MD_RESERVED_SECTORS*2)
+       if (dsize < MD_RESERVED_SECTORS*2)
                return 2;
        
-       offset = MD_NEW_SIZE_SECTORS(size);
+       offset = MD_NEW_SIZE_SECTORS(dsize>>9);
 
        offset *= 512;
 
@@ -375,6 +394,32 @@ int map_name(mapping_t *map, char *name)
        return UnSet;
 }
 
+
+int is_standard(char *dev)
+{
+       /* tests if dev is a "standard" md dev name.
+        * i.e if the last component is "/dNN" or "/mdNN",
+        * where NN is a string of digits 
+        */
+       dev = strrchr(dev, '/');
+       if (!dev)
+               return 0;
+       if (strncmp(dev, "/d",2)==0)
+               dev += 2;
+       else if (strncmp(dev, "/md", 3)==0)
+               dev += 3;
+       else
+               return 0;
+       if (!*dev)
+               return 0;
+       while (isdigit(*dev))
+               dev++;
+       if (*dev)
+               return 0;
+       return 1;
+}
+
+
 /*
  * convert a major/minor pair for a block device into a name in /dev, if possible.
  * On the first call, walk /dev collecting name.
@@ -421,23 +466,32 @@ int add_dev(const char *name, const struct stat *stb, int flag)
     return 0;
 }
 
+/*
+ * Find a block device with the right major/minor number.
+ * Avoid /dev/mdNN and /dev/md/dNN is possible
+ */
 char *map_dev(int major, int minor)
 {
-    struct devmap *p;
-    if (!devlist_ready) {
+       struct devmap *p;
+       char *std = NULL;
+       if (!devlist_ready) {
 #ifndef __dietlibc__
-       nftw("/dev", add_dev, 10, FTW_PHYS);
+               nftw("/dev", add_dev, 10, FTW_PHYS);
 #else
-       ftw("/dev", add_dev, 10);
+               ftw("/dev", add_dev, 10);
 #endif
-       devlist_ready=1;
-    }
+               devlist_ready=1;
+       }
 
-    for (p=devlist; p; p=p->next)
-       if (p->major == major &&
-           p->minor == minor)
-           return p->name;
-    return NULL;
+       for (p=devlist; p; p=p->next)
+               if (p->major == major &&
+                   p->minor == minor) {
+                       if (is_standard(p->name))
+                               std = p->name;
+                       else
+                               return p->name;
+               }
+       return std;
 }
 
 #endif
@@ -504,16 +558,20 @@ char *human_size_brief(long long bytes)
        return buf;
 }
 
-static int mdp_major = -1;
-void get_mdp_major(void)
+int get_mdp_major(void)
 {
-       FILE *fl = fopen("/proc/devices", "r");
+static int mdp_major = -1;
+       FILE *fl;
        char *w;
        int have_block = 0;
        int have_devices = 0;
        int last_num = -1;
+
+       if (mdp_major != -1)
+               return mdp_major;
+       fl = fopen("/proc/devices", "r");
        if (!fl)
-               return;
+               return -1;
        while ((w = conf_word(fl, 1))) {
                if (have_block && strcmp(w, "devices:")==0)
                        have_devices = 1;
@@ -525,6 +583,7 @@ void get_mdp_major(void)
                free(w);
        }
        fclose(fl);
+       return mdp_major;
 }
 
 
@@ -536,12 +595,12 @@ char *get_md_name(int dev)
        static char devname[50];
        struct stat stb;
        dev_t rdev;
+       char *dn;
 
        if (dev < 0) {
-
-               if (mdp_major < 0) get_mdp_major();
-               if (mdp_major < 0) return NULL;
-               rdev = MKDEV(mdp_major, (-1-dev)<<6);
+               int mdp =  get_mdp_major();
+               if (mdp < 0) return NULL;
+               rdev = MKDEV(mdp, (-1-dev)<<6);
                sprintf(devname, "/dev/md/d%d", -1-dev);
                if (stat(devname, &stb) == 0
                    && (S_IFMT&stb.st_mode) == S_IFBLK
@@ -561,9 +620,13 @@ char *get_md_name(int dev)
                    && (stb.st_rdev == rdev))
                        return devname;
        }
+       dn = map_dev(MAJOR(rdev), MINOR(rdev));
+       if (dn)
+               return dn;
        sprintf(devname, "/dev/.tmp.md%d", dev);
        if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
-               return NULL;
+               if (errno != EEXIST)
+                       return NULL;
 
        if (stat(devname, &stb) == 0
            && (S_IFMT&stb.st_mode) == S_IFBLK