]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Grow: support --array-size changes
authorNeilBrown <neilb@suse.de>
Mon, 13 Jul 2009 05:00:02 +0000 (15:00 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 13 Jul 2009 05:00:02 +0000 (15:00 +1000)
With 2.6.30 it is possible to tell the md driver to clip an array to a
size smaller than the real size of the array.  This option gives
access to that feature.  The size change does not persist
across restarts.

Signed-off-by: NeilBrown <neilb@suse.de>
ReadMe.c
mdadm.8
mdadm.c
mdadm.h
util.c

index a1944796f588fc7ba592d6306a1d33cc6e521993..170e39532708c9d6bf932e47fed4faa525f26bad 100644 (file)
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -86,11 +86,11 @@ char Version[] = Name " - v3.0-rc1 - 11th May 2009\n";
  *     At the time if writing, there is only minimal support.
  */
 
-char short_options[]="-ABCDEFGIQhVXWvqbc:i:l:p:m:n:x:u:c:d:z:U:sarfRSow1tye:";
+char short_options[]="-ABCDEFGIQhVXWZvqbc:i:l:p:m:n:x:u:c:d:z:U:sarfRSow1tye:";
 char short_bitmap_options[]=
-                   "-ABCDEFGIQhVXWvqb:c:i:l:p:m:n:x:u:c:d:z:U:sarfRSow1tye:";
+                   "-ABCDEFGIQhVXWZvqb:c:i:l:p:m:n:x:u:c:d:z:U:sarfRSow1tye:";
 char short_bitmap_auto_options[]=
-                   "-ABCDEFGIQhVXWvqb:c:i:l:p:m:n:x:u:c:d:z:U:sa:rfRSow1tye:";
+                   "-ABCDEFGIQhVXWZvqb:c:i:l:p:m:n:x:u:c:d:z:U:sa:rfRSow1tye:";
 
 struct option long_options[] = {
     {"manage",    0, 0, '@'},
@@ -182,6 +182,7 @@ struct option long_options[] = {
     {"syslog",    0, 0, 'y'},
     /* For Grow */
     {"backup-file", 1,0, BackupFile},
+    {"array-size", 1, 0, 'Z'},
 
     /* For Incremental */
     {"rebuild-map", 0, 0, 'r'},
@@ -525,6 +526,8 @@ char Help_grow[] =
 "  --backup-file= file : A file on a differt device to store data for a\n"
 "                      : short time while increasing raid-devices on a\n"
 "                      : RAID4/5/6 array. Not needed when a spare is present.\n"
+"  --array-size=  -Z   : Change visible size of array.  This does not change\n"
+"                      : any data on the device, and is not stable across restarts.\n"
 ;
 
 char Help_incr[] =
diff --git a/mdadm.8 b/mdadm.8
index 3b4f47d8264368881c26616436803d892f80196e..079914feeccfbcd38367de4580710a2cf37e8a70 100644 (file)
--- a/mdadm.8
+++ b/mdadm.8
@@ -593,6 +593,21 @@ raid-devices in a RAID5 if there  are no spare devices available.
 See the section below on RAID_DEVICE CHANGES.  The file should be
 stored on a separate device, not on the raid array being reshaped.
 
+.TP
+.BR \-\-array-size= ", " \-Z
+Set the size of the array which is seen by users of the device such as
+filesystems.  This can be less that the real size, but never greater.
+The size set this way does not persist across restarts of the array.
+
+This is most useful when reducing the number of devices in a RAID5 or
+RAID6.  Such arrays require the array-size to be reduced before a
+reshape can be performed that reduces the real size.
+
+A value of
+.B max
+restores the apparent size of the array to be whatever the real
+amount of available space is.
+
 .TP
 .BR \-N ", " \-\-name=
 Set a
diff --git a/mdadm.c b/mdadm.c
index 99a177186bb60fd336ea2a4a10801eafce2fa7fd..2417f10ad40cff9ccb9302adfa9faad188324e54 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -46,6 +46,7 @@ int main(int argc, char *argv[])
 
        int chunk = 0;
        long long size = -1;
+       long long array_size = -1;
        int level = UnSet;
        int layout = UnSet;
        int raiddisks = 0;
@@ -397,6 +398,24 @@ int main(int argc, char *argv[])
                        }
                        continue;
 
+               case O(GROW,'Z'): /* array size */
+                       if (array_size >= 0) {
+                               fprintf(stderr, Name ": array-size may only be specified once. "
+                                       "Second value is %s.\n", optarg);
+                               exit(2);
+                       }
+                       if (strcmp(optarg, "max") == 0)
+                               array_size = 0;
+                       else {
+                               array_size = parse_size(optarg);
+                               if (array_size <= 0) {
+                                       fprintf(stderr, Name ": invalid array size: %s\n",
+                                               optarg);
+                                       exit(2);
+                               }
+                       }
+                       continue;
+
                case O(GROW,'l'): /* hack - needed to understand layout */
                case O(CREATE,'l'):
                case O(BUILD,'l'): /* set raid level*/
@@ -1372,6 +1391,28 @@ int main(int argc, char *argv[])
                break;
 
        case GROW:
+               if (array_size >= 0) {
+                       /* alway impose array size first, independent of
+                        * anything else
+                        */
+                       struct mdinfo sra;
+                       int err;
+                       sysfs_init(&sra, mdfd, 0);
+                       if (array_size == 0)
+                               err = sysfs_set_str(&sra, NULL, "array_size", "default");
+                       else
+                               err = sysfs_set_num(&sra, NULL, "array_size", array_size / 2);
+                       if (err < 0) {
+                               if (errno == E2BIG)
+                                       fprintf(stderr, Name ": --array-size setting"
+                                               " is too large.\n");
+                               else
+                                       fprintf(stderr, Name ": current kernel does"
+                                               " not support setting --array-size\n");
+                               rv = 1;
+                               break;
+                       }
+               }
                if (devs_found > 1) {
 
                        /* must be '-a'. */
@@ -1398,7 +1439,7 @@ int main(int argc, char *argv[])
                        if (delay == 0) delay = DEFAULT_BITMAP_DELAY;
                        rv = Grow_addbitmap(devlist->devname, mdfd, bitmap_file,
                                            bitmap_chunk, delay, write_behind, force);
-               } else
+               } else if (array_size < 0)
                        fprintf(stderr, Name ": no changes to --grow\n");
                break;
        case INCREMENTAL:
diff --git a/mdadm.h b/mdadm.h
index 89ec77a4b140815af8019b84e0de2ec0b7a78763..bf7e59d22d6e496ed65114d7557a200fd2a52ce3 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -774,6 +774,7 @@ extern unsigned long bitmap_sectors(struct bitmap_super_s *bsb);
 
 extern int md_get_version(int fd);
 extern int get_linux_version(void);
+extern long long parse_size(char *size);
 extern int parse_uuid(char *str, int uuid[4]);
 extern int check_ext2(int fd, char *name);
 extern int check_reiser(int fd, char *name);
diff --git a/util.c b/util.c
index f09fd843c9aa8bec32aeb0e39da7e6c47e9ba5c2..080decc222a970bf36a9e2329c6eb7b27f307678 100644 (file)
--- a/util.c
+++ b/util.c
@@ -154,6 +154,37 @@ int get_linux_version()
        return (a*1000000)+(b*1000)+c;
 }
 
+long long parse_size(char *size)
+{
+       /* parse 'size' which should be a number optionally
+        * followed by 'K', 'M', or 'G'.
+        * Without a suffix, K is assumed.
+        * Number returned is in sectors (half-K)
+        */
+       char *c;
+       long long s = strtoll(size, &c, 10);
+       if (s > 0) {
+               switch (*c) {
+               case 'K':
+                       c++;
+               default:
+                       s *= 2;
+                       break;
+               case 'M':
+                       c++;
+                       s *= 1024 * 2;
+                       break;
+               case 'G':
+                       c++;
+                       s *= 1024 * 1024 * 2;
+                       break;
+               }
+       }
+       if (*c)
+               s = 0;
+       return s;
+}
+
 void remove_partitions(int fd)
 {
        /* remove partitions from this block devices.