Add optional -o argument to the graid label to specify some metadata

format options. Use it for specifying byte order for the DDF metadata:
big-endian defined by specification and little-endian used by Adaptec.
This commit is contained in:
mav 2012-05-03 05:32:56 +00:00
parent 62cde8b2a2
commit 6a0688c8fd
7 changed files with 74 additions and 17 deletions

View File

@ -48,11 +48,12 @@ struct g_command class_commands[] = {
{ "label", G_FLAG_VERBOSE, NULL,
{
{ 'f', "force", NULL, G_TYPE_BOOL },
{ 'o', "fmtopt", G_VAL_OPTIONAL, G_TYPE_STRING },
{ 'S', "size", G_VAL_OPTIONAL, G_TYPE_NUMBER },
{ 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER },
G_OPT_SENTINEL
},
"[-fv] [-S size] [-s stripsize] format label level prov ..."
"[-fv] [-o fmtopt] [-S size] [-s stripsize] format label level prov ..."
},
{ "add", G_FLAG_VERBOSE, NULL,
{

View File

@ -34,6 +34,7 @@
.Nm
.Cm label
.Op Fl f
.Op Fl o Ar fmtopt
.Op Fl S Ar size
.Op Fl s Ar strip
.Ar format
@ -119,6 +120,8 @@ Additional options include:
.It Fl f
Enforce specified configuration creation if it is officially unsupported,
but technically can be created.
.It Fl o Ar fmtopt
Specifies metadata format options.
.It Fl S Ar size
Use
.Ar size
@ -205,14 +208,18 @@ The format defined by the SNIA Common RAID Disk Data Format v2.0 specification.
Used by some Adaptec RAID BIOSes and some hardware RAID controllers.
Because of high format flexibility different implementations support
different set of features and have different on-disk metadata layouts.
To provide compatibility, the GEOM RAID class mimics capabilities and
metadata layout of the first detected DDF array.
To provide compatibility, the GEOM RAID class mimics capabilities
of the first detected DDF array.
Respecting that, it may support different number of disks per volume,
volumes per array, partitions per disk, etc.
The following configurations are supported: RAID0 (2+ disks), RAID1 (2+ disks),
RAID1E (3+ disks), RAID3 (3+ disks), RAID4 (3+ disks), RAID5 (3+ disks),
RAID5E (4+ disks), RAID5EE (4+ disks), RAID5R (3+ disks), RAID6 (4+ disks),
RAIDMDF (5+ disks), RAID10 (4+ disks), SINGLE (1 disk), CONCAT (2+ disks).
.Pp
Format supports two options "BE" and "LE", that mean big-endian byte order
defined by specification (default) and little-endian used by some Adaptec
controllers.
.It Intel
The format used by Intel RAID BIOS.
Supports up to two volumes per array.

View File

@ -2143,7 +2143,7 @@ g_raid_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
G_RAID_DEBUG(2, "Tasting provider %s.", pp->name);
gp = g_new_geomf(mp, "mirror:taste");
gp = g_new_geomf(mp, "raid:taste");
/*
* This orphan function should be never called.
*/
@ -2173,7 +2173,8 @@ g_raid_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
}
int
g_raid_create_node_format(const char *format, struct g_geom **gp)
g_raid_create_node_format(const char *format, struct gctl_req *req,
struct g_geom **gp)
{
struct g_raid_md_class *class;
struct g_raid_md_object *obj;
@ -2191,7 +2192,7 @@ g_raid_create_node_format(const char *format, struct g_geom **gp)
obj = (void *)kobj_create((kobj_class_t)class, M_RAID,
M_WAITOK);
obj->mdo_class = class;
status = G_RAID_MD_CREATE(obj, &g_raid_class, gp);
status = G_RAID_MD_CREATE_REQ(obj, &g_raid_class, req, gp);
if (status != G_RAID_MD_TASTE_NEW)
kobj_delete((kobj_t)obj, M_RAID);
return (status);

View File

@ -382,7 +382,8 @@ const char * g_raid_disk_state2str(int state);
struct g_raid_softc * g_raid_create_node(struct g_class *mp,
const char *name, struct g_raid_md_object *md);
int g_raid_create_node_format(const char *format, struct g_geom **gp);
int g_raid_create_node_format(const char *format, struct gctl_req *req,
struct g_geom **gp);
struct g_raid_volume * g_raid_create_volume(struct g_raid_softc *sc,
const char *name, int id);
struct g_raid_disk * g_raid_create_disk(struct g_raid_softc *sc);

View File

@ -88,7 +88,7 @@ g_raid_ctl_label(struct gctl_req *req, struct g_class *mp)
gctl_error(req, "No format recieved.");
return;
}
crstatus = g_raid_create_node_format(format, &geom);
crstatus = g_raid_create_node_format(format, req, &geom);
if (crstatus == G_RAID_MD_TASTE_FAIL) {
gctl_error(req, "Failed to create array with format '%s'.",
format);

View File

@ -49,12 +49,21 @@ HEADER {
# Default implementations of methods.
CODE {
static int
g_raid_md_create_default(struct g_raid_md_object *md)
g_raid_md_create_default(struct g_raid_md_object *md,
struct g_class *mp, struct g_geom **gp)
{
return (G_RAID_MD_TASTE_FAIL);
}
static int
g_raid_md_create_req_default(struct g_raid_md_object *md,
struct g_class *mp, struct gctl_req *req, struct g_geom **gp)
{
return (G_RAID_MD_CREATE(md, mp, gp));
}
static int
g_raid_md_ctl_default(struct g_raid_md_object *md,
struct gctl_req *req)
@ -95,6 +104,14 @@ METHOD int create {
struct g_geom **gp;
} DEFAULT g_raid_md_create_default;
# create_req() - create new node from scratch, with request argument.
METHOD int create_req {
struct g_raid_md_object *md;
struct g_class *mp;
struct gctl_req *req;
struct g_geom **gp;
} DEFAULT g_raid_md_create_req_default;
# taste() - taste disk and, if needed, create new node.
METHOD int taste {
struct g_raid_md_object *md;

View File

@ -88,6 +88,7 @@ struct g_raid_md_ddf_pervolume {
struct g_raid_md_ddf_object {
struct g_raid_md_object mdio_base;
u_int mdio_bigendian;
struct ddf_meta mdio_meta;
int mdio_starting;
struct callout mdio_start_co; /* STARTING state timer. */
@ -95,7 +96,7 @@ struct g_raid_md_ddf_object {
struct root_hold_token *mdio_rootmount; /* Root mount delay token. */
};
static g_raid_md_create_t g_raid_md_create_ddf;
static g_raid_md_create_req_t g_raid_md_create_req_ddf;
static g_raid_md_taste_t g_raid_md_taste_ddf;
static g_raid_md_event_t g_raid_md_event_ddf;
static g_raid_md_volume_event_t g_raid_md_volume_event_ddf;
@ -107,7 +108,7 @@ static g_raid_md_free_volume_t g_raid_md_free_volume_ddf;
static g_raid_md_free_t g_raid_md_free_ddf;
static kobj_method_t g_raid_md_ddf_methods[] = {
KOBJMETHOD(g_raid_md_create, g_raid_md_create_ddf),
KOBJMETHOD(g_raid_md_create_req, g_raid_md_create_req_ddf),
KOBJMETHOD(g_raid_md_taste, g_raid_md_taste_ddf),
KOBJMETHOD(g_raid_md_event, g_raid_md_event_ddf),
KOBJMETHOD(g_raid_md_volume_event, g_raid_md_volume_event_ddf),
@ -562,6 +563,7 @@ ddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample)
struct timespec ts;
struct clocktime ct;
struct g_raid_md_ddf_perdisk *pd;
struct g_raid_md_ddf_object *mdi;
struct ddf_meta *meta;
struct ddf_pd_entry *pde;
off_t anchorlba;
@ -572,13 +574,14 @@ ddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample)
if (sample->hdr == NULL)
sample = NULL;
mdi = (struct g_raid_md_ddf_object *)disk->d_softc->sc_md;
pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
meta = &pd->pd_meta;
ss = disk->d_consumer->provider->sectorsize;
anchorlba = disk->d_consumer->provider->mediasize / ss - 1;
meta->sectorsize = ss;
meta->bigendian = sample ? sample->bigendian : 0;
meta->bigendian = sample ? sample->bigendian : mdi->mdio_bigendian;
getnanotime(&ts);
clock_ts_to_ct(&ts, &ct);
@ -2012,11 +2015,26 @@ g_raid_md_ddf_new_disk(struct g_raid_disk *disk)
}
static int
g_raid_md_create_ddf(struct g_raid_md_object *md, struct g_class *mp,
struct g_geom **gp)
g_raid_md_create_req_ddf(struct g_raid_md_object *md, struct g_class *mp,
struct gctl_req *req, struct g_geom **gp)
{
struct g_geom *geom;
struct g_raid_softc *sc;
struct g_raid_md_ddf_object *mdi, *mdi1;
char name[16];
const char *fmtopt;
int be = 1;
mdi = (struct g_raid_md_ddf_object *)md;
fmtopt = gctl_get_asciiparam(req, "fmtopt");
if (fmtopt == NULL || strcasecmp(fmtopt, "BE") == 0)
be = 1;
else if (strcasecmp(fmtopt, "LE") == 0)
be = 0;
else {
gctl_error(req, "Incorrect fmtopt argument.");
return (G_RAID_MD_TASTE_FAIL);
}
/* Search for existing node. */
LIST_FOREACH(geom, &mp->geom, geom) {
@ -2027,6 +2045,9 @@ g_raid_md_create_ddf(struct g_raid_md_object *md, struct g_class *mp,
continue;
if (sc->sc_md->mdo_class != md->mdo_class)
continue;
mdi1 = (struct g_raid_md_ddf_object *)sc->sc_md;
if (mdi1->mdio_bigendian != be)
continue;
break;
}
if (geom != NULL) {
@ -2035,7 +2056,9 @@ g_raid_md_create_ddf(struct g_raid_md_object *md, struct g_class *mp,
}
/* Create new one if not found. */
sc = g_raid_create_node(mp, "DDF", md);
mdi->mdio_bigendian = be;
snprintf(name, sizeof(name), "DDF%s", be ? "" : "-LE");
sc = g_raid_create_node(mp, name, md);
if (sc == NULL)
return (G_RAID_MD_TASTE_FAIL);
md->mdo_softc = sc;
@ -2053,11 +2076,13 @@ g_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp,
struct g_raid_disk *disk;
struct ddf_meta meta;
struct g_raid_md_ddf_perdisk *pd;
struct g_raid_md_ddf_object *mdi;
struct g_geom *geom;
int error, result, len;
int error, result, len, be;
char name[16];
G_RAID_DEBUG(1, "Tasting DDF on %s", cp->provider->name);
mdi = (struct g_raid_md_ddf_object *)md;
pp = cp->provider;
/* Read metadata from device. */
@ -2070,6 +2095,7 @@ g_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp,
g_access(cp, -1, 0, 0);
if (error != 0)
return (G_RAID_MD_TASTE_FAIL);
be = meta.bigendian;
/* Metadata valid. Print it. */
g_raid_md_ddf_print(&meta);
@ -2084,6 +2110,9 @@ g_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp,
continue;
if (sc->sc_md->mdo_class != md->mdo_class)
continue;
mdi = (struct g_raid_md_ddf_object *)sc->sc_md;
if (mdi->mdio_bigendian != be)
continue;
break;
}
@ -2094,7 +2123,8 @@ g_raid_md_taste_ddf(struct g_raid_md_object *md, struct g_class *mp,
} else { /* Not found matching node -- create one. */
result = G_RAID_MD_TASTE_NEW;
snprintf(name, sizeof(name), "DDF");
mdi->mdio_bigendian = be;
snprintf(name, sizeof(name), "DDF%s", be ? "" : "-LE");
sc = g_raid_create_node(mp, name, md);
md->mdo_softc = sc;
geom = sc->sc_geom;