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:
NeilBrown 2008-12-04 16:08:33 +11:00
parent e46273ebe4
commit 8592f29d64
4 changed files with 205 additions and 47 deletions

View File

@ -81,6 +81,7 @@ int Create(struct supertype *st, char *mddev,
unsigned long safe_mode_delay = 0;
char chosen_name[1024];
struct map_ent *map = NULL;
unsigned long long newsize;
int major_num = BITMAP_MAJOR_HI;
@ -147,13 +148,11 @@ int Create(struct supertype *st, char *mddev,
else
st = NULL;
}
if (have_container)
subdevs = raiddisks;
}
if (fd >= 0)
close(fd);
if (have_container) {
subdevs = 0;
devlist = NULL;
}
}
if (st && st->ss->external && sparedisks) {
fprintf(stderr,
@ -238,16 +237,23 @@ int Create(struct supertype *st, char *mddev,
fprintf(stderr, Name ": unknown level %d\n", level);
return 1;
}
newsize = size * 2;
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;
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 */
info.array.active_disks = 0;
info.array.working_disks = 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;
unsigned long long freesize;
if (strcasecmp(dname, "missing")==0) {
@ -341,6 +347,8 @@ int Create(struct supertype *st, char *mddev,
close(fd);
}
}
if (have_container)
info.array.working_disks = raiddisks;
if (fail) {
fprintf(stderr, Name ": create aborted\n");
return 1;
@ -366,9 +374,9 @@ int Create(struct supertype *st, char *mddev,
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)
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);
warn = 1;
}
@ -669,10 +677,15 @@ int Create(struct supertype *st, char *mddev,
abort();
if (dnum == insert_point) {
moved_disk = dv;
}
if (dnum == insert_point ||
strcasecmp(dv->devname, "missing")==0)
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) {
case 1:
@ -689,31 +702,43 @@ int Create(struct supertype *st, char *mddev,
if (dv->writemostly == 1)
inf->disk.state |= (1<<MD_DISK_WRITEMOSTLY);
if (st->ss->external && st->subarray[0])
fd = open(dv->devname, O_RDWR);
else
fd = open(dv->devname, O_RDWR|O_EXCL);
if (have_container)
fd = -1;
else {
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) {
fprintf(stderr, Name ": failed to open %s "
"after earlier success - aborting\n",
dv->devname);
goto abort;
if (fd < 0) {
fprintf(stderr, Name ": failed to open %s "
"after earlier success - aborting\n",
dv->devname);
goto abort;
}
fstat(fd, &stb);
inf->disk.major = major(stb.st_rdev);
inf->disk.minor = minor(stb.st_rdev);
}
fstat(fd, &stb);
inf->disk.major = major(stb.st_rdev);
inf->disk.minor = minor(stb.st_rdev);
remove_partitions(fd);
if (fd >= 0)
remove_partitions(fd);
if (st->ss->add_to_super(st, &inf->disk,
fd, dv->devname))
goto abort;
st->ss->getinfo_super(st, inf);
safe_mode_delay = inf->safe_mode_delay;
/* getinfo_super might have lost these ... */
inf->disk.major = major(stb.st_rdev);
inf->disk.minor = minor(stb.st_rdev);
if (have_container && verbose > 0)
fprintf(stderr, Name ": Using %s for device %d\n",
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;
case 2:
inf->errors = 0;
@ -731,7 +756,8 @@ int Create(struct supertype *st, char *mddev,
}
break;
}
if (dv == moved_disk && dnum != insert_point) break;
if (!have_container &&
dv == moved_disk && dnum != insert_point) break;
}
if (pass == 1) {
st->ss->write_init_super(st);

View File

@ -448,7 +448,7 @@ extern struct superswitch {
*/
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 determination is made either by:
* load_super being given a 'component' string.

View File

@ -423,10 +423,14 @@ struct ddf_super {
unsigned long long size; /* sectors */
int pdnum; /* index in ->phys */
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;
void *mdupdate; /* hold metadata update */
struct vcl *vlist[0]; /* max_part in size */
} *dlist, *add_list;
};
@ -1325,6 +1329,7 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info)
struct vcl *vc = ddf->currentconf;
int cd = ddf->currentdev;
int j;
struct dl *dl;
/* 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);
}
for (dl = ddf->dlist; dl ; dl = dl->next)
if (dl->raiddisk == info->disk.raid_disk)
break;
info->disk.major = 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.raid_disk = find refnum in the table and use index;
// 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.
* We might also want to update the type in the phys_disk
* section.
*
* Alternately: fd == -1 and we have already chosen which device to
* use and recorded in dlist->raid_disk;
*/
struct dl *dl;
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;
struct extent *ex;
for (dl = ddf->dlist; dl ; dl = dl->next)
if (dl->major == dk->major &&
dl->minor == dk->minor)
break;
if (fd == -1) {
for (dl = ddf->dlist; dl ; dl = dl->next)
if (dl->raiddisk == dk->raid_disk)
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)))
return;
@ -2017,8 +2038,10 @@ static void add_to_super_ddf_bvd(struct supertype *st,
return;
dl->vlist[i] = ddf->currentconf;
dl->fd = fd;
dl->devname = devname;
if (fd >= 0)
dl->fd = fd;
if (devname)
dl->devname = devname;
/* Check how many working raid_disks, and if we can mark
* array as optimal yet
@ -2331,6 +2354,96 @@ static __u64 avail_size_ddf(struct supertype *st, __u64 devsize)
}
#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
validate_geometry_ddf_container(struct supertype *st,
int level, int layout, int raiddisks,
@ -2369,15 +2482,6 @@ static int validate_geometry_ddf(struct supertype *st,
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) {
/* Initial sanity check. Exclude illegal levels. */
int i;
@ -2387,9 +2491,29 @@ static int validate_geometry_ddf(struct supertype *st,
if (ddf_level_num[i].num1 == MAXINT)
return 0;
/* 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;
}
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.
* If it is a container, we read it in and do automagic allocations,
* no other devices should be given.

View File

@ -2387,6 +2387,14 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
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) {
/* creating in a given container */
return validate_geometry_imsm_volume(st, level, layout,