From patchwork Thu Apr 18 08:41:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Gleixner X-Patchwork-Id: 10906723 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 15C3C161F for ; Thu, 18 Apr 2019 09:06:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EF033289C5 for ; Thu, 18 Apr 2019 09:06:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E2A0C28A9B; Thu, 18 Apr 2019 09:06:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 61DA2289DA for ; Thu, 18 Apr 2019 09:06:21 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8189D6B0008; Thu, 18 Apr 2019 05:06:12 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 7A00B6B000D; Thu, 18 Apr 2019 05:06:12 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 1F86E6B0010; Thu, 18 Apr 2019 05:06:12 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by kanga.kvack.org (Postfix) with ESMTP id 9BCB76B000A for ; Thu, 18 Apr 2019 05:06:11 -0400 (EDT) Received: by mail-wr1-f71.google.com with SMTP id m13so1510059wrr.17 for ; Thu, 18 Apr 2019 02:06:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-original-authentication-results:x-gm-message-state:message-id :user-agent:date:from:to:cc:subject:references:mime-version; bh=IbpSsAiPcW8cv6WMadHzF6JIvxj3aoR9tMjXje3c20A=; b=i2/jYz1EXIL7VLX9u6Wv4+dHHE7SkF854I/4ils5tFeH2Me4GISr7NqX0aODa2J7EB GAa/RZbnNyVVqRGRQChpZ6bTlOIZrnUmFhQIKMSw6CducfeX9Tillkt1OPz+ergb2V9i zV1YDATkPl0+n+g4UC5kJzlNWFwyKS7L7Sc/juSuumoeTU9gAg0zyls/GR5hPoZmYcHr FuaNsN0VzTbIne7EDxINzqnOHwmK/LNKxmYQfgc36EoRrkDflv8ZEHFDG2Tn+ZtnxtoI GuYVNK1zkxqkyw2g6uEOlI77sFQOc5KMJXYjQoaT69UDTPAWKZK4Jsr/j7G1wpl88jaZ CZxA== X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of tglx@linutronix.de designates 2a01:7a0:2:106d:700::1 as permitted sender) smtp.mailfrom=tglx@linutronix.de X-Gm-Message-State: APjAAAUFLEHi0fFNcCn1Xeh4RDYtXyT/scQzQP1bXyrqPVTTgOCaRHB9 XxTOXZuoMppYMbENhs5STf/qskFBRdH6oZlpmVwhQ56QAK663H+jrYPBaITaSw9LZkdGPYqNDAF MJNA3nKUMAdeSV6vOncX4RyTP0iClBdO0zK/laOkP5xdcpoCHmH68449kVClIGgQjLA== X-Received: by 2002:a5d:558c:: with SMTP id i12mr1998103wrv.123.1555578371086; Thu, 18 Apr 2019 02:06:11 -0700 (PDT) X-Google-Smtp-Source: APXvYqwIetfm2w0NmaGu+VbePCFGRuUun89Hg5tVe3/Y5H10PO+PDXMEjm/UmvlLIbci++LkuB7F X-Received: by 2002:a5d:558c:: with SMTP id i12mr1998020wrv.123.1555578369934; Thu, 18 Apr 2019 02:06:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1555578369; cv=none; d=google.com; s=arc-20160816; b=UqkUC+6eRTDS7CS/KbpYlZ7HgocXbYXz0WS3nLAL7TgLDcg1XdwI0rQtwwpGR3A1/5 dFGpyNi+J2wDK9leUYtS0aeyFfrz7WQj3fyf+r5qjfr/uXGyrKBkgz2SOh+Wh+SVbRxr 9sTQkzzagXPzTYfwbL5X7vwiUdmyEV/95ReUx+t/Ek7zCLlcmVa5ywqFq/hGYjRjkr4u xhXYLKxy/5FQMuSprKA6EiGuRo/EKBYA/SQnqMz2r7jhKGAn098ix2TvUk5VDF+61fy2 vSZ/R8aUC74OVhrWcCnyv57+mEM8REVD0FbE3wzidh2hYc+sJ3G6au+tUXI65+T/ZkiX tIQA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=mime-version:references:subject:cc:to:from:date:user-agent :message-id; bh=IbpSsAiPcW8cv6WMadHzF6JIvxj3aoR9tMjXje3c20A=; b=ztE7rN3ZOuYmEtCJEjs5l2bw9O9Ak4GDaXON8ewkbs3sTt+E88sgE/CvpSjtzyYtYO yWwbcoAwQM9OhBU8DRgUMkqMhQ+PAOP5+1vZ39iR+RZ/nW3XFrVOiq/LL7Hg8JXmnfyL BF0LXJHXyZeU9sHPoTs1SW/Xr91qMX+RxY3KOFHWP6VP8yIABDrULJcwsfwuU2kkbjSw YWflTysycpIkhHeZA8qr3899gqoL2CGm/c/hbMP+ZpgR036AvmsGArSeTzePFlWbOtXU 9r3YBW8swSue2q8sTJSjziEnhTsciLxazRvDmcRJ4BIE56LRPgK/ZbnYXOE7VomPV0Ue siLA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of tglx@linutronix.de designates 2a01:7a0:2:106d:700::1 as permitted sender) smtp.mailfrom=tglx@linutronix.de Received: from Galois.linutronix.de (Galois.linutronix.de. [2a01:7a0:2:106d:700::1]) by mx.google.com with ESMTPS id e7si1276796wrc.181.2019.04.18.02.06.09 for (version=TLS1_2 cipher=AES128-SHA bits=128/128); Thu, 18 Apr 2019 02:06:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of tglx@linutronix.de designates 2a01:7a0:2:106d:700::1 as permitted sender) client-ip=2a01:7a0:2:106d:700::1; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of tglx@linutronix.de designates 2a01:7a0:2:106d:700::1 as permitted sender) smtp.mailfrom=tglx@linutronix.de Received: from localhost ([127.0.0.1] helo=nanos.tec.linutronix.de) by Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from ) id 1hH2zb-0001m0-4R; Thu, 18 Apr 2019 11:06:03 +0200 Message-Id: <20190418084253.234868907@linutronix.de> User-Agent: quilt/0.65 Date: Thu, 18 Apr 2019 10:41:21 +0200 From: Thomas Gleixner To: LKML Cc: Josh Poimboeuf , x86@kernel.org, Andy Lutomirski , Steven Rostedt , Alexander Potapenko , Alexey Dobriyan , Andrew Morton , Pekka Enberg , linux-mm@kvack.org, David Rientjes , Christoph Lameter , Catalin Marinas , Dmitry Vyukov , Andrey Ryabinin , kasan-dev@googlegroups.com, Mike Rapoport , Akinobu Mita , iommu@lists.linux-foundation.org, Robin Murphy , Christoph Hellwig , Marek Szyprowski , Johannes Thumshirn , David Sterba , Chris Mason , Josef Bacik , linux-btrfs@vger.kernel.org, dm-devel@redhat.com, Mike Snitzer , Alasdair Kergon , intel-gfx@lists.freedesktop.org, Joonas Lahtinen , Maarten Lankhorst , dri-devel@lists.freedesktop.org, David Airlie , Jani Nikula , Daniel Vetter , Rodrigo Vivi , linux-arch@vger.kernel.org Subject: [patch V2 02/29] stacktrace: Provide helpers for common stack trace operations References: <20190418084119.056416939@linutronix.de> MIME-Version: 1.0 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP All operations with stack traces are based on struct stack_trace. That's a horrible construct as the struct is a kitchen sink for input and output. Quite some usage sites embed it into their own data structures which creates weird indirections. There is absolutely no point in doing so. For all use cases a storage array and the number of valid stack trace entries in the array is sufficient. Provide helper functions which avoid the struct stack_trace indirection so the usage sites can be cleaned up. Signed-off-by: Thomas Gleixner --- include/linux/stacktrace.h | 27 +++++++ kernel/stacktrace.c | 160 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 172 insertions(+), 15 deletions(-) --- a/include/linux/stacktrace.h +++ b/include/linux/stacktrace.h @@ -3,11 +3,26 @@ #define __LINUX_STACKTRACE_H #include +#include struct task_struct; struct pt_regs; #ifdef CONFIG_STACKTRACE +void stack_trace_print(unsigned long *trace, unsigned int nr_entries, + int spaces); +int stack_trace_snprint(char *buf, size_t size, unsigned long *entries, + unsigned int nr_entries, int spaces); +unsigned int stack_trace_save(unsigned long *store, unsigned int size, + unsigned int skipnr); +unsigned int stack_trace_save_tsk(struct task_struct *task, + unsigned long *store, unsigned int size, + unsigned int skipnr); +unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store, + unsigned int size, unsigned int skipnr); +unsigned int stack_trace_save_user(unsigned long *store, unsigned int size); + +/* Internal interfaces. Do not use in generic code */ struct stack_trace { unsigned int nr_entries, max_entries; unsigned long *entries; @@ -41,4 +56,16 @@ extern void save_stack_trace_user(struct # define save_stack_trace_tsk_reliable(tsk, trace) ({ -ENOSYS; }) #endif /* CONFIG_STACKTRACE */ +#if defined(CONFIG_STACKTRACE) && defined(CONFIG_HAVE_RELIABLE_STACKTRACE) +int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store, + unsigned int size); +#else +static inline int stack_trace_save_tsk_reliable(struct task_struct *tsk, + unsigned long *store, + unsigned int size) +{ + return -ENOSYS; +} +#endif + #endif /* __LINUX_STACKTRACE_H */ --- a/kernel/stacktrace.c +++ b/kernel/stacktrace.c @@ -11,35 +11,52 @@ #include #include -void print_stack_trace(struct stack_trace *trace, int spaces) +/** + * stack_trace_print - Print the entries in the stack trace + * @entries: Pointer to storage array + * @nr_entries: Number of entries in the storage array + * @spaces: Number of leading spaces to print + */ +void stack_trace_print(unsigned long *entries, unsigned int nr_entries, + int spaces) { - int i; + unsigned int i; - if (WARN_ON(!trace->entries)) + if (WARN_ON(!entries)) return; - for (i = 0; i < trace->nr_entries; i++) - printk("%*c%pS\n", 1 + spaces, ' ', (void *)trace->entries[i]); + for (i = 0; i < nr_entries; i++) + printk("%*c%pS\n", 1 + spaces, ' ', (void *)entries[i]); +} +EXPORT_SYMBOL_GPL(stack_trace_print); + +void print_stack_trace(struct stack_trace *trace, int spaces) +{ + stack_trace_print(trace->entries, trace->nr_entries, spaces); } EXPORT_SYMBOL_GPL(print_stack_trace); -int snprint_stack_trace(char *buf, size_t size, - struct stack_trace *trace, int spaces) +/** + * stack_trace_snprint - Print the entries in the stack trace into a buffer + * @buf: Pointer to the print buffer + * @size: Size of the print buffer + * @entries: Pointer to storage array + * @nr_entries: Number of entries in the storage array + * @spaces: Number of leading spaces to print + */ +int stack_trace_snprint(char *buf, size_t size, unsigned long *entries, + unsigned int nr_entries, int spaces) { - int i; - int generated; - int total = 0; + unsigned int generated, i, total = 0; - if (WARN_ON(!trace->entries)) + if (WARN_ON(!entries)) return 0; - for (i = 0; i < trace->nr_entries; i++) { + for (i = 0; i < nr_entries; i++) { generated = snprintf(buf, size, "%*c%pS\n", 1 + spaces, ' ', - (void *)trace->entries[i]); + (void *)entries[i]); total += generated; - - /* Assume that generated isn't a negative number */ if (generated >= size) { buf += size; size = 0; @@ -51,6 +68,14 @@ int snprint_stack_trace(char *buf, size_ return total; } +EXPORT_SYMBOL_GPL(stack_trace_snprint); + +int snprint_stack_trace(char *buf, size_t size, + struct stack_trace *trace, int spaces) +{ + return stack_trace_snprint(buf, size, trace->entries, + trace->nr_entries, spaces); +} EXPORT_SYMBOL_GPL(snprint_stack_trace); /* @@ -77,3 +102,108 @@ save_stack_trace_tsk_reliable(struct tas WARN_ONCE(1, KERN_INFO "save_stack_tsk_reliable() not implemented yet.\n"); return -ENOSYS; } + +/** + * stack_trace_save - Save a stack trace into a storage array + * @store: Pointer to storage array + * @size: Size of the storage array + * @skipnr: Number of entries to skip at the start of the stack trace + */ +unsigned int stack_trace_save(unsigned long *store, unsigned int size, + unsigned int skipnr) +{ + struct stack_trace trace = { + .entries = store, + .max_entries = size, + .skip = skipnr + 1, + }; + + save_stack_trace(&trace); + return trace.nr_entries; +} +EXPORT_SYMBOL_GPL(stack_trace_save); + +/** + * stack_trace_save_tsk - Save a task stack trace into a storage array + * @task: The task to examine + * @store: Pointer to storage array + * @size: Size of the storage array + * @skipnr: Number of entries to skip at the start of the stack trace + */ +unsigned int stack_trace_save_tsk(struct task_struct *task, + unsigned long *store, unsigned int size, + unsigned int skipnr) +{ + struct stack_trace trace = { + .entries = store, + .max_entries = size, + .skip = skipnr + 1, + }; + + save_stack_trace_tsk(task, &trace); + return trace.nr_entries; +} + +/** + * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array + * @regs: Pointer to pt_regs to examine + * @store: Pointer to storage array + * @size: Size of the storage array + * @skipnr: Number of entries to skip at the start of the stack trace + */ +unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store, + unsigned int size, unsigned int skipnr) +{ + struct stack_trace trace = { + .entries = store, + .max_entries = size, + .skip = skipnr, + }; + + save_stack_trace_regs(regs, &trace); + return trace.nr_entries; +} + +#ifdef CONFIG_HAVE_RELIABLE_STACKTRACE +/** + * stack_trace_save_tsk_reliable - Save task stack with verification + * @tsk: Pointer to the task to examine + * @store: Pointer to storage array + * @size: Size of the storage array + * + * Returns: An error if it detects any unreliable features of the + * stack. Otherwise it guarantees that the stack trace is + * reliable and returns the number of entries stored. + * + * If the task is not 'current', the caller *must* ensure the task is inactive. + */ +int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store, + unsigned int size) +{ + struct stack_trace trace = { + .entries = store, + .max_entries = size, + }; + int ret = save_stack_trace_tsk_reliable(tsk, &trace); + + return ret ? ret : trace.nr_entries; +} +#endif + +#ifdef CONFIG_USER_STACKTRACE_SUPPORT +/** + * stack_trace_save_user - Save a user space stack trace into a storage array + * @store: Pointer to storage array + * @size: Size of the storage array + */ +unsigned int stack_trace_save_user(unsigned long *store, unsigned int size) +{ + struct stack_trace trace = { + .entries = store, + .max_entries = size, + }; + + save_stack_trace_user(&trace); + return trace.nr_entries; +} +#endif /* CONFIG_USER_STACKTRACE_SUPPORT */