Received: by 2002:a05:6a10:a0d1:0:0:0:0 with SMTP id j17csp369660pxa; Fri, 14 Aug 2020 06:39:12 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyhYpG/U+1qWVJdviDIUdfImFRXUlWXZ7BC1YjkYX16JojM9zXSctsMrdvQvi7HMTCmtrJD X-Received: by 2002:a05:6402:2379:: with SMTP id a25mr2238343eda.180.1597412352528; Fri, 14 Aug 2020 06:39:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1597412352; cv=none; d=google.com; s=arc-20160816; b=GafD/HPFAb/j1C/arPHD0Or7SRJvn5Vq+WhFwlaFGS+LaPtUFSL7WynKy0h0yI/di8 cdVYuuCPQQvCoozzvU2h75bnVsyxqh7WLwhsQFzIVZNzXIrlaue6RVU57QUGwgY4oPcI 6zFOEOF4ht9kURxfjkljsUYcK4jJ7w/Uf0ObjXJ9ScsY080Pwg74KEk24VZSo6B/XQWO ycFPQyITr9I4Tna48OHSGa/TpVlJfZYodvh5pVLUndsirOgdCgTdDCrYejVaSOvFyIyL ZmNprd9RKAqVQG3832927NpFaOcYlr6P1H/4dWvI4I4ygIfgnDo5Jilz/RyHhIblmU2a 6VxQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:ironport-sdr:dkim-signature; bh=0pgMPV92f759j772BAb65TdIH1uz74Ejo9KR80SU1HU=; b=f1uJXPyA9bHu9ERFPhnxdJE6XeGli/WxTafjn8WsQ+Z0RIhwKbSncGEDoVsZKqx/Y7 Bx306rG3s5JeZ/Qeo6KTnm1mSE2jjCba7j//JzYbPvd+mmEkcqPkl6zEK+ooAo4Qa2Js t46McCx25PuBeH7KjPiSCKarHNJtlrSF12CZLJgZakmhcXrEqRckA1h2kt16ebIt+h5r Z+SAT1AuZ8rqiKwP7Fsy0rvrBeO2hBoh2v8GsRXUdS3kx9ZGU53XUjfox3UZuSuabo1t GibUJ0JVJLF0x3APWAe+OseGWRip+m0TqC7W62p/kn1nOIITToH5sHXhadbQWHqLmXUo bG3A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass (test mode) header.i=@axis.com header.s=axis-central1 header.b=Q8PTC4Eu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=axis.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id a7si5236519ejg.108.2020.08.14.06.38.49; Fri, 14 Aug 2020 06:39:12 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass (test mode) header.i=@axis.com header.s=axis-central1 header.b=Q8PTC4Eu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=axis.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728289AbgHNNb4 (ORCPT + 99 others); Fri, 14 Aug 2020 09:31:56 -0400 Received: from smtp1.axis.com ([195.60.68.17]:55130 "EHLO smtp1.axis.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726237AbgHNNb4 (ORCPT ); Fri, 14 Aug 2020 09:31:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axis.com; l=10159; q=dns/txt; s=axis-central1; t=1597411915; x=1628947915; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=0pgMPV92f759j772BAb65TdIH1uz74Ejo9KR80SU1HU=; b=Q8PTC4EuDRxOBrIPR5hcTZZKxPMHpSUutrkeB8eCMa9Jz4ZZHkYfpH1I UeCcF//XeQW2WDKTVK2Rh5TggnpIJIVLJW6l17cigD2jqeiRMIyFWKXzw bHQlTWZKElI/X1GU0ZLZfUtA0Q6jbzRX3eUtA+EzrPscfTTJ+1Ecq+VUs sof1Zdk+9tSpqA8eDmd2VJz4OyuX5jW7ODsVTkHVf0KGbB1eE349zJ7EM Hv9LcMZE0YoIsmgw4IJgfXnGapNxizbeOivSwhqprldFwsFqZe0s5dBGX I8Tk+wbwMkrYAidG3nBcyUYKQkh7sX3ugaEdWbqRcO/04Lz/NnFe48t7S w==; IronPort-SDR: sMWGEmpxnLxU8ogXyUUWxWrdbbvFlnQ8FkWgQPPmXmQPSLBPr6HuCmUziTwNd+26CAaH58/tI/ VOB9C34IxJt1RuhLL1DNuTcGQd7i9G1XFUP/KBBvs+lH1eOyVmNUp4qocs8lczgMEYXs8h8YAz 8R/lXDZEZNYJfeTMth1Agur3aLJEUXeH+t3a6S25xC8cFY80LX8E/X4c5pJjPh+KR0pIu2HaCz Qsvjeaovtg9uvbKY0gEJTQ312SxwM/+OHjwKwoAcQ4YXAjqnL+jv6qlnOgbY/+q40tSBnzzz77 fSs= X-IronPort-AV: E=Sophos;i="5.76,312,1592863200"; d="scan'208";a="11808837" From: Vincent Whitchurch To: , , CC: , , , , , , Vincent Whitchurch Subject: [PATCH v2] dynamic debug: allow printing to trace event Date: Fri, 14 Aug 2020 15:31:51 +0200 Message-ID: <20200814133151.7759-1-vincent.whitchurch@axis.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When debugging device drivers, I've found it very useful to be able to redirect existing pr_debug()/dev_dbg() prints to the trace buffer instead of dmesg. Among the many advantages of the trace buffer is that it can be dynamically resized, allows these prints to combined with other trace events, and doesn't fill up system logs. Since dynamic debug already has hooks in these call sites, getting these prints into the ftrace buffer is straightforward if we have dynamic debug do it. Add an "x" flag to make the dynamic debug call site print to a new printk:dynamic trace event. The trace event can be emitted instead of or in addition to the printk(). The print buffer is statically allocated and managed using code borrowed from __ftrace_trace_stack() and is limited to 256 bytes (four of these are allocated per CPU to handle the various contexts); anything larger will be truncated. Signed-off-by: Vincent Whitchurch --- v2: - Remove stack buffer and use code similar to __ftrace_trace_stack() - Use an event with the same class as printk:console .../admin-guide/dynamic-debug-howto.rst | 1 + include/linux/dynamic_debug.h | 7 +- include/trace/events/printk.h | 12 +- lib/dynamic_debug.c | 155 +++++++++++++++--- 4 files changed, 146 insertions(+), 29 deletions(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index e5a8def45f3f..d2ebee464db7 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -229,6 +229,7 @@ of the characters:: The flags are:: p enables the pr_debug() callsite. + x enables trace to the printk:dynamic event f Include the function name in the printed message l Include line number in the printed message m Include module name in the printed message diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index aa9ff9e1c0b3..f599ed21ecc5 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -27,13 +27,16 @@ struct _ddebug { * writes commands to /dynamic_debug/control */ #define _DPRINTK_FLAGS_NONE 0 -#define _DPRINTK_FLAGS_PRINT (1<<0) /* printk() a message using the format */ +#define _DPRINTK_FLAGS_PRINTK (1<<0) /* printk() a message using the format */ #define _DPRINTK_FLAGS_INCL_MODNAME (1<<1) #define _DPRINTK_FLAGS_INCL_FUNCNAME (1<<2) #define _DPRINTK_FLAGS_INCL_LINENO (1<<3) #define _DPRINTK_FLAGS_INCL_TID (1<<4) +#define _DPRINTK_FLAGS_TRACE (1<<5) +#define _DPRINTK_FLAGS_PRINT (_DPRINTK_FLAGS_PRINTK | \ + _DPRINTK_FLAGS_TRACE) #if defined DEBUG -#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT +#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINTK #else #define _DPRINTK_FLAGS_DEFAULT 0 #endif diff --git a/include/trace/events/printk.h b/include/trace/events/printk.h index 13d405b2fd8b..6c89121a1669 100644 --- a/include/trace/events/printk.h +++ b/include/trace/events/printk.h @@ -7,7 +7,7 @@ #include -TRACE_EVENT(console, +DECLARE_EVENT_CLASS(printk, TP_PROTO(const char *text, size_t len), TP_ARGS(text, len), @@ -31,6 +31,16 @@ TRACE_EVENT(console, TP_printk("%s", __get_str(msg)) ); + +DEFINE_EVENT(printk, console, + TP_PROTO(const char *text, size_t len), + TP_ARGS(text, len) +); + +DEFINE_EVENT(printk, dynamic, + TP_PROTO(const char *text, size_t len), + TP_ARGS(text, len) +); #endif /* _TRACE_PRINTK_H */ /* This part must be outside protection */ diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 1d012e597cc3..76fc3e33fe41 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -84,11 +85,12 @@ static inline const char *trim_prefix(const char *path) } static struct { unsigned flag:8; char opt_char; } opt_array[] = { - { _DPRINTK_FLAGS_PRINT, 'p' }, + { _DPRINTK_FLAGS_PRINTK, 'p' }, { _DPRINTK_FLAGS_INCL_MODNAME, 'm' }, { _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' }, { _DPRINTK_FLAGS_INCL_LINENO, 'l' }, { _DPRINTK_FLAGS_INCL_TID, 't' }, + { _DPRINTK_FLAGS_TRACE, 'x' }, { _DPRINTK_FLAGS_NONE, '_' }, }; @@ -600,6 +602,96 @@ static char *dynamic_emit_prefix(const struct _ddebug *desc, char *buf) return buf; } +/* + * This code is heavily based on __ftrace_trace_stack(). + * + * Allow 4 levels of nesting: normal, softirq, irq, NMI. + */ +#define DYNAMIC_TRACE_NESTING 4 + +struct dynamic_trace_buf { + char buf[256]; +}; + +struct dynamic_trace_bufs { + struct dynamic_trace_buf bufs[DYNAMIC_TRACE_NESTING]; +}; + +static DEFINE_PER_CPU(struct dynamic_trace_bufs, dynamic_trace_bufs); +static DEFINE_PER_CPU(int, dynamic_trace_reserve); + +static void dynamic_trace(const char *fmt, va_list args) +{ + struct dynamic_trace_buf *buf; + int bufidx; + int len; + + preempt_disable_notrace(); + + bufidx = __this_cpu_inc_return(dynamic_trace_reserve) - 1; + + if (WARN_ON_ONCE(bufidx > DYNAMIC_TRACE_NESTING)) + goto out; + + /* For the same reasons as in __ftrace_trace_stack(). */ + barrier(); + + buf = this_cpu_ptr(dynamic_trace_bufs.bufs) + bufidx; + + len = vscnprintf(buf->buf, sizeof(buf->buf), fmt, args); + trace_dynamic(buf->buf, len); + +out: + /* As above. */ + barrier(); + __this_cpu_dec(dynamic_trace_reserve); + preempt_enable_notrace(); +} + +static void dynamic_printk(unsigned int flags, const char *fmt, ...) +{ + if (flags & _DPRINTK_FLAGS_TRACE) { + va_list args; + + va_start(args, fmt); + /* + * All callers include the KERN_DEBUG prefix to keep the + * vprintk case simple; strip it out for tracing. + */ + dynamic_trace(fmt + strlen(KERN_DEBUG), args); + va_end(args); + } + + if (flags & _DPRINTK_FLAGS_PRINTK) { + va_list args; + + va_start(args, fmt); + vprintk(fmt, args); + va_end(args); + } +} + +static void dynamic_dev_printk(unsigned int flags, const struct device *dev, + const char *fmt, ...) +{ + + if (flags & _DPRINTK_FLAGS_TRACE) { + va_list args; + + va_start(args, fmt); + dynamic_trace(fmt, args); + va_end(args); + } + + if (flags & _DPRINTK_FLAGS_PRINTK) { + va_list args; + + va_start(args, fmt); + dev_vprintk_emit(LOGLEVEL_DEBUG, dev, fmt, args); + va_end(args); + } +} + void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...) { va_list args; @@ -614,7 +706,8 @@ void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...) vaf.fmt = fmt; vaf.va = &args; - printk(KERN_DEBUG "%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf); + dynamic_printk(descriptor->flags, KERN_DEBUG "%s%pV", + dynamic_emit_prefix(descriptor, buf), &vaf); va_end(args); } @@ -624,6 +717,7 @@ void __dynamic_dev_dbg(struct _ddebug *descriptor, const struct device *dev, const char *fmt, ...) { struct va_format vaf; + unsigned int flags; va_list args; BUG_ON(!descriptor); @@ -633,16 +727,18 @@ void __dynamic_dev_dbg(struct _ddebug *descriptor, vaf.fmt = fmt; vaf.va = &args; + flags = descriptor->flags; if (!dev) { - printk(KERN_DEBUG "(NULL device *): %pV", &vaf); + dynamic_printk(flags, KERN_DEBUG "(NULL device *): %pV", + &vaf); } else { char buf[PREFIX_SIZE]; - dev_printk_emit(LOGLEVEL_DEBUG, dev, "%s%s %s: %pV", - dynamic_emit_prefix(descriptor, buf), - dev_driver_string(dev), dev_name(dev), - &vaf); + dynamic_dev_printk(flags, dev, "%s%s %s: %pV", + dynamic_emit_prefix(descriptor, buf), + dev_driver_string(dev), dev_name(dev), + &vaf); } va_end(args); @@ -655,6 +751,7 @@ void __dynamic_netdev_dbg(struct _ddebug *descriptor, const struct net_device *dev, const char *fmt, ...) { struct va_format vaf; + unsigned int flags; va_list args; BUG_ON(!descriptor); @@ -664,22 +761,24 @@ void __dynamic_netdev_dbg(struct _ddebug *descriptor, vaf.fmt = fmt; vaf.va = &args; + flags = descriptor->flags; if (dev && dev->dev.parent) { char buf[PREFIX_SIZE]; - dev_printk_emit(LOGLEVEL_DEBUG, dev->dev.parent, - "%s%s %s %s%s: %pV", - dynamic_emit_prefix(descriptor, buf), - dev_driver_string(dev->dev.parent), - dev_name(dev->dev.parent), - netdev_name(dev), netdev_reg_state(dev), - &vaf); + dynamic_dev_printk(flags, dev->dev.parent, + "%s%s %s %s%s: %pV", + dynamic_emit_prefix(descriptor, buf), + dev_driver_string(dev->dev.parent), + dev_name(dev->dev.parent), + netdev_name(dev), netdev_reg_state(dev), + &vaf); } else if (dev) { - printk(KERN_DEBUG "%s%s: %pV", netdev_name(dev), - netdev_reg_state(dev), &vaf); + dynamic_printk(flags, KERN_DEBUG "%s%s: %pV", + netdev_name(dev), netdev_reg_state(dev), &vaf); } else { - printk(KERN_DEBUG "(NULL net_device): %pV", &vaf); + dynamic_printk(flags, KERN_DEBUG "(NULL net_device): %pV", + &vaf); } va_end(args); @@ -694,27 +793,31 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor, const struct ib_device *ibdev, const char *fmt, ...) { struct va_format vaf; + unsigned int flags; va_list args; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; + flags = descriptor->flags; if (ibdev && ibdev->dev.parent) { char buf[PREFIX_SIZE]; - dev_printk_emit(LOGLEVEL_DEBUG, ibdev->dev.parent, - "%s%s %s %s: %pV", - dynamic_emit_prefix(descriptor, buf), - dev_driver_string(ibdev->dev.parent), - dev_name(ibdev->dev.parent), - dev_name(&ibdev->dev), - &vaf); + dynamic_dev_printk(flags, ibdev->dev.parent, + "%s%s %s %s: %pV", + dynamic_emit_prefix(descriptor, buf), + dev_driver_string(ibdev->dev.parent), + dev_name(ibdev->dev.parent), + dev_name(&ibdev->dev), + &vaf); } else if (ibdev) { - printk(KERN_DEBUG "%s: %pV", dev_name(&ibdev->dev), &vaf); + dynamic_printk(flags, KERN_DEBUG "%s: %pV", + dev_name(&ibdev->dev), &vaf); } else { - printk(KERN_DEBUG "(NULL ib_device): %pV", &vaf); + dynamic_printk(flags, KERN_DEBUG "(NULL ib_device): %pV", + &vaf); } va_end(args); -- 2.25.1