From patchwork Thu Apr 16 23:03:42 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tejun Heo X-Patchwork-Id: 461872 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 69CD8140293 for ; Fri, 17 Apr 2015 09:10:29 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=Ss9hkDaZ; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753747AbbDPXJi (ORCPT ); Thu, 16 Apr 2015 19:09:38 -0400 Received: from mail-qk0-f177.google.com ([209.85.220.177]:35981 "EHLO mail-qk0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753512AbbDPXE0 (ORCPT ); Thu, 16 Apr 2015 19:04:26 -0400 Received: by qku63 with SMTP id 63so143243961qku.3; Thu, 16 Apr 2015 16:04:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=tkUhSt1XHWkFpZ2xmsMTz3mk0iyvpHFFhYHGtjDSqdw=; b=Ss9hkDaZPXCz+QZOZq26YFvh07/ykPK8vF8F78LRl/aJd106txiCzQskcBbCqybgw8 U5NJ8xKsQ51joqXStDW1A+xMXihuorwJo6KkRM+U6LpZH/EJmdBszA0y0lRutEjdZG1S x/vSPKhKhutv4KzkEOARldvDBpc0swh2X1TZn9xNd41tiN2gqkWhBrJu+HGe/3Q7YQPd 2YBQDhOowDJGwfWQF/93HyybOoAOGjxn611FbZO+IFZ37VM4p/i+8u15+ApECCnxVmk3 XO3S8aUITJ1SujBbW6K1QrZw2cnXwGbUydmfO/6lEtKBlUEq2p9gPbn2YC2wvLSJG/AU x3zA== X-Received: by 10.140.151.200 with SMTP id 191mr129795qhx.95.1429225465203; Thu, 16 Apr 2015 16:04:25 -0700 (PDT) Received: from htj.duckdns.org.lan (207-38-238-8.c3-0.wsd-ubr1.qens-wsd.ny.cable.rcn.com. [207.38.238.8]) by mx.google.com with ESMTPSA id z77sm6677670qkg.44.2015.04.16.16.04.24 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 16 Apr 2015 16:04:24 -0700 (PDT) From: Tejun Heo To: akpm@linux-foundation.org, davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Tejun Heo , Kay Sievers , Petr Mladek Subject: [PATCH 05/16] printk: implement log_seq_range() and ext_log_from_seq() Date: Thu, 16 Apr 2015 19:03:42 -0400 Message-Id: <1429225433-11946-6-git-send-email-tj@kernel.org> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1429225433-11946-1-git-send-email-tj@kernel.org> References: <1429225433-11946-1-git-send-email-tj@kernel.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Implement two functions to access log messages by their sequence numbers. * log_seq_range() determines the currently available sequence number range. * ext_log_from_seq() outputs log message identified by a given sequence number in the extended format. These will be used to implement reliable netconsole. Signed-off-by: Tejun Heo Cc: Kay Sievers Cc: Petr Mladek --- include/linux/printk.h | 14 ++++++++ kernel/printk/printk.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/include/linux/printk.h b/include/linux/printk.h index 58b1fec..4fd3bb4 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -6,6 +6,7 @@ #include #include #include +#include extern const char linux_banner[]; extern const char linux_proc_banner[]; @@ -169,6 +170,8 @@ void __init setup_log_buf(int early); void dump_stack_set_arch_desc(const char *fmt, ...); void dump_stack_print_info(const char *log_lvl); void show_regs_print_info(const char *log_lvl); +void log_seq_range(u64 *beginp, u64 *endp); +ssize_t ext_log_from_seq(char *buf, size_t size, u64 log_seq); #else static inline __printf(1, 0) int vprintk(const char *s, va_list args) @@ -228,6 +231,17 @@ static inline void dump_stack_print_info(const char *log_lvl) static inline void show_regs_print_info(const char *log_lvl) { } + +static inline void log_seq_range(u64 *begin_seqp, u64 *end_seqp) +{ + *begin_seqp = 0; + *end_seqp = 0; +} + +static inline ssize_t ext_log_from_seq(char *buf, size_t size, u64 log_seq) +{ + return -ERANGE; +} #endif extern asmlinkage void dump_stack(void) __cold; diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 349a37b..904413e 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -617,6 +617,102 @@ static ssize_t msg_print_ext_body(char *buf, size_t size, return p - buf; } +/** + * log_seq_range - get the range of available log sequence numbers + * @begin_seqp: output parameter for the begin of the range + * @end_seqp: output parameter for the end of the range + * + * Returns the log sequence number range [*@begin_seqp, *@ends_seqp) which + * is currently available to be retrieved using ext_log_from_seq(). Note + * that the range may shift anytime. + */ +void log_seq_range(u64 *begin_seqp, u64 *end_seqp) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&logbuf_lock, flags); + *begin_seqp = log_first_seq; + *end_seqp = log_next_seq; + raw_spin_unlock_irqrestore(&logbuf_lock, flags); +} +EXPORT_SYMBOL_GPL(log_seq_range); + +/** + * ext_log_from_seq - obtain log message in extended format from its seq number + * @buf: output buffer + * @size: size of @buf + * @log_seq: target log sequence number + * + * Print the log message with @log_seq as its sequence number into @buf + * using the extended format. On success, returns the length of formatted + * output excluding the terminating '\0'. If @log_seq doesn't match any + * message, -ERANGE is returned. + * + * Due to the way messages are stored, accessing @log_seq requires seeking + * the log buffer sequentially. As the last looked up position is cached, + * accessing messages in ascending sequence order is recommended. + */ +ssize_t ext_log_from_seq(char *buf, size_t size, u64 log_seq) +{ + static u64 seq_hint; + static u32 idx_hint; + static enum log_flags prev_flags_hint; + struct printk_log *msg; + enum log_flags prev_flags = 0; + unsigned long flags; + ssize_t len; + u32 seq; + u32 prev_idx, idx; + + raw_spin_lock_irqsave(&logbuf_lock, flags); + + if (log_seq < log_first_seq || log_seq >= log_next_seq) { + len = -ERANGE; + goto out_unlock; + } + + /* + * Seek to @log_seq to determine its index. The last looked up seq + * and index are cached to accelerate in-order accesses. For now, + * @prev_flags is best effort. It'd be better to restructure it so + * that the current entry carries all the relevant information + * without depending on the previous one. + */ + seq = log_first_seq; + idx = log_first_idx; + + if (seq < seq_hint && seq_hint <= log_seq) { + seq = seq_hint; + idx = idx_hint; + prev_flags = prev_flags_hint; + } + + prev_idx = idx; + while (seq < log_seq) { + seq++; + prev_idx = idx; + idx = log_next(idx); + } + + if (prev_idx != idx) + prev_flags = log_from_idx(prev_idx)->flags; + msg = log_from_idx(idx); + + /* entry located, format it */ + len = msg_print_ext_header(buf, size, msg, seq, prev_flags); + len += msg_print_ext_body(buf + len, size - len, + log_dict(msg), msg->dict_len, + log_text(msg), msg->text_len); + + seq_hint = seq; + idx_hint = idx; + prev_flags_hint = prev_flags; +out_unlock: + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + return len; +} +EXPORT_SYMBOL_GPL(ext_log_from_seq); + /* /dev/kmsg - userspace message inject/listen interface */ struct devkmsg_user { u64 seq;