#include <linux/seq_file.h>
#include <sys/kstat.h>
-#include <spl-debug.h>
+#include <sys/vmem.h>
+#include <sys/cmn_err.h>
-#ifdef SS_DEBUG_SUBSYS
-#undef SS_DEBUG_SUBSYS
-#endif
-
-#define SS_DEBUG_SUBSYS SS_KSTAT
#ifndef HAVE_PDE_DATA
#define PDE_DATA(x) (PDE(x)->data)
#endif
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)
{
"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);
}
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)
{
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);
}
kstat_seq_data_addr(kstat_t *ksp, loff_t n)
{
void *rc = NULL;
- SENTRY;
switch (ksp->ks_type) {
case KSTAT_TYPE_RAW:
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);
}
- SRETURN(rc);
+ return (rc);
}
static void *
loff_t n = *pos;
kstat_t *ksp = (kstat_t *)f->private;
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;
ksp->ks_snaptime = gethrtime();
if (!n && kstat_seq_show_headers(f))
- SRETURN(NULL);
+ return (NULL);
if (n >= ksp->ks_ndata)
- SRETURN(NULL);
+ return (NULL);
- SRETURN(kstat_seq_data_addr(ksp, n));
+ return (kstat_seq_data_addr(ksp, n));
}
static void *
{
kstat_t *ksp = (kstat_t *)f->private;
ASSERT(ksp->ks_magic == KS_MAGIC);
- SENTRY;
++*pos;
if (*pos >= ksp->ks_ndata)
- SRETURN(NULL);
+ return (NULL);
- SRETURN(kstat_seq_data_addr(ksp, *pos));
+ return (kstat_seq_data_addr(ksp, *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 = {
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();
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);
}
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;
}
EXPORT_SYMBOL(__kstat_create);
+static int
+kstat_detect_collision(kstat_t *ksp)
+{
+ kstat_module_t *module;
+ kstat_t *tmp;
+ char parent[KSTAT_STRLEN+1];
+ char *cp;
+
+ (void) strlcpy(parent, ksp->ks_module, sizeof(parent));
+
+ if ((cp = strrchr(parent, '/')) == NULL)
+ return (0);
+
+ cp[0] = '\0';
+ if ((module = kstat_find_module(parent)) != NULL) {
+ list_for_each_entry(tmp, &module->ksm_kstat_list, ks_list)
+ if (strncmp(tmp->ks_name, cp+1, KSTAT_STRLEN) == 0)
+ return (EEXIST);
+ }
+
+ return (0);
+}
+
void
__kstat_install(kstat_t *ksp)
{
module = kstat_find_module(ksp->ks_module);
if (module == NULL) {
+ if (kstat_detect_collision(ksp) != 0) {
+ cmn_err(CE_WARN, "kstat_create('%s', '%s'): namespace" \
+ " collision", ksp->ks_module, ksp->ks_name);
+ goto out;
+ }
module = kstat_create_module(ksp->ks_module);
if (module == NULL)
goto out;
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);
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);
}
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;
int
spl_kstat_init(void)
{
- SENTRY;
mutex_init(&kstat_module_lock, NULL, MUTEX_DEFAULT, NULL);
INIT_LIST_HEAD(&kstat_module_list);
kstat_id = 0;
- SRETURN(0);
+ return (0);
}
void
spl_kstat_fini(void)
{
- SENTRY;
ASSERT(list_empty(&kstat_module_list));
mutex_destroy(&kstat_module_lock);
- SEXIT;
}