NeilBrown: Grow: support --array-size changes

Martin F. Krafft madduck at alioth.debian.org
Wed Jan 27 02:01:33 UTC 2010


Module: mdadm
Branch: master
Commit: 84e11361aa37c92c3c016095e5db7f4fc434ac18
URL:    http://git.debian.org/?p=pkg-mdadm/mdadm.git;a=commit;h=84e11361aa37c92c3c016095e5db7f4fc434ac18

Author: NeilBrown <neilb at suse.de>
Date:   Mon Jul 13 15:00:02 2009 +1000

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 <neilb at suse.de>

---

 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 a194479..170e395 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 3b4f47d..079914f 100644
--- a/mdadm.8
+++ b/mdadm.8
@@ -594,6 +594,21 @@ 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
 .B name
diff --git a/mdadm.c b/mdadm.c
index 99a1771..2417f10 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 89ec77a..bf7e59d 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 f09fd84..080decc 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.




More information about the pkg-mdadm-commits mailing list