Skip to content

Commit d126145

Browse files
John Gallagherbehlendorf
John Gallagher
authored andcommitted
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 openzfs#7819
1 parent 3ed2fbc commit d126145

24 files changed

+1086
-558
lines changed

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ AC_CONFIG_FILES([
283283
tests/zfs-tests/tests/functional/inheritance/Makefile
284284
tests/zfs-tests/tests/functional/inuse/Makefile
285285
tests/zfs-tests/tests/functional/io/Makefile
286-
tests/zfs-tests/tests/functional/kstat/Makefile
287286
tests/zfs-tests/tests/functional/large_files/Makefile
288287
tests/zfs-tests/tests/functional/largest_pool/Makefile
289288
tests/zfs-tests/tests/functional/link_count/Makefile
@@ -301,6 +300,7 @@ AC_CONFIG_FILES([
301300
tests/zfs-tests/tests/functional/pool_checkpoint/Makefile
302301
tests/zfs-tests/tests/functional/poolversion/Makefile
303302
tests/zfs-tests/tests/functional/privilege/Makefile
303+
tests/zfs-tests/tests/functional/procfs/Makefile
304304
tests/zfs-tests/tests/functional/projectquota/Makefile
305305
tests/zfs-tests/tests/functional/pyzfs/Makefile
306306
tests/zfs-tests/tests/functional/quota/Makefile

include/spl/sys/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ KERNEL_H = \
2828
$(top_srcdir)/include/spl/sys/param.h \
2929
$(top_srcdir)/include/spl/sys/processor.h \
3030
$(top_srcdir)/include/spl/sys/proc.h \
31+
$(top_srcdir)/include/spl/sys/procfs_list.h \
3132
$(top_srcdir)/include/spl/sys/random.h \
3233
$(top_srcdir)/include/spl/sys/rwlock.h \
3334
$(top_srcdir)/include/spl/sys/shrinker.h \

include/spl/sys/kstat.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,30 +98,34 @@ typedef struct kstat_raw_ops {
9898
void *(*addr)(kstat_t *ksp, loff_t index);
9999
} kstat_raw_ops_t;
100100

101+
typedef struct kstat_proc_entry {
102+
char kpe_name[KSTAT_STRLEN+1]; /* kstat name */
103+
char kpe_module[KSTAT_STRLEN+1]; /* provider module name */
104+
kstat_module_t *kpe_owner; /* kstat module linkage */
105+
struct list_head kpe_list; /* kstat linkage */
106+
struct proc_dir_entry *kpe_proc; /* procfs entry */
107+
} kstat_proc_entry_t;
108+
101109
struct kstat_s {
102110
int ks_magic; /* magic value */
103111
kid_t ks_kid; /* unique kstat ID */
104112
hrtime_t ks_crtime; /* creation time */
105113
hrtime_t ks_snaptime; /* last access time */
106-
char ks_module[KSTAT_STRLEN+1]; /* provider module name */
107114
int ks_instance; /* provider module instance */
108-
char ks_name[KSTAT_STRLEN+1]; /* kstat name */
109115
char ks_class[KSTAT_STRLEN+1]; /* kstat class */
110116
uchar_t ks_type; /* kstat data type */
111117
uchar_t ks_flags; /* kstat flags */
112118
void *ks_data; /* kstat type-specific data */
113119
uint_t ks_ndata; /* # of data records */
114120
size_t ks_data_size; /* size of kstat data section */
115-
struct proc_dir_entry *ks_proc; /* proc linkage */
116121
kstat_update_t *ks_update; /* dynamic updates */
117122
void *ks_private; /* private data */
118123
kmutex_t ks_private_lock; /* kstat private data lock */
119124
kmutex_t *ks_lock; /* kstat data lock */
120-
struct list_head ks_list; /* kstat linkage */
121-
kstat_module_t *ks_owner; /* kstat module linkage */
122125
kstat_raw_ops_t ks_raw_ops; /* ops table for raw type */
123126
char *ks_raw_buf; /* buf used for raw ops */
124127
size_t ks_raw_bufsize; /* size of raw ops buffer */
128+
kstat_proc_entry_t ks_proc; /* data for procfs entry */
125129
};
126130

127131
typedef struct kstat_named_s {
@@ -189,6 +193,12 @@ extern kstat_t *__kstat_create(const char *ks_module, int ks_instance,
189193
const char *ks_name, const char *ks_class, uchar_t ks_type,
190194
uint_t ks_ndata, uchar_t ks_flags);
191195

196+
extern void kstat_proc_entry_init(kstat_proc_entry_t *kpep,
197+
const char *module, const char *name);
198+
extern void kstat_proc_entry_delete(kstat_proc_entry_t *kpep);
199+
extern void kstat_proc_entry_install(kstat_proc_entry_t *kpep,
200+
const struct file_operations *file_ops, void *data);
201+
192202
extern void __kstat_install(kstat_t *ksp);
193203
extern void __kstat_delete(kstat_t *ksp);
194204
extern void kstat_waitq_enter(kstat_io_t *);

include/spl/sys/procfs_list.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9+
* or http://www.opensolaris.org/os/licensing.
10+
* See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*
13+
* When distributing Covered Code, include this CDDL HEADER in each
14+
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15+
* If applicable, add the following below this CDDL HEADER, with the
16+
* fields enclosed by brackets "[]" replaced with your own identifying
17+
* information: Portions Copyright [yyyy] [name of copyright owner]
18+
*
19+
* CDDL HEADER END
20+
*/
21+
/*
22+
* Copyright (c) 2018 by Delphix. All rights reserved.
23+
*/
24+
25+
#ifndef _SPL_PROCFS_LIST_H
26+
#define _SPL_PROCFS_LIST_H
27+
28+
#include <sys/kstat.h>
29+
#include <sys/mutex.h>
30+
#include <linux/proc_fs.h>
31+
#include <linux/seq_file.h>
32+
33+
typedef struct procfs_list procfs_list_t;
34+
struct procfs_list {
35+
/* Accessed only by user of a procfs_list */
36+
void *pl_private;
37+
38+
/*
39+
* Accessed both by user of a procfs_list and by procfs_list
40+
* implementation
41+
*/
42+
kmutex_t pl_lock;
43+
list_t pl_list;
44+
45+
/* Accessed only by procfs_list implementation */
46+
uint64_t pl_next_id;
47+
int (*pl_show)(struct seq_file *f, void *p);
48+
int (*pl_show_header)(struct seq_file *f);
49+
int (*pl_clear)(procfs_list_t *procfs_list);
50+
size_t pl_node_offset;
51+
kstat_proc_entry_t pl_kstat_entry;
52+
};
53+
54+
typedef struct procfs_list_node {
55+
list_node_t pln_link;
56+
uint64_t pln_id;
57+
} procfs_list_node_t;
58+
59+
void procfs_list_install(const char *module,
60+
const char *name,
61+
procfs_list_t *procfs_list,
62+
int (*show)(struct seq_file *f, void *p),
63+
int (*show_header)(struct seq_file *f),
64+
int (*clear)(procfs_list_t *procfs_list),
65+
size_t procfs_list_node_off);
66+
void procfs_list_uninstall(procfs_list_t *procfs_list);
67+
void procfs_list_destroy(procfs_list_t *procfs_list);
68+
69+
void procfs_list_add(procfs_list_t *procfs_list, void *p);
70+
71+
#endif /* _SPL_PROCFS_LIST_H */

include/sys/spa.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -863,22 +863,27 @@ extern boolean_t spa_refcount_zero(spa_t *spa);
863863
#define SCL_STATE_ALL (SCL_STATE | SCL_L2ARC | SCL_ZIO)
864864

865865
/* Historical pool statistics */
866-
typedef struct spa_stats_history {
866+
typedef struct spa_history_kstat {
867867
kmutex_t lock;
868868
uint64_t count;
869869
uint64_t size;
870870
kstat_t *kstat;
871871
void *private;
872872
list_t list;
873-
} spa_stats_history_t;
873+
} spa_history_kstat_t;
874+
875+
typedef struct spa_history_list {
876+
uint64_t size;
877+
procfs_list_t procfs_list;
878+
} spa_history_list_t;
874879

875880
typedef struct spa_stats {
876-
spa_stats_history_t read_history;
877-
spa_stats_history_t txg_history;
878-
spa_stats_history_t tx_assign_histogram;
879-
spa_stats_history_t io_history;
880-
spa_stats_history_t mmp_history;
881-
spa_stats_history_t state; /* pool state */
881+
spa_history_list_t read_history;
882+
spa_history_list_t txg_history;
883+
spa_history_kstat_t tx_assign_histogram;
884+
spa_history_kstat_t io_history;
885+
spa_history_list_t mmp_history;
886+
spa_history_kstat_t state; /* pool state */
882887
} spa_stats_t;
883888

884889
typedef enum txg_state {
@@ -911,7 +916,7 @@ extern void spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs);
911916
extern int spa_mmp_history_set_skip(spa_t *spa, uint64_t mmp_kstat_id);
912917
extern int spa_mmp_history_set(spa_t *spa, uint64_t mmp_kstat_id, int io_error,
913918
hrtime_t duration);
914-
extern void *spa_mmp_history_add(spa_t *spa, uint64_t txg, uint64_t timestamp,
919+
extern void spa_mmp_history_add(spa_t *spa, uint64_t txg, uint64_t timestamp,
915920
uint64_t mmp_delay, vdev_t *vd, int label, uint64_t mmp_kstat_id,
916921
int error);
917922

include/sys/zfs_context.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include <sys/ctype.h>
6363
#include <sys/disp.h>
6464
#include <sys/trace.h>
65+
#include <sys/procfs_list.h>
6566
#include <linux/dcache_compat.h>
6667
#include <linux/utsname_compat.h>
6768

@@ -351,6 +352,37 @@ extern void kstat_set_raw_ops(kstat_t *ksp,
351352
int (*data)(char *buf, size_t size, void *data),
352353
void *(*addr)(kstat_t *ksp, loff_t index));
353354

355+
/*
356+
* procfs list manipulation
357+
*/
358+
359+
struct seq_file { };
360+
void seq_printf(struct seq_file *m, const char *fmt, ...);
361+
362+
typedef struct procfs_list {
363+
void *pl_private;
364+
kmutex_t pl_lock;
365+
list_t pl_list;
366+
uint64_t pl_next_id;
367+
size_t pl_node_offset;
368+
} procfs_list_t;
369+
370+
typedef struct procfs_list_node {
371+
list_node_t pln_link;
372+
uint64_t pln_id;
373+
} procfs_list_node_t;
374+
375+
void procfs_list_install(const char *module,
376+
const char *name,
377+
procfs_list_t *procfs_list,
378+
int (*show)(struct seq_file *f, void *p),
379+
int (*show_header)(struct seq_file *f),
380+
int (*clear)(procfs_list_t *procfs_list),
381+
size_t procfs_list_node_off);
382+
void procfs_list_uninstall(procfs_list_t *procfs_list);
383+
void procfs_list_destroy(procfs_list_t *procfs_list);
384+
void procfs_list_add(procfs_list_t *procfs_list, void *p);
385+
354386
/*
355387
* Kernel memory
356388
*/

include/sys/zfs_debug.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,6 @@ extern void __dprintf(const char *file, const char *func,
7676

7777
extern void zfs_panic_recover(const char *fmt, ...);
7878

79-
typedef struct zfs_dbgmsg {
80-
list_node_t zdm_node;
81-
time_t zdm_timestamp;
82-
int zdm_size;
83-
char zdm_msg[1]; /* variable length allocation */
84-
} zfs_dbgmsg_t;
85-
8679
extern void zfs_dbgmsg_init(void);
8780
extern void zfs_dbgmsg_fini(void);
8881

lib/libzpool/kernel.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,57 @@ cv_broadcast(kcondvar_t *cv)
424424
VERIFY0(pthread_cond_broadcast(cv));
425425
}
426426

427+
/*
428+
* =========================================================================
429+
* procfs list
430+
* =========================================================================
431+
*/
432+
433+
void
434+
seq_printf(struct seq_file *m, const char *fmt, ...)
435+
{}
436+
437+
void
438+
procfs_list_install(const char *module,
439+
const char *name,
440+
procfs_list_t *procfs_list,
441+
int (*show)(struct seq_file *f, void *p),
442+
int (*show_header)(struct seq_file *f),
443+
int (*clear)(procfs_list_t *procfs_list),
444+
size_t procfs_list_node_off)
445+
{
446+
mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL);
447+
list_create(&procfs_list->pl_list,
448+
procfs_list_node_off + sizeof (procfs_list_node_t),
449+
procfs_list_node_off + offsetof(procfs_list_node_t, pln_link));
450+
procfs_list->pl_next_id = 1;
451+
procfs_list->pl_node_offset = procfs_list_node_off;
452+
}
453+
454+
void
455+
procfs_list_uninstall(procfs_list_t *procfs_list)
456+
{}
457+
458+
void
459+
procfs_list_destroy(procfs_list_t *procfs_list)
460+
{
461+
ASSERT(list_is_empty(&procfs_list->pl_list));
462+
list_destroy(&procfs_list->pl_list);
463+
mutex_destroy(&procfs_list->pl_lock);
464+
}
465+
466+
#define NODE_ID(procfs_list, obj) \
467+
(((procfs_list_node_t *)(((char *)obj) + \
468+
(procfs_list)->pl_node_offset))->pln_id)
469+
470+
void
471+
procfs_list_add(procfs_list_t *procfs_list, void *p)
472+
{
473+
ASSERT(MUTEX_HELD(&procfs_list->pl_lock));
474+
NODE_ID(procfs_list, p) = procfs_list->pl_next_id++;
475+
list_insert_tail(&procfs_list->pl_list, p);
476+
}
477+
427478
/*
428479
* =========================================================================
429480
* vnode operations

module/spl/Makefile.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ $(MODULE)-objs += spl-kobj.o
1818
$(MODULE)-objs += spl-kstat.o
1919
$(MODULE)-objs += spl-mutex.o
2020
$(MODULE)-objs += spl-proc.o
21+
$(MODULE)-objs += spl-procfs-list.o
2122
$(MODULE)-objs += spl-rwlock.o
2223
$(MODULE)-objs += spl-taskq.o
2324
$(MODULE)-objs += spl-thread.o

0 commit comments

Comments
 (0)