Path: blob/main/sys/contrib/openzfs/module/os/linux/zfs/zfs_debug.c
48774 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.23* Copyright (c) 2012, 2014 by Delphix. All rights reserved.24*/2526#include <sys/zfs_context.h>27#include <sys/trace_zfs.h>2829typedef struct zfs_dbgmsg {30procfs_list_node_t zdm_node;31uint64_t zdm_timestamp;32uint_t zdm_size;33char zdm_msg[]; /* variable length allocation */34} zfs_dbgmsg_t;3536static procfs_list_t zfs_dbgmsgs;37static uint_t zfs_dbgmsg_size = 0;38static uint_t zfs_dbgmsg_maxsize = 4<<20; /* 4MB */3940/*41* Internal ZFS debug messages are enabled by default.42*43* # Print debug messages44* cat /proc/spl/kstat/zfs/dbgmsg45*46* # Disable the kernel debug message log.47* echo 0 > /sys/module/zfs/parameters/zfs_dbgmsg_enable48*49* # Clear the kernel debug message log.50* echo 0 >/proc/spl/kstat/zfs/dbgmsg51*/52int zfs_dbgmsg_enable = B_TRUE;5354static int55zfs_dbgmsg_show_header(struct seq_file *f)56{57seq_printf(f, "%-12s %-8s\n", "timestamp", "message");58return (0);59}6061static int62zfs_dbgmsg_show(struct seq_file *f, void *p)63{64zfs_dbgmsg_t *zdm = (zfs_dbgmsg_t *)p;65seq_printf(f, "%-12llu %-s\n",66(u_longlong_t)zdm->zdm_timestamp, zdm->zdm_msg);67return (0);68}6970static void71zfs_dbgmsg_purge(uint_t max_size)72{73while (zfs_dbgmsg_size > max_size) {74zfs_dbgmsg_t *zdm = list_remove_head(&zfs_dbgmsgs.pl_list);75if (zdm == NULL)76return;7778uint_t size = zdm->zdm_size;79kmem_free(zdm, size);80zfs_dbgmsg_size -= size;81}82}8384static int85zfs_dbgmsg_clear(procfs_list_t *procfs_list)86{87(void) procfs_list;88mutex_enter(&zfs_dbgmsgs.pl_lock);89zfs_dbgmsg_purge(0);90mutex_exit(&zfs_dbgmsgs.pl_lock);91return (0);92}9394void95zfs_dbgmsg_init(void)96{97procfs_list_install("zfs",98NULL,99"dbgmsg",1000600,101&zfs_dbgmsgs,102zfs_dbgmsg_show,103zfs_dbgmsg_show_header,104zfs_dbgmsg_clear,105offsetof(zfs_dbgmsg_t, zdm_node));106}107108void109zfs_dbgmsg_fini(void)110{111procfs_list_uninstall(&zfs_dbgmsgs);112zfs_dbgmsg_purge(0);113114procfs_list_destroy(&zfs_dbgmsgs);115}116117void118__set_error(const char *file, const char *func, int line, int err)119{120/*121* To enable this:122*123* $ echo 512 >/sys/module/zfs/parameters/zfs_flags124*/125if (zfs_flags & ZFS_DEBUG_SET_ERROR)126__dprintf(B_FALSE, file, func, line, "error %lu",127(ulong_t)err);128}129130void131__zfs_dbgmsg(char *buf)132{133uint_t size = sizeof (zfs_dbgmsg_t) + strlen(buf) + 1;134zfs_dbgmsg_t *zdm = kmem_zalloc(size, KM_SLEEP);135zdm->zdm_size = size;136zdm->zdm_timestamp = gethrestime_sec();137strcpy(zdm->zdm_msg, buf);138139mutex_enter(&zfs_dbgmsgs.pl_lock);140procfs_list_add(&zfs_dbgmsgs, zdm);141zfs_dbgmsg_size += size;142zfs_dbgmsg_purge(zfs_dbgmsg_maxsize);143mutex_exit(&zfs_dbgmsgs.pl_lock);144}145146void147__dprintf(boolean_t dprint, const char *file, const char *func,148int line, const char *fmt, ...)149{150const char *newfile;151va_list adx;152size_t size;153char *buf;154char *nl;155int i;156char *prefix = (dprint) ? "dprintf: " : "";157158size = 1024;159buf = kmem_alloc(size, KM_SLEEP);160161/*162* Get rid of annoying prefix to filename.163*/164newfile = strrchr(file, '/');165if (newfile != NULL) {166newfile = newfile + 1; /* Get rid of leading / */167} else {168newfile = file;169}170171i = snprintf(buf, size, "%px %s%s:%d:%s(): ",172curthread, prefix, newfile, line, func);173174if (i < size) {175va_start(adx, fmt);176(void) vsnprintf(buf + i, size - i, fmt, adx);177va_end(adx);178}179180/*181* Get rid of trailing newline for dprintf logs.182*/183if (dprint && buf[0] != '\0') {184nl = &buf[strlen(buf) - 1];185if (*nl == '\n')186*nl = '\0';187}188189/*190* To get this data enable the zfs__dprintf trace point as shown:191*192* # Enable zfs__dprintf tracepoint, clear the tracepoint ring buffer193* $ echo 1 > /sys/kernel/debug/tracing/events/zfs/enable194* $ echo 0 > /sys/kernel/debug/tracing/trace195*196* # Dump the ring buffer.197* $ cat /sys/kernel/debug/tracing/trace198*/199DTRACE_PROBE1(zfs__dprintf, char *, buf);200201/*202* To get this data:203*204* $ cat /proc/spl/kstat/zfs/dbgmsg205*206* To clear the buffer:207* $ echo 0 > /proc/spl/kstat/zfs/dbgmsg208*/209__zfs_dbgmsg(buf);210211kmem_free(buf, size);212}213214module_param(zfs_dbgmsg_enable, int, 0644);215MODULE_PARM_DESC(zfs_dbgmsg_enable, "Enable ZFS debug message log");216217module_param(zfs_dbgmsg_maxsize, uint, 0644);218MODULE_PARM_DESC(zfs_dbgmsg_maxsize, "Maximum ZFS debug log size");219220221