]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Add --data-offset flag for Create and Grow
authorNeilBrown <neilb@suse.de>
Wed, 9 May 2012 10:49:31 +0000 (20:49 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 9 May 2012 10:49:31 +0000 (20:49 +1000)
This can be used to over-ride the automatic assignment of
data offset.
For --create, it is useful to re-create old arrays where different
   defaults applied.
For --grow it may be able to force a reshape in the reverse direction.

Signed-off-by: NeilBrown <neilb@suse.de>
Create.c
Grow.c
ReadMe.c
mdadm.8.in
mdadm.c
mdadm.h
super1.c

index 6ba438332dacdd2ef7ba0e88b4c1e9cc72f0389a..b4b680477039a101312816034ba2abab64544d80 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -72,7 +72,7 @@ int Create(struct supertype *st, char *mddev,
           int subdevs, struct mddev_dev *devlist,
           int runstop, int verbose, int force, int assume_clean,
           char *bitmap_file, int bitmap_chunk, int write_behind,
-          int delay, int autof)
+          int delay, int autof, unsigned long long data_offset)
 {
        /*
         * Create a new raid array.
@@ -263,7 +263,7 @@ int Create(struct supertype *st, char *mddev,
                size &= ~(unsigned long long)(chunk - 1);
        newsize = size * 2;
        if (st && ! st->ss->validate_geometry(st, level, layout, raiddisks,
-                                             &chunk, size*2, -1LL, NULL,
+                                             &chunk, size*2, data_offset, NULL,
                                              &newsize, verbose>=0))
                return 1;
 
@@ -346,7 +346,7 @@ int Create(struct supertype *st, char *mddev,
                                        layout = default_layout(st, level, verbose);
                                switch (st->ss->validate_geometry(
                                                st, level, layout, raiddisks,
-                                               &chunk, size*2, -1LL, dname,
+                                               &chunk, size*2, data_offset, dname,
                                                &freesize, verbose > 0)) {
                                case -1: /* Not valid, message printed, and not
                                          * worth checking any further */
@@ -382,7 +382,7 @@ int Create(struct supertype *st, char *mddev,
                                layout = default_layout(st, level, 0);
                        if (!st->ss->validate_geometry(st, level, layout,
                                                       raiddisks,
-                                                      &chunk, size*2, -1LL,
+                                                      &chunk, size*2, data_offset,
                                                       dname, &freesize,
                                                       verbose >= 0)) {
 
@@ -484,7 +484,8 @@ int Create(struct supertype *st, char *mddev,
                        /* size is meaningful */
                        if (!st->ss->validate_geometry(st, level, layout,
                                                       raiddisks,
-                                                      &chunk, minsize*2, -1LL,
+                                                      &chunk, minsize*2,
+                                                      data_offset,
                                                       NULL, NULL, 0)) {
                                fprintf(stderr, Name ": devices too large for RAID level %d\n", level);
                                return 1;
@@ -692,7 +693,8 @@ int Create(struct supertype *st, char *mddev,
                                name += 2;
                }
        }
-       if (!st->ss->init_super(st, &info.array, size, name, homehost, uuid, -1LL))
+       if (!st->ss->init_super(st, &info.array, size, name, homehost,
+                               uuid, data_offset))
                goto abort_locked;
 
        total_slots = info.array.nr_disks;
diff --git a/Grow.c b/Grow.c
index 330e7195fb0444f415e6ed20c2c2eda35e6bb8a1..f4a438246d6defae416a7bb992df3718eedc82df 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -1440,6 +1440,7 @@ static int reshape_container(char *container, char *devname,
 int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                 long long size,
                 int level, char *layout_str, int chunksize, int raid_disks,
+                long long data_offset,
                 struct mddev_dev *devlist,
                 int assume_clean, int force)
 {
@@ -1477,6 +1478,11 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
        struct mdinfo info;
        struct mdinfo *sra;
 
+       if (data_offset >= 0) {
+               fprintf(stderr, Name ": --grow --data-offset not yet supported\n");
+               return 1;
+       }
+
        if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) {
                fprintf(stderr, Name ": %s is not an active md array - aborting\n",
                        devname);
index 8ee82348c612409c92a219218c6c6b6dc8c1cf46..67d809b93c28f472bdaa8a514d9be7cd32b7096c 100644 (file)
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -145,6 +145,7 @@ struct option long_options[] = {
     {"re-add",    0, 0,  ReAdd},
     {"homehost",  1, 0,  HomeHost},
     {"symlinks",  1, 0,  Symlinks},
+    {"data-offset",1, 0, DataOffset},
 
     /* For assemble */
     {"uuid",      1, 0, 'u'},
@@ -362,6 +363,8 @@ char Help_create[] =
 "  --raid-devices= -n : number of active devices in array\n"
 "  --spare-devices= -x: number of spares (eXtras) devices in initial array\n"
 "  --size=       -z   : Size (in K) of each drive in RAID1/4/5/6/10 - optional\n"
+"  --data-offset=     : Space to leave between start of device and start\n"
+"                     : of array data.\n"
 "  --force       -f   : Honour devices as listed on command line.  Don't\n"
 "                     : insert a missing drive for RAID5.\n"
 "  --run         -R   : insist of running the array even if not all\n"
@@ -547,6 +550,7 @@ char Help_grow[] =
 "                      : 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"
+"  --data-offset=      : Location on device to move start of data to.\n"
 ;
 
 char Help_incr[] =
index 1ec38d0360307d0b1235eb35615b74f09b082fee..2ef17b0637c28ca69b4048a70a8c688866cfe258 100644 (file)
@@ -767,6 +767,34 @@ or layout.  See the GROW MODE section below on RAID\-DEVICES CHANGES.
 The file must be stored on a separate device, not on the RAID array
 being reshaped.
 
+.TP
+.B \-\-data\-offset=
+Arrays with 1.x metadata can leave a gap between the start of the
+device and the start of array data.  This gap can be used for various
+metadata.  The start of data is known as the
+.IR data\-offset .
+Normally an appropriate data offset is computed automatically.
+However it can be useful to set it explicitly such as when re-creating
+an array which was originally created using a different version of
+.I mdadm
+which computed a different offset.
+
+Setting the offset explicitly over-rides the default.  The value given
+is in Kilobytes unless an 'M' or 'G' suffix is given.
+
+Since Linux 3.4,
+.B \-\-data\-offset
+can also be used with
+.B --grow
+for some RAID levels (initially on RAID10).  This allows the
+data-offset to be changed as part of the reshape process.  When the
+data offset is changed, no backup file is required as the difference
+in offsets is used to provide the same functionality.
+
+When the new offset is earlier than the old offset, the number of
+devices in the array cannot shrink.  When it is after the old offset,
+the number of devices in the array cannot increase.
+
 .TP
 .BR \-\-continue
 This option is complementary to the
diff --git a/mdadm.c b/mdadm.c
index 846bc9641af062d7436721e72794cb66c3903521..f290c29975e335ccd76d5cececdc4b9b945b0e77 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -42,6 +42,7 @@ int main(int argc, char *argv[])
        int chunk = 0;
        long long size = -1;
        long long array_size = -1;
+       long long data_offset = -1;
        int level = UnSet;
        int layout = UnSet;
        char *layout_str = NULL;
@@ -466,6 +467,21 @@ int main(int argc, char *argv[])
                        }
                        continue;
 
+               case O(CREATE,DataOffset):
+               case O(GROW,DataOffset):
+                       if (data_offset >= 0) {
+                               fprintf(stderr, Name ": data-offset may only be specified one. "
+                                       "Second value is %s.\n", optarg);
+                               exit(2);
+                       }
+                       data_offset = parse_size(optarg);
+                       if (data_offset < 0) {
+                               fprintf(stderr, Name ": invalid data-offset: %s\n",
+                                       optarg);
+                               exit(2);
+                       }
+                       continue;
+
                case O(GROW,'l'):
                case O(CREATE,'l'):
                case O(BUILD,'l'): /* set raid level*/
@@ -1449,7 +1465,8 @@ int main(int argc, char *argv[])
                            raiddisks, sparedisks, ident.name, homehost,
                            ident.uuid_set ? ident.uuid : NULL,
                            devs_found-1, devlist->next, runstop, verbose-quiet, force, assume_clean,
-                           bitmap_file, bitmap_chunk, write_behind, delay, autof);
+                           bitmap_file, bitmap_chunk, write_behind, delay, autof,
+                           data_offset);
                break;
        case MISC:
                if (devmode == 'E') {
@@ -1705,6 +1722,7 @@ int main(int argc, char *argv[])
                           || chunk != 0 || level != UnSet) {
                        rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file,
                                          size, level, layout_str, chunk, raiddisks,
+                                         data_offset,
                                          devlist->next,
                                          assume_clean, force);
                } else if (array_size < 0)
diff --git a/mdadm.h b/mdadm.h
index b3c9f5344ba2200440ef6ba022347bfa6f2d3307..c3f612602a59555d457c47efd232aceecb69efdd 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -323,6 +323,7 @@ enum special_options {
        Continue,
        OffRootOpt,
        Prefer,
+       DataOffset,
 };
 
 /* structures read from config file */
@@ -1052,6 +1053,7 @@ extern int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int dela
 extern int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                        long long size,
                        int level, char *layout_str, int chunksize, int raid_disks,
+                       long long data_offset,
                        struct mddev_dev *devlist,
                        int assume_clean, int force);
 extern int Grow_restart(struct supertype *st, struct mdinfo *info,
@@ -1088,7 +1090,8 @@ extern int Create(struct supertype *st, char *mddev,
                  char *name, char *homehost, int *uuid,
                  int subdevs, struct mddev_dev *devlist,
                  int runstop, int verbose, int force, int assume_clean,
-                 char *bitmap_file, int bitmap_chunk, int write_behind, int delay, int autof);
+                 char *bitmap_file, int bitmap_chunk, int write_behind, int delay, int autof,
+                 unsigned long long data_offset);
 
 extern int Detail(char *dev, int brief, int export, int test, char *homehost, char *prefer);
 extern int Detail_Platform(struct superswitch *ss, int scan, int verbose);
index ee7b18b2de83be2de37c57f00655f5124146b00f..e6495ac8a0a41ba8b8d119d8d56d015cc016457a 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -1189,9 +1189,9 @@ static int write_init_super1(struct supertype *st)
                        sb->data_size = __cpu_to_le64(sb_offset - bm_space);
                        break;
                case 1:
+                       sb->super_offset = __cpu_to_le64(0);
                        data_offset = (long long)(int64_t)__le64_to_cpu(sb->data_offset);
                        if (data_offset < 0) {
-                               sb->super_offset = __cpu_to_le64(0);
                                reserved = bm_space + 4*2;
                                /* Try for multiple of 1Meg so it is nicely aligned */
                                #define ONE_MEG (2*1024)
@@ -1210,10 +1210,10 @@ static int write_init_super1(struct supertype *st)
                        sb->data_size = __cpu_to_le64(dsize - reserved);
                        break;
                case 2:
+                       sb_offset = 4*2;
+                       sb->super_offset = __cpu_to_le64(4*2);
                        data_offset = (long long)(int64_t)__le64_to_cpu(sb->data_offset);
                        if (data_offset < 0) {
-                               sb_offset = 4*2;
-                               sb->super_offset = __cpu_to_le64(4*2);
                                if (4*2 + 4*2 + bm_space + __le64_to_cpu(sb->size)
                                    > dsize)
                                        bm_space = dsize - __le64_to_cpu(sb->size)