]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Allow data-offset to be specified per-device for create
authorNeilBrown <neilb@suse.de>
Thu, 4 Oct 2012 06:34:21 +0000 (16:34 +1000)
committerNeilBrown <neilb@suse.de>
Thu, 4 Oct 2012 06:34:21 +0000 (16:34 +1000)
 mdadm --create /dev/md0 .... /dev/sda1:1024 /dev/sdb1:2048 ...

The size is in K unless a suffix: K M G is given.
The suffix 's' means sectors.

Signed-off-by: NeilBrown <neilb@suse.de>
Create.c
Manage.c
managemon.c
mdadm.8.in
mdadm.c
mdadm.h
super-ddf.c
super-intel.c
super0.c
super1.c
util.c

index 91c641f55ce718041740dbd7793bb5021db0609c..d6dcdbf3d66262eeed6f10932bef8eca0d4f2e03 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -289,6 +289,7 @@ int Create(struct supertype *st, char *mddev,
                char *dname = dv->devname;
                unsigned long long freesize;
                int dfd;
+               char *doff;
 
                if (strcasecmp(dname, "missing")==0) {
                        if (first_missing > dnum)
@@ -298,6 +299,16 @@ int Create(struct supertype *st, char *mddev,
                        missing_disks ++;
                        continue;
                }
+               if (data_offset != VARIABLE_OFFSET) {
+                       doff = strchr(dname, ':');
+                       if (doff) {
+                               *doff++ = 0;
+                               dv->data_offset = parse_size(doff);
+                       } else
+                               dv->data_offset = INVALID_SECTORS;
+               } else
+                       dv->data_offset = data_offset;
+
                dfd = open(dname, O_RDONLY);
                if (dfd < 0) {
                        pr_err("cannot open %s: %s\n",
@@ -335,7 +346,7 @@ int Create(struct supertype *st, char *mddev,
                                switch (st->ss->validate_geometry(
                                                st, s->level, s->layout, s->raiddisks,
                                                &s->chunk, s->size*2,
-                                               data_offset, dname,
+                                               dv->data_offset, dname,
                                                &freesize, c->verbose > 0)) {
                                case -1: /* Not valid, message printed, and not
                                          * worth checking any further */
@@ -372,7 +383,7 @@ int Create(struct supertype *st, char *mddev,
                        if (!st->ss->validate_geometry(st, s->level, s->layout,
                                                       s->raiddisks,
                                                       &s->chunk, s->size*2,
-                                                      data_offset,
+                                                      dv->data_offset,
                                                       dname, &freesize,
                                                       c->verbose >= 0)) {
 
@@ -866,7 +877,8 @@ int Create(struct supertype *st, char *mddev,
                                if (fd >= 0)
                                        remove_partitions(fd);
                                if (st->ss->add_to_super(st, &inf->disk,
-                                                        fd, dv->devname)) {
+                                                        fd, dv->devname,
+                                                        dv->data_offset)) {
                                        ioctl(mdfd, STOP_ARRAY, NULL);
                                        goto abort;
                                }
index d2b92a20e0cda19fcc6c57bd28068c92b19e7ab1..296feeb7f6f424adc31831212a91dfa323a6fa8f 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -733,7 +733,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
                        disc.state |= 1 << MD_DISK_WRITEMOSTLY;
                dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
                if (tst->ss->add_to_super(tst, &disc, dfd,
-                                         dv->devname))
+                                         dv->devname, INVALID_SECTORS))
                        return -1;
                if (tst->ss->write_init_super(tst))
                        return -1;
@@ -791,7 +791,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
                if (mdmon_running(tst->container_dev))
                        tst->update_tail = &tst->updates;
                if (tst->ss->add_to_super(tst, &disc, dfd,
-                                         dv->devname)) {
+                                         dv->devname, INVALID_SECTORS)) {
                        close(dfd);
                        close(container_fd);
                        return -1;
index ef351b3970b28b42f2e0c919a16030354a317f15..f0399b886d5f9cf3027630395777eb18f42b9073 100644 (file)
@@ -304,7 +304,7 @@ static void add_disk_to_container(struct supertype *st, struct mdinfo *sd)
        st2->ss->free_super(st2);
 
        st->update_tail = &update;
-       st->ss->add_to_super(st, &dk, dfd, NULL);
+       st->ss->add_to_super(st, &dk, dfd, NULL, INVALID_SECTORS);
        st->ss->write_init_super(st);
        queue_metadata_update(update);
        st->update_tail = NULL;
index 255b6505009f8143f6a71ec8cb6d7fce012fd6f2..a2d3d00cc0935f8545927b52a34f0a46732616e6 100644 (file)
@@ -787,7 +787,7 @@ Since Linux 3.4,
 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 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.
 
@@ -795,6 +795,17 @@ 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.
 
+When creating an array,
+.B \-\-data\-offset
+can be specified as
+.BR variable .
+In the case each member device is expected to have a offset appended
+to the name, separated by a colon.  This makes it possible to recreate
+exactly an array which has varying data offsets (as can happen when
+different versions of
+.I mdadm
+are used to add different devices).
+
 .TP
 .BR \-\-continue
 This option is complementary to the
diff --git a/mdadm.c b/mdadm.c
index 5f395714e240307851b18ed51413ec8834a4c796..42544f1affbe448d4a3f37ae32366dd67d3ca08c 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -465,7 +465,11 @@ int main(int argc, char *argv[])
                                        "Second value is %s.\n", optarg);
                                exit(2);
                        }
-                       data_offset = parse_size(optarg);
+                       if (mode == CREATE &&
+                           strcmp(optarg, "variable") == 0)
+                               data_offset = VARIABLE_OFFSET;
+                       else
+                               data_offset = parse_size(optarg);
                        if (data_offset == INVALID_SECTORS) {
                                fprintf(stderr, Name ": invalid data-offset: %s\n",
                                        optarg);
diff --git a/mdadm.h b/mdadm.h
index 457cc5831e2f7f2c845400a6ef14c18a8da12235..e142c502d8d0f1d264c40d920b5f6e94644a8ac3 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -433,6 +433,7 @@ struct mddev_dev {
                                 */
        char writemostly;       /* 1 for 'set writemostly', 2 for 'clear writemostly' */
        char used;              /* set when used */
+       long long data_offset;
        struct mddev_dev *next;
 };
 
@@ -742,7 +743,8 @@ extern struct superswitch {
         * when hot-adding a spare.
         */
        int (*add_to_super)(struct supertype *st, mdu_disk_info_t *dinfo,
-                           int fd, char *devname);
+                           int fd, char *devname,
+                           unsigned long long data_offset);
        /* update the metadata to delete a device,
         * when hot-removing.
         */
@@ -1479,5 +1481,7 @@ char *xstrdup(const char *str);
  * a value for 'invalid'.  Use '1'.
  */
 #define INVALID_SECTORS 1
+/* And another special number needed for --data_offset=variable */
+#define VARIABLE_OFFSET 3
 
 extern int __offroot;
index baadc7959429606e9147e66f4957784f19185351..4a6f623709d7316f374a7d3fb65388ccfe839193 100644 (file)
@@ -2174,7 +2174,8 @@ static void add_to_super_ddf_bvd(struct supertype *st,
  * expanding a pre-existing container
  */
 static int add_to_super_ddf(struct supertype *st,
-                            mdu_disk_info_t *dk, int fd, char *devname)
+                           mdu_disk_info_t *dk, int fd, char *devname,
+                           unsigned long long data_offset)
 {
        struct ddf_super *ddf = st->sb;
        struct dl *dd;
index fc1d6ab83184ba9088d08249a529e40b75b6ad64..e311d0c8c175a005017a59c9ced19eff250ed2d1 100644 (file)
@@ -4937,7 +4937,8 @@ int mark_spare(struct dl *disk)
 }
 
 static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
-                            int fd, char *devname)
+                            int fd, char *devname,
+                            unsigned long long data_offset)
 {
        struct intel_super *super = st->sb;
        struct dl *dd;
index 4e6375f120acd99ecac6fff675104e3c3a3ba2ff..ac56d05cda296f8bfebb5f24718cbcbb61b9a4a3 100644 (file)
--- a/super0.c
+++ b/super0.c
@@ -695,7 +695,7 @@ struct devinfo {
 #ifndef MDASSEMBLE
 /* Add a device to the superblock being created */
 static int add_to_super0(struct supertype *st, mdu_disk_info_t *dinfo,
-                         int fd, char *devname)
+                        int fd, char *devname, unsigned long long data_offset)
 {
        mdp_super_t *sb = st->sb;
        mdp_disk_t *dk = &sb->disks[dinfo->number];
index 8f5f3071bb1c018801effd24839fad457e452a8e..d6b69fbe93bc80f9d0c7cd617d2e9005e12a9a66 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -1106,13 +1106,14 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
 struct devinfo {
        int fd;
        char *devname;
+       long long data_offset;
        mdu_disk_info_t disk;
        struct devinfo *next;
 };
 #ifndef MDASSEMBLE
 /* Add a device to the superblock being created */
 static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
-                         int fd, char *devname)
+                        int fd, char *devname, unsigned long long data_offset)
 {
        struct mdp_superblock_1 *sb = st->sb;
        __u16 *rp = sb->dev_roles + dk->number;
@@ -1140,6 +1141,7 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
        di->fd = fd;
        di->devname = devname;
        di->disk = *dk;
+       di->data_offset = data_offset;
        di->next = NULL;
        *dip = di;
 
@@ -1338,14 +1340,13 @@ static int write_init_super1(struct supertype *st)
                        headroom/2 >= __le32_to_cpu(sb->chunksize) * 2)
                        headroom >>= 1;
 
-
+               data_offset = di->data_offset;
                switch(st->minor_version) {
                case 0:
                        sb_offset = dsize;
                        sb_offset -= 8*2;
                        sb_offset &= ~(4*2-1);
                        sb->super_offset = __cpu_to_le64(sb_offset);
-                       data_offset = __le64_to_cpu(sb->data_offset);
                        if (data_offset == INVALID_SECTORS)
                                sb->data_offset = 0;
                        if (sb_offset < array_size + bm_space)
@@ -1358,7 +1359,6 @@ static int write_init_super1(struct supertype *st)
                        break;
                case 1:
                        sb->super_offset = __cpu_to_le64(0);
-                       data_offset = __le64_to_cpu(sb->data_offset);
                        if (data_offset == INVALID_SECTORS) {
                                reserved = bm_space + 4*2;
                                if (reserved < headroom)
@@ -1386,7 +1386,6 @@ static int write_init_super1(struct supertype *st)
                case 2:
                        sb_offset = 4*2;
                        sb->super_offset = __cpu_to_le64(4*2);
-                       data_offset = __le64_to_cpu(sb->data_offset);
                        if (data_offset == INVALID_SECTORS) {
                                if (4*2 + 4*2 + bm_space + array_size
                                    > dsize)
diff --git a/util.c b/util.c
index 4bd07e1b969f9f04664b238687b142748bbf6e40..5e653f49e0076014e857b8d1c02796a9177268ce 100644 (file)
--- a/util.c
+++ b/util.c
@@ -213,6 +213,9 @@ unsigned long long parse_size(char *size)
                        c++;
                        s *= 1024 * 1024 * 2;
                        break;
+               case 's': /* sectors */
+                       c++;
+                       break;
                }
        } else
                s = INVALID_SECTORS;