From nobody Wed May 11 01:44:24 2022 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 04E631ACC005; Wed, 11 May 2022 01:44:25 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Kyd4S6ljGz3FRw; Wed, 11 May 2022 01:44:24 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1652233465; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4ROXXD2kjBfCZzD/QKkP3EIvGEeBowkvepfPPNCybEM=; b=xhW39CJVQnHrFbI05sNOKKeUeqshlOTkSOTOzrRdVP+VV0aezA+4HUF7Sa3poWjzGYEnBV EeuiP1JLWYv+JUPPLmQ78IF7ToyMwuL7ebkWQj7Aaxjn1gx11fFvn83ljYC5VYOuSGiwJS /9j6q0McnirOYFOyRBY6eNa27hoAWLdhvb6bk6mGe+1QilX5frWRLLUONRH9S+8uZic7VB 8d8sGg8vSwsIrhEbQu4xE3WmLKkeHa6/uoJWEd8AemKbo1ZGjvNJ9qWszDRS+ingsJiKzh iBTj34j7UBH5YmksKO0NbkK7yxocog28QXppyEw4XXVS87/uZ5jVVohl1gmeKg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id C78D810F89; Wed, 11 May 2022 01:44:24 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 24B1iOa9061104; Wed, 11 May 2022 01:44:24 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 24B1iOnm061103; Wed, 11 May 2022 01:44:24 GMT (envelope-from git) Date: Wed, 11 May 2022 01:44:24 GMT Message-Id: <202205110144.24B1iOnm061103@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Alexander Motin Subject: git: 5f6a3a81f63c - stable/13 - GEOM: Introduce partial confxml API List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mav X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 5f6a3a81f63c037a8f67978d08ebb9c7ac2c213f Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1652233465; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4ROXXD2kjBfCZzD/QKkP3EIvGEeBowkvepfPPNCybEM=; b=gWjsOFJoWz0xZLwfCvS5SssvGnTATwjtrp5nDkMhtKTlVBsleQncRqatNeR+HNlu27HRkz 9sDguIfgSY/JjYaJqvnV8iizgqp5uDk2wmCtIN8Hw5/wxZ9n4NZvAXCXGHMPVI4YKbXq5r secoe01IJyB6TkDnEX0hGsrkyJeC0GawCyouusR3k1IEUdxD9+woz5LOdE0i8otaNNGoCj 2Uyygj+UZkO7DhrYG4iKrmA7oAGvVY6iY6XV8UBvWn5+0sY4a/AWGxvm0LOiADiLYmDPnJ QZO4frURrFGjknw/+M0aO2Gys22WXM6JvqPG1+RzY7S/6b4pRdQCWWQFz9IDiA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1652233465; a=rsa-sha256; cv=none; b=OamipTTxLkF5ga4XoYiGo7zANeR227rKFrtRI/8zlafRq1h61BiFfU6++A1FGvAt42TCca /nc+O6MslrzECtDV2INEi5R1fgJMpbW7St2TZuWmSqJfDFhqgjCb3Y78IHk4DDHenPRDHZ RXq0eOQpIhixL3QSkXeHwo58RMS0E0X/6Rx/gc9HpeMpWTSMGOWpQlxfDUO3YKwnRN6ASw XBg2OMIu/ly8qC6Hep5tJXSgVpWQN4nKxFwpYTC+OHMYuW3iSlqGNoLuxWwLp3LWWqpzAH nuzBcqLq+45TmSW29SB15guwtWCmAbkjxJkThpe0nNIqBam7aX4r9N4X9Syeiw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by mav: URL: https://cgit.FreeBSD.org/src/commit/?id=5f6a3a81f63c037a8f67978d08ebb9c7ac2c213f commit 5f6a3a81f63c037a8f67978d08ebb9c7ac2c213f Author: Alexander Motin AuthorDate: 2022-03-12 16:49:37 +0000 Commit: Alexander Motin CommitDate: 2022-05-11 01:20:25 +0000 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 a1b399338814..2b1860eb7548 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 330a4708251d..2d8f02053a69 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 48565f707b03..a6bb130fd5a7 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 824800070933..a6da0e6d163f 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 9be27208a98c..339a8d34729f 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 b29d73327df8..9b43910b88f9 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 d9ba42b005de..365afcef60fe 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 ba22a2c5216a..f246891d4626 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 067ab43f7d05..58077147ff8d 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 67c46d715885..121793b18007 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);