aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/mdconfig/Makefile4
-rw-r--r--sbin/mdconfig/mdconfig.c219
-rw-r--r--sys/dev/md/md.c62
3 files changed, 220 insertions, 65 deletions
diff --git a/sbin/mdconfig/Makefile b/sbin/mdconfig/Makefile
index 1d5aff263653..636265cf0405 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 <bsd.prog.mk>
diff --git a/sbin/mdconfig/mdconfig.c b/sbin/mdconfig/mdconfig.c
index 7bf169c29b0f..ed781763f3d2 100644
--- a/sbin/mdconfig/mdconfig.c
+++ b/sbin/mdconfig/mdconfig.c
@@ -10,31 +10,48 @@
*
*/
#include <sys/param.h>
+#include <sys/devicestat.h>
#include <sys/ioctl.h>
#include <sys/linker.h>
#include <sys/mdioctl.h>
#include <sys/module.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <assert.h>
+#include <devstat.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <libgeom.h>
#include <libutil.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-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 = "<a>";
+ 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 bc998274ae8d..f91a93ea8272 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<unit>%d</unit>\n", indent,
+ mp->unit);
+ sbuf_printf(sb, "%s<sectorsize>%ju</sectorsize>\n",
+ indent, (uintmax_t) mp->sectorsize);
+ sbuf_printf(sb, "%s<fwheads>%ju</fwheads>\n",
+ indent, (uintmax_t) mp->fwheads);
+ sbuf_printf(sb, "%s<fwsectors>%ju</fwsectors>\n",
+ indent, (uintmax_t) mp->fwsectors);
+ sbuf_printf(sb, "%s<length>%ju</length>\n",
+ indent, (uintmax_t) mp->mediasize);
+ sbuf_printf(sb, "%s<type>%s</type>\n", indent,
+ type);
+ if (mp->type == MD_VNODE && mp->vnode != NULL)
+ sbuf_printf(sb, "%s<file>%s</file>\n",
+ indent, mp->file);
+ }
+ }
+}
+
+static void
g_md_fini(struct g_class *mp __unused)
{