From 84e11361aa37c92c3c016095e5db7f4fc434ac18 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 13 Jul 2009 15:00:02 +1000 Subject: [PATCH] Grow: support --array-size changes 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 --- ReadMe.c | 9 ++++++--- mdadm.8 | 15 +++++++++++++++ mdadm.c | 43 ++++++++++++++++++++++++++++++++++++++++++- mdadm.h | 1 + util.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 4 deletions(-) diff --git a/ReadMe.c b/ReadMe.c index a1944796..170e3953 100644 --- 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 3b4f47d8..079914fe 100644 --- 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 99a17718..2417f10a 100644 --- 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 89ec77a4..bf7e59d2 100644 --- 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 f09fd843..080decc2 100644 --- 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. -- 2.39.2