mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
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 <allan@klarasystems.com> Reviewed-by: Ryan Moeller <ryan@ixsystems.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Matt Macy <mmacy@FreeBSD.org> Closes #10890
This commit is contained in:
committed by
Brian Behlendorf
parent
227273efa4
commit
c70c6e004e
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ void
|
||||
zfs_dbgmsg_init(void)
|
||||
{
|
||||
procfs_list_install("zfs",
|
||||
NULL,
|
||||
"dbgmsg",
|
||||
0600,
|
||||
&zfs_dbgmsgs,
|
||||
|
||||
@@ -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,
|
||||
|
||||
+6
-20
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user