freebsd/kstat: allow multi-level module names

This extends the existing special-case for zfs/poolname to split and
create any number of intermediate sysctl names, so that multi-level
module names are possible.

Sponsored-by: Klara, Inc.
Sponsored-by: Syneto
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
This commit is contained in:
Rob Norris 2024-05-16 14:58:15 +10:00 committed by Rob Norris
parent e31ed02433
commit 2c251e814c
1 changed files with 26 additions and 42 deletions

View File

@ -27,6 +27,10 @@
* [1] https://illumos.org/man/1M/kstat
* [2] https://illumos.org/man/9f/kstat_create
*/
/*
* Copyright (c) 2024, Klara, Inc.
* Copyright (c) 2024, Syneto
*/
#include <sys/types.h>
#include <sys/param.h>
@ -287,7 +291,7 @@ __kstat_create(const char *module, int instance, const char *name,
char buf[KSTAT_STRLEN];
struct sysctl_oid *root;
kstat_t *ksp;
char *pool;
char *p, *frag;
KASSERT(instance == 0, ("instance=%d", instance));
if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO))
@ -345,74 +349,54 @@ __kstat_create(const char *module, int instance, const char *name,
else
ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP);
/*
* Some kstats use a module name like "zfs/poolname" to distinguish a
* set of kstats belonging to a specific pool. Split on '/' to add an
* extra node for the pool name if needed.
*/
sysctl_ctx_init(&ksp->ks_sysctl_ctx);
(void) strlcpy(buf, module, KSTAT_STRLEN);
module = buf;
pool = strchr(module, '/');
if (pool != NULL)
*pool++ = '\0';
/*
* Create sysctl tree for those statistics:
*
* kstat.<module>[.<pool>].<class>.<name>
* Walk over the module name, splitting on '/', and create the
* intermediate nodes.
*/
sysctl_ctx_init(&ksp->ks_sysctl_ctx);
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx,
SYSCTL_STATIC_CHILDREN(_kstat), OID_AUTO, module, CTLFLAG_RW, 0,
"");
if (root == NULL) {
printf("%s: Cannot create kstat.%s tree!\n", __func__, module);
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
free(ksp, M_KSTAT);
return (NULL);
}
if (pool != NULL) {
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx,
SYSCTL_CHILDREN(root), OID_AUTO, pool, CTLFLAG_RW, 0, "");
root = NULL;
p = buf;
while ((frag = strsep(&p, "/")) != NULL) {
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, root ?
SYSCTL_CHILDREN(root) : SYSCTL_STATIC_CHILDREN(_kstat),
OID_AUTO, frag, CTLFLAG_RW, 0, "");
if (root == NULL) {
printf("%s: Cannot create kstat.%s.%s tree!\n",
__func__, module, pool);
printf("%s: Cannot create kstat.%s tree!\n",
__func__, buf);
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
free(ksp, M_KSTAT);
return (NULL);
}
if (p != NULL && p > frag)
p[-1] = '.';
}
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root),
OID_AUTO, class, CTLFLAG_RW, 0, "");
if (root == NULL) {
if (pool != NULL)
printf("%s: Cannot create kstat.%s.%s.%s tree!\n",
__func__, module, pool, class);
else
printf("%s: Cannot create kstat.%s.%s tree!\n",
__func__, module, class);
printf("%s: Cannot create kstat.%s.%s tree!\n",
__func__, buf, class);
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
free(ksp, M_KSTAT);
return (NULL);
}
if (ksp->ks_type == KSTAT_TYPE_NAMED) {
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx,
SYSCTL_CHILDREN(root),
OID_AUTO, name, CTLFLAG_RW, 0, "");
if (root == NULL) {
if (pool != NULL)
printf("%s: Cannot create kstat.%s.%s.%s.%s "
"tree!\n", __func__, module, pool, class,
name);
else
printf("%s: Cannot create kstat.%s.%s.%s "
"tree!\n", __func__, module, class, name);
printf("%s: Cannot create kstat.%s.%s.%s tree!\n",
__func__, buf, class, name);
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
free(ksp, M_KSTAT);
return (NULL);
}
}
ksp->ks_sysctl_root = root;
return (ksp);