From nobody Sat Mar 12 16:55:56 2022 X-Original-To: dev-commits-src-all@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 20EDE1A1334C; Sat, 12 Mar 2022 16:55:57 +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 4KG87x0Gsfz4fVB; Sat, 12 Mar 2022 16:55:57 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1647104157; 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=8Cwxfq67nccnzEVQVKUjr2pXXczh1UvZhYgNek9oou0=; b=oAjqb5ubsXTlTahCZL5u1YPpyvVGsWuoOVWrVT2d7SEpY7i0OZnu17UilWY4v2T8r4z8wo +y2QC95bHwJDDQ5DQU5LTSB49NtHJuAvzNowbr851xKuOIaqTQRvpscD5n6XLVrpmsJa/z z957et0zIBBckdgLxCO397PsivQm3ydr8lc8fI6y2uNNPRSSr9zbIGcHFtbTrKPzIKsLDJ i5LJt5mWxwm2gCvCCa25PLE1CF0Rv4GlXIYmc/atibVQ6u53vP5odLpHpfAwtqHQ6fJtgs NGQiEOrD5y128CHBvQVBzk3qKFKxDUhX2UUV7DSSyzlqzS/rE1/2WRETMkbiaA== 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 DD4C2B45; Sat, 12 Mar 2022 16:55:56 +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 22CGtupH054785; Sat, 12 Mar 2022 16:55:56 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 22CGtuQw054784; Sat, 12 Mar 2022 16:55:56 GMT (envelope-from git) Date: Sat, 12 Mar 2022 16:55:56 GMT Message-Id: <202203121655.22CGtuQw054784@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alexander Motin Subject: git: 7f16b501e25b - main - GEOM: Introduce partial confxml API List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@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/main X-Git-Reftype: branch X-Git-Commit: 7f16b501e25b6c792fefc4535e0d1b8363392fe0 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1647104157; 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=8Cwxfq67nccnzEVQVKUjr2pXXczh1UvZhYgNek9oou0=; b=NaBhjbDs+q/Z0F8s+EIs4PgExODde8LYa8ZKupn+vN6jwKeK8/cE0MfLTl3ZGe00qK5gyd GpZzT2PppeACOOyIjFRocYCWyLQGDf/oQWr+0jO9CwPk998K77hcaQvDk4hkaDu3i8cTaX GST6+DHWCTf7m4dLc0q++A0yhIcvDJIgGW3P1kIcHE5cS1rbEgCcK4BwIkh616bXxVbaKs u8g+NVPd+kBfAwRXCnbdqH9h5vSw6ZmA/pA7CYRO1Y/F6l8K34PLQYMKrOUR6ZGzgpAAxr Rm26Mva99fBvJ1wZ95uwx8p0yXjmcmmwICGszEsJKQwzb5LREN+5lQNfKYPyPg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1647104157; a=rsa-sha256; cv=none; b=c6iTIU6JxzS0HznYCWnmh1g+c3TFzyUq1JWbS+IgNMjTlOLnXnfY3xtpZfQlufZdoUtiJ8 PBo9MtzyxuRO9ThCl8tGcKEhyjLvCcY8+3oYh8+YvxikgBd2V0MFFoz3pLHToFFMn9ET4U vOVhSyZ6SSBTaLQ3iDkArgVUqdYm+pDECDvMrX4MPcG9F00LP/tuwZVlECjX3S0Z1MGpXq 8CZnGXjEUtmuGuCuxzGEkhG9WLmLoEOEnCeiYYqUL+Lj8zigCw5p5hyYQKhc51ofvyh/+G e9p0xh4Dd8YL5D8j7BR4upPJT4EoZ59vkPMOuVxwk1h3z2lMv45M+T97w896oA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by mav: URL: https://cgit.FreeBSD.org/src/commit/?id=7f16b501e25b6c792fefc4535e0d1b8363392fe0 commit 7f16b501e25b6c792fefc4535e0d1b8363392fe0 Author: Alexander Motin AuthorDate: 2022-03-12 16:49:37 +0000 Commit: Alexander Motin CommitDate: 2022-03-12 16:55:52 +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 --- 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 fbd9336b2e50..70d21e346c9b 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -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); diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c index 307ccd989ca0..0f1dce934b63 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. @@ -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(); } 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 bef5374e6f38..b4d139d76218 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);