summaryrefslogtreecommitdiffstats
path: root/include/sys/debug.h
diff options
context:
space:
mode:
authorbehlendo <behlendo@7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c>2008-04-18 23:39:58 +0000
committerbehlendo <behlendo@7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c>2008-04-18 23:39:58 +0000
commit57d1b1885897c9b079a6355a6d54d684ad003d46 (patch)
tree941352e2acfedadd3b97f0af780a2a7a2e910540 /include/sys/debug.h
parent55152ebbb46fb8e382ed18e58cc570c61e224c21 (diff)
First commit of lustre style internal debug support. These
changes bring over everything lustre had for debugging with two exceptions. I dropped by the debug daemon and upcalls just because it made things a little easier. They can be readded easily enough if we feel they are needed. Everything compiles and seems to work on first inspection but I suspect there are a handful of issues still lingering which I'll be sorting out right away. I just wanted to get all these changes commited and safe. I'm getting a little paranoid about losing them. git-svn-id: https://outreach.scidac.gov/svn/spl/trunk@75 7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c
Diffstat (limited to 'include/sys/debug.h')
-rw-r--r--include/sys/debug.h313
1 files changed, 310 insertions, 3 deletions
diff --git a/include/sys/debug.h b/include/sys/debug.h
index 4a6ed5c3d..a670c0374 100644
--- a/include/sys/debug.h
+++ b/include/sys/debug.h
@@ -1,11 +1,318 @@
#ifndef _SPL_DEBUG_H
#define _SPL_DEBUG_H
+#include <linux/sched.h> /* THREAD_SIZE */
+#include <linux/proc_fs.h>
+
extern unsigned long spl_debug_mask;
extern unsigned long spl_debug_subsys;
-void __dprintf(const char *file, const char *func, int line, const char *fmt, ...);
-void spl_set_debug_mask(unsigned long mask);
-void spl_set_debug_subsys(unsigned long mask);
+#define S_UNDEFINED 0x00000001
+#define S_ATOMIC 0x00000002
+#define S_KOBJ 0x00000004
+#define S_VNODE 0x00000008
+#define S_TIME 0x00000010
+#define S_RWLOCK 0x00000020
+#define S_THREAD 0x00000040
+#define S_CONDVAR 0x00000080
+#define S_MUTEX 0x00000100
+#define S_RNG 0x00000200
+#define S_TASKQ 0x00000400
+#define S_KMEM 0x00000800
+#define S_DEBUG 0x00001000
+#define S_GENERIC 0x00002000
+#define S_PROC 0x00004000
+
+#define D_TRACE 0x00000001
+#define D_INFO 0x00000002
+#define D_WARNING 0x00000004
+#define D_ERROR 0x00000008
+#define D_EMERG 0x00000010
+#define D_CONSOLE 0x00000020
+#define D_IOCTL 0x00000040
+#define D_DPRINTF 0x00000080
+#define D_OTHER 0x00000100
+
+#define D_CANTMASK (D_ERROR | D_EMERG | D_WARNING | D_CONSOLE)
+#define DEBUG_SUBSYSTEM S_UNDEFINED
+
+int debug_init(void);
+void debug_fini(void);
+int spl_debug_mask2str(char *str, int size, unsigned long mask, int is_subsys);
+int spl_debug_str2mask(unsigned long *mask, const char *str, int is_subsys);
+
+extern unsigned long spl_debug_subsys;
+extern unsigned long spl_debug_mask;
+extern unsigned long spl_debug_printk;
+extern int spl_debug_mb;
+extern unsigned int spl_debug_binary;
+extern unsigned int spl_debug_catastrophe;
+extern unsigned int spl_debug_panic_on_bug;
+extern char spl_debug_file_path[PATH_MAX];
+extern unsigned int spl_console_ratelimit;
+extern long spl_console_max_delay;
+extern long spl_console_min_delay;
+extern unsigned int spl_console_backoff;
+extern unsigned int spl_debug_stack;
+
+#define TCD_MAX_PAGES (5 << (20 - PAGE_SHIFT))
+#define TCD_STOCK_PAGES (TCD_MAX_PAGES)
+#define TRACE_CONSOLE_BUFFER_SIZE 1024
+
+#define SPL_DEFAULT_MAX_DELAY (600 * HZ)
+#define SPL_DEFAULT_MIN_DELAY ((HZ + 1) / 2)
+#define SPL_DEFAULT_BACKOFF 2
+
+typedef struct {
+ unsigned long cdls_next;
+ int cdls_count;
+ long cdls_delay;
+} spl_debug_limit_state_t;
+
+/* Three trace data types */
+typedef enum {
+ TCD_TYPE_PROC,
+ TCD_TYPE_SOFTIRQ,
+ TCD_TYPE_IRQ,
+ TCD_TYPE_MAX
+} tcd_type_t;
+
+union trace_data_union {
+ struct trace_cpu_data {
+ /* pages with trace records not yet processed by tracefiled */
+ struct list_head tcd_pages;
+ /* number of pages on ->tcd_pages */
+ unsigned long tcd_cur_pages;
+ /* Max number of pages allowed on ->tcd_pages */
+ unsigned long tcd_max_pages;
+
+ /*
+ * preallocated pages to write trace records into. Pages from
+ * ->tcd_stock_pages are moved to ->tcd_pages by spl_debug_msg().
+ *
+ * This list is necessary, because on some platforms it's
+ * impossible to perform efficient atomic page allocation in a
+ * non-blockable context.
+ *
+ * Such platforms fill ->tcd_stock_pages "on occasion", when
+ * tracing code is entered in blockable context.
+ *
+ * trace_get_tage_try() tries to get a page from
+ * ->tcd_stock_pages first and resorts to atomic page
+ * allocation only if this queue is empty. ->tcd_stock_pages
+ * is replenished when tracing code is entered in blocking
+ * context (darwin-tracefile.c:trace_get_tcd()). We try to
+ * maintain TCD_STOCK_PAGES (40 by default) pages in this
+ * queue. Atomic allocation is only required if more than
+ * TCD_STOCK_PAGES pagesful are consumed by trace records all
+ * emitted in non-blocking contexts. Which is quite unlikely.
+ */
+ struct list_head tcd_stock_pages;
+ /* number of pages on ->tcd_stock_pages */
+ unsigned long tcd_cur_stock_pages;
+
+ unsigned short tcd_shutting_down;
+ unsigned short tcd_cpu;
+ unsigned short tcd_type;
+ /* The factors to share debug memory. */
+ unsigned short tcd_pages_factor;
+ } tcd;
+ char __pad[L1_CACHE_ALIGN(sizeof(struct trace_cpu_data))];
+};
+
+extern union trace_data_union (*trace_data[TCD_TYPE_MAX])[NR_CPUS];
+
+#define tcd_for_each(tcd, i, j) \
+ for (i = 0; trace_data[i] != NULL; i++) \
+ for (j = 0, ((tcd) = &(*trace_data[i])[j].tcd); \
+ j < num_possible_cpus(); j++, (tcd) = &(*trace_data[i])[j].tcd)
+
+#define tcd_for_each_type_lock(tcd, i) \
+ for (i = 0; trace_data[i] && \
+ (tcd = &(*trace_data[i])[smp_processor_id()].tcd) && \
+ trace_lock_tcd(tcd); trace_unlock_tcd(tcd), i++)
+
+struct trace_page {
+ struct page * page; /* page itself */
+ struct list_head linkage; /* Used by lists in trace_data_union */
+ unsigned int used; /* number of bytes used within this page */
+ unsigned short cpu; /* cpu that owns this page */
+ unsigned short type; /* type(context) of this page */
+};
+
+struct page_collection {
+ struct list_head pc_pages;
+ spinlock_t pc_lock;
+ int pc_want_daemon_pages;
+};
+
+/* ASSERTION that is safe to use within the debug system */
+#define __ASSERT(cond) \
+do { \
+ if (unlikely(!(cond))) { \
+ printk(KERN_ERR "ASSERTION("#cond") failed"); \
+ BUG(); \
+ } \
+} while (0)
+
+#define __ASSERT_TAGE_INVARIANT(tage) \
+do { \
+ __ASSERT(tage != NULL); \
+ __ASSERT(tage->page != NULL); \
+ __ASSERT(tage->used <= PAGE_SIZE); \
+ __ASSERT(page_count(tage->page) > 0); \
+} while(0)
+
+/* ASSERTION that will debug log used outside the debug sysytem */
+#define ASSERT(cond) \
+do { \
+ if (unlikely(!(cond))) { \
+ spl_debug_msg(NULL, DEBUG_SUBSYSTEM, D_EMERG, \
+ __FILE__, __FUNCTION__, __LINE__, \
+ "ASSERTION(" #cond ") failed\n"); \
+ spl_debug_bug(__FILE__, __FUNCTION__, __LINE__); \
+ } \
+} while (0)
+
+#define ASSERTF(cond, fmt, a...) \
+do { \
+ if (unlikely(!(cond))) { \
+ spl_debug_msg(NULL, DEBUG_SUBSYSTEM, D_EMERG, \
+ __FILE__, __FUNCTION__, __LINE__, \
+ "ASSERTION(" #cond ") failed:" fmt, \
+ ## a); \
+ spl_debug_bug(__FILE__, __FUNCTION__, __LINE__) \
+ } \
+} while (0)
+
+#define VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE, FMT, CAST) \
+do { \
+ const TYPE __left = (TYPE)(LEFT); \
+ const TYPE __right = (TYPE)(RIGHT); \
+ if (!(__left OP __right)) { \
+ spl_debug_msg(NULL, DEBUG_SUBSYSTEM, D_EMERG, \
+ __FILE__, __FUNCTION__, __LINE__, \
+ "VERIFY3(" FMT " " #OP " " FMT ")\n", \
+ CAST __left, CAST __right); \
+ spl_debug_bug(__FILE__, __FUNCTION__, __LINE__) \
+ } \
+} while (0)
+
+#define VERIFY3S(x,y,z) VERIFY3_IMPL(x, y, z, int64_t, "%ld", (long))
+#define VERIFY3U(x,y,z) VERIFY3_IMPL(x, y, z, uint64_t, "%lu", (unsigned long))
+#define VERIFY3P(x,y,z) VERIFY3_IMPL(x, y, z, uintptr_t, "%p", (void *))
+
+#define ASSERT3S(x,y,z) VERIFY3S(x, y, z)
+#define ASSERT3U(x,y,z) VERIFY3U(x, y, z)
+#define ASSERT3P(x,y,z) VERIFY3P(x, y, z)
+
+#define VERIFY(x) ASSERT(x)
+#define SBUG() spl_debug_bug(__FILE__, __FUNCTION__, __LINE__);
+
+#define spl_debug_msg(cdls, subsys, mask, file, fn, line, format, a...) \
+ spl_debug_vmsg(cdls, subsys, mask, file, fn, \
+ line, NULL, NULL, format, ##a)
+
+#ifdef __ia64__
+#define CDEBUG_STACK() (THREAD_SIZE - \
+ ((unsigned long)__builtin_dwarf_cfa() & \
+ (THREAD_SIZE - 1)))
+#else
+#define CDEBUG_STACK() (THREAD_SIZE - \
+ ((unsigned long)__builtin_frame_address(0) & \
+ (THREAD_SIZE - 1)))
+# endif /* __ia64__ */
+
+#define __CHECK_STACK(file, func, line) \
+do { \
+ unsigned long _stack = CDEBUG_STACK(); \
+ \
+ if (_stack > (3*THREAD_SIZE/4) && _stack > spl_debug_stack) { \
+ spl_debug_stack = _stack; \
+ spl_debug_msg(NULL, D_TRACE, D_WARNING, \
+ file, func, line, \
+ "Exceeded maximum safe stack " \
+ "%lu/%lu\n", _stack, THREAD_SIZE); \
+ __ASSERT(0); \
+ } \
+} while (0)
+
+#define CHECK_STACK()__CHECK_STACK(__FILE__, __func__, __LINE__)
+
+#define __CDEBUG(cdls, subsys, mask, format, a...) \
+do { \
+ CHECK_STACK(); \
+ \
+ if (((mask) & D_CANTMASK) != 0 || \
+ ((spl_debug_mask & (mask)) != 0 && \
+ (spl_debug_subsys & (subsys)) != 0)) \
+ spl_debug_msg(cdls, subsys, mask, \
+ __FILE__, __FUNCTION__, __LINE__, \
+ format, ## a); \
+} while (0)
+
+#define CDEBUG(mask, format, a...) \
+ __CDEBUG(NULL, DEBUG_SUBSYSTEM, mask, format, ## a)
+
+#define __CDEBUG_LIMIT(subsys, mask, format, a...) \
+do { \
+ static spl_debug_limit_state_t cdls; \
+ \
+ __CDEBUG(&cdls, subsys, mask, format, ## a); \
+} while (0)
+
+#define CDEBUG_LIMIT(mask, format, a...) \
+ __CDEBUG_LIMIT(DEBUG_SUBSYSTEM, mask, format, ## a)
+
+#define dprintf(fmt, a...) CDEBUG_LIMIT(D_INFO, fmt, ## a)
+#define CWARN(fmt, a...) CDEBUG_LIMIT(D_WARNING, fmt, ## a)
+#define CERROR(fmt, a...) CDEBUG_LIMIT(D_ERROR, fmt, ## a)
+#define CEMERG(fmt, a...) CDEBUG_LIMIT(D_EMERG, fmt, ## a)
+#define CONSOLE(mask, fmt, a...) CDEBUG(D_CONSOLE | (mask), fmt, ## a)
+
+#define GOTO(label, rc) \
+do { \
+ long GOTO__ret = (long)(rc); \
+ CDEBUG(D_TRACE,"Process leaving via %s (rc=%lu : %ld : %lx)\n", \
+ #label, (unsigned long)GOTO__ret, (signed long)GOTO__ret,\
+ (signed long)GOTO__ret); \
+ goto label; \
+} while (0)
+
+#define RETURN(rc) \
+do { \
+ typeof(rc) RETURN__ret = (rc); \
+ CDEBUG(D_TRACE, "Process leaving (rc=%lu : %ld : %lx)\n", \
+ (long)RETURN__ret, (long)RETURN__ret, (long)RETURN__ret);\
+ return RETURN__ret; \
+} while (0)
+
+#define ENTRY \
+do { \
+ CDEBUG(D_TRACE, "Process entered\n"); \
+} while (0)
+
+#define EXIT \
+do { \
+ CDEBUG(D_TRACE, "Process leaving\n"); \
+} while(0)
+
+extern int spl_debug_vmsg(spl_debug_limit_state_t *cdls, int subsys, int mask,
+ const char *file, const char *fn, const int line,
+ const char *format1, va_list args, const char *format2, ...);
+
+extern unsigned long spl_debug_set_mask(unsigned long mask);
+extern unsigned long spl_debug_get_mask(void);
+extern unsigned long spl_debug_set_subsys(unsigned long mask);
+extern unsigned long spl_debug_get_subsys(void);
+extern int spl_debug_set_mb(int mb);
+extern int spl_debug_get_mb(void);
+
+extern int spl_debug_dumplog(void);
+extern void spl_debug_dumpstack(struct task_struct *tsk);
+extern void spl_debug_bug(char *file, const char *func, const int line);
+
+extern int spl_debug_clear_buffer(void);
+extern int spl_debug_mark_buffer(char *text);
#endif /* SPL_DEBUG_H */