From 8e4d13764bdfc916c23fb22158c65e486dce631c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fran=C3=A7ois=20Tigeot?= Date: Sun, 16 Nov 2014 12:35:45 +0100 Subject: [PATCH] sysctl: Give each device its own context and subtree * Add device_get_sysctl_ctx() and device_get_sysctl_tree() functions * All devices now have an associated sysctl tree under the "dev" root Obtained-from: FreeBSD --- sys/kern/subr_bus.c | 155 ++++++++++++++++++++++++++++++++++++++++++ sys/sys/bus.h | 2 + sys/sys/bus_private.h | 8 +++ 3 files changed, 165 insertions(+) diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index c9c986b966..3a64b1d366 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -54,6 +54,7 @@ #include SYSCTL_NODE(_hw, OID_AUTO, bus, CTLFLAG_RW, NULL, NULL); +SYSCTL_NODE(, OID_AUTO, dev, CTLFLAG_RW, NULL, NULL); MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); @@ -100,6 +101,144 @@ void print_devclass_list(void); #define print_devclass_list() /* nop */ #endif +/* + * dev sysctl tree + */ + +enum { + DEVCLASS_SYSCTL_PARENT, +}; + +static int +devclass_sysctl_handler(SYSCTL_HANDLER_ARGS) +{ + devclass_t dc = (devclass_t)arg1; + const char *value; + + switch (arg2) { + case DEVCLASS_SYSCTL_PARENT: + value = dc->parent ? dc->parent->name : ""; + break; + default: + return (EINVAL); + } + return (SYSCTL_OUT(req, value, strlen(value))); +} + +static void +devclass_sysctl_init(devclass_t dc) +{ + + if (dc->sysctl_tree != NULL) + return; + sysctl_ctx_init(&dc->sysctl_ctx); + dc->sysctl_tree = SYSCTL_ADD_NODE(&dc->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_dev), OID_AUTO, dc->name, + CTLFLAG_RD, NULL, ""); + SYSCTL_ADD_PROC(&dc->sysctl_ctx, SYSCTL_CHILDREN(dc->sysctl_tree), + OID_AUTO, "%parent", CTLTYPE_STRING | CTLFLAG_RD, + dc, DEVCLASS_SYSCTL_PARENT, devclass_sysctl_handler, "A", + "parent class"); +} + +enum { + DEVICE_SYSCTL_DESC, + DEVICE_SYSCTL_DRIVER, + DEVICE_SYSCTL_LOCATION, + DEVICE_SYSCTL_PNPINFO, + DEVICE_SYSCTL_PARENT, +}; + +static int +device_sysctl_handler(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + const char *value; + char *buf; + int error; + + buf = NULL; + switch (arg2) { + case DEVICE_SYSCTL_DESC: + value = dev->desc ? dev->desc : ""; + break; + case DEVICE_SYSCTL_DRIVER: + value = dev->driver ? dev->driver->name : ""; + break; + case DEVICE_SYSCTL_LOCATION: + value = buf = kmalloc(1024, M_BUS, M_WAITOK | M_ZERO); + bus_child_location_str(dev, buf, 1024); + break; + case DEVICE_SYSCTL_PNPINFO: + value = buf = kmalloc(1024, M_BUS, M_WAITOK | M_ZERO); + bus_child_pnpinfo_str(dev, buf, 1024); + break; + case DEVICE_SYSCTL_PARENT: + value = dev->parent ? dev->parent->nameunit : ""; + break; + default: + return (EINVAL); + } + error = SYSCTL_OUT(req, value, strlen(value)); + if (buf != NULL) + kfree(buf, M_BUS); + return (error); +} + +static void +device_sysctl_init(device_t dev) +{ + devclass_t dc = dev->devclass; + + if (dev->sysctl_tree != NULL) + return; + devclass_sysctl_init(dc); + sysctl_ctx_init(&dev->sysctl_ctx); + dev->sysctl_tree = SYSCTL_ADD_NODE(&dev->sysctl_ctx, + SYSCTL_CHILDREN(dc->sysctl_tree), OID_AUTO, + dev->nameunit + strlen(dc->name), + CTLFLAG_RD, NULL, ""); + SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), + OID_AUTO, "%desc", CTLTYPE_STRING | CTLFLAG_RD, + dev, DEVICE_SYSCTL_DESC, device_sysctl_handler, "A", + "device description"); + SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), + OID_AUTO, "%driver", CTLTYPE_STRING | CTLFLAG_RD, + dev, DEVICE_SYSCTL_DRIVER, device_sysctl_handler, "A", + "device driver name"); + SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), + OID_AUTO, "%location", CTLTYPE_STRING | CTLFLAG_RD, + dev, DEVICE_SYSCTL_LOCATION, device_sysctl_handler, "A", + "device location relative to parent"); + SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), + OID_AUTO, "%pnpinfo", CTLTYPE_STRING | CTLFLAG_RD, + dev, DEVICE_SYSCTL_PNPINFO, device_sysctl_handler, "A", + "device identification"); + SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), + OID_AUTO, "%parent", CTLTYPE_STRING | CTLFLAG_RD, + dev, DEVICE_SYSCTL_PARENT, device_sysctl_handler, "A", + "parent device"); +} + +static void +device_sysctl_update(device_t dev) +{ + devclass_t dc = dev->devclass; + + if (dev->sysctl_tree == NULL) + return; + sysctl_rename_oid(dev->sysctl_tree, dev->nameunit + strlen(dc->name)); +} + +static void +device_sysctl_fini(device_t dev) +{ + if (dev->sysctl_tree == NULL) + return; + sysctl_ctx_free(&dev->sysctl_ctx); + dev->sysctl_tree = NULL; +} + static void device_attach_async(device_t dev); static void device_attach_thread(void *arg); static int device_doattach(device_t dev); @@ -1387,6 +1526,18 @@ device_get_flags(device_t dev) return(dev->devflags); } +struct sysctl_ctx_list * +device_get_sysctl_ctx(device_t dev) +{ + return (&dev->sysctl_ctx); +} + +struct sysctl_oid * +device_get_sysctl_tree(device_t dev) +{ + return (dev->sysctl_tree); +} + int device_print_prettyname(device_t dev) { @@ -1721,11 +1872,13 @@ device_doattach(device_t dev) int hasclass = (dev->devclass != NULL); int error; + device_sysctl_init(dev); error = DEVICE_ATTACH(dev); if (error == 0) { dev->state = DS_ATTACHED; if (bootverbose && !device_is_quiet(dev)) device_print_child(bus, dev); + device_sysctl_update(dev); devadded(dev); } else { kprintf("device_probe_and_attach: %s%d attach returned %d\n", @@ -1735,6 +1888,7 @@ device_doattach(device_t dev) device_set_devclass(dev, 0); device_set_driver(dev, NULL); dev->state = DS_NOTPRESENT; + device_sysctl_fini(dev); } return(error); } @@ -1762,6 +1916,7 @@ device_detach(device_t dev) dev->state = DS_NOTPRESENT; device_set_driver(dev, NULL); + device_sysctl_fini(dev); return(0); } diff --git a/sys/sys/bus.h b/sys/sys/bus.h index c730b262cb..1f2e94c8a8 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -373,6 +373,8 @@ const char *device_get_nameunit(device_t dev); void *device_get_softc(device_t dev); device_state_t device_get_state(device_t dev); int device_get_unit(device_t dev); +struct sysctl_ctx_list *device_get_sysctl_ctx(device_t dev); +struct sysctl_oid *device_get_sysctl_tree(device_t dev); int device_is_alive(device_t dev); /* did probe succeed? */ int device_is_attached(device_t dev); /* did attach succeed? */ int device_is_enabled(device_t dev); diff --git a/sys/sys/bus_private.h b/sys/sys/bus_private.h index dd407ba930..3176053bcd 100644 --- a/sys/sys/bus_private.h +++ b/sys/sys/bus_private.h @@ -30,6 +30,8 @@ #ifndef _SYS_BUS_PRIVATE_H_ #define _SYS_BUS_PRIVATE_H_ +#include + #if !defined(_KERNEL) && !defined(_KERNEL_STRUCTURES) #error "This file should not be included by userland programs." @@ -63,6 +65,9 @@ struct devclass { char *name; device_t *devices; /* array of devices indexed by unit */ int maxunit; /* size of devices array */ + + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; }; /* @@ -131,6 +136,9 @@ struct device { u_char pad; void *ivars; void *softc; + + struct sysctl_ctx_list sysctl_ctx; /**< state for sysctl variables */ + struct sysctl_oid *sysctl_tree; /**< state for sysctl variables */ }; struct device_op_desc { -- 2.41.0