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 <neilb@suse.de>
This commit is contained in:
NeilBrown 2012-10-04 16:34:21 +10:00
parent ee2429e0bc
commit 72ca9bcff3
11 changed files with 52 additions and 17 deletions

View File

@ -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;
}

View File

@ -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;

View 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;

View 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

View File

@ -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);

View File

@ -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;

View 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;

View 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;

View File

@ -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];

View File

@ -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)

3
util.c
View File

@ -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;