summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Create.c86
-rw-r--r--mdadm.h2
-rw-r--r--super-ddf.c156
-rw-r--r--super-intel.c8
4 files changed, 205 insertions, 47 deletions
diff --git a/Create.c b/Create.c
index 7ea39c4f..422b46df 100644
--- a/Create.c
+++ b/Create.c
@@ -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;
+ continue;
}
- if (dnum == insert_point ||
- strcasecmp(dv->devname, "missing")==0)
+ 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 (fd < 0) {
- fprintf(stderr, Name ": failed to open %s "
- "after earlier success - aborting\n",
- dv->devname);
- goto abort;
+ 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;
+ }
+ 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);
diff --git a/mdadm.h b/mdadm.h
index b0966e6f..610e1d1b 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -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.
diff --git a/super-ddf.c b/super-ddf.c
index 3c97bb67..3b3cac05 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -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.
diff --git a/super-intel.c b/super-intel.c
index f78957f1..b908375d 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -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,