From 56d40a686b0504042a088943154ba7b0dde36d51 Mon Sep 17 00:00:00 2001 From: Prakash Surya Date: Thu, 12 Sep 2013 16:14:51 -0700 Subject: [PATCH 1/5] Add callbacks for displaying KSTAT_TYPE_RAW kstats The current implementation for displaying kstats of type KSTAT_TYPE_RAW is rather crude. This patch attempts to enhance this handling by allowing a kstat user to register formatting callbacks which can optionally be used. The callbacks allow the user to implement functions for interpreting their data and transposing it into a character buffer. This buffer, containing a string representation of the raw data, is then be displayed through the current /proc textual interface. Additionally the kstats are made writable because it's now possible to provide a useful handler via the existing ks_update() interface. Signed-off-by: Prakash Surya Signed-off-by: Brian Behlendorf Issue #296 --- include/sys/kstat.h | 20 ++++++- module/spl/spl-kstat.c | 119 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 123 insertions(+), 16 deletions(-) diff --git a/include/sys/kstat.h b/include/sys/kstat.h index da3c5899db..75b384714c 100644 --- a/include/sys/kstat.h +++ b/include/sys/kstat.h @@ -33,6 +33,7 @@ #include #define KSTAT_STRLEN 31 +#define KSTAT_RAW_MAX (128*1024) /* For reference valid classes are: * disk, tape, net, controller, vm, kvm, hat, streams, kstat, misc @@ -79,6 +80,7 @@ #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 */ @@ -90,7 +92,13 @@ typedef struct kstat_module { struct proc_dir_entry *ksm_proc; /* proc entry */ } kstat_module_t; -typedef struct kstat_s { +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; + +struct kstat_s { int ks_magic; /* magic value */ kid_t ks_kid; /* unique kstat ID */ hrtime_t ks_crtime; /* creation time */ @@ -110,7 +118,10 @@ typedef struct kstat_s { kmutex_t ks_lock; /* kstat data lock */ struct list_head ks_list; /* kstat linkage */ kstat_module_t *ks_owner; /* kstat module linkage */ -} kstat_t; + 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 */ +}; typedef struct kstat_named_s { char name[KSTAT_STRLEN]; /* name of counter */ @@ -188,6 +199,10 @@ typedef struct kstat_txg { 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, @@ -195,6 +210,7 @@ extern kstat_t *__kstat_create(const char *ks_module, int ks_instance, extern void __kstat_install(kstat_t *ksp); extern void __kstat_delete(kstat_t *ksp); +#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) diff --git a/module/spl/spl-kstat.c b/module/spl/spl-kstat.c index 4e900c066a..57aabe2d02 100644 --- a/module/spl/spl-kstat.c +++ b/module/spl/spl-kstat.c @@ -41,10 +41,25 @@ static kmutex_t kstat_module_lock; static struct list_head kstat_module_list; static kid_t kstat_id; -static void +static int +kstat_resize_raw(kstat_t *ksp) +{ + if (ksp->ks_raw_bufsize == KSTAT_RAW_MAX) + return ENOMEM; + + vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize); + ksp->ks_raw_bufsize = MIN(ksp->ks_raw_bufsize * 2, KSTAT_RAW_MAX); + ksp->ks_raw_buf = vmem_alloc(ksp->ks_raw_bufsize, KM_SLEEP); + + return 0; +} + +static int kstat_seq_show_headers(struct seq_file *f) { kstat_t *ksp = (kstat_t *)f->private; + int rc = 0; + ASSERT(ksp->ks_magic == KS_MAGIC); seq_printf(f, "%d %d 0x%02x %d %d %lld %lld\n", @@ -54,7 +69,17 @@ kstat_seq_show_headers(struct seq_file *f) switch (ksp->ks_type) { case KSTAT_TYPE_RAW: - seq_printf(f, "raw data"); +restart: + if (ksp->ks_raw_ops.headers) { + rc = ksp->ks_raw_ops.headers( + ksp->ks_raw_buf, ksp->ks_raw_bufsize); + if (rc == ENOMEM && !kstat_resize_raw(ksp)) + goto restart; + if (!rc) + seq_puts(f, ksp->ks_raw_buf); + } else { + seq_printf(f, "raw data\n"); + } break; case KSTAT_TYPE_NAMED: seq_printf(f, "%-31s %-4s %s\n", @@ -92,6 +117,8 @@ kstat_seq_show_headers(struct seq_file *f) default: PANIC("Undefined kstat type %d\n", ksp->ks_type); } + + return -rc; } static int @@ -232,9 +259,19 @@ kstat_seq_show(struct seq_file *f, void *p) switch (ksp->ks_type) { case KSTAT_TYPE_RAW: - ASSERT(ksp->ks_ndata == 1); - rc = kstat_seq_show_raw(f, ksp->ks_data, - ksp->ks_data_size); +restart: + if (ksp->ks_raw_ops.data) { + rc = ksp->ks_raw_ops.data( + ksp->ks_raw_buf, ksp->ks_raw_bufsize, p); + if (rc == ENOMEM && !kstat_resize_raw(ksp)) + goto restart; + if (!rc) + seq_puts(f, ksp->ks_raw_buf); + } else { + ASSERT(ksp->ks_ndata == 1); + rc = kstat_seq_show_raw(f, ksp->ks_data, + ksp->ks_data_size); + } break; case KSTAT_TYPE_NAMED: rc = kstat_seq_show_named(f, (kstat_named_t *)p); @@ -255,13 +292,17 @@ kstat_seq_show(struct seq_file *f, void *p) PANIC("Undefined kstat type %d\n", ksp->ks_type); } - return rc; + return -rc; } int kstat_default_update(kstat_t *ksp, int rw) { ASSERT(ksp != NULL); + + if (rw == KSTAT_WRITE) + return (EACCES); + return 0; } @@ -273,7 +314,10 @@ kstat_seq_data_addr(kstat_t *ksp, loff_t n) switch (ksp->ks_type) { case KSTAT_TYPE_RAW: - rc = ksp->ks_data; + if (ksp->ks_raw_ops.addr) + rc = ksp->ks_raw_ops.addr(ksp, n); + else + rc = ksp->ks_data; break; case KSTAT_TYPE_NAMED: rc = ksp->ks_data + n * sizeof(kstat_named_t); @@ -307,13 +351,18 @@ kstat_seq_start(struct seq_file *f, loff_t *pos) mutex_enter(&ksp->ks_lock); + if (ksp->ks_type == KSTAT_TYPE_RAW) { + ksp->ks_raw_bufsize = PAGE_SIZE; + ksp->ks_raw_buf = vmem_alloc(ksp->ks_raw_bufsize, KM_SLEEP); + } + /* Dynamically update kstat, on error existing kstats are used */ (void) ksp->ks_update(ksp, KSTAT_READ); ksp->ks_snaptime = gethrtime(); - if (!n) - kstat_seq_show_headers(f); + if (!n && kstat_seq_show_headers(f)) + SRETURN(NULL); if (n >= ksp->ks_ndata) SRETURN(NULL); @@ -341,6 +390,9 @@ kstat_seq_stop(struct seq_file *f, void *v) kstat_t *ksp = (kstat_t *)f->private; ASSERT(ksp->ks_magic == KS_MAGIC); + if (ksp->ks_type == KSTAT_TYPE_RAW) + vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize); + mutex_exit(&ksp->ks_lock); } @@ -408,13 +460,47 @@ proc_kstat_open(struct inode *inode, struct file *filp) return rc; } +static ssize_t +proc_kstat_write(struct file *filp, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct seq_file *f = filp->private_data; + kstat_t *ksp = f->private; + int rc; + + ASSERT(ksp->ks_magic == KS_MAGIC); + + mutex_enter(ksp->ks_lock); + rc = ksp->ks_update(ksp, KSTAT_WRITE); + mutex_exit(ksp->ks_lock); + + if (rc) + return (-rc); + + *ppos += len; + return (len); +} + static struct file_operations proc_kstat_operations = { - .open = proc_kstat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, + .open = proc_kstat_open, + .write = proc_kstat_write, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, }; +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)) +{ + ksp->ks_raw_ops.headers = headers; + ksp->ks_raw_ops.data = data; + ksp->ks_raw_ops.addr = addr; +} +EXPORT_SYMBOL(__kstat_set_raw_ops); + 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, @@ -453,6 +539,11 @@ __kstat_create(const char *ks_module, int ks_instance, const char *ks_name, ksp->ks_flags = ks_flags; ksp->ks_update = kstat_default_update; ksp->ks_private = NULL; + ksp->ks_raw_ops.headers = NULL; + ksp->ks_raw_ops.data = NULL; + ksp->ks_raw_ops.addr = NULL; + ksp->ks_raw_buf = NULL; + ksp->ks_raw_bufsize = 0; switch (ksp->ks_type) { case KSTAT_TYPE_RAW: @@ -526,7 +617,7 @@ __kstat_install(kstat_t *ksp) mutex_enter(&ksp->ks_lock); ksp->ks_owner = module; - ksp->ks_proc = proc_create_data(ksp->ks_name, 0444, + ksp->ks_proc = proc_create_data(ksp->ks_name, 0644, module->ksm_proc, &proc_kstat_operations, (void *)ksp); if (ksp->ks_proc == NULL) { list_del_init(&ksp->ks_list); From 09f38b7e60eea27637780822f86f80da8938bb1f Mon Sep 17 00:00:00 2001 From: Prakash Surya Date: Tue, 24 Sep 2013 16:11:56 -0700 Subject: [PATCH 2/5] Add wrappers for accessing PID and command info This change adds simple wrappers for accessing a thread's PID and command character string. Signed-off-by: Prakash Surya Signed-off-by: Brian Behlendorf Issue #296 --- include/sys/thread.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sys/thread.h b/include/sys/thread.h index 369b3061d2..864a74bba9 100644 --- a/include/sys/thread.h +++ b/include/sys/thread.h @@ -51,6 +51,8 @@ typedef void (*thread_func_t)(void *); #define thread_exit() __thread_exit() #define thread_join(t) VERIFY(0) #define curthread current +#define getcomm() current->comm +#define getpid() current->pid extern kthread_t *__thread_create(caddr_t stk, size_t stksize, thread_func_t func, const char *name, From ce07767f79c926acdbdf7bb272f05e89820f31c3 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Mon, 30 Sep 2013 11:32:42 -0700 Subject: [PATCH 3/5] Revert "Add KSTAT_TYPE_TXG type" This reverts commit dba79fcbf2cc50be5caef84ae01657e884ac5d89 in favor of using the generic KSTAT_TYPE_RAW callbacks. The advantage of this approach is that arbitrary types can be added without the need to add them to the SPL. Signed-off-by: Brian Behlendorf Issue #296 --- include/sys/kstat.h | 23 +---------------------- module/spl/spl-kstat.c | 39 --------------------------------------- 2 files changed, 1 insertion(+), 61 deletions(-) diff --git a/include/sys/kstat.h b/include/sys/kstat.h index 75b384714c..6e3c0cdfee 100644 --- a/include/sys/kstat.h +++ b/include/sys/kstat.h @@ -44,8 +44,7 @@ #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_TYPE_TXG 5 /* txg sync; ks_ndata >= 1 */ -#define KSTAT_NUM_TYPES 6 +#define KSTAT_NUM_TYPES 5 #define KSTAT_DATA_CHAR 0 #define KSTAT_DATA_INT32 1 @@ -176,26 +175,6 @@ typedef struct kstat_timer { hrtime_t stop_time; /* previous event stop time */ } kstat_timer_t; -typedef enum kstat_txg_state { - TXG_STATE_OPEN = 1, - TXG_STATE_QUIESCING = 2, - TXG_STATE_SYNCING = 3, - TXG_STATE_COMMITTED = 4, -} kstat_txg_state_t; - -typedef struct kstat_txg { - u_longlong_t txg; /* txg id */ - kstat_txg_state_t state; /* txg state */ - hrtime_t birth; /* birth time stamp */ - 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 open_time; /* open time */ - hrtime_t quiesce_time;/* quiesce time */ - hrtime_t sync_time; /* sync time */ -} kstat_txg_t; - int spl_kstat_init(void); void spl_kstat_fini(void); diff --git a/module/spl/spl-kstat.c b/module/spl/spl-kstat.c index 57aabe2d02..ee65f4a77f 100644 --- a/module/spl/spl-kstat.c +++ b/module/spl/spl-kstat.c @@ -106,14 +106,6 @@ restart: "name", "events", "elapsed", "min", "max", "start", "stop"); break; - case KSTAT_TYPE_TXG: - seq_printf(f, - "%-8s %-5s %-13s %-12s %-12s %-8s %-8s " - "%-12s %-12s %-12s\n", - "txg", "state", "birth", - "nread", "nwritten", "reads", "writes", - "otime", "qtime", "stime"); - break; default: PANIC("Undefined kstat type %d\n", ksp->ks_type); } @@ -228,27 +220,6 @@ kstat_seq_show_timer(struct seq_file *f, kstat_timer_t *ktp) return 0; } -static int -kstat_seq_show_txg(struct seq_file *f, kstat_txg_t *ktp) -{ - char state; - - switch (ktp->state) { - case TXG_STATE_OPEN: state = 'O'; break; - case TXG_STATE_QUIESCING: state = 'Q'; break; - case TXG_STATE_SYNCING: state = 'S'; break; - case TXG_STATE_COMMITTED: state = 'C'; break; - default: state = '?'; break; - } - - seq_printf(f, - "%-8llu %-5c %-13llu %-12llu %-12llu %-8u %-8u " - "%12lld %12lld %12lld\n", ktp->txg, state, ktp->birth, - ktp->nread, ktp->nwritten, ktp->reads, ktp->writes, - ktp->open_time, ktp->quiesce_time, ktp->sync_time); - return 0; -} - static int kstat_seq_show(struct seq_file *f, void *p) { @@ -285,9 +256,6 @@ restart: case KSTAT_TYPE_TIMER: rc = kstat_seq_show_timer(f, (kstat_timer_t *)p); break; - case KSTAT_TYPE_TXG: - rc = kstat_seq_show_txg(f, (kstat_txg_t *)p); - break; default: PANIC("Undefined kstat type %d\n", ksp->ks_type); } @@ -331,9 +299,6 @@ kstat_seq_data_addr(kstat_t *ksp, loff_t n) case KSTAT_TYPE_TIMER: rc = ksp->ks_data + n * sizeof(kstat_timer_t); break; - case KSTAT_TYPE_TXG: - rc = ksp->ks_data + n * sizeof(kstat_txg_t); - break; default: PANIC("Undefined kstat type %d\n", ksp->ks_type); } @@ -566,10 +531,6 @@ __kstat_create(const char *ks_module, int ks_instance, const char *ks_name, ksp->ks_ndata = ks_ndata; ksp->ks_data_size = ks_ndata * sizeof(kstat_timer_t); break; - case KSTAT_TYPE_TXG: - ksp->ks_ndata = ks_ndata; - ksp->ks_data_size = ks_ndata * sizeof(kstat_timer_t); - break; default: PANIC("Undefined kstat type %d\n", ksp->ks_type); } From ffbf0e57c2ad9e72ab437c7982f443926cb26325 Mon Sep 17 00:00:00 2001 From: Cyril Plisko Date: Tue, 13 Aug 2013 15:15:36 +0300 Subject: [PATCH 4/5] Kstat to use private lock by default While porting Illumos #3537 I found that ks_lock member of kstat_t structure is different between Illumos and SPL. It is a pointer to the kmutex_t in Illumos, but the mutex lock itself in SPL. Apparently Illumos kstat API allows consumer to override the lock if required. With SPL implementation it is not possible anymore. Things were alright until the first attempt to actually override the lock. Porting of Illumos #3537 introduced such code for the first time. In order to provide the Solaris/Illumos like functionality we: 1. convert ks_lock to "kmutex_t *ks_lock" 2. create a new field "kmutex_t ks_private_lock" 3. On kstat_create() ks_lock = &ks_private_lock Thus if consumer doesn't care we still have our internal lock in use. If, however, consumer does care she has a chance to set ks_lock to anything else before calling kstat_install(). The rest of the code will use ks_lock regardless of its origin. Signed-off-by: Ned Bass Signed-off-by: Brian Behlendorf Issue #286 --- include/sys/kstat.h | 3 ++- module/spl/spl-kstat.c | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/sys/kstat.h b/include/sys/kstat.h index 6e3c0cdfee..97d8596f7d 100644 --- a/include/sys/kstat.h +++ b/include/sys/kstat.h @@ -114,7 +114,8 @@ struct kstat_s { struct proc_dir_entry *ks_proc; /* proc linkage */ kstat_update_t *ks_update; /* dynamic updates */ void *ks_private; /* private data */ - kmutex_t ks_lock; /* kstat data lock */ + 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 */ diff --git a/module/spl/spl-kstat.c b/module/spl/spl-kstat.c index ee65f4a77f..7932678d76 100644 --- a/module/spl/spl-kstat.c +++ b/module/spl/spl-kstat.c @@ -314,7 +314,7 @@ kstat_seq_start(struct seq_file *f, loff_t *pos) ASSERT(ksp->ks_magic == KS_MAGIC); SENTRY; - mutex_enter(&ksp->ks_lock); + mutex_enter(ksp->ks_lock); if (ksp->ks_type == KSTAT_TYPE_RAW) { ksp->ks_raw_bufsize = PAGE_SIZE; @@ -352,13 +352,13 @@ kstat_seq_next(struct seq_file *f, void *p, loff_t *pos) static void kstat_seq_stop(struct seq_file *f, void *v) { - kstat_t *ksp = (kstat_t *)f->private; - ASSERT(ksp->ks_magic == KS_MAGIC); + kstat_t *ksp = (kstat_t *)f->private; + ASSERT(ksp->ks_magic == KS_MAGIC); if (ksp->ks_type == KSTAT_TYPE_RAW) vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize); - mutex_exit(&ksp->ks_lock); + mutex_exit(ksp->ks_lock); } static struct seq_operations kstat_seq_ops = { @@ -491,7 +491,8 @@ __kstat_create(const char *ks_module, int ks_instance, const char *ks_name, mutex_exit(&kstat_module_lock); ksp->ks_magic = KS_MAGIC; - mutex_init(&ksp->ks_lock, NULL, MUTEX_DEFAULT, NULL); + mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL); + ksp->ks_lock = &ksp->ks_private_lock; INIT_LIST_HEAD(&ksp->ks_list); ksp->ks_crtime = gethrtime(); @@ -576,7 +577,7 @@ __kstat_install(kstat_t *ksp) list_add_tail(&ksp->ks_list, &module->ksm_kstat_list); - mutex_enter(&ksp->ks_lock); + mutex_enter(ksp->ks_lock); ksp->ks_owner = module; ksp->ks_proc = proc_create_data(ksp->ks_name, 0644, module->ksm_proc, &proc_kstat_operations, (void *)ksp); @@ -585,7 +586,7 @@ __kstat_install(kstat_t *ksp) if (list_empty(&module->ksm_kstat_list)) kstat_delete_module(module); } - mutex_exit(&ksp->ks_lock); + mutex_exit(ksp->ks_lock); out: mutex_exit(&kstat_module_lock); } @@ -611,7 +612,8 @@ __kstat_delete(kstat_t *ksp) if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL)) kmem_free(ksp->ks_data, ksp->ks_data_size); - mutex_destroy(&ksp->ks_lock); + ksp->ks_lock = NULL; + mutex_destroy(&ksp->ks_private_lock); kmem_free(ksp, sizeof(*ksp)); return; From f483a97a417ca7292d6a7d516a72558d385f2370 Mon Sep 17 00:00:00 2001 From: Ned Bass Date: Mon, 26 Aug 2013 16:42:11 -0700 Subject: [PATCH 5/5] 3537 add kstat_waitq_enter and friends These kstat interfaces are required to port "Illumos #3537 want pool io kstats" to ZFS on Linux. kstat_waitq_enter() kstat_waitq_exit() kstat_runq_enter() kstat_runq_exit() Additionally, zero out the ks_data buffer in __kstat_create() so that the kstat_io_t counters are initialized to zero. Signed-off-by: Brian Behlendorf --- include/sys/kstat.h | 4 +++ module/spl/spl-kstat.c | 68 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/sys/kstat.h b/include/sys/kstat.h index 97d8596f7d..faf6b81dab 100644 --- a/include/sys/kstat.h +++ b/include/sys/kstat.h @@ -189,6 +189,10 @@ extern kstat_t *__kstat_create(const char *ks_module, int ks_instance, uchar_t ks_flags); 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) diff --git a/module/spl/spl-kstat.c b/module/spl/spl-kstat.c index 7932678d76..c604a32f2a 100644 --- a/module/spl/spl-kstat.c +++ b/module/spl/spl-kstat.c @@ -54,6 +54,72 @@ kstat_resize_raw(kstat_t *ksp) return 0; } +void +kstat_waitq_enter(kstat_io_t *kiop) +{ + hrtime_t new, delta; + ulong_t wcnt; + + new = gethrtime(); + delta = new - kiop->wlastupdate; + kiop->wlastupdate = new; + wcnt = kiop->wcnt++; + if (wcnt != 0) { + kiop->wlentime += delta * wcnt; + kiop->wtime += delta; + } +} +EXPORT_SYMBOL(kstat_waitq_enter); + +void +kstat_waitq_exit(kstat_io_t *kiop) +{ + hrtime_t new, delta; + ulong_t wcnt; + + new = gethrtime(); + delta = new - kiop->wlastupdate; + kiop->wlastupdate = new; + wcnt = kiop->wcnt--; + ASSERT((int)wcnt > 0); + kiop->wlentime += delta * wcnt; + kiop->wtime += delta; +} +EXPORT_SYMBOL(kstat_waitq_exit); + +void +kstat_runq_enter(kstat_io_t *kiop) +{ + hrtime_t new, delta; + ulong_t rcnt; + + new = gethrtime(); + delta = new - kiop->rlastupdate; + kiop->rlastupdate = new; + rcnt = kiop->rcnt++; + if (rcnt != 0) { + kiop->rlentime += delta * rcnt; + kiop->rtime += delta; + } +} +EXPORT_SYMBOL(kstat_runq_enter); + +void +kstat_runq_exit(kstat_io_t *kiop) +{ + hrtime_t new, delta; + ulong_t rcnt; + + new = gethrtime(); + delta = new - kiop->rlastupdate; + kiop->rlastupdate = new; + rcnt = kiop->rcnt--; + ASSERT((int)rcnt > 0); + kiop->rlentime += delta * rcnt; + kiop->rtime += delta; +} +EXPORT_SYMBOL(kstat_runq_exit); + static int kstat_seq_show_headers(struct seq_file *f) { @@ -539,7 +605,7 @@ __kstat_create(const char *ks_module, int ks_instance, const char *ks_name, if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL) { ksp->ks_data = NULL; } else { - ksp->ks_data = kmem_alloc(ksp->ks_data_size, KM_SLEEP); + ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP); if (ksp->ks_data == NULL) { kmem_free(ksp, sizeof(*ksp)); ksp = NULL;