From 5f6a3a81f63c037a8f67978d08ebb9c7ac2c213f Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 12 Mar 2022 11:49:37 -0500 Subject: [PATCH] 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 (cherry picked from commit 7f16b501e25b6c792fefc4535e0d1b8363392fe0) --- lib/geom/mirror/geom_mirror.c | 26 ++++---- lib/geom/part/geom_part.c | 90 ++++++++++++++------------- lib/libgeom/geom_getxml.c | 41 +++++++++++++ lib/libgeom/geom_xml2tree.c | 50 ++++++++++----- lib/libgeom/libgeom.h | 2 + sbin/geom/core/geom.c | 10 ++- sys/geom/geom.h | 1 + sys/geom/geom_ctl.c | 111 ++++++++++++++++++++++++++-------- sys/geom/geom_dump.c | 55 ++++++++++------- sys/geom/geom_int.h | 2 +- 10 files changed, 264 insertions(+), 124 deletions(-) diff --git a/lib/geom/mirror/geom_mirror.c b/lib/geom/mirror/geom_mirror.c index a1b39933881..2b1860eb754 100644 --- a/lib/geom/mirror/geom_mirror.c +++ b/lib/geom/mirror/geom_mirror.c @@ -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) diff --git a/lib/geom/part/geom_part.c b/lib/geom/part/geom_part.c index 330a4708251..2d8f02053a6 100644 --- a/lib/geom/part/geom_part.c +++ b/lib/geom/part/geom_part.c @@ -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); diff --git a/lib/libgeom/geom_getxml.c b/lib/libgeom/geom_getxml.c index 48565f707b0..a6bb130fd5a 100644 --- a/lib/libgeom/geom_getxml.c +++ b/lib/libgeom/geom_getxml.c @@ -3,6 +3,7 @@ * * Copyright (c) 2003 Poul-Henning Kamp * All rights reserved. + * Copyright (c) 2022 Alexander Motin * * 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); +} diff --git a/lib/libgeom/geom_xml2tree.c b/lib/libgeom/geom_xml2tree.c index 82480007093..a6da0e6d163 100644 --- a/lib/libgeom/geom_xml2tree.c +++ b/lib/libgeom/geom_xml2tree.c @@ -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) { diff --git a/lib/libgeom/libgeom.h b/lib/libgeom/libgeom.h index 9be27208a98..339a8d34729 100644 --- a/lib/libgeom/libgeom.h +++ b/lib/libgeom/libgeom.h @@ -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 */ diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c index b29d73327df..9b43910b88f 100644 --- a/sbin/geom/core/geom.c +++ b/sbin/geom/core/geom.c @@ -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++) { diff --git a/sys/geom/geom.h b/sys/geom/geom.h index d9ba42b005d..365afcef60f 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -432,6 +432,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); diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c index ba22a2c5216..f246891d462 100644 --- a/sys/geom/geom_ctl.c +++ b/sys/geom/geom_ctl.c @@ -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 * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. @@ -310,7 +311,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; @@ -320,7 +321,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) @@ -330,31 +331,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 * @@ -438,6 +439,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) { @@ -450,16 +507,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(); } diff --git a/sys/geom/geom_dump.c b/sys/geom/geom_dump.c index 067ab43f7d0..58077147ff8 100644 --- a/sys/geom/geom_dump.c +++ b/sys/geom/geom_dump.c @@ -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 * * 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, " \n", gp); sbuf_printf(sb, " \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, " \n"); } - LIST_FOREACH(cp2, &gp->consumer, consumer) { - if (cp != NULL && cp != cp2) - continue; - g_conf_consumer(sb, cp2); - } + 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, " \n"); +} - LIST_FOREACH(pp2, &gp->provider, provider) { - if (pp != NULL && pp != pp2) - continue; - g_conf_provider(sb, pp2); +static bool +g_conf_matchgp(struct g_geom *gp, struct g_geom **gps) +{ + + if (gps == NULL) + return (true); + for (; *gps != NULL; gps++) { + if (*gps == gp) + return (true); } - sbuf_cat(sb, " \n"); + return (false); } static void -g_conf_class(struct sbuf *sb, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp) +g_conf_class(struct sbuf *sb, struct g_class *mp, struct g_geom **gps) { - struct g_geom *gp2; + struct g_geom *gp; sbuf_printf(sb, " \n", mp); sbuf_cat(sb, " "); g_conf_cat_escaped(sb, mp->name); sbuf_cat(sb, "\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, " \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, "\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, "\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 diff --git a/sys/geom/geom_int.h b/sys/geom/geom_int.h index 67c46d71588..121793b1800 100644 --- a/sys/geom/geom_int.h +++ b/sys/geom/geom_int.h @@ -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); -- 2.45.0