Create: support autolayout when creating in a DDF
If, when creating an array, a signal target device is given which is a container, then allow the metadata handler to choose which devices to use. This is currently only supported for DDF. Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
parent
e46273ebe4
commit
8592f29d64
86
Create.c
86
Create.c
|
@ -81,6 +81,7 @@ int Create(struct supertype *st, char *mddev,
|
||||||
unsigned long safe_mode_delay = 0;
|
unsigned long safe_mode_delay = 0;
|
||||||
char chosen_name[1024];
|
char chosen_name[1024];
|
||||||
struct map_ent *map = NULL;
|
struct map_ent *map = NULL;
|
||||||
|
unsigned long long newsize;
|
||||||
|
|
||||||
int major_num = BITMAP_MAJOR_HI;
|
int major_num = BITMAP_MAJOR_HI;
|
||||||
|
|
||||||
|
@ -147,13 +148,11 @@ int Create(struct supertype *st, char *mddev,
|
||||||
else
|
else
|
||||||
st = NULL;
|
st = NULL;
|
||||||
}
|
}
|
||||||
|
if (have_container)
|
||||||
|
subdevs = raiddisks;
|
||||||
}
|
}
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
close(fd);
|
close(fd);
|
||||||
if (have_container) {
|
|
||||||
subdevs = 0;
|
|
||||||
devlist = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (st && st->ss->external && sparedisks) {
|
if (st && st->ss->external && sparedisks) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -238,16 +237,23 @@ int Create(struct supertype *st, char *mddev,
|
||||||
fprintf(stderr, Name ": unknown level %d\n", level);
|
fprintf(stderr, Name ": unknown level %d\n", level);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newsize = size * 2;
|
||||||
if (st && ! st->ss->validate_geometry(st, level, layout, raiddisks,
|
if (st && ! st->ss->validate_geometry(st, level, layout, raiddisks,
|
||||||
chunk, size*2, NULL, NULL, verbose>=0))
|
chunk, size*2, NULL, &newsize, verbose>=0))
|
||||||
return 1;
|
return 1;
|
||||||
|
if (size == 0) {
|
||||||
|
size = newsize / 2;
|
||||||
|
if (size && verbose > 0)
|
||||||
|
fprintf(stderr, Name ": setting size to %lluK\n",
|
||||||
|
(unsigned long long)size);
|
||||||
|
}
|
||||||
|
|
||||||
/* now look at the subdevs */
|
/* now look at the subdevs */
|
||||||
info.array.active_disks = 0;
|
info.array.active_disks = 0;
|
||||||
info.array.working_disks = 0;
|
info.array.working_disks = 0;
|
||||||
dnum = 0;
|
dnum = 0;
|
||||||
for (dv=devlist; dv; dv=dv->next, dnum++) {
|
for (dv=devlist; dv && !have_container; dv=dv->next, dnum++) {
|
||||||
char *dname = dv->devname;
|
char *dname = dv->devname;
|
||||||
unsigned long long freesize;
|
unsigned long long freesize;
|
||||||
if (strcasecmp(dname, "missing")==0) {
|
if (strcasecmp(dname, "missing")==0) {
|
||||||
|
@ -341,6 +347,8 @@ int Create(struct supertype *st, char *mddev,
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (have_container)
|
||||||
|
info.array.working_disks = raiddisks;
|
||||||
if (fail) {
|
if (fail) {
|
||||||
fprintf(stderr, Name ": create aborted\n");
|
fprintf(stderr, Name ": create aborted\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -366,9 +374,9 @@ int Create(struct supertype *st, char *mddev,
|
||||||
fprintf(stderr, Name ": size set to %lluK\n", size);
|
fprintf(stderr, Name ": size set to %lluK\n", size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (level > 0 && ((maxsize-size)*100 > maxsize)) {
|
if (!have_container && level > 0 && ((maxsize-size)*100 > maxsize)) {
|
||||||
if (runstop != 1 || verbose >= 0)
|
if (runstop != 1 || verbose >= 0)
|
||||||
fprintf(stderr, Name ": largest drive (%s) exceed size (%lluK) by more than 1%%\n",
|
fprintf(stderr, Name ": largest drive (%s) exceeds size (%lluK) by more than 1%%\n",
|
||||||
maxdisc, size);
|
maxdisc, size);
|
||||||
warn = 1;
|
warn = 1;
|
||||||
}
|
}
|
||||||
|
@ -669,10 +677,15 @@ int Create(struct supertype *st, char *mddev,
|
||||||
abort();
|
abort();
|
||||||
if (dnum == insert_point) {
|
if (dnum == insert_point) {
|
||||||
moved_disk = dv;
|
moved_disk = dv;
|
||||||
}
|
|
||||||
if (dnum == insert_point ||
|
|
||||||
strcasecmp(dv->devname, "missing")==0)
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
if (strcasecmp(dv->devname, "missing")==0)
|
||||||
|
continue;
|
||||||
|
if (have_container)
|
||||||
|
moved_disk = NULL;
|
||||||
|
if (have_container && dnum < info.array.raid_disks - 1)
|
||||||
|
/* repeatedly use the container */
|
||||||
|
moved_disk = dv;
|
||||||
|
|
||||||
switch(pass) {
|
switch(pass) {
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -689,31 +702,43 @@ int Create(struct supertype *st, char *mddev,
|
||||||
if (dv->writemostly == 1)
|
if (dv->writemostly == 1)
|
||||||
inf->disk.state |= (1<<MD_DISK_WRITEMOSTLY);
|
inf->disk.state |= (1<<MD_DISK_WRITEMOSTLY);
|
||||||
|
|
||||||
if (st->ss->external && st->subarray[0])
|
if (have_container)
|
||||||
fd = open(dv->devname, O_RDWR);
|
fd = -1;
|
||||||
else
|
else {
|
||||||
fd = open(dv->devname, O_RDWR|O_EXCL);
|
if (st->ss->external && st->subarray[0])
|
||||||
|
fd = open(dv->devname, O_RDWR);
|
||||||
|
else
|
||||||
|
fd = open(dv->devname, O_RDWR|O_EXCL);
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
fprintf(stderr, Name ": failed to open %s "
|
fprintf(stderr, Name ": failed to open %s "
|
||||||
"after earlier success - aborting\n",
|
"after earlier success - aborting\n",
|
||||||
dv->devname);
|
dv->devname);
|
||||||
goto abort;
|
goto abort;
|
||||||
|
}
|
||||||
|
fstat(fd, &stb);
|
||||||
|
inf->disk.major = major(stb.st_rdev);
|
||||||
|
inf->disk.minor = minor(stb.st_rdev);
|
||||||
}
|
}
|
||||||
fstat(fd, &stb);
|
if (fd >= 0)
|
||||||
inf->disk.major = major(stb.st_rdev);
|
remove_partitions(fd);
|
||||||
inf->disk.minor = minor(stb.st_rdev);
|
|
||||||
|
|
||||||
remove_partitions(fd);
|
|
||||||
if (st->ss->add_to_super(st, &inf->disk,
|
if (st->ss->add_to_super(st, &inf->disk,
|
||||||
fd, dv->devname))
|
fd, dv->devname))
|
||||||
goto abort;
|
goto abort;
|
||||||
st->ss->getinfo_super(st, inf);
|
st->ss->getinfo_super(st, inf);
|
||||||
safe_mode_delay = inf->safe_mode_delay;
|
safe_mode_delay = inf->safe_mode_delay;
|
||||||
|
|
||||||
/* getinfo_super might have lost these ... */
|
if (have_container && verbose > 0)
|
||||||
inf->disk.major = major(stb.st_rdev);
|
fprintf(stderr, Name ": Using %s for device %d\n",
|
||||||
inf->disk.minor = minor(stb.st_rdev);
|
map_dev(inf->disk.major,
|
||||||
|
inf->disk.minor,
|
||||||
|
0), dnum);
|
||||||
|
|
||||||
|
if (!have_container) {
|
||||||
|
/* getinfo_super might have lost these ... */
|
||||||
|
inf->disk.major = major(stb.st_rdev);
|
||||||
|
inf->disk.minor = minor(stb.st_rdev);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
inf->errors = 0;
|
inf->errors = 0;
|
||||||
|
@ -731,7 +756,8 @@ int Create(struct supertype *st, char *mddev,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (dv == moved_disk && dnum != insert_point) break;
|
if (!have_container &&
|
||||||
|
dv == moved_disk && dnum != insert_point) break;
|
||||||
}
|
}
|
||||||
if (pass == 1) {
|
if (pass == 1) {
|
||||||
st->ss->write_init_super(st);
|
st->ss->write_init_super(st);
|
||||||
|
|
2
mdadm.h
2
mdadm.h
|
@ -448,7 +448,7 @@ extern struct superswitch {
|
||||||
*/
|
*/
|
||||||
void (*uuid_from_super)(struct supertype *st, int uuid[4]);
|
void (*uuid_from_super)(struct supertype *st, int uuid[4]);
|
||||||
|
|
||||||
/* Extra generic details from metadata. This could be details about
|
/* Extract generic details from metadata. This could be details about
|
||||||
* the container, or about an individual array within the container.
|
* the container, or about an individual array within the container.
|
||||||
* The determination is made either by:
|
* The determination is made either by:
|
||||||
* load_super being given a 'component' string.
|
* load_super being given a 'component' string.
|
||||||
|
|
156
super-ddf.c
156
super-ddf.c
|
@ -423,10 +423,14 @@ struct ddf_super {
|
||||||
unsigned long long size; /* sectors */
|
unsigned long long size; /* sectors */
|
||||||
int pdnum; /* index in ->phys */
|
int pdnum; /* index in ->phys */
|
||||||
struct spare_assign *spare;
|
struct spare_assign *spare;
|
||||||
|
void *mdupdate; /* hold metadata update */
|
||||||
|
|
||||||
|
/* These fields used by auto-layout */
|
||||||
|
int raiddisk; /* slot to fill in autolayout */
|
||||||
|
__u64 esize;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
struct disk_data disk;
|
struct disk_data disk;
|
||||||
void *mdupdate; /* hold metadata update */
|
|
||||||
struct vcl *vlist[0]; /* max_part in size */
|
struct vcl *vlist[0]; /* max_part in size */
|
||||||
} *dlist, *add_list;
|
} *dlist, *add_list;
|
||||||
};
|
};
|
||||||
|
@ -1325,6 +1329,7 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info)
|
||||||
struct vcl *vc = ddf->currentconf;
|
struct vcl *vc = ddf->currentconf;
|
||||||
int cd = ddf->currentdev;
|
int cd = ddf->currentdev;
|
||||||
int j;
|
int j;
|
||||||
|
struct dl *dl;
|
||||||
|
|
||||||
/* FIXME this returns BVD info - what if we want SVD ?? */
|
/* FIXME this returns BVD info - what if we want SVD ?? */
|
||||||
|
|
||||||
|
@ -1346,8 +1351,15 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info)
|
||||||
info->component_size = __be64_to_cpu(vc->conf.blocks);
|
info->component_size = __be64_to_cpu(vc->conf.blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (dl = ddf->dlist; dl ; dl = dl->next)
|
||||||
|
if (dl->raiddisk == info->disk.raid_disk)
|
||||||
|
break;
|
||||||
info->disk.major = 0;
|
info->disk.major = 0;
|
||||||
info->disk.minor = 0;
|
info->disk.minor = 0;
|
||||||
|
if (dl) {
|
||||||
|
info->disk.major = dl->major;
|
||||||
|
info->disk.minor = dl->minor;
|
||||||
|
}
|
||||||
// info->disk.number = __be32_to_cpu(ddf->disk.refnum);
|
// info->disk.number = __be32_to_cpu(ddf->disk.refnum);
|
||||||
// info->disk.raid_disk = find refnum in the table and use index;
|
// info->disk.raid_disk = find refnum in the table and use index;
|
||||||
// info->disk.state = ???;
|
// info->disk.state = ???;
|
||||||
|
@ -1965,6 +1977,9 @@ static void add_to_super_ddf_bvd(struct supertype *st,
|
||||||
* the phys_refnum and lba_offset for the newly created vd_config.
|
* the phys_refnum and lba_offset for the newly created vd_config.
|
||||||
* We might also want to update the type in the phys_disk
|
* We might also want to update the type in the phys_disk
|
||||||
* section.
|
* section.
|
||||||
|
*
|
||||||
|
* Alternately: fd == -1 and we have already chosen which device to
|
||||||
|
* use and recorded in dlist->raid_disk;
|
||||||
*/
|
*/
|
||||||
struct dl *dl;
|
struct dl *dl;
|
||||||
struct ddf_super *ddf = st->sb;
|
struct ddf_super *ddf = st->sb;
|
||||||
|
@ -1975,10 +1990,16 @@ static void add_to_super_ddf_bvd(struct supertype *st,
|
||||||
unsigned long long blocks, pos, esize;
|
unsigned long long blocks, pos, esize;
|
||||||
struct extent *ex;
|
struct extent *ex;
|
||||||
|
|
||||||
for (dl = ddf->dlist; dl ; dl = dl->next)
|
if (fd == -1) {
|
||||||
if (dl->major == dk->major &&
|
for (dl = ddf->dlist; dl ; dl = dl->next)
|
||||||
dl->minor == dk->minor)
|
if (dl->raiddisk == dk->raid_disk)
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
for (dl = ddf->dlist; dl ; dl = dl->next)
|
||||||
|
if (dl->major == dk->major &&
|
||||||
|
dl->minor == dk->minor)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!dl || ! (dk->state & (1<<MD_DISK_SYNC)))
|
if (!dl || ! (dk->state & (1<<MD_DISK_SYNC)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2017,8 +2038,10 @@ static void add_to_super_ddf_bvd(struct supertype *st,
|
||||||
return;
|
return;
|
||||||
dl->vlist[i] = ddf->currentconf;
|
dl->vlist[i] = ddf->currentconf;
|
||||||
|
|
||||||
dl->fd = fd;
|
if (fd >= 0)
|
||||||
dl->devname = devname;
|
dl->fd = fd;
|
||||||
|
if (devname)
|
||||||
|
dl->devname = devname;
|
||||||
|
|
||||||
/* Check how many working raid_disks, and if we can mark
|
/* Check how many working raid_disks, and if we can mark
|
||||||
* array as optimal yet
|
* array as optimal yet
|
||||||
|
@ -2331,6 +2354,96 @@ static __u64 avail_size_ddf(struct supertype *st, __u64 devsize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MDASSEMBLE
|
#ifndef MDASSEMBLE
|
||||||
|
|
||||||
|
static int reserve_space(struct supertype *st, int raiddisks,
|
||||||
|
unsigned long long size, int chunk,
|
||||||
|
unsigned long long *freesize)
|
||||||
|
{
|
||||||
|
/* Find 'raiddisks' spare extents at least 'size' big (but
|
||||||
|
* only caring about multiples of 'chunk') and remember
|
||||||
|
* them.
|
||||||
|
* If the cannot be found, fail.
|
||||||
|
*/
|
||||||
|
struct dl *dl;
|
||||||
|
struct ddf_super *ddf = st->sb;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
for (dl = ddf->dlist; dl ; dl=dl->next) {
|
||||||
|
dl->raiddisk = -1;
|
||||||
|
dl->esize = 0;
|
||||||
|
}
|
||||||
|
/* Now find largest extent on each device */
|
||||||
|
for (dl = ddf->dlist ; dl ; dl=dl->next) {
|
||||||
|
struct extent *e = get_extents(ddf, dl);
|
||||||
|
unsigned long long pos = 0;
|
||||||
|
int i = 0;
|
||||||
|
int found = 0;
|
||||||
|
unsigned long long minsize = size;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
minsize = chunk;
|
||||||
|
|
||||||
|
if (!e)
|
||||||
|
continue;
|
||||||
|
do {
|
||||||
|
unsigned long long esize;
|
||||||
|
esize = e[i].start - pos;
|
||||||
|
if (esize >= minsize) {
|
||||||
|
found = 1;
|
||||||
|
minsize = esize;
|
||||||
|
}
|
||||||
|
pos = e[i].start + e[i].size;
|
||||||
|
i++;
|
||||||
|
} while (e[i-1].size);
|
||||||
|
if (found) {
|
||||||
|
cnt++;
|
||||||
|
dl->esize = minsize;
|
||||||
|
}
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
|
if (cnt < raiddisks) {
|
||||||
|
fprintf(stderr, Name ": not enough devices with space to create array.\n");
|
||||||
|
return 0; /* No enough free spaces large enough */
|
||||||
|
}
|
||||||
|
if (size == 0) {
|
||||||
|
/* choose the largest size of which there are at least 'raiddisk' */
|
||||||
|
for (dl = ddf->dlist ; dl ; dl=dl->next) {
|
||||||
|
struct dl *dl2;
|
||||||
|
if (dl->esize <= size)
|
||||||
|
continue;
|
||||||
|
/* This is bigger than 'size', see if there are enough */
|
||||||
|
cnt = 0;
|
||||||
|
for (dl2 = dl; dl2 ; dl2=dl2->next)
|
||||||
|
if (dl2->esize >= dl->esize)
|
||||||
|
cnt++;
|
||||||
|
if (cnt >= raiddisks)
|
||||||
|
size = dl->esize;
|
||||||
|
}
|
||||||
|
if (chunk) {
|
||||||
|
size = size / chunk;
|
||||||
|
size *= chunk;
|
||||||
|
}
|
||||||
|
*freesize = size;
|
||||||
|
if (size < 32) {
|
||||||
|
fprintf(stderr, Name ": not enough spare devices to create array.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* We have a 'size' of which there are enough spaces.
|
||||||
|
* We simply do a first-fit */
|
||||||
|
cnt = 0;
|
||||||
|
for (dl = ddf->dlist ; dl && cnt < raiddisks ; dl=dl->next) {
|
||||||
|
if (dl->esize < size)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dl->raiddisk = cnt;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
validate_geometry_ddf_container(struct supertype *st,
|
validate_geometry_ddf_container(struct supertype *st,
|
||||||
int level, int layout, int raiddisks,
|
int level, int layout, int raiddisks,
|
||||||
|
@ -2369,15 +2482,6 @@ static int validate_geometry_ddf(struct supertype *st,
|
||||||
verbose);
|
verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->sb) {
|
|
||||||
/* A container has already been opened, so we are
|
|
||||||
* creating in there. Maybe a BVD, maybe an SVD.
|
|
||||||
* Should make a distinction one day.
|
|
||||||
*/
|
|
||||||
return validate_geometry_ddf_bvd(st, level, layout, raiddisks,
|
|
||||||
chunk, size, dev, freesize,
|
|
||||||
verbose);
|
|
||||||
}
|
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
/* Initial sanity check. Exclude illegal levels. */
|
/* Initial sanity check. Exclude illegal levels. */
|
||||||
int i;
|
int i;
|
||||||
|
@ -2387,9 +2491,29 @@ static int validate_geometry_ddf(struct supertype *st,
|
||||||
if (ddf_level_num[i].num1 == MAXINT)
|
if (ddf_level_num[i].num1 == MAXINT)
|
||||||
return 0;
|
return 0;
|
||||||
/* Should check layout? etc */
|
/* Should check layout? etc */
|
||||||
|
|
||||||
|
if (st->sb && freesize) {
|
||||||
|
/* --create was given a container to create in.
|
||||||
|
* So we need to check that there are enough
|
||||||
|
* free spaces and return the amount of space.
|
||||||
|
* We may as well remember which drives were
|
||||||
|
* chosen so that add_to_super/getinfo_super
|
||||||
|
* can return them.
|
||||||
|
*/
|
||||||
|
return reserve_space(st, raiddisks, size, chunk, freesize);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (st->sb) {
|
||||||
|
/* A container has already been opened, so we are
|
||||||
|
* creating in there. Maybe a BVD, maybe an SVD.
|
||||||
|
* Should make a distinction one day.
|
||||||
|
*/
|
||||||
|
return validate_geometry_ddf_bvd(st, level, layout, raiddisks,
|
||||||
|
chunk, size, dev, freesize,
|
||||||
|
verbose);
|
||||||
|
}
|
||||||
/* This is the first device for the array.
|
/* This is the first device for the array.
|
||||||
* If it is a container, we read it in and do automagic allocations,
|
* If it is a container, we read it in and do automagic allocations,
|
||||||
* no other devices should be given.
|
* no other devices should be given.
|
||||||
|
|
|
@ -2387,6 +2387,14 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
|
||||||
verbose);
|
verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dev) {
|
||||||
|
if (st->sb && freesize) {
|
||||||
|
/* Should do auto-layout here */
|
||||||
|
fprintf(stderr, Name ": IMSM does not support auto-layout yet\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (st->sb) {
|
if (st->sb) {
|
||||||
/* creating in a given container */
|
/* creating in a given container */
|
||||||
return validate_geometry_imsm_volume(st, level, layout,
|
return validate_geometry_imsm_volume(st, level, layout,
|
||||||
|
|
Loading…
Reference in New Issue