summaryrefslogtreecommitdiffstats
path: root/fs/xfs/support/ktrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/support/ktrace.c')
-rw-r--r--fs/xfs/support/ktrace.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/fs/xfs/support/ktrace.c b/fs/xfs/support/ktrace.c
new file mode 100644
index 00000000000..3dae14c8c55
--- /dev/null
+++ b/fs/xfs/support/ktrace.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+
+static kmem_zone_t *ktrace_hdr_zone;
+static kmem_zone_t *ktrace_ent_zone;
+static int ktrace_zentries;
+
+void
+ktrace_init(int zentries)
+{
+ ktrace_zentries = zentries;
+
+ ktrace_hdr_zone = kmem_zone_init(sizeof(ktrace_t),
+ "ktrace_hdr");
+ ASSERT(ktrace_hdr_zone);
+
+ ktrace_ent_zone = kmem_zone_init(ktrace_zentries
+ * sizeof(ktrace_entry_t),
+ "ktrace_ent");
+ ASSERT(ktrace_ent_zone);
+}
+
+void
+ktrace_uninit(void)
+{
+ kmem_cache_destroy(ktrace_hdr_zone);
+ kmem_cache_destroy(ktrace_ent_zone);
+}
+
+/*
+ * ktrace_alloc()
+ *
+ * Allocate a ktrace header and enough buffering for the given
+ * number of entries.
+ */
+ktrace_t *
+ktrace_alloc(int nentries, int sleep)
+{
+ ktrace_t *ktp;
+ ktrace_entry_t *ktep;
+
+ ktp = (ktrace_t*)kmem_zone_alloc(ktrace_hdr_zone, sleep);
+
+ if (ktp == (ktrace_t*)NULL) {
+ /*
+ * KM_SLEEP callers don't expect failure.
+ */
+ if (sleep & KM_SLEEP)
+ panic("ktrace_alloc: NULL memory on KM_SLEEP request!");
+
+ return NULL;
+ }
+
+ /*
+ * Special treatment for buffers with the ktrace_zentries entries
+ */
+ if (nentries == ktrace_zentries) {
+ ktep = (ktrace_entry_t*)kmem_zone_zalloc(ktrace_ent_zone,
+ sleep);
+ } else {
+ ktep = (ktrace_entry_t*)kmem_zalloc((nentries * sizeof(*ktep)),
+ sleep);
+ }
+
+ if (ktep == NULL) {
+ /*
+ * KM_SLEEP callers don't expect failure.
+ */
+ if (sleep & KM_SLEEP)
+ panic("ktrace_alloc: NULL memory on KM_SLEEP request!");
+
+ kmem_free(ktp, sizeof(*ktp));
+
+ return NULL;
+ }
+
+ spinlock_init(&(ktp->kt_lock), "kt_lock");
+
+ ktp->kt_entries = ktep;
+ ktp->kt_nentries = nentries;
+ ktp->kt_index = 0;
+ ktp->kt_rollover = 0;
+ return ktp;
+}
+
+
+/*
+ * ktrace_free()
+ *
+ * Free up the ktrace header and buffer. It is up to the caller
+ * to ensure that no-one is referencing it.
+ */
+void
+ktrace_free(ktrace_t *ktp)
+{
+ int entries_size;
+
+ if (ktp == (ktrace_t *)NULL)
+ return;
+
+ spinlock_destroy(&ktp->kt_lock);
+
+ /*
+ * Special treatment for the Vnode trace buffer.
+ */
+ if (ktp->kt_nentries == ktrace_zentries) {
+ kmem_zone_free(ktrace_ent_zone, ktp->kt_entries);
+ } else {
+ entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t));
+
+ kmem_free(ktp->kt_entries, entries_size);
+ }
+
+ kmem_zone_free(ktrace_hdr_zone, ktp);
+}
+
+
+/*
+ * Enter the given values into the "next" entry in the trace buffer.
+ * kt_index is always the index of the next entry to be filled.
+ */
+void
+ktrace_enter(
+ ktrace_t *ktp,
+ void *val0,
+ void *val1,
+ void *val2,
+ void *val3,
+ void *val4,
+ void *val5,
+ void *val6,
+ void *val7,
+ void *val8,
+ void *val9,
+ void *val10,
+ void *val11,
+ void *val12,
+ void *val13,
+ void *val14,
+ void *val15)
+{
+ static lock_t wrap_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long flags;
+ int index;
+ ktrace_entry_t *ktep;
+
+ ASSERT(ktp != NULL);
+
+ /*
+ * Grab an entry by pushing the index up to the next one.
+ */
+ spin_lock_irqsave(&wrap_lock, flags);
+ index = ktp->kt_index;
+ if (++ktp->kt_index == ktp->kt_nentries)
+ ktp->kt_index = 0;
+ spin_unlock_irqrestore(&wrap_lock, flags);
+
+ if (!ktp->kt_rollover && index == ktp->kt_nentries - 1)
+ ktp->kt_rollover = 1;
+
+ ASSERT((index >= 0) && (index < ktp->kt_nentries));
+
+ ktep = &(ktp->kt_entries[index]);
+
+ ktep->val[0] = val0;
+ ktep->val[1] = val1;
+ ktep->val[2] = val2;
+ ktep->val[3] = val3;
+ ktep->val[4] = val4;
+ ktep->val[5] = val5;
+ ktep->val[6] = val6;
+ ktep->val[7] = val7;
+ ktep->val[8] = val8;
+ ktep->val[9] = val9;
+ ktep->val[10] = val10;
+ ktep->val[11] = val11;
+ ktep->val[12] = val12;
+ ktep->val[13] = val13;
+ ktep->val[14] = val14;
+ ktep->val[15] = val15;
+}
+
+/*
+ * Return the number of entries in the trace buffer.
+ */
+int
+ktrace_nentries(
+ ktrace_t *ktp)
+{
+ if (ktp == NULL) {
+ return 0;
+ }
+
+ return (ktp->kt_rollover ? ktp->kt_nentries : ktp->kt_index);
+}
+
+/*
+ * ktrace_first()
+ *
+ * This is used to find the start of the trace buffer.
+ * In conjunction with ktrace_next() it can be used to
+ * iterate through the entire trace buffer. This code does
+ * not do any locking because it is assumed that it is called
+ * from the debugger.
+ *
+ * The caller must pass in a pointer to a ktrace_snap
+ * structure in which we will keep some state used to
+ * iterate through the buffer. This state must not touched
+ * by any code outside of this module.
+ */
+ktrace_entry_t *
+ktrace_first(ktrace_t *ktp, ktrace_snap_t *ktsp)
+{
+ ktrace_entry_t *ktep;
+ int index;
+ int nentries;
+
+ if (ktp->kt_rollover)
+ index = ktp->kt_index;
+ else
+ index = 0;
+
+ ktsp->ks_start = index;
+ ktep = &(ktp->kt_entries[index]);
+
+ nentries = ktrace_nentries(ktp);
+ index++;
+ if (index < nentries) {
+ ktsp->ks_index = index;
+ } else {
+ ktsp->ks_index = 0;
+ if (index > nentries)
+ ktep = NULL;
+ }
+ return ktep;
+}
+
+/*
+ * ktrace_next()
+ *
+ * This is used to iterate through the entries of the given
+ * trace buffer. The caller must pass in the ktrace_snap_t
+ * structure initialized by ktrace_first(). The return value
+ * will be either a pointer to the next ktrace_entry or NULL
+ * if all of the entries have been traversed.
+ */
+ktrace_entry_t *
+ktrace_next(
+ ktrace_t *ktp,
+ ktrace_snap_t *ktsp)
+{
+ int index;
+ ktrace_entry_t *ktep;
+
+ index = ktsp->ks_index;
+ if (index == ktsp->ks_start) {
+ ktep = NULL;
+ } else {
+ ktep = &ktp->kt_entries[index];
+ }
+
+ index++;
+ if (index == ktrace_nentries(ktp)) {
+ ktsp->ks_index = 0;
+ } else {
+ ktsp->ks_index = index;
+ }
+
+ return ktep;
+}
+
+/*
+ * ktrace_skip()
+ *
+ * Skip the next "count" entries and return the entry after that.
+ * Return NULL if this causes us to iterate past the beginning again.
+ */
+ktrace_entry_t *
+ktrace_skip(
+ ktrace_t *ktp,
+ int count,
+ ktrace_snap_t *ktsp)
+{
+ int index;
+ int new_index;
+ ktrace_entry_t *ktep;
+ int nentries = ktrace_nentries(ktp);
+
+ index = ktsp->ks_index;
+ new_index = index + count;
+ while (new_index >= nentries) {
+ new_index -= nentries;
+ }
+ if (index == ktsp->ks_start) {
+ /*
+ * We've iterated around to the start, so we're done.
+ */
+ ktep = NULL;
+ } else if ((new_index < index) && (index < ktsp->ks_index)) {
+ /*
+ * We've skipped past the start again, so we're done.
+ */
+ ktep = NULL;
+ ktsp->ks_index = ktsp->ks_start;
+ } else {
+ ktep = &(ktp->kt_entries[new_index]);
+ new_index++;
+ if (new_index == nentries) {
+ ktsp->ks_index = 0;
+ } else {
+ ktsp->ks_index = new_index;
+ }
+ }
+ return ktep;
+}