aboutsummaryrefslogtreecommitdiffstats
path: root/include/spl
diff options
context:
space:
mode:
authorJohn Gallagher <[email protected]>2018-09-26 11:08:12 -0700
committerBrian Behlendorf <[email protected]>2018-09-26 11:08:12 -0700
commitd12614521a307c709778e5f7f91ae6085f63f9e0 (patch)
tree130e6dde286d0da760612a7f4d9595a660777011 /include/spl
parent3ed2fbcc1ce36fdc516aa11848692a4e4c4a2bc0 (diff)
Fixes for procfs files backed by linked lists
There are some issues with the way the seq_file interface is implemented for kstats backed by linked lists (zfs_dbgmsgs and certain per-pool debugging info): * We don't account for the fact that seq_file sometimes visits a node multiple times, which results in missing messages when read through procfs. * We don't keep separate state for each reader of a file, so concurrent readers will receive incorrect results. * We don't account for the fact that entries may have been removed from the list between read syscalls, so reading from these files in procfs can cause the system to crash. This change fixes these issues and adds procfs_list, a wrapper around a linked list which abstracts away the details of implementing the seq_file interface for a list and exposing the contents of the list through procfs. Reviewed by: Don Brady <[email protected]> Reviewed-by: Serapheim Dimitropoulos <[email protected]> Reviewed by: Brad Lewis <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: John Gallagher <[email protected]> External-issue: LX-1211 Closes #7819
Diffstat (limited to 'include/spl')
-rw-r--r--include/spl/sys/Makefile.am1
-rw-r--r--include/spl/sys/kstat.h20
-rw-r--r--include/spl/sys/procfs_list.h71
3 files changed, 87 insertions, 5 deletions
diff --git a/include/spl/sys/Makefile.am b/include/spl/sys/Makefile.am
index d58ed0e20..e596ff373 100644
--- a/include/spl/sys/Makefile.am
+++ b/include/spl/sys/Makefile.am
@@ -28,6 +28,7 @@ KERNEL_H = \
$(top_srcdir)/include/spl/sys/param.h \
$(top_srcdir)/include/spl/sys/processor.h \
$(top_srcdir)/include/spl/sys/proc.h \
+ $(top_srcdir)/include/spl/sys/procfs_list.h \
$(top_srcdir)/include/spl/sys/random.h \
$(top_srcdir)/include/spl/sys/rwlock.h \
$(top_srcdir)/include/spl/sys/shrinker.h \
diff --git a/include/spl/sys/kstat.h b/include/spl/sys/kstat.h
index f197ce455..53274d8f5 100644
--- a/include/spl/sys/kstat.h
+++ b/include/spl/sys/kstat.h
@@ -98,30 +98,34 @@ typedef struct kstat_raw_ops {
void *(*addr)(kstat_t *ksp, loff_t index);
} kstat_raw_ops_t;
+typedef struct kstat_proc_entry {
+ char kpe_name[KSTAT_STRLEN+1]; /* kstat name */
+ char kpe_module[KSTAT_STRLEN+1]; /* provider module name */
+ kstat_module_t *kpe_owner; /* kstat module linkage */
+ struct list_head kpe_list; /* kstat linkage */
+ struct proc_dir_entry *kpe_proc; /* procfs entry */
+} kstat_proc_entry_t;
+
struct kstat_s {
int ks_magic; /* magic value */
kid_t ks_kid; /* unique kstat ID */
hrtime_t ks_crtime; /* creation time */
hrtime_t ks_snaptime; /* last access time */
- char ks_module[KSTAT_STRLEN+1]; /* provider module name */
int ks_instance; /* provider module instance */
- char ks_name[KSTAT_STRLEN+1]; /* kstat name */
char ks_class[KSTAT_STRLEN+1]; /* kstat class */
uchar_t ks_type; /* kstat data type */
uchar_t ks_flags; /* kstat flags */
void *ks_data; /* kstat type-specific data */
uint_t ks_ndata; /* # of data records */
size_t ks_data_size; /* size of kstat data section */
- struct proc_dir_entry *ks_proc; /* proc linkage */
kstat_update_t *ks_update; /* dynamic updates */
void *ks_private; /* 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 */
- kstat_module_t *ks_owner; /* kstat module linkage */
kstat_raw_ops_t ks_raw_ops; /* ops table for raw type */
char *ks_raw_buf; /* buf used for raw ops */
size_t ks_raw_bufsize; /* size of raw ops buffer */
+ kstat_proc_entry_t ks_proc; /* data for procfs entry */
};
typedef struct kstat_named_s {
@@ -189,6 +193,12 @@ 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);
+extern void kstat_proc_entry_init(kstat_proc_entry_t *kpep,
+ const char *module, const char *name);
+extern void kstat_proc_entry_delete(kstat_proc_entry_t *kpep);
+extern void kstat_proc_entry_install(kstat_proc_entry_t *kpep,
+ const struct file_operations *file_ops, void *data);
+
extern void __kstat_install(kstat_t *ksp);
extern void __kstat_delete(kstat_t *ksp);
extern void kstat_waitq_enter(kstat_io_t *);
diff --git a/include/spl/sys/procfs_list.h b/include/spl/sys/procfs_list.h
new file mode 100644
index 000000000..cbcb4bcff
--- /dev/null
+++ b/include/spl/sys/procfs_list.h
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2018 by Delphix. All rights reserved.
+ */
+
+#ifndef _SPL_PROCFS_LIST_H
+#define _SPL_PROCFS_LIST_H
+
+#include <sys/kstat.h>
+#include <sys/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+typedef struct procfs_list procfs_list_t;
+struct procfs_list {
+ /* Accessed only by user of a procfs_list */
+ void *pl_private;
+
+ /*
+ * Accessed both by user of a procfs_list and by procfs_list
+ * implementation
+ */
+ kmutex_t pl_lock;
+ list_t pl_list;
+
+ /* Accessed only by procfs_list implementation */
+ 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;
+ kstat_proc_entry_t pl_kstat_entry;
+};
+
+typedef struct procfs_list_node {
+ list_node_t pln_link;
+ uint64_t pln_id;
+} procfs_list_node_t;
+
+void procfs_list_install(const char *module,
+ const char *name,
+ procfs_list_t *procfs_list,
+ int (*show)(struct seq_file *f, void *p),
+ int (*show_header)(struct seq_file *f),
+ int (*clear)(procfs_list_t *procfs_list),
+ size_t procfs_list_node_off);
+void procfs_list_uninstall(procfs_list_t *procfs_list);
+void procfs_list_destroy(procfs_list_t *procfs_list);
+
+void procfs_list_add(procfs_list_t *procfs_list, void *p);
+
+#endif /* _SPL_PROCFS_LIST_H */