From 2a5afd7475409bb7cdb8473d9d796d7b58572117 Mon Sep 17 00:00:00 2001 From: wkoszek Date: Sun, 26 Mar 2006 23:21:11 +0000 Subject: Teach md(4) and mdconfig(8) how to understand XML. Right now there won't be a problem with listing large number of md(4) devices. Either 'list' or 'query' mode uses XML. Additionally, new functionality was introduced. It's possible to pass multiple devices to -u: # ./mdconfig -l -u md0,md1 Approved by: cognet (mentor) --- sbin/mdconfig/Makefile | 4 +- sbin/mdconfig/mdconfig.c | 219 +++++++++++++++++++++++++++++++++-------------- sys/dev/md/md.c | 62 ++++++++++++++ 3 files changed, 220 insertions(+), 65 deletions(-) diff --git a/sbin/mdconfig/Makefile b/sbin/mdconfig/Makefile index 1d5aff2..636265c 100644 --- a/sbin/mdconfig/Makefile +++ b/sbin/mdconfig/Makefile @@ -4,7 +4,7 @@ PROG= mdconfig MAN= mdconfig.8 MLINKS= mdconfig.8 vnconfig.8 -DPADD= ${LIBUTIL} -LDADD= -lutil +DPADD= ${LIBUTIL} ${LIBGEOM} +LDADD= -lutil -lgeom .include diff --git a/sbin/mdconfig/mdconfig.c b/sbin/mdconfig/mdconfig.c index 7bf169c..ed78176 100644 --- a/sbin/mdconfig/mdconfig.c +++ b/sbin/mdconfig/mdconfig.c @@ -10,31 +10,48 @@ * */ #include +#include #include #include #include #include +#include #include #include +#include #include #include #include #include +#include #include +#include #include #include #include #include -static int list(const int); -static int query(const int, const int); -static void usage(void); static struct md_ioctl mdio; static enum {UNSET, ATTACH, DETACH, LIST} action = UNSET; static int nflag; +static void usage(void); +static int md_find(char *, const char *); +static int md_query(char *name); +static int md_list(char *units, int opt); +static char *geom_config_get(struct gconf *g, char *name); +static void geom_config_dump(struct gconf *g); +static void md_prthumanval(char *length); + +#define OPT_VERBOSE 0x01 +#define OPT_UNIT 0x02 +#define OPT_DONE 0x04 +#define OPT_LIST 0x10 + +#define CLASS_NAME_MD "MD" + static void usage() { @@ -58,6 +75,7 @@ main(int argc, char **argv) int ch, fd, i; char *p; int cmdline = 0; + char *mdunit; bzero(&mdio, sizeof(mdio)); mdio.md_file = malloc(PATH_MAX); @@ -195,13 +213,7 @@ main(int argc, char **argv) case 'u': if (cmdline != 2 && cmdline != 3) usage(); - if (!strncmp(optarg, "/dev/", 5)) - optarg += 5; - if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1)) - optarg += sizeof(MD_NAME) - 1; - mdio.md_unit = strtoul(optarg, &p, 0); - if (mdio.md_unit == (unsigned)ULONG_MAX || *p != '\0') - errx(1, "bad unit: %s", optarg); + mdunit = optarg; mdio.md_options &= ~MD_AUTOUNIT; break; case 'x': @@ -244,10 +256,15 @@ main(int argc, char **argv) } } if (action == LIST) { - if (mdio.md_options & MD_AUTOUNIT) - list(fd); - else - query(fd, mdio.md_unit); + if (mdio.md_options & MD_AUTOUNIT) { + /* + * Listing all devices. This is why we pass NULL + * together with OPT_LIST. + */ + md_list(NULL, OPT_LIST); + } else { + md_query(mdunit); + } } else if (action == ATTACH) { if (cmdline < 2) usage(); @@ -268,73 +285,149 @@ main(int argc, char **argv) return (0); } +/* + * Lists md(4) disks. Is used also as a query routine, since it handles XML + * interface. 'units' can be NULL for listing memory disks. It might be + * coma-separated string containing md(4) disk names. 'opt' distinguished + * between list and query mode. + */ static int -mdunitcmp(const void *a, const void *b) +md_list(char *units, int opt) +{ + struct gmesh gm; + struct gprovider *pp; + struct gconsumer *cp; + struct gconf *gc; + struct gconfig *gce; + struct gident *gid; + struct devstat *gsp, *gsq; + struct ggeom *gg; + struct gclass *gcl; + void *sq; + int retcode; + signed int ch; + int nl; + char *type, *file, *length; + + type = file = length = NULL; + + retcode = geom_gettree(&gm); + if (retcode != 0) + return (-1); + retcode = geom_stats_open(); + if (retcode != 0) + return (-1); + sq = geom_stats_snapshot_get(); + if (sq == NULL) + return (-1); + + while ((gsp = geom_stats_snapshot_next(sq)) != NULL) { + gid = geom_lookupid(&gm, gsp->id); + if (gid == NULL) + continue; + if (gid->lg_what == ISPROVIDER) { + pp = gid->lg_ptr; + gg = pp->lg_geom; + gcl = gg->lg_class; + if (strcmp(gcl->lg_name, CLASS_NAME_MD) != 0) + continue; + if ((opt & OPT_UNIT) && (units != NULL)) { + retcode = md_find(units, pp->lg_name); + if (retcode != 1) + continue; + } + gc = &pp->lg_config; + printf("%s", pp->lg_name); + if (opt & OPT_VERBOSE || opt & OPT_UNIT) { + type = geom_config_get(gc, "type"); + if (strcmp(type, "vnode") == 0) + file = geom_config_get(gc, "file"); + length = geom_config_get(gc, "length"); + if (length == NULL) + length = ""; + printf("\t%s\t", type); + md_prthumanval(length); + if (file != NULL) { + printf("\t%s", file); + file = NULL; + } + } + opt |= OPT_DONE; + if (opt & OPT_LIST) + printf(" "); + else + printf("\n"); + } + } + if ((opt & OPT_LIST) && (opt & OPT_DONE)) + printf("\n"); + /* XXX: Check if it's enough to clean everything. */ + geom_stats_snapshot_free(sq); + return (-1); +} + +/* + * Returns value of 'name' from gconfig structure. + */ +static char * +geom_config_get(struct gconf *g, char *name) { - return (*(int *)a - *(int *)b); + struct gconfig *gce; + + LIST_FOREACH(gce, g, lg_config) { + if (strcmp(gce->lg_name, name) == 0) + return (gce->lg_val); + } + return (NULL); } +/* + * List is comma separated list of MD disks. name is a + * device name we look for. Returns 1 if found and 0 + * otherwise. + */ static int -list(const int fd) +md_find(char *list, const char *name) { - int unit; - int mdcount; + int ret; + char num[16]; + char *ptr, *p, *u; - if (ioctl(fd, MDIOCLIST, &mdio) < 0) - err(1, "ioctl(/dev/%s)", MDCTL_NAME); - mdcount = mdio.md_pad[0]; - assert(mdcount < MDNPAD - 1); - if (mdcount > 0) - qsort(&mdio.md_pad[1], mdcount, sizeof(mdio.md_pad[0]), mdunitcmp); - for (unit = 0; unit < mdcount; unit++) { - printf("%s%s%d", unit > 0 ? " " : "", - nflag ? "" : MD_NAME, mdio.md_pad[unit + 1]); + ret = 0; + ptr = strdup(list); + if (ptr == NULL) + return (-1); + for (p = ptr; (u = strsep(&p, ",")) != NULL;) { + if (strncmp(u, "/dev/", 5) == 0) + u += 5; + /* Just in case user specified number instead of full name */ + snprintf(num, sizeof(num), "md%s", u); + if (strcmp(u, name) == 0 || strcmp(num, name) == 0) { + ret = 1; + break; + } } - if (unit > 0) - printf("\n"); - return (0); + free(ptr); + return (ret); } static void -prthumanval(int64_t bytes) +md_prthumanval(char *length) { char buf[6]; + uint64_t bytes; + char *endptr; + bytes = strtoul(length, &endptr, 10); + if (bytes == (unsigned)ULONG_MAX || *endptr != '\0') + return; humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), bytes, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); (void)printf("%6s", buf); } -static int -query(const int fd, const int unit) +int +md_query(char *name) { - - mdio.md_version = MDIOVERSION; - mdio.md_unit = unit; - - if (ioctl(fd, MDIOCQUERY, &mdio) < 0) - err(1, "ioctl(/dev/%s)", MDCTL_NAME); - - (void)printf("%s%d\t", MD_NAME, mdio.md_unit); - switch (mdio.md_type) { - case MD_MALLOC: - (void)printf("malloc"); - break; - case MD_PRELOAD: - (void)printf("preload"); - break; - case MD_SWAP: - (void)printf("swap"); - break; - case MD_VNODE: - (void)printf("vnode"); - break; - } - printf("\t"); - prthumanval(mdio.md_mediasize); - if (mdio.md_type == MD_VNODE) - printf("\t%s", mdio.md_file); - printf("\n"); - - return (0); + return (md_list(name, OPT_UNIT)); } diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index bc99827..f91a93e 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -120,6 +120,8 @@ static g_init_t g_md_init; static g_fini_t g_md_fini; static g_start_t g_md_start; static g_access_t g_md_access; +static void g_md_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, + struct g_consumer *cp __unused, struct g_provider *pp); static int mdunits; static struct cdev *status_dev = 0; @@ -140,6 +142,7 @@ struct g_class g_md_class = { .fini = g_md_fini, .start = g_md_start, .access = g_md_access, + .dumpconf = g_md_dumpconf, }; DECLARE_GEOM_CLASS(g_md_class, g_md); @@ -1178,6 +1181,65 @@ g_md_init(struct g_class *mp __unused) } static void +g_md_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, + struct g_consumer *cp __unused, struct g_provider *pp) +{ + struct md_s *mp; + char *type; + + mp = gp->softc; + if (mp == NULL) + return; + + switch (mp->type) { + case MD_MALLOC: + type = "malloc"; + break; + case MD_PRELOAD: + type = "preload"; + break; + case MD_VNODE: + type = "vnode"; + break; + case MD_SWAP: + type = "swap"; + break; + default: + type = "unknown"; + break; + } + + if (pp != NULL) { + if (indent == NULL) { + sbuf_printf(sb, " u %d", mp->unit); + sbuf_printf(sb, " s %ju", (uintmax_t) mp->sectorsize); + sbuf_printf(sb, " f %ju", (uintmax_t) mp->fwheads); + sbuf_printf(sb, " fs %ju", (uintmax_t) mp->fwsectors); + sbuf_printf(sb, " l %ju", (uintmax_t) mp->mediasize); + sbuf_printf(sb, " t %s", type); + if (mp->type == MD_VNODE && mp->vnode != NULL) + sbuf_printf(sb, " file %s", mp->file); + } else { + sbuf_printf(sb, "%s%d\n", indent, + mp->unit); + sbuf_printf(sb, "%s%ju\n", + indent, (uintmax_t) mp->sectorsize); + sbuf_printf(sb, "%s%ju\n", + indent, (uintmax_t) mp->fwheads); + sbuf_printf(sb, "%s%ju\n", + indent, (uintmax_t) mp->fwsectors); + sbuf_printf(sb, "%s%ju\n", + indent, (uintmax_t) mp->mediasize); + sbuf_printf(sb, "%s%s\n", indent, + type); + if (mp->type == MD_VNODE && mp->vnode != NULL) + sbuf_printf(sb, "%s%s\n", + indent, mp->file); + } + } +} + +static void g_md_fini(struct g_class *mp __unused) { -- cgit v1.1