summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ReadMe.c9
-rw-r--r--mdadm.815
-rw-r--r--mdadm.c43
-rw-r--r--mdadm.h1
-rw-r--r--util.c31
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.