]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Grow: refuse to grow a 0.90 array beyond 2TB
authorNeilBrown <neilb@suse.de>
Thu, 8 Sep 2011 03:08:51 +0000 (13:08 +1000)
committerNeilBrown <neilb@suse.de>
Thu, 8 Sep 2011 03:08:51 +0000 (13:08 +1000)
A kernel bug makes handling for arrays using more than 2TB per device
incorrect, and the kernel doesn't stop an array from growing beyond
any limit.
This is fixed in 3.1

So prior to 3.1, make sure not to ask for an array to grow bigger than
2TB per device.

Signed-off-by: NeilBrown <neilb@suse.de>
Grow.c

diff --git a/Grow.c b/Grow.c
index 048351d7fab236b77738789572b80afa8d1fe578..17d14b6740d90251a3d820bb5614e0ef280478d6 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -1446,6 +1446,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
        /* ========= set size =============== */
        if (size >= 0 && (size == 0 || size != array.size)) {
                long long orig_size = get_component_size(fd)/2;
+               long long min_csize;
                struct mdinfo *mdi;
 
                if (orig_size == 0)
@@ -1461,10 +1462,40 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                /* Update the size of each member device in case
                 * they have been resized.  This will never reduce
                 * below the current used-size.  The "size" attribute
-                * understand '0' to mean 'max'.
+                * understands '0' to mean 'max'.
                 */
-               for (mdi = sra->devs; mdi; mdi = mdi->next)
-                       sysfs_set_num(sra, mdi, "size", size);
+               min_csize = 0;
+               for (mdi = sra->devs; mdi; mdi = mdi->next) {
+                       if (sysfs_set_num(sra, mdi, "size", size) < 0)
+                               break;
+                       if (array.not_persistent == 0 &&
+                           array.major_version == 0 &&
+                           get_linux_version() < 3001000) {
+                               /* Dangerous to allow size to exceed 2TB */
+                               unsigned long long csize;
+                               if (sysfs_get_ll(sra, mdi, "size", &csize) == 0) {
+                                       if (csize >= 2ULL*1024*1024*1024)
+                                               csize = 2ULL*1024*1024*1024;
+                                       if ((min_csize == 0 || (min_csize
+                                                               > (long long)csize)))
+                                               min_csize = csize;
+                               }
+                       }
+               }
+               if (min_csize && size > min_csize) {
+                       fprintf(stderr, Name ": Cannot safely make this array "
+                               "use more than 2TB per device on this kernel.\n");
+                       rv = 1;
+                       goto release;
+               }
+               if (min_csize && size == 0) {
+                       /* Don't let the kernel choose a size - it will get
+                        * it wrong
+                        */
+                       fprintf(stderr, Name ": Limited v0.90 array to "
+                               "2TB per device\n");
+                       size = min_csize;
+               }
 
                array.size = size;
                if (array.size != size) {