]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Fix problems with array.size overflowing on large arrays.
authorNeil Brown <neilb@suse.de>
Mon, 28 Apr 2008 06:29:37 +0000 (16:29 +1000)
committerNeil Brown <neilb@suse.de>
Mon, 28 Apr 2008 06:29:37 +0000 (16:29 +1000)
array.size is 32bits and counts K.  So for arrays with
more than 4Terrabytes, it can overflow.
The correct number can be read from sysfs, but there are still
a few places that use array.size and risk truncation.  What is worse.
they compare a number of kilobytes with a number of sectors !!

So use get_component_size() to read the sysfs information, and be
more consistent about units.

ChangeLog
Detail.c
Manage.c

index fdf720d24cacf2d8b057314c596184c4c2b715e6..fd42b4e1ea69ce7a3c3f9e78c8ccf0997527f056 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,8 @@
 Changes Prior to this release
     -   Avoid segfault when parsing /proc/mdstat with auto-read-only
        arrays.
+    -   Fix problem with failing to add devices to v.large (>4TB) arrays,
+       cause by problems with device-size overflow.
 
 Changes Prior to 2.6.4 release
     -   Make "--create --auto=mdp" work for non-standard device names.
index de1f409e8fe8498fc100e963f42f30a7c0095b1c..6199d26fc5617793794776f1987cdbd000e7c99a 100644 (file)
--- a/Detail.c
+++ b/Detail.c
@@ -191,7 +191,7 @@ int Detail(char *dev, int brief, int export, int test, char *homehost)
                                if (dsize > 0)
                                        printf("  Used Dev Size : %llu%s\n",
                                               dsize,
-                                        human_size((long long)array.size<<10));
+                                        human_size((long long)dsize<<10));
                                else
                                        printf("  Used Dev Size : unknown\n");
                        } else
index f17105a85202ff14092494d646246c9229f2c31c..1fb8468981886342d76f9786a8ff90a203f27c47 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -188,6 +188,7 @@ int Manage_subdevs(char *devname, int fd,
         */
        mdu_array_info_t array;
        mdu_disk_info_t disc;
+       unsigned long long array_size;
        mddev_dev_t dv, next = NULL;
        struct stat stb;
        int j, jnext = 0;
@@ -202,6 +203,14 @@ int Manage_subdevs(char *devname, int fd,
                return 1;
        }
 
+       /* array.size is only 32 bit and may be truncated.
+        * So read from sysfs if possible, and record number of sectors
+        */
+
+       array_size = get_component_size(fd);
+       if (array_size <= 0)
+               array_size = array.size * 2;
+
        tst = super_by_fd(fd);
        if (!tst) {
                fprintf(stderr, Name ": unsupport array - version %d.%d\n",
@@ -337,7 +346,7 @@ int Manage_subdevs(char *devname, int fd,
 
                                /* Make sure device is large enough */
                                if (tst->ss->avail_size(tst, ldsize/512) <
-                                   array.size) {
+                                   array_size) {
                                        fprintf(stderr, Name ": %s not large enough to join array\n",
                                                dv->devname);
                                        return 1;
@@ -412,7 +421,7 @@ int Manage_subdevs(char *devname, int fd,
                                /* non-persistent. Must ensure that new drive
                                 * is at least array.size big.
                                 */
-                               if (ldsize/512 < array.size) {
+                               if (ldsize/512 < array_size) {
                                        fprintf(stderr, Name ": %s not large enough to join array\n",
                                                dv->devname);
                                        return 1;