From 72ca9bcff34d705fde5670a76cee7b85c0033c94 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 4 Oct 2012 16:34:21 +1000 Subject: [PATCH] Allow data-offset to be specified per-device for create 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 --- Create.c | 18 +++++++++++++++--- Manage.c | 4 ++-- managemon.c | 2 +- mdadm.8.in | 13 ++++++++++++- mdadm.c | 6 +++++- mdadm.h | 6 +++++- super-ddf.c | 3 ++- super-intel.c | 3 ++- super0.c | 2 +- super1.c | 9 ++++----- util.c | 3 +++ 11 files changed, 52 insertions(+), 17 deletions(-) diff --git a/Create.c b/Create.c index 91c641f5..d6dcdbf3 100644 --- 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; } diff --git a/Manage.c b/Manage.c index d2b92a20..296feeb7 100644 --- 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; diff --git a/managemon.c b/managemon.c index ef351b39..f0399b88 100644 --- a/managemon.c +++ b/managemon.c @@ -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; diff --git a/mdadm.8.in b/mdadm.8.in index 255b6505..a2d3d00c 100644 --- a/mdadm.8.in +++ b/mdadm.8.in @@ -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 5f395714..42544f1a 100644 --- 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 457cc583..e142c502 100644 --- 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; diff --git a/super-ddf.c b/super-ddf.c index baadc795..4a6f6237 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -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; diff --git a/super-intel.c b/super-intel.c index fc1d6ab8..e311d0c8 100644 --- a/super-intel.c +++ b/super-intel.c @@ -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; diff --git a/super0.c b/super0.c index 4e6375f1..ac56d05c 100644 --- 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]; diff --git a/super1.c b/super1.c index 8f5f3071..d6b69fbe 100644 --- 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 4bd07e1b..5e653f49 100644 --- 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; -- 2.39.2