char *name, int *uuid,
int subdevs, struct mddev_dev *devlist,
struct shape *s,
- struct context *c)
+ struct context *c, unsigned long long data_offset)
{
/*
* Create a new raid array.
newsize = s->size * 2;
if (st && ! st->ss->validate_geometry(st, s->level, s->layout, s->raiddisks,
&s->chunk, s->size*2,
- INVALID_SECTORS, NULL,
+ data_offset, NULL,
&newsize, c->verbose>=0))
return 1;
switch (st->ss->validate_geometry(
st, s->level, s->layout, s->raiddisks,
&s->chunk, s->size*2,
- INVALID_SECTORS, dname,
+ data_offset, dname,
&freesize, c->verbose > 0)) {
case -1: /* Not valid, message printed, and not
* worth checking any further */
if (!st->ss->validate_geometry(st, s->level, s->layout,
s->raiddisks,
&s->chunk, s->size*2,
- INVALID_SECTORS,
+ data_offset,
dname, &freesize,
c->verbose >= 0)) {
if (!st->ss->validate_geometry(st, s->level, s->layout,
s->raiddisks,
&s->chunk, minsize*2,
- INVALID_SECTORS,
+ data_offset,
NULL, NULL, 0)) {
pr_err("devices too large for RAID level %d\n", s->level);
return 1;
}
}
if (!st->ss->init_super(st, &info.array, s->size, name, c->homehost, uuid,
- INVALID_SECTORS))
+ data_offset))
goto abort_locked;
total_slots = info.array.nr_disks;
int Grow_reshape(char *devname, int fd,
struct mddev_dev *devlist,
+ unsigned long long data_offset,
struct context *c, struct shape *s)
{
/* Make some changes in the shape of an array.
struct mdinfo info;
struct mdinfo *sra;
+ if (data_offset != INVALID_SECTORS) {
+ fprintf(stderr, Name ": --grow --data-offset not yet supported\n");
+ return 1;
+ }
+
if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) {
pr_err("%s is not an active md array - aborting\n",
devname);
{"re-add", 0, 0, ReAdd},
{"homehost", 1, 0, HomeHost},
{"symlinks", 1, 0, Symlinks},
+ {"data-offset",1, 0, DataOffset},
/* For assemble */
{"uuid", 1, 0, 'u'},
" --raid-devices= -n : number of active devices in array\n"
" --spare-devices= -x: number of spare (eXtra) 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"
" : when changing parameters other than raid-devices\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[] =
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
int i;
unsigned long long array_size = 0;
+ unsigned long long data_offset = INVALID_SECTORS;
struct mddev_ident ident;
char *configfile = NULL;
int devmode = 0;
}
continue;
+ case O(CREATE,DataOffset):
+ case O(GROW,DataOffset):
+ if (data_offset != INVALID_SECTORS) {
+ 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 == INVALID_SECTORS) {
+ 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*/
rv = Create(ss, devlist->devname,
ident.name, ident.uuid_set ? ident.uuid : NULL,
devs_found-1, devlist->next,
- &s, &c);
+ &s, &c, data_offset);
break;
case MISC:
if (devmode == 'E') {
else if (s.size > 0 || s.raiddisks || s.layout_str != NULL
|| s.chunk != 0 || s.level != UnSet) {
rv = Grow_reshape(devlist->devname, mdfd,
- devlist->next, &c, &s);
+ devlist->next,
+ data_offset, &c, &s);
} else if (array_size == 0)
pr_err("no changes to --grow\n");
break;
OffRootOpt,
Prefer,
KillOpt,
+ DataOffset,
};
enum prefix_standard {
struct context *c, struct shape *s);
extern int Grow_reshape(char *devname, int fd,
struct mddev_dev *devlist,
+ unsigned long long data_offset,
struct context *c, struct shape *s);
extern int Grow_restart(struct supertype *st, struct mdinfo *info,
int *fdlist, int cnt, char *backup_file, int verbose);
char *name, int *uuid,
int subdevs, struct mddev_dev *devlist,
struct shape *s,
- struct context *c);
+ struct context *c,
+ unsigned long long data_offset);
extern int Detail(char *dev, struct context *c);
extern int Detail_Platform(struct superswitch *ss, int scan, int verbose, int export, char *controller_path);