mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-29 12:29:35 +03:00
d12614521a
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 <don.brady@delphix.com> Reviewed-by: Serapheim Dimitropoulos <serapheim@delphix.com> Reviewed by: Brad Lewis <brad.lewis@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: John Gallagher <john.gallagher@delphix.com> External-issue: LX-1211 Closes #7819
218 lines
7.4 KiB
C
218 lines
7.4 KiB
C
/*
|
|
* Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
|
|
* Copyright (C) 2007 The Regents of the University of California.
|
|
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
|
|
* Written by Brian Behlendorf <behlendorf1@llnl.gov>.
|
|
* UCRL-CODE-235197
|
|
*
|
|
* This file is part of the SPL, Solaris Porting Layer.
|
|
* For details, see <http://zfsonlinux.org/>.
|
|
*
|
|
* The SPL is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* The SPL is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with the SPL. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef _SPL_KSTAT_H
|
|
#define _SPL_KSTAT_H
|
|
|
|
#include <linux/module.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/kmem.h>
|
|
#include <sys/mutex.h>
|
|
#include <sys/proc.h>
|
|
|
|
#define KSTAT_STRLEN 255
|
|
#define KSTAT_RAW_MAX (128*1024)
|
|
|
|
/*
|
|
* For reference valid classes are:
|
|
* disk, tape, net, controller, vm, kvm, hat, streams, kstat, misc
|
|
*/
|
|
|
|
#define KSTAT_TYPE_RAW 0 /* can be anything; ks_ndata >= 1 */
|
|
#define KSTAT_TYPE_NAMED 1 /* name/value pair; ks_ndata >= 1 */
|
|
#define KSTAT_TYPE_INTR 2 /* interrupt stats; ks_ndata == 1 */
|
|
#define KSTAT_TYPE_IO 3 /* I/O stats; ks_ndata == 1 */
|
|
#define KSTAT_TYPE_TIMER 4 /* event timer; ks_ndata >= 1 */
|
|
#define KSTAT_NUM_TYPES 5
|
|
|
|
#define KSTAT_DATA_CHAR 0
|
|
#define KSTAT_DATA_INT32 1
|
|
#define KSTAT_DATA_UINT32 2
|
|
#define KSTAT_DATA_INT64 3
|
|
#define KSTAT_DATA_UINT64 4
|
|
#define KSTAT_DATA_LONG 5
|
|
#define KSTAT_DATA_ULONG 6
|
|
#define KSTAT_DATA_STRING 7
|
|
#define KSTAT_NUM_DATAS 8
|
|
|
|
#define KSTAT_INTR_HARD 0
|
|
#define KSTAT_INTR_SOFT 1
|
|
#define KSTAT_INTR_WATCHDOG 2
|
|
#define KSTAT_INTR_SPURIOUS 3
|
|
#define KSTAT_INTR_MULTSVC 4
|
|
#define KSTAT_NUM_INTRS 5
|
|
|
|
#define KSTAT_FLAG_VIRTUAL 0x01
|
|
#define KSTAT_FLAG_VAR_SIZE 0x02
|
|
#define KSTAT_FLAG_WRITABLE 0x04
|
|
#define KSTAT_FLAG_PERSISTENT 0x08
|
|
#define KSTAT_FLAG_DORMANT 0x10
|
|
#define KSTAT_FLAG_INVALID 0x20
|
|
#define KSTAT_FLAG_LONGSTRINGS 0x40
|
|
#define KSTAT_FLAG_NO_HEADERS 0x80
|
|
|
|
#define KS_MAGIC 0x9d9d9d9d
|
|
|
|
/* Dynamic updates */
|
|
#define KSTAT_READ 0
|
|
#define KSTAT_WRITE 1
|
|
|
|
struct kstat_s;
|
|
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 */
|
|
|
|
typedef struct kstat_module {
|
|
char ksm_name[KSTAT_STRLEN+1]; /* module name */
|
|
struct list_head ksm_module_list; /* module linkage */
|
|
struct list_head ksm_kstat_list; /* list of kstat entries */
|
|
struct proc_dir_entry *ksm_proc; /* proc entry */
|
|
} kstat_module_t;
|
|
|
|
typedef struct kstat_raw_ops {
|
|
int (*headers)(char *buf, size_t size);
|
|
int (*data)(char *buf, size_t size, void *data);
|
|
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 */
|
|
int ks_instance; /* provider module instance */
|
|
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 */
|
|
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 */
|
|
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 {
|
|
char name[KSTAT_STRLEN]; /* name of counter */
|
|
uchar_t data_type; /* data type */
|
|
union {
|
|
char c[16]; /* 128-bit int */
|
|
int32_t i32; /* 32-bit signed int */
|
|
uint32_t ui32; /* 32-bit unsigned int */
|
|
int64_t i64; /* 64-bit signed int */
|
|
uint64_t ui64; /* 64-bit unsigned int */
|
|
long l; /* native signed long */
|
|
ulong_t ul; /* native unsigned long */
|
|
struct {
|
|
union {
|
|
char *ptr; /* NULL-term string */
|
|
char __pad[8]; /* 64-bit padding */
|
|
} addr;
|
|
uint32_t len; /* # bytes for strlen + '\0' */
|
|
} string;
|
|
} value;
|
|
} kstat_named_t;
|
|
|
|
#define KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.string.addr.ptr)
|
|
#define KSTAT_NAMED_STR_BUFLEN(knptr) ((knptr)->value.string.len)
|
|
|
|
typedef struct kstat_intr {
|
|
uint_t intrs[KSTAT_NUM_INTRS];
|
|
} kstat_intr_t;
|
|
|
|
typedef struct kstat_io {
|
|
u_longlong_t nread; /* number of bytes read */
|
|
u_longlong_t nwritten; /* number of bytes written */
|
|
uint_t reads; /* number of read operations */
|
|
uint_t writes; /* number of write operations */
|
|
hrtime_t wtime; /* cumulative wait (pre-service) time */
|
|
hrtime_t wlentime; /* cumulative wait len*time product */
|
|
hrtime_t wlastupdate; /* last time wait queue changed */
|
|
hrtime_t rtime; /* cumulative run (service) time */
|
|
hrtime_t rlentime; /* cumulative run length*time product */
|
|
hrtime_t rlastupdate; /* last time run queue changed */
|
|
uint_t wcnt; /* count of elements in wait state */
|
|
uint_t rcnt; /* count of elements in run state */
|
|
} kstat_io_t;
|
|
|
|
typedef struct kstat_timer {
|
|
char name[KSTAT_STRLEN+1]; /* event name */
|
|
u_longlong_t num_events; /* number of events */
|
|
hrtime_t elapsed_time; /* cumulative elapsed time */
|
|
hrtime_t min_time; /* shortest event duration */
|
|
hrtime_t max_time; /* longest event duration */
|
|
hrtime_t start_time; /* previous event start time */
|
|
hrtime_t stop_time; /* previous event stop time */
|
|
} kstat_timer_t;
|
|
|
|
int spl_kstat_init(void);
|
|
void spl_kstat_fini(void);
|
|
|
|
extern void __kstat_set_raw_ops(kstat_t *ksp,
|
|
int (*headers)(char *buf, size_t size),
|
|
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);
|
|
|
|
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 *);
|
|
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_raw_ops(k, h, d, a) \
|
|
__kstat_set_raw_ops(k, h, d, a)
|
|
#define kstat_create(m, i, n, c, t, s, f) \
|
|
__kstat_create(m, i, n, c, t, s, f)
|
|
|
|
#define kstat_install(k) __kstat_install(k)
|
|
#define kstat_delete(k) __kstat_delete(k)
|
|
|
|
#endif /* _SPL_KSTAT_H */
|