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:
Alexander Motin 2012-05-03 05:32:56 +00:00
parent 6107adc3f5
commit 8df8e26adc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=234940
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, { "label", G_FLAG_VERBOSE, NULL,
{ {
{ 'f', "force", NULL, G_TYPE_BOOL }, { 'f', "force", NULL, G_TYPE_BOOL },
{ 'o', "fmtopt", G_VAL_OPTIONAL, G_TYPE_STRING },
{ 'S', "size", G_VAL_OPTIONAL, G_TYPE_NUMBER }, { 'S', "size", G_VAL_OPTIONAL, G_TYPE_NUMBER },
{ 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER }, { 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER },
G_OPT_SENTINEL 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, { "add", G_FLAG_VERBOSE, NULL,
{ {

View File

@ -34,6 +34,7 @@
.Nm .Nm
.Cm label .Cm label
.Op Fl f .Op Fl f
.Op Fl o Ar fmtopt
.Op Fl S Ar size .Op Fl S Ar size
.Op Fl s Ar strip .Op Fl s Ar strip
.Ar format .Ar format
@ -119,6 +120,8 @@ Additional options include:
.It Fl f .It Fl f
Enforce specified configuration creation if it is officially unsupported, Enforce specified configuration creation if it is officially unsupported,
but technically can be created. but technically can be created.
.It Fl o Ar fmtopt
Specifies metadata format options.
.It Fl S Ar size .It Fl S Ar size
Use Use
.Ar size .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. Used by some Adaptec RAID BIOSes and some hardware RAID controllers.
Because of high format flexibility different implementations support Because of high format flexibility different implementations support
different set of features and have different on-disk metadata layouts. different set of features and have different on-disk metadata layouts.
To provide compatibility, the GEOM RAID class mimics capabilities and To provide compatibility, the GEOM RAID class mimics capabilities
metadata layout of the first detected DDF array. of the first detected DDF array.
Respecting that, it may support different number of disks per volume, Respecting that, it may support different number of disks per volume,
volumes per array, partitions per disk, etc. volumes per array, partitions per disk, etc.
The following configurations are supported: RAID0 (2+ disks), RAID1 (2+ disks), The following configurations are supported: RAID0 (2+ disks), RAID1 (2+ disks),
RAID1E (3+ disks), RAID3 (3+ disks), RAID4 (3+ disks), RAID5 (3+ 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), RAID5E (4+ disks), RAID5EE (4+ disks), RAID5R (3+ disks), RAID6 (4+ disks),
RAIDMDF (5+ disks), RAID10 (4+ disks), SINGLE (1 disk), CONCAT (2+ 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 .It Intel
The format used by Intel RAID BIOS. The format used by Intel RAID BIOS.
Supports up to two volumes per array. 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_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
G_RAID_DEBUG(2, "Tasting provider %s.", 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. * 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 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_class *class;
struct g_raid_md_object *obj; 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, obj = (void *)kobj_create((kobj_class_t)class, M_RAID,
M_WAITOK); M_WAITOK);
obj->mdo_class = class; 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) if (status != G_RAID_MD_TASTE_NEW)
kobj_delete((kobj_t)obj, M_RAID); kobj_delete((kobj_t)obj, M_RAID);
return (status); 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, struct g_raid_softc * g_raid_create_node(struct g_class *mp,
const char *name, struct g_raid_md_object *md); 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, struct g_raid_volume * g_raid_create_volume(struct g_raid_softc *sc,
const char *name, int id); const char *name, int id);
struct g_raid_disk * g_raid_create_disk(struct g_raid_softc *sc); 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."); gctl_error(req, "No format recieved.");
return; 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) { if (crstatus == G_RAID_MD_TASTE_FAIL) {
gctl_error(req, "Failed to create array with format '%s'.", gctl_error(req, "Failed to create array with format '%s'.",
format); format);

View File

@ -49,12 +49,21 @@ HEADER {
# Default implementations of methods. # Default implementations of methods.
CODE { CODE {
static int 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); 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 static int
g_raid_md_ctl_default(struct g_raid_md_object *md, g_raid_md_ctl_default(struct g_raid_md_object *md,
struct gctl_req *req) struct gctl_req *req)
@ -95,6 +104,14 @@ METHOD int create {
struct g_geom **gp; struct g_geom **gp;
} DEFAULT g_raid_md_create_default; } 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. # taste() - taste disk and, if needed, create new node.
METHOD int taste { METHOD int taste {
struct g_raid_md_object *md; 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_ddf_object {
struct g_raid_md_object mdio_base; struct g_raid_md_object mdio_base;
u_int mdio_bigendian;
struct ddf_meta mdio_meta; struct ddf_meta mdio_meta;
int mdio_starting; int mdio_starting;
struct callout mdio_start_co; /* STARTING state timer. */ 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. */ 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_taste_t g_raid_md_taste_ddf;
static g_raid_md_event_t g_raid_md_event_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; 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 g_raid_md_free_t g_raid_md_free_ddf;
static kobj_method_t g_raid_md_ddf_methods[] = { 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_taste, g_raid_md_taste_ddf),
KOBJMETHOD(g_raid_md_event, g_raid_md_event_ddf), KOBJMETHOD(g_raid_md_event, g_raid_md_event_ddf),
KOBJMETHOD(g_raid_md_volume_event, g_raid_md_volume_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 timespec ts;
struct clocktime ct; struct clocktime ct;
struct g_raid_md_ddf_perdisk *pd; struct g_raid_md_ddf_perdisk *pd;
struct g_raid_md_ddf_object *mdi;
struct ddf_meta *meta; struct ddf_meta *meta;
struct ddf_pd_entry *pde; struct ddf_pd_entry *pde;
off_t anchorlba; off_t anchorlba;
@ -572,13 +574,14 @@ ddf_meta_create(struct g_raid_disk *disk, struct ddf_meta *sample)
if (sample->hdr == NULL) if (sample->hdr == NULL)
sample = 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; pd = (struct g_raid_md_ddf_perdisk *)disk->d_md_data;
meta = &pd->pd_meta; meta = &pd->pd_meta;
ss = disk->d_consumer->provider->sectorsize; ss = disk->d_consumer->provider->sectorsize;
anchorlba = disk->d_consumer->provider->mediasize / ss - 1; anchorlba = disk->d_consumer->provider->mediasize / ss - 1;
meta->sectorsize = ss; meta->sectorsize = ss;
meta->bigendian = sample ? sample->bigendian : 0; meta->bigendian = sample ? sample->bigendian : mdi->mdio_bigendian;
getnanotime(&ts); getnanotime(&ts);
clock_ts_to_ct(&ts, &ct); clock_ts_to_ct(&ts, &ct);
@ -2012,11 +2015,26 @@ g_raid_md_ddf_new_disk(struct g_raid_disk *disk)
} }
static int static int
g_raid_md_create_ddf(struct g_raid_md_object *md, struct g_class *mp, g_raid_md_create_req_ddf(struct g_raid_md_object *md, struct g_class *mp,
struct g_geom **gp) struct gctl_req *req, struct g_geom **gp)
{ {
struct g_geom *geom; struct g_geom *geom;
struct g_raid_softc *sc; 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. */ /* Search for existing node. */
LIST_FOREACH(geom, &mp->geom, geom) { 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; continue;
if (sc->sc_md->mdo_class != md->mdo_class) if (sc->sc_md->mdo_class != md->mdo_class)
continue; continue;
mdi1 = (struct g_raid_md_ddf_object *)sc->sc_md;
if (mdi1->mdio_bigendian != be)
continue;
break; break;
} }
if (geom != NULL) { 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. */ /* 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) if (sc == NULL)
return (G_RAID_MD_TASTE_FAIL); return (G_RAID_MD_TASTE_FAIL);
md->mdo_softc = sc; 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 g_raid_disk *disk;
struct ddf_meta meta; struct ddf_meta meta;
struct g_raid_md_ddf_perdisk *pd; struct g_raid_md_ddf_perdisk *pd;
struct g_raid_md_ddf_object *mdi;
struct g_geom *geom; struct g_geom *geom;
int error, result, len; int error, result, len, be;
char name[16]; char name[16];
G_RAID_DEBUG(1, "Tasting DDF on %s", cp->provider->name); G_RAID_DEBUG(1, "Tasting DDF on %s", cp->provider->name);
mdi = (struct g_raid_md_ddf_object *)md;
pp = cp->provider; pp = cp->provider;
/* Read metadata from device. */ /* 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); g_access(cp, -1, 0, 0);
if (error != 0) if (error != 0)
return (G_RAID_MD_TASTE_FAIL); return (G_RAID_MD_TASTE_FAIL);
be = meta.bigendian;
/* Metadata valid. Print it. */ /* Metadata valid. Print it. */
g_raid_md_ddf_print(&meta); 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; continue;
if (sc->sc_md->mdo_class != md->mdo_class) if (sc->sc_md->mdo_class != md->mdo_class)
continue; continue;
mdi = (struct g_raid_md_ddf_object *)sc->sc_md;
if (mdi->mdio_bigendian != be)
continue;
break; 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. */ } else { /* Not found matching node -- create one. */
result = G_RAID_MD_TASTE_NEW; 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); sc = g_raid_create_node(mp, name, md);
md->mdo_softc = sc; md->mdo_softc = sc;
geom = sc->sc_geom; geom = sc->sc_geom;