GEOM: Introduce partial confxml API

Traditionally the GEOM's primary channel of information from kernel to
user-space was confxml, fetched by libgeom through kern.geom.confxml
sysctl.  It is convenient and informative, representing full state of
GEOM in a single XML document.  But problems start to arise on systems
with hundreds of disks, where the full confxml size reaches many
megabytes, taking significant time to first write it and then parse.

This patch introduces alternative solution, allowing to fetch much
smaller XML document, subset of the full confxml, limited to 64KB and
representing only one specified geom and optionally its parents.  It
uses existing GEOM control interface, extended with new "getxml" verb.
In case of any error, such as the buffer overflow, it just transparently
falls back to traditional full confxml.  This patch uses the new API in
user-space GEOM tools where it is possible.

Reviewed by:	imp
MFC after:	2 month
Sponsored by:	iXsystems, Inc.
Differential Revision:	https://reviews.freebsd.org/D34529
This commit is contained in:
Alexander Motin 2022-03-12 11:49:37 -05:00
parent db11c57a6c
commit 7f16b501e2
10 changed files with 266 additions and 126 deletions

View File

@ -440,32 +440,30 @@ mirror_resize(struct gctl_req *req, unsigned flags __unused)
struct gconsumer *cp;
off_t size;
int error, nargs;
const char *name;
const char *name, *g;
char ssize[30];
nargs = gctl_get_int(req, "nargs");
if (nargs < 1) {
gctl_error(req, "Too few arguments.");
return;
}
error = geom_gettree(&mesh);
if (error)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
if (nargs != 1)
errx(EXIT_FAILURE, "Invalid number of arguments.");
name = gctl_get_ascii(req, "class");
if (name == NULL)
abort();
g = gctl_get_ascii(req, "arg0");
if (g == NULL)
abort();
error = geom_gettree_geom(&mesh, name, g, 1);
if (error)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
classp = find_class(&mesh, name);
if (classp == NULL)
errx(EXIT_FAILURE, "Class %s not found.", name);
name = gctl_get_ascii(req, "arg0");
if (name == NULL)
abort();
gp = find_geom(classp, name);
gp = find_geom(classp, g);
if (gp == NULL)
errx(EXIT_FAILURE, "No such geom: %s.", name);
errx(EXIT_FAILURE, "No such geom: %s.", g);
pp = LIST_FIRST(&gp->lg_provider);
if (pp == NULL)
errx(EXIT_FAILURE, "Provider of geom %s not found.", name);
errx(EXIT_FAILURE, "Provider of geom %s not found.", g);
size = pp->lg_mediasize;
name = gctl_get_ascii(req, "size");
if (name == NULL)

View File

@ -329,31 +329,31 @@ gpart_autofill_resize(struct gctl_req *req)
struct gprovider *pp;
off_t last, size, start, new_size;
off_t lba, new_lba, alignment, offset;
const char *s;
const char *g, *s;
int error, idx, has_alignment;
idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX);
if (idx < 1)
errx(EXIT_FAILURE, "invalid partition index");
error = geom_gettree(&mesh);
if (error)
return (error);
s = gctl_get_ascii(req, "class");
if (s == NULL)
abort();
g = gctl_get_ascii(req, "arg0");
if (g == NULL)
abort();
error = geom_gettree_geom(&mesh, s, g, 1);
if (error)
return (error);
cp = find_class(&mesh, s);
if (cp == NULL)
errx(EXIT_FAILURE, "Class %s not found.", s);
s = gctl_get_ascii(req, "arg0");
if (s == NULL)
abort();
gp = find_geom(cp, s);
gp = find_geom(cp, g);
if (gp == NULL)
errx(EXIT_FAILURE, "No such geom: %s.", s);
errx(EXIT_FAILURE, "No such geom: %s.", g);
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
if (pp == NULL)
errx(EXIT_FAILURE, "Provider for geom %s not found.", s);
errx(EXIT_FAILURE, "Provider for geom %s not found.", g);
s = gctl_get_ascii(req, "alignment");
has_alignment = (*s == '*') ? 0 : 1;
@ -454,7 +454,7 @@ gpart_autofill(struct gctl_req *req)
off_t size, start, a_lba;
off_t lba, len, alignment, offset;
uintmax_t grade;
const char *s;
const char *g, *s;
int error, has_size, has_start, has_alignment;
s = gctl_get_ascii(req, "verb");
@ -463,22 +463,22 @@ gpart_autofill(struct gctl_req *req)
if (strcmp(s, "add") != 0)
return (0);
error = geom_gettree(&mesh);
if (error)
return (error);
s = gctl_get_ascii(req, "class");
if (s == NULL)
abort();
g = gctl_get_ascii(req, "arg0");
if (g == NULL)
abort();
error = geom_gettree_geom(&mesh, s, g, 1);
if (error)
return (error);
cp = find_class(&mesh, s);
if (cp == NULL)
errx(EXIT_FAILURE, "Class %s not found.", s);
s = gctl_get_ascii(req, "arg0");
if (s == NULL)
abort();
gp = find_geom(cp, s);
gp = find_geom(cp, g);
if (gp == NULL) {
if (g_device_path(s) == NULL) {
errx(EXIT_FAILURE, "No such geom %s.", s);
if (g_device_path(g) == NULL) {
errx(EXIT_FAILURE, "No such geom %s.", g);
} else {
/*
* We don't free memory allocated by g_device_path() as
@ -486,12 +486,12 @@ gpart_autofill(struct gctl_req *req)
*/
errx(EXIT_FAILURE,
"No partitioning scheme found on geom %s. Create one first using 'gpart create'.",
s);
g);
}
}
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
if (pp == NULL)
errx(EXIT_FAILURE, "Provider for geom %s not found.", s);
errx(EXIT_FAILURE, "Provider for geom %s not found.", g);
s = gctl_get_ascii(req, "alignment");
has_alignment = (*s == '*') ? 0 : 1;
@ -742,7 +742,12 @@ gpart_show(struct gctl_req *req, unsigned int fl __unused)
name = gctl_get_ascii(req, "class");
if (name == NULL)
abort();
error = geom_gettree(&mesh);
nargs = gctl_get_int(req, "nargs");
if (nargs == 1) {
error = geom_gettree_geom(&mesh, name,
gctl_get_ascii(req, "arg0"), 1);
} else
error = geom_gettree(&mesh);
if (error != 0)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
classp = find_class(&mesh, name);
@ -751,7 +756,6 @@ gpart_show(struct gctl_req *req, unsigned int fl __unused)
errx(EXIT_FAILURE, "Class %s not found.", name);
}
show_providers = gctl_get_int(req, "show_providers");
nargs = gctl_get_int(req, "nargs");
if (nargs > 0) {
for (i = 0; i < nargs; i++) {
name = gctl_get_ascii(req, "arg%d", i);
@ -776,34 +780,33 @@ gpart_backup(struct gctl_req *req, unsigned int fl __unused)
struct gclass *classp;
struct gprovider *pp;
struct ggeom *gp;
const char *s, *scheme;
const char *g, *s, *scheme;
off_t sector, end;
off_t length;
int error, i, windex, wblocks, wtype;
if (gctl_get_int(req, "nargs") != 1)
errx(EXIT_FAILURE, "Invalid number of arguments.");
error = geom_gettree(&mesh);
if (error != 0)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
s = gctl_get_ascii(req, "class");
if (s == NULL)
abort();
g = gctl_get_ascii(req, "arg0");
if (g == NULL)
abort();
error = geom_gettree_geom(&mesh, s, g, 0);
if (error != 0)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
classp = find_class(&mesh, s);
if (classp == NULL) {
geom_deletetree(&mesh);
errx(EXIT_FAILURE, "Class %s not found.", s);
}
s = gctl_get_ascii(req, "arg0");
if (s == NULL)
abort();
gp = find_geom(classp, s);
gp = find_geom(classp, g);
if (gp == NULL)
errx(EXIT_FAILURE, "No such geom: %s.", s);
errx(EXIT_FAILURE, "No such geom: %s.", g);
scheme = find_geomcfg(gp, "scheme");
if (scheme == NULL)
abort();
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
s = find_geomcfg(gp, "last");
if (s == NULL)
abort();
@ -1201,11 +1204,14 @@ gpart_bootcode(struct gctl_req *req, unsigned int fl)
struct gmesh mesh;
struct gclass *classp;
struct ggeom *gp;
const char *s;
const char *g, *s;
void *bootcode, *partcode;
size_t bootsize, partsize;
int error, idx, vtoc8;
if (gctl_get_int(req, "nargs") != 1)
errx(EXIT_FAILURE, "Invalid number of arguments.");
if (gctl_has_param(req, GPART_PARAM_BOOTCODE)) {
s = gctl_get_ascii(req, GPART_PARAM_BOOTCODE);
bootsize = 800 * 1024; /* Arbitrary limit. */
@ -1228,7 +1234,10 @@ gpart_bootcode(struct gctl_req *req, unsigned int fl)
s = gctl_get_ascii(req, "class");
if (s == NULL)
abort();
error = geom_gettree(&mesh);
g = gctl_get_ascii(req, "arg0");
if (g == NULL)
abort();
error = geom_gettree_geom(&mesh, s, g, 0);
if (error != 0)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
classp = find_class(&mesh, s);
@ -1236,14 +1245,9 @@ gpart_bootcode(struct gctl_req *req, unsigned int fl)
geom_deletetree(&mesh);
errx(EXIT_FAILURE, "Class %s not found.", s);
}
if (gctl_get_int(req, "nargs") != 1)
errx(EXIT_FAILURE, "Invalid number of arguments.");
s = gctl_get_ascii(req, "arg0");
if (s == NULL)
abort();
gp = find_geom(classp, s);
gp = find_geom(classp, g);
if (gp == NULL)
errx(EXIT_FAILURE, "No such geom: %s.", s);
errx(EXIT_FAILURE, "No such geom: %s.", g);
s = find_geomcfg(gp, "scheme");
if (s == NULL)
errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name);

View File

@ -3,6 +3,7 @@
*
* Copyright (c) 2003 Poul-Henning Kamp
* All rights reserved.
* Copyright (c) 2022 Alexander Motin <mav@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -50,6 +51,13 @@
*/
#define GEOM_GETXML_RETRIES 4
/*
* Size of confxml buffer to request via getxml control request. It is
* expected to be sufficient for single geom and its parents. In case of
* overflow fall back to requesting full confxml via sysctl interface.
*/
#define GEOM_GETXML_BUFFER 65536
char *
geom_getxml(void)
{
@ -87,3 +95,36 @@ geom_getxml(void)
return (NULL);
}
char *
geom_getxml_geom(const char *class, const char *geom, int parents)
{
struct gctl_req *r;
char *p;
const char *errstr;
int nargs = 0;
p = malloc(GEOM_GETXML_BUFFER);
if (p == NULL)
return (NULL);
r = gctl_get_handle();
gctl_ro_param(r, "class", -1, class);
gctl_ro_param(r, "verb", -1, "getxml");
gctl_ro_param(r, "parents", sizeof(parents), &parents);
if (geom) {
gctl_ro_param(r, "arg0", -1, geom);
nargs = 1;
}
gctl_ro_param(r, "nargs", sizeof(nargs), &nargs);
p[0] = '\0';
gctl_add_param(r, "output", GEOM_GETXML_BUFFER, p,
GCTL_PARAM_WR | GCTL_PARAM_ASCII);
errstr = gctl_issue(r);
if (errstr != NULL && errstr[0] != '\0') {
gctl_free(r);
free(p);
return (geom_getxml());
}
gctl_free(r);
return (p);
}

View File

@ -358,6 +358,17 @@ geom_lookupid(struct gmesh *gmp, const void *id)
return (NULL);
}
static void *
geom_lookupidptr(struct gmesh *gmp, const void *id)
{
struct gident *gip;
gip = geom_lookupid(gmp, id);
if (gip)
return (gip->lg_ptr);
return (NULL);
}
int
geom_xml2tree(struct gmesh *gmp, char *p)
{
@ -430,22 +441,19 @@ geom_xml2tree(struct gmesh *gmp, char *p)
/* Substitute all identifiers */
LIST_FOREACH(cl, &gmp->lg_class, lg_class) {
LIST_FOREACH(ge, &cl->lg_geom, lg_geom) {
ge->lg_class =
geom_lookupid(gmp, ge->lg_class)->lg_ptr;
LIST_FOREACH(pr, &ge->lg_provider, lg_provider) {
pr->lg_geom =
geom_lookupid(gmp, pr->lg_geom)->lg_ptr;
}
ge->lg_class = geom_lookupidptr(gmp, ge->lg_class);
LIST_FOREACH(pr, &ge->lg_provider, lg_provider)
pr->lg_geom = geom_lookupidptr(gmp, pr->lg_geom);
LIST_FOREACH(co, &ge->lg_consumer, lg_consumer) {
co->lg_geom =
geom_lookupid(gmp, co->lg_geom)->lg_ptr;
co->lg_geom = geom_lookupidptr(gmp, co->lg_geom);
if (co->lg_provider != NULL) {
co->lg_provider =
geom_lookupid(gmp,
co->lg_provider)->lg_ptr;
LIST_INSERT_HEAD(
&co->lg_provider->lg_consumers,
co, lg_consumers);
co->lg_provider = geom_lookupidptr(gmp,
co->lg_provider);
if (co->lg_provider != NULL) {
LIST_INSERT_HEAD(
&co->lg_provider->lg_consumers,
co, lg_consumers);
}
}
}
}
@ -467,6 +475,20 @@ geom_gettree(struct gmesh *gmp)
return (error);
}
int
geom_gettree_geom(struct gmesh *gmp, const char *c, const char *g, int parents)
{
char *p;
int error;
p = geom_getxml_geom(c, g, parents);
if (p == NULL)
return (errno);
error = geom_xml2tree(gmp, p);
free(p);
return (error);
}
static void
delete_config(struct gconf *gp)
{

View File

@ -56,6 +56,7 @@ void geom_stats_snapshot_reset(void *);
struct devstat *geom_stats_snapshot_next(void *);
char *geom_getxml(void);
char *geom_getxml_geom(const char *, const char *, int);
/* geom_xml2tree.c */
@ -137,6 +138,7 @@ struct gprovider {
struct gident * geom_lookupid(struct gmesh *, const void *);
int geom_xml2tree(struct gmesh *, char *);
int geom_gettree(struct gmesh *);
int geom_gettree_geom(struct gmesh *, const char *, const char *, int);
void geom_deletetree(struct gmesh *);
/* geom_ctl.c */

View File

@ -996,7 +996,7 @@ std_list_available(void)
struct gclass *classp;
int error;
error = geom_gettree(&mesh);
error = geom_gettree_geom(&mesh, gclass_name, "", 0);
if (error != 0)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
classp = find_class(&mesh, gclass_name);
@ -1015,7 +1015,12 @@ std_list(struct gctl_req *req, unsigned flags __unused)
const char *name;
int all, error, i, nargs;
error = geom_gettree(&mesh);
nargs = gctl_get_int(req, "nargs");
if (nargs == 1) {
error = geom_gettree_geom(&mesh, gclass_name,
gctl_get_ascii(req, "arg0"), 1);
} else
error = geom_gettree(&mesh);
if (error != 0)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
classp = find_class(&mesh, gclass_name);
@ -1023,7 +1028,6 @@ std_list(struct gctl_req *req, unsigned flags __unused)
geom_deletetree(&mesh);
errx(EXIT_FAILURE, "Class '%s' not found.", gclass_name);
}
nargs = gctl_get_int(req, "nargs");
all = gctl_get_int(req, "all");
if (nargs > 0) {
for (i = 0; i < nargs; i++) {

View File

@ -431,6 +431,7 @@ int g_is_geom_thread(struct thread *td);
int gctl_set_param(struct gctl_req *req, const char *param, void const *ptr, int len);
void gctl_set_param_err(struct gctl_req *req, const char *param, void const *ptr, int len);
void *gctl_get_param(struct gctl_req *req, const char *param, int *len);
void *gctl_get_param_flags(struct gctl_req *req, const char *param, int flags, int *len);
char const *gctl_get_asciiparam(struct gctl_req *req, const char *param);
void *gctl_get_paraml(struct gctl_req *req, const char *param, int len);
void *gctl_get_paraml_opt(struct gctl_req *req, const char *param, int len);

View File

@ -4,6 +4,7 @@
* Copyright (c) 2002 Poul-Henning Kamp
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
* Copyright (c) 2022 Alexander Motin <mav@FreeBSD.org>
*
* This software was developed for the FreeBSD Project by Poul-Henning Kamp
* and NAI Labs, the Security Research Division of Network Associates, Inc.
@ -363,7 +364,7 @@ gctl_set_param_err(struct gctl_req *req, const char *param, void const *ptr,
}
void *
gctl_get_param(struct gctl_req *req, const char *param, int *len)
gctl_get_param_flags(struct gctl_req *req, const char *param, int flags, int *len)
{
u_int i;
void *p;
@ -373,7 +374,7 @@ gctl_get_param(struct gctl_req *req, const char *param, int *len)
ap = &req->arg[i];
if (strcmp(param, ap->name))
continue;
if (!(ap->flag & GCTL_PARAM_RD))
if ((ap->flag & flags) != flags)
continue;
p = ap->kvalue;
if (len != NULL)
@ -383,31 +384,31 @@ gctl_get_param(struct gctl_req *req, const char *param, int *len)
return (NULL);
}
void *
gctl_get_param(struct gctl_req *req, const char *param, int *len)
{
return (gctl_get_param_flags(req, param, GCTL_PARAM_RD, len));
}
char const *
gctl_get_asciiparam(struct gctl_req *req, const char *param)
{
u_int i;
char const *p;
struct gctl_req_arg *ap;
int len;
for (i = 0; i < req->narg; i++) {
ap = &req->arg[i];
if (strcmp(param, ap->name))
continue;
if (!(ap->flag & GCTL_PARAM_RD))
continue;
p = ap->kvalue;
if (ap->len < 1) {
gctl_error(req, "No length argument (%s)", param);
return (NULL);
}
if (p[ap->len - 1] != '\0') {
gctl_error(req, "Unterminated argument (%s)", param);
return (NULL);
}
return (p);
p = gctl_get_param_flags(req, param, GCTL_PARAM_RD, &len);
if (p == NULL)
return (NULL);
if (len < 1) {
gctl_error(req, "Argument without length (%s)", param);
return (NULL);
}
return (NULL);
if (p[len - 1] != '\0') {
gctl_error(req, "Unterminated argument (%s)", param);
return (NULL);
}
return (p);
}
void *
@ -491,6 +492,62 @@ gctl_get_provider(struct gctl_req *req, char const *arg)
return (NULL);
}
static void
g_ctl_getxml(struct gctl_req *req, struct g_class *mp)
{
const char *name;
char *buf;
struct sbuf *sb;
int len, i = 0, n = 0, *parents;
struct g_geom *gp, **gps;
struct g_consumer *cp;
parents = gctl_get_paraml(req, "parents", sizeof(*parents));
if (parents == NULL)
return;
name = gctl_get_asciiparam(req, "arg0");
n = 0;
LIST_FOREACH(gp, &mp->geom, geom) {
if (name && strcmp(gp->name, name) != 0)
continue;
n++;
if (*parents) {
LIST_FOREACH(cp, &gp->consumer, consumer)
n++;
}
}
gps = g_malloc((n + 1) * sizeof(*gps), M_WAITOK);
i = 0;
LIST_FOREACH(gp, &mp->geom, geom) {
if (name && strcmp(gp->name, name) != 0)
continue;
gps[i++] = gp;
if (*parents) {
LIST_FOREACH(cp, &gp->consumer, consumer) {
if (cp->provider != NULL)
gps[i++] = cp->provider->geom;
}
}
}
KASSERT(i == n, ("different number of geoms found (%d != %d)",
i, n));
gps[i] = 0;
buf = gctl_get_param_flags(req, "output", GCTL_PARAM_WR, &len);
if (buf == NULL) {
gctl_error(req, "output parameter missing");
g_free(gps);
return;
}
sb = sbuf_new(NULL, buf, len, SBUF_FIXEDLEN | SBUF_INCLUDENUL);
g_conf_specific(sb, gps);
gctl_set_param(req, "output", buf, 0);
if (sbuf_error(sb))
gctl_error(req, "output buffer overflow");
sbuf_delete(sb);
g_free(gps);
}
static void
g_ctl_req(void *arg, int flag __unused)
{
@ -503,16 +560,18 @@ g_ctl_req(void *arg, int flag __unused)
mp = gctl_get_class(req, "class");
if (mp == NULL)
return;
if (mp->ctlreq == NULL) {
gctl_error(req, "Class takes no requests");
return;
}
verb = gctl_get_param(req, "verb", NULL);
if (verb == NULL) {
gctl_error(req, "Verb missing");
return;
}
mp->ctlreq(req, mp, verb);
if (strcmp(verb, "getxml") == 0) {
g_ctl_getxml(req, mp);
} else if (mp->ctlreq == NULL) {
gctl_error(req, "Class takes no requests");
} else {
mp->ctlreq(req, mp, verb);
}
g_topology_assert();
}

View File

@ -4,6 +4,7 @@
* Copyright (c) 2002 Poul-Henning Kamp
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
* Copyright (c) 2013-2022 Alexander Motin <mav@FreeBSD.org>
*
* This software was developed for the FreeBSD Project by Poul-Henning Kamp
* and NAI Labs, the Security Research Division of Network Associates, Inc.
@ -242,10 +243,10 @@ g_conf_provider(struct sbuf *sb, struct g_provider *pp)
}
static void
g_conf_geom(struct sbuf *sb, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
g_conf_geom(struct sbuf *sb, struct g_geom *gp)
{
struct g_consumer *cp2;
struct g_provider *pp2;
struct g_consumer *cp;
struct g_provider *pp;
sbuf_printf(sb, " <geom id=\"%p\">\n", gp);
sbuf_printf(sb, " <class ref=\"%p\"/>\n", gp->class);
@ -260,48 +261,56 @@ g_conf_geom(struct sbuf *sb, struct g_geom *gp, struct g_provider *pp, struct g_
gp->dumpconf(sb, "\t", gp, NULL, NULL);
sbuf_cat(sb, " </config>\n");
}
LIST_FOREACH(cp2, &gp->consumer, consumer) {
if (cp != NULL && cp != cp2)
continue;
g_conf_consumer(sb, cp2);
}
LIST_FOREACH(pp2, &gp->provider, provider) {
if (pp != NULL && pp != pp2)
continue;
g_conf_provider(sb, pp2);
}
LIST_FOREACH(cp, &gp->consumer, consumer)
g_conf_consumer(sb, cp);
LIST_FOREACH(pp, &gp->provider, provider)
g_conf_provider(sb, pp);
sbuf_cat(sb, " </geom>\n");
}
static void
g_conf_class(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
static bool
g_conf_matchgp(struct g_geom *gp, struct g_geom **gps)
{
struct g_geom *gp2;
if (gps == NULL)
return (true);
for (; *gps != NULL; gps++) {
if (*gps == gp)
return (true);
}
return (false);
}
static void
g_conf_class(struct sbuf *sb, struct g_class *mp, struct g_geom **gps)
{
struct g_geom *gp;
sbuf_printf(sb, " <class id=\"%p\">\n", mp);
sbuf_cat(sb, " <name>");
g_conf_cat_escaped(sb, mp->name);
sbuf_cat(sb, "</name>\n");
LIST_FOREACH(gp2, &mp->geom, geom) {
if (gp != NULL && gp != gp2)
LIST_FOREACH(gp, &mp->geom, geom) {
if (!g_conf_matchgp(gp, gps))
continue;
g_conf_geom(sb, gp2, pp, cp);
g_conf_geom(sb, gp);
if (sbuf_error(sb))
break;
}
sbuf_cat(sb, " </class>\n");
}
void
g_conf_specific(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
g_conf_specific(struct sbuf *sb, struct g_geom **gps)
{
struct g_class *mp2;
g_topology_assert();
sbuf_cat(sb, "<mesh>\n");
LIST_FOREACH(mp2, &g_classes, class) {
if (mp != NULL && mp != mp2)
continue;
g_conf_class(sb, mp2, gp, pp, cp);
g_conf_class(sb, mp2, gps);
if (sbuf_error(sb))
break;
}
sbuf_cat(sb, "</mesh>\n");
sbuf_finish(sb);
@ -313,7 +322,7 @@ g_confxml(void *p, int flag)
KASSERT(flag != EV_CANCEL, ("g_confxml was cancelled"));
g_topology_assert();
g_conf_specific(p, NULL, NULL, NULL, NULL);
g_conf_specific(p, NULL);
}
void

View File

@ -46,7 +46,7 @@ extern int g_collectstats;
/* geom_dump.c */
void g_confxml(void *, int flag);
void g_conf_specific(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp);
void g_conf_specific(struct sbuf *sb, struct g_geom **gps);
void g_conf_cat_escaped(struct sbuf *sb, const char *buf);
void g_conf_printf_escaped(struct sbuf *sb, const char *fmt, ...);
void g_confdot(void *, int flag);