summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Macy <[email protected]>2020-09-23 16:43:51 -0700
committerGitHub <[email protected]>2020-09-23 16:43:51 -0700
commit7b8363d7f0ca85a2dde7473d6079147387f2f1fc (patch)
tree9a2c7e3cc8822be6b150e7de3c068e5d9e6793ae
parent3dad29fb4b085a159d26e2322dc07b46950ff72e (diff)
FreeBSD: Add support for procfs_list
The procfs_list interface is required by several kstats. Implement this functionality for FreeBSD to provide access to these kstats. Reviewed-by: Allan Jude <[email protected]> Reviewed-by: Ryan Moeller <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Matt Macy <[email protected]> Closes #10890
-rw-r--r--include/os/freebsd/spl/sys/kstat.h18
-rw-r--r--include/os/freebsd/spl/sys/procfs_list.h13
-rw-r--r--include/os/linux/spl/sys/procfs_list.h1
-rw-r--r--include/sys/zfs_context.h1
-rw-r--r--lib/libzpool/kernel.c1
-rw-r--r--module/os/freebsd/spl/spl_kstat.c84
-rw-r--r--module/os/freebsd/spl/spl_procfs_list.c86
-rw-r--r--module/os/linux/spl/spl-procfs-list.c10
-rw-r--r--module/os/linux/zfs/zfs_debug.c1
-rw-r--r--module/zfs/spa_misc.c1
-rw-r--r--module/zfs/spa_stats.c26
11 files changed, 201 insertions, 41 deletions
diff --git a/include/os/freebsd/spl/sys/kstat.h b/include/os/freebsd/spl/sys/kstat.h
index 74c3da8ec..5ceb88b29 100644
--- a/include/os/freebsd/spl/sys/kstat.h
+++ b/include/os/freebsd/spl/sys/kstat.h
@@ -83,6 +83,14 @@ typedef struct kstat_s kstat_t;
typedef int kid_t; /* unique kstat id */
typedef int kstat_update_t(struct kstat_s *, int); /* dynamic update cb */
+struct seq_file {
+ char *sf_buf;
+ size_t sf_size;
+};
+
+void seq_printf(struct seq_file *m, const char *fmt, ...);
+
+
typedef struct kstat_module {
char ksm_name[KSTAT_STRLEN+1]; /* module name */
struct list_head ksm_module_list; /* module linkage */
@@ -92,6 +100,7 @@ typedef struct kstat_module {
typedef struct kstat_raw_ops {
int (*headers)(char *buf, size_t size);
+ int (*seq_headers)(struct seq_file *);
int (*data)(char *buf, size_t size, void *data);
void *(*addr)(kstat_t *ksp, loff_t index);
} kstat_raw_ops_t;
@@ -112,6 +121,7 @@ struct kstat_s {
size_t ks_data_size; /* size of kstat data section */
kstat_update_t *ks_update; /* dynamic updates */
void *ks_private; /* private data */
+ void *ks_private1; /* private data */
kmutex_t ks_private_lock; /* kstat private data lock */
kmutex_t *ks_lock; /* kstat data lock */
struct list_head ks_list; /* kstat linkage */
@@ -185,6 +195,12 @@ extern void __kstat_set_raw_ops(kstat_t *ksp,
int (*data)(char *buf, size_t size, void *data),
void* (*addr)(kstat_t *ksp, loff_t index));
+extern void __kstat_set_seq_raw_ops(kstat_t *ksp,
+ int (*headers)(struct seq_file *),
+ int (*data)(char *buf, size_t size, void *data),
+ void* (*addr)(kstat_t *ksp, loff_t index));
+
+
extern kstat_t *__kstat_create(const char *ks_module, int ks_instance,
const char *ks_name, const char *ks_class, uchar_t ks_type,
uint_t ks_ndata, uchar_t ks_flags);
@@ -196,6 +212,8 @@ extern void kstat_waitq_exit(kstat_io_t *);
extern void kstat_runq_enter(kstat_io_t *);
extern void kstat_runq_exit(kstat_io_t *);
+#define kstat_set_seq_raw_ops(k, h, d, a) \
+ __kstat_set_seq_raw_ops(k, h, d, a)
#define kstat_set_raw_ops(k, h, d, a) \
__kstat_set_raw_ops(k, h, d, a)
#define kstat_create(m, i, n, c, t, s, f) \
diff --git a/include/os/freebsd/spl/sys/procfs_list.h b/include/os/freebsd/spl/sys/procfs_list.h
index 5d623c369..da13f0387 100644
--- a/include/os/freebsd/spl/sys/procfs_list.h
+++ b/include/os/freebsd/spl/sys/procfs_list.h
@@ -33,16 +33,18 @@
* procfs list manipulation
*/
-struct seq_file { };
-void seq_printf(struct seq_file *m, const char *fmt, ...);
-
-typedef struct procfs_list {
+typedef struct procfs_list procfs_list_t;
+struct procfs_list {
void *pl_private;
+ void *pl_next_data;
kmutex_t pl_lock;
list_t pl_list;
uint64_t pl_next_id;
+ int (*pl_show)(struct seq_file *f, void *p);
+ int (*pl_show_header)(struct seq_file *f);
+ int (*pl_clear)(procfs_list_t *procfs_list);
size_t pl_node_offset;
-} procfs_list_t;
+};
typedef struct procfs_list_node {
list_node_t pln_link;
@@ -50,6 +52,7 @@ typedef struct procfs_list_node {
} procfs_list_node_t;
void procfs_list_install(const char *module,
+ const char *submodule,
const char *name,
mode_t mode,
procfs_list_t *procfs_list,
diff --git a/include/os/linux/spl/sys/procfs_list.h b/include/os/linux/spl/sys/procfs_list.h
index eb1519c0a..9bb437f55 100644
--- a/include/os/linux/spl/sys/procfs_list.h
+++ b/include/os/linux/spl/sys/procfs_list.h
@@ -57,6 +57,7 @@ typedef struct procfs_list_node {
} procfs_list_node_t;
void procfs_list_install(const char *module,
+ const char *submodule,
const char *name,
mode_t mode,
procfs_list_t *procfs_list,
diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h
index e33f52c17..d9f5ed580 100644
--- a/include/sys/zfs_context.h
+++ b/include/sys/zfs_context.h
@@ -386,6 +386,7 @@ typedef struct procfs_list_node {
} procfs_list_node_t;
void procfs_list_install(const char *module,
+ const char *submodule,
const char *name,
mode_t mode,
procfs_list_t *procfs_list,
diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
index 145b21d40..ca3578993 100644
--- a/lib/libzpool/kernel.c
+++ b/lib/libzpool/kernel.c
@@ -444,6 +444,7 @@ seq_printf(struct seq_file *m, const char *fmt, ...)
void
procfs_list_install(const char *module,
+ const char *submodule,
const char *name,
mode_t mode,
procfs_list_t *procfs_list,
diff --git a/module/os/freebsd/spl/spl_kstat.c b/module/os/freebsd/spl/spl_kstat.c
index f21575142..4cc77e20a 100644
--- a/module/os/freebsd/spl/spl_kstat.c
+++ b/module/os/freebsd/spl/spl_kstat.c
@@ -55,6 +55,17 @@ __kstat_set_raw_ops(kstat_t *ksp,
ksp->ks_raw_ops.addr = addr;
}
+void
+__kstat_set_seq_raw_ops(kstat_t *ksp,
+ int (*headers)(struct seq_file *f),
+ int (*data)(char *buf, size_t size, void *data),
+ void *(*addr)(kstat_t *ksp, loff_t index))
+{
+ ksp->ks_raw_ops.seq_headers = headers;
+ ksp->ks_raw_ops.data = data;
+ ksp->ks_raw_ops.addr = addr;
+}
+
static int
kstat_default_update(kstat_t *ksp, int rw)
{
@@ -160,7 +171,7 @@ kstat_sysctl_raw(SYSCTL_HANDLER_ARGS)
void *data;
kstat_t *ksp = arg1;
void *(*addr_op)(kstat_t *ksp, loff_t index);
- int n, rc = 0;
+ int n, has_header, rc = 0;
sb = sbuf_new_auto();
if (sb == NULL)
@@ -180,14 +191,25 @@ kstat_sysctl_raw(SYSCTL_HANDLER_ARGS)
ksp->ks_raw_buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
n = 0;
+ has_header = (ksp->ks_raw_ops.headers ||
+ ksp->ks_raw_ops.seq_headers);
+
restart_headers:
if (ksp->ks_raw_ops.headers) {
rc = ksp->ks_raw_ops.headers(
ksp->ks_raw_buf, ksp->ks_raw_bufsize);
+ } else if (ksp->ks_raw_ops.seq_headers) {
+ struct seq_file f;
+
+ f.sf_buf = ksp->ks_raw_buf;
+ f.sf_size = ksp->ks_raw_bufsize;
+ rc = ksp->ks_raw_ops.seq_headers(&f);
+ }
+ if (has_header) {
if (rc == ENOMEM && !kstat_resize_raw(ksp))
goto restart_headers;
if (rc == 0)
- sbuf_printf(sb, "%s", ksp->ks_raw_buf);
+ sbuf_printf(sb, "\n%s", ksp->ks_raw_buf);
}
while ((data = addr_op(ksp, n)) != NULL) {
@@ -220,16 +242,21 @@ kstat_t *
__kstat_create(const char *module, int instance, const char *name,
const char *class, uchar_t ks_type, uint_t ks_ndata, uchar_t flags)
{
+ char buf[KSTAT_STRLEN];
struct sysctl_oid *root;
kstat_t *ksp;
+ char *pool;
KASSERT(instance == 0, ("instance=%d", instance));
if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO))
ASSERT(ks_ndata == 1);
+ if (class == NULL)
+ class = "misc";
+
/*
- * Allocate the main structure. We don't need to copy module/class/name
- * stuff in here, because it is only used for sysctl node creation
+ * Allocate the main structure. We don't need to keep a copy of
+ * module in here, because it is only used for sysctl node creation
* done in this function.
*/
ksp = malloc(sizeof (*ksp), M_KSTAT, M_WAITOK|M_ZERO);
@@ -237,8 +264,8 @@ __kstat_create(const char *module, int instance, const char *name,
ksp->ks_crtime = gethrtime();
ksp->ks_snaptime = ksp->ks_crtime;
ksp->ks_instance = instance;
- strncpy(ksp->ks_name, name, KSTAT_STRLEN);
- strncpy(ksp->ks_class, class, KSTAT_STRLEN);
+ (void) strlcpy(ksp->ks_name, name, KSTAT_STRLEN);
+ (void) strlcpy(ksp->ks_class, class, KSTAT_STRLEN);
ksp->ks_type = ks_type;
ksp->ks_flags = flags;
ksp->ks_update = kstat_default_update;
@@ -280,10 +307,22 @@ __kstat_create(const char *module, int instance, const char *name,
ksp = NULL;
}
}
+
+ /*
+ * 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.
+ */
+ (void) strlcpy(buf, module, KSTAT_STRLEN);
+ module = buf;
+ pool = strchr(module, '/');
+ if (pool != NULL)
+ *pool++ = '\0';
+
/*
* Create sysctl tree for those statistics:
*
- * kstat.<module>.<class>.<name>.
+ * kstat.<module>[.<pool>].<class>.<name>
*/
sysctl_ctx_init(&ksp->ks_sysctl_ctx);
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx,
@@ -295,11 +334,26 @@ __kstat_create(const char *module, int instance, const char *name,
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, "");
+ if (root == NULL) {
+ printf("%s: Cannot create kstat.%s.%s tree!\n",
+ __func__, module, pool);
+ sysctl_ctx_free(&ksp->ks_sysctl_ctx);
+ free(ksp, M_KSTAT);
+ return (NULL);
+ }
+ }
root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root),
OID_AUTO, class, CTLFLAG_RW, 0, "");
if (root == NULL) {
- printf("%s: Cannot create kstat.%s.%s tree!\n", __func__,
- module, class);
+ 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);
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
free(ksp, M_KSTAT);
return (NULL);
@@ -309,8 +363,13 @@ __kstat_create(const char *module, int instance, const char *name,
SYSCTL_CHILDREN(root),
OID_AUTO, name, CTLFLAG_RW, 0, "");
if (root == NULL) {
- printf("%s: Cannot create kstat.%s.%s.%s tree!\n",
- __func__, module, class, name);
+ 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);
sysctl_ctx_free(&ksp->ks_sysctl_ctx);
free(ksp, M_KSTAT);
return (NULL);
@@ -411,7 +470,6 @@ kstat_install(kstat_t *ksp)
switch (ksp->ks_type) {
case KSTAT_TYPE_NAMED:
return (kstat_install_named(ksp));
- break;
case KSTAT_TYPE_RAW:
if (ksp->ks_raw_ops.data) {
root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
@@ -426,7 +484,6 @@ kstat_install(kstat_t *ksp)
CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE,
ksp, 0, kstat_sysctl_raw, "", ksp->ks_name);
}
- VERIFY(root != NULL);
break;
case KSTAT_TYPE_IO:
root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
@@ -440,6 +497,7 @@ kstat_install(kstat_t *ksp)
default:
panic("unsupported kstat type %d\n", ksp->ks_type);
}
+ VERIFY(root != NULL);
ksp->ks_sysctl_root = root;
}
diff --git a/module/os/freebsd/spl/spl_procfs_list.c b/module/os/freebsd/spl/spl_procfs_list.c
index 7b4ae9d0e..e8448ce00 100644
--- a/module/os/freebsd/spl/spl_procfs_list.c
+++ b/module/os/freebsd/spl/spl_procfs_list.c
@@ -32,12 +32,74 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/procfs_list.h>
+typedef struct procfs_list_iter {
+ procfs_list_t *pli_pl;
+ void *pli_elt;
+} pli_t;
+
void
-seq_printf(struct seq_file *m, const char *fmt, ...)
-{}
+seq_printf(struct seq_file *f, const char *fmt, ...)
+{
+ va_list adx;
+
+ va_start(adx, fmt);
+ (void) vsnprintf(f->sf_buf, f->sf_size, fmt, adx);
+ va_end(adx);
+}
+
+static int
+procfs_list_update(kstat_t *ksp, int rw)
+{
+ procfs_list_t *pl = ksp->ks_private;
+
+ if (rw == KSTAT_WRITE)
+ pl->pl_clear(pl);
+
+ return (0);
+}
+
+static int
+procfs_list_data(char *buf, size_t size, void *data)
+{
+ pli_t *p;
+ void *elt;
+ procfs_list_t *pl;
+ struct seq_file f;
+
+ p = data;
+ pl = p->pli_pl;
+ elt = p->pli_elt;
+ free(p, M_TEMP);
+ f.sf_buf = buf;
+ f.sf_size = size;
+ return (pl->pl_show(&f, elt));
+}
+
+static void *
+procfs_list_addr(kstat_t *ksp, loff_t n)
+{
+ procfs_list_t *pl = ksp->ks_private;
+ void *elt = ksp->ks_private1;
+ pli_t *p = NULL;
+
+
+ if (n == 0)
+ ksp->ks_private1 = list_head(&pl->pl_list);
+ else if (elt)
+ ksp->ks_private1 = list_next(&pl->pl_list, elt);
+
+ if (ksp->ks_private1) {
+ p = malloc(sizeof (*p), M_TEMP, M_WAITOK);
+ p->pli_pl = pl;
+ p->pli_elt = ksp->ks_private1;
+ }
+
+ return (p);
+}
void
procfs_list_install(const char *module,
+ const char *submodule,
const char *name,
mode_t mode,
procfs_list_t *procfs_list,
@@ -46,12 +108,31 @@ procfs_list_install(const char *module,
int (*clear)(procfs_list_t *procfs_list),
size_t procfs_list_node_off)
{
+ kstat_t *procfs_kstat;
+
mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL);
list_create(&procfs_list->pl_list,
procfs_list_node_off + sizeof (procfs_list_node_t),
procfs_list_node_off + offsetof(procfs_list_node_t, pln_link));
+ procfs_list->pl_show = show;
+ procfs_list->pl_show_header = show_header;
+ procfs_list->pl_clear = clear;
procfs_list->pl_next_id = 1;
procfs_list->pl_node_offset = procfs_list_node_off;
+
+ procfs_kstat = kstat_create(module, 0, name, submodule,
+ KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
+
+ if (procfs_kstat) {
+ procfs_kstat->ks_lock = &procfs_list->pl_lock;
+ procfs_kstat->ks_ndata = UINT32_MAX;
+ procfs_kstat->ks_private = procfs_list;
+ procfs_kstat->ks_update = procfs_list_update;
+ kstat_set_seq_raw_ops(procfs_kstat, show_header,
+ procfs_list_data, procfs_list_addr);
+ kstat_install(procfs_kstat);
+ procfs_list->pl_private = procfs_kstat;
+ }
}
void
@@ -62,6 +143,7 @@ void
procfs_list_destroy(procfs_list_t *procfs_list)
{
ASSERT(list_is_empty(&procfs_list->pl_list));
+ kstat_delete(procfs_list->pl_private);
list_destroy(&procfs_list->pl_list);
mutex_destroy(&procfs_list->pl_lock);
}
diff --git a/module/os/linux/spl/spl-procfs-list.c b/module/os/linux/spl/spl-procfs-list.c
index 189d6a7c6..778da7bc4 100644
--- a/module/os/linux/spl/spl-procfs-list.c
+++ b/module/os/linux/spl/spl-procfs-list.c
@@ -207,6 +207,7 @@ static const kstat_proc_op_t procfs_list_operations = {
*/
void
procfs_list_install(const char *module,
+ const char *submodule,
const char *name,
mode_t mode,
procfs_list_t *procfs_list,
@@ -215,6 +216,12 @@ procfs_list_install(const char *module,
int (*clear)(procfs_list_t *procfs_list),
size_t procfs_list_node_off)
{
+ char *modulestr;
+
+ if (submodule != NULL)
+ modulestr = kmem_asprintf("%s/%s", module, submodule);
+ else
+ modulestr = kmem_asprintf("%s", module);
mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL);
list_create(&procfs_list->pl_list,
procfs_list_node_off + sizeof (procfs_list_node_t),
@@ -225,9 +232,10 @@ procfs_list_install(const char *module,
procfs_list->pl_clear = clear;
procfs_list->pl_node_offset = procfs_list_node_off;
- kstat_proc_entry_init(&procfs_list->pl_kstat_entry, module, name);
+ kstat_proc_entry_init(&procfs_list->pl_kstat_entry, modulestr, name);
kstat_proc_entry_install(&procfs_list->pl_kstat_entry, mode,
&procfs_list_operations, procfs_list);
+ kmem_strfree(modulestr);
}
EXPORT_SYMBOL(procfs_list_install);
diff --git a/module/os/linux/zfs/zfs_debug.c b/module/os/linux/zfs/zfs_debug.c
index d98463f1b..8d7f04097 100644
--- a/module/os/linux/zfs/zfs_debug.c
+++ b/module/os/linux/zfs/zfs_debug.c
@@ -94,6 +94,7 @@ void
zfs_dbgmsg_init(void)
{
procfs_list_install("zfs",
+ NULL,
"dbgmsg",
0600,
&zfs_dbgmsgs,
diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c
index 41f0ddbde..042104728 100644
--- a/module/zfs/spa_misc.c
+++ b/module/zfs/spa_misc.c
@@ -2169,6 +2169,7 @@ spa_import_progress_init(void)
spa_import_progress_list;
procfs_list_install("zfs",
+ NULL,
"import_progress",
0644,
&spa_import_progress_list->procfs_list,
diff --git a/module/zfs/spa_stats.c b/module/zfs/spa_stats.c
index cf0be3c45..c3eacc142 100644
--- a/module/zfs/spa_stats.c
+++ b/module/zfs/spa_stats.c
@@ -122,14 +122,11 @@ static void
spa_read_history_init(spa_t *spa)
{
spa_history_list_t *shl = &spa->spa_stats.read_history;
- char *module;
shl->size = 0;
-
- module = kmem_asprintf("zfs/%s", spa_name(spa));
-
shl->procfs_list.pl_private = shl;
- procfs_list_install(module,
+ procfs_list_install("zfs",
+ spa_name(spa),
"reads",
0600,
&shl->procfs_list,
@@ -137,8 +134,6 @@ spa_read_history_init(spa_t *spa)
spa_read_history_show_header,
spa_read_history_clear,
offsetof(spa_read_history_t, srh_node));
-
- kmem_strfree(module);
}
static void
@@ -293,14 +288,11 @@ static void
spa_txg_history_init(spa_t *spa)
{
spa_history_list_t *shl = &spa->spa_stats.txg_history;
- char *module;
shl->size = 0;
-
- module = kmem_asprintf("zfs/%s", spa_name(spa));
-
shl->procfs_list.pl_private = shl;
- procfs_list_install(module,
+ procfs_list_install("zfs",
+ spa_name(spa),
"txgs",
0644,
&shl->procfs_list,
@@ -308,8 +300,6 @@ spa_txg_history_init(spa_t *spa)
spa_txg_history_show_header,
spa_txg_history_clear,
offsetof(spa_txg_history_t, sth_node));
-
- kmem_strfree(module);
}
static void
@@ -699,14 +689,12 @@ static void
spa_mmp_history_init(spa_t *spa)
{
spa_history_list_t *shl = &spa->spa_stats.mmp_history;
- char *module;
shl->size = 0;
- module = kmem_asprintf("zfs/%s", spa_name(spa));
-
shl->procfs_list.pl_private = shl;
- procfs_list_install(module,
+ procfs_list_install("zfs",
+ spa_name(spa),
"multihost",
0644,
&shl->procfs_list,
@@ -714,8 +702,6 @@ spa_mmp_history_init(spa_t *spa)
spa_mmp_history_show_header,
spa_mmp_history_clear,
offsetof(spa_mmp_history_t, smh_node));
-
- kmem_strfree(module);
}
static void