X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=module%2Fzfs%2Fzfs_debug.c;h=b5f93fd9bebb4cb31136e89c7470de8850b6bc5d;hb=d12614521a;hp=e1675c818a7d4ccddbbdc401f7462de8618175a7;hpb=0b39b9f96f1170523ad6e4a3e8319198a574de27;p=mirror_zfs.git diff --git a/module/zfs/zfs_debug.c b/module/zfs/zfs_debug.c index e1675c818..b5f93fd9b 100644 --- a/module/zfs/zfs_debug.c +++ b/module/zfs/zfs_debug.c @@ -25,98 +25,206 @@ #include -list_t zfs_dbgmsgs; -int zfs_dbgmsg_size; -kmutex_t zfs_dbgmsgs_lock; +typedef struct zfs_dbgmsg { + procfs_list_node_t zdm_node; + time_t zdm_timestamp; + int zdm_size; + char zdm_msg[1]; /* variable length allocation */ +} zfs_dbgmsg_t; + +procfs_list_t zfs_dbgmsgs; +int zfs_dbgmsg_size = 0; int zfs_dbgmsg_maxsize = 4<<20; /* 4MB */ +/* + * Internal ZFS debug messages are enabled by default. + * + * # Print debug messages + * cat /proc/spl/kstat/zfs/dbgmsg + * + * # Disable the kernel debug message log. + * echo 0 > /sys/module/zfs/parameters/zfs_dbgmsg_enable + * + * # Clear the kernel debug message log. + * echo 0 >/proc/spl/kstat/zfs/dbgmsg + */ +int zfs_dbgmsg_enable = 1; + +static int +zfs_dbgmsg_show_header(struct seq_file *f) +{ + seq_printf(f, "%-12s %-8s\n", "timestamp", "message"); + return (0); +} + +static int +zfs_dbgmsg_show(struct seq_file *f, void *p) +{ + zfs_dbgmsg_t *zdm = (zfs_dbgmsg_t *)p; + seq_printf(f, "%-12llu %-s\n", + (u_longlong_t)zdm->zdm_timestamp, zdm->zdm_msg); + return (0); +} + +static void +zfs_dbgmsg_purge(int max_size) +{ + while (zfs_dbgmsg_size > max_size) { + zfs_dbgmsg_t *zdm = list_remove_head(&zfs_dbgmsgs.pl_list); + if (zdm == NULL) + return; + + int size = zdm->zdm_size; + kmem_free(zdm, size); + zfs_dbgmsg_size -= size; + } +} + +static int +zfs_dbgmsg_clear(procfs_list_t *procfs_list) +{ + mutex_enter(&zfs_dbgmsgs.pl_lock); + zfs_dbgmsg_purge(0); + mutex_exit(&zfs_dbgmsgs.pl_lock); + return (0); +} + void zfs_dbgmsg_init(void) { - list_create(&zfs_dbgmsgs, sizeof (zfs_dbgmsg_t), + procfs_list_install("zfs", + "dbgmsg", + &zfs_dbgmsgs, + zfs_dbgmsg_show, + zfs_dbgmsg_show_header, + zfs_dbgmsg_clear, offsetof(zfs_dbgmsg_t, zdm_node)); - mutex_init(&zfs_dbgmsgs_lock, NULL, MUTEX_DEFAULT, NULL); } void zfs_dbgmsg_fini(void) { - zfs_dbgmsg_t *zdm; + procfs_list_uninstall(&zfs_dbgmsgs); + zfs_dbgmsg_purge(0); - while ((zdm = list_remove_head(&zfs_dbgmsgs)) != NULL) { - int size = sizeof (zfs_dbgmsg_t) + strlen(zdm->zdm_msg); - kmem_free(zdm, size); - zfs_dbgmsg_size -= size; - } - mutex_destroy(&zfs_dbgmsgs_lock); - ASSERT0(zfs_dbgmsg_size); + /* + * TODO - decide how to make this permanent + */ +#ifdef _KERNEL + procfs_list_destroy(&zfs_dbgmsgs); +#endif } -/* - * To get this data enable the zfs__dbgmsg tracepoint as shown: - * - * # Enable zfs__dbgmsg tracepoint, clear the tracepoint ring buffer - * $ echo 1 > /sys/kernel/debug/tracing/events/zfs/enable - * $ echo 0 > /sys/kernel/debug/tracing/trace - * - * # Dump the ring buffer. - * $ cat /sys/kernel/debug/tracing/trace - */ void -zfs_dbgmsg(const char *fmt, ...) +__set_error(const char *file, const char *func, int line, int err) +{ + /* + * To enable this: + * + * $ echo 512 >/sys/module/zfs/parameters/zfs_flags + */ + if (zfs_flags & ZFS_DEBUG_SET_ERROR) + __dprintf(file, func, line, "error %lu", err); +} + +#ifdef _KERNEL +static void +__zfs_dbgmsg(char *buf) { - int size; + int size = sizeof (zfs_dbgmsg_t) + strlen(buf); + zfs_dbgmsg_t *zdm = kmem_zalloc(size, KM_SLEEP); + zdm->zdm_size = size; + zdm->zdm_timestamp = gethrestime_sec(); + strcpy(zdm->zdm_msg, buf); + + mutex_enter(&zfs_dbgmsgs.pl_lock); + procfs_list_add(&zfs_dbgmsgs, zdm); + zfs_dbgmsg_size += size; + zfs_dbgmsg_purge(MAX(zfs_dbgmsg_maxsize, 0)); + mutex_exit(&zfs_dbgmsgs.pl_lock); +} + +void +__dprintf(const char *file, const char *func, int line, const char *fmt, ...) +{ + const char *newfile; va_list adx; + size_t size; + char *buf; char *nl; - zfs_dbgmsg_t *zdm; + int i; - va_start(adx, fmt); - size = vsnprintf(NULL, 0, fmt, adx); - va_end(adx); + size = 1024; + buf = kmem_alloc(size, KM_SLEEP); /* - * There is one byte of string in sizeof (zfs_dbgmsg_t), used - * for the terminating null. + * Get rid of annoying prefix to filename. */ - zdm = kmem_alloc(sizeof (zfs_dbgmsg_t) + size, KM_PUSHPAGE); - zdm->zdm_timestamp = gethrestime_sec(); + newfile = strrchr(file, '/'); + if (newfile != NULL) { + newfile = newfile + 1; /* Get rid of leading / */ + } else { + newfile = file; + } - va_start(adx, fmt); - (void) vsnprintf(zdm->zdm_msg, size + 1, fmt, adx); - va_end(adx); + i = snprintf(buf, size, "%s:%d:%s(): ", newfile, line, func); + + if (i < size) { + va_start(adx, fmt); + (void) vsnprintf(buf + i, size - i, fmt, adx); + va_end(adx); + } /* * Get rid of trailing newline. */ - nl = strrchr(zdm->zdm_msg, '\n'); + nl = strrchr(buf, '\n'); if (nl != NULL) *nl = '\0'; - DTRACE_PROBE1(zfs__dbgmsg, char *, zdm->zdm_msg); + /* + * To get this data enable the zfs__dprintf trace point as shown: + * + * # Enable zfs__dprintf tracepoint, clear the tracepoint ring buffer + * $ echo 1 > /sys/kernel/debug/tracing/events/zfs/enable + * $ echo 0 > /sys/kernel/debug/tracing/trace + * + * # Dump the ring buffer. + * $ cat /sys/kernel/debug/tracing/trace + */ + DTRACE_PROBE1(zfs__dprintf, char *, buf); - mutex_enter(&zfs_dbgmsgs_lock); - list_insert_tail(&zfs_dbgmsgs, zdm); - zfs_dbgmsg_size += sizeof (zfs_dbgmsg_t) + size; - while (zfs_dbgmsg_size > zfs_dbgmsg_maxsize) { - zdm = list_remove_head(&zfs_dbgmsgs); - size = sizeof (zfs_dbgmsg_t) + strlen(zdm->zdm_msg); - kmem_free(zdm, size); - zfs_dbgmsg_size -= size; - } - mutex_exit(&zfs_dbgmsgs_lock); + /* + * To get this data: + * + * $ cat /proc/spl/kstat/zfs/dbgmsg + * + * To clear the buffer: + * $ echo 0 > /proc/spl/kstat/zfs/dbgmsg + */ + __zfs_dbgmsg(buf); + + kmem_free(buf, size); } +#else + void zfs_dbgmsg_print(const char *tag) { -#if !defined(_KERNEL) - zfs_dbgmsg_t *zdm; - (void) printf("ZFS_DBGMSG(%s):\n", tag); - mutex_enter(&zfs_dbgmsgs_lock); - for (zdm = list_head(&zfs_dbgmsgs); zdm; - zdm = list_next(&zfs_dbgmsgs, zdm)) + mutex_enter(&zfs_dbgmsgs.pl_lock); + for (zfs_dbgmsg_t *zdm = list_head(&zfs_dbgmsgs.pl_list); zdm != NULL; + zdm = list_next(&zfs_dbgmsgs.pl_list, zdm)) (void) printf("%s\n", zdm->zdm_msg); - mutex_exit(&zfs_dbgmsgs_lock); -#endif /* !_KERNEL */ + mutex_exit(&zfs_dbgmsgs.pl_lock); } +#endif /* _KERNEL */ + +#ifdef _KERNEL +module_param(zfs_dbgmsg_enable, int, 0644); +MODULE_PARM_DESC(zfs_dbgmsg_enable, "Enable ZFS debug message log"); + +module_param(zfs_dbgmsg_maxsize, int, 0644); +MODULE_PARM_DESC(zfs_dbgmsg_maxsize, "Maximum ZFS debug log size"); +#endif