From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5902EC4321E for ; Thu, 21 Apr 2022 23:49:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442799AbiDUXvs (ORCPT ); Thu, 21 Apr 2022 19:51:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49294 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1382719AbiDUXvj (ORCPT ); Thu, 21 Apr 2022 19:51:39 -0400 Received: from mail-qk1-x72e.google.com (mail-qk1-x72e.google.com [IPv6:2607:f8b0:4864:20::72e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A331442EF1; Thu, 21 Apr 2022 16:48:46 -0700 (PDT) Received: by mail-qk1-x72e.google.com with SMTP id d198so4742566qkc.12; Thu, 21 Apr 2022 16:48:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lgfGsgMv5iDJepG0Wr5n+Un2iVDKg5VOEf+xgmHxDBs=; b=HnKbyKSoxnnhHUla82G+r44n6xKnHl/lyquu70quAWvEGruswnnMwJVrbtkYeWAGaS lXo1884Mu/n97iJ5ppuIoGSLA8Lx2yq8g4SA61iceqgIE/uHZpYDgZDSz44jhm7qc/V0 UMi0uQQXaUtdJaDEe+CLU/x/ngyaAt9yZE8HV7bunAF9d31kUd56empFtZ65SGbFffQQ cEUUcOKXjlXbcACC94P3DYR9nqm7TTBMtqDCwd3mP1ie2bpBDiyHWVvK62IpDcIKlNz+ oCX42OTFko8ueeliHHMPuv7eQRpipnDUrdp1mqmh002tbmlWAv4QLX2SmxYkOpaCSUhP y+bA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=lgfGsgMv5iDJepG0Wr5n+Un2iVDKg5VOEf+xgmHxDBs=; b=NOfcZ0rm3XdbIcCtwwCDfXeukz5ABYTbf6DTTNyEU0fV7qddBIwcRZOLbpA7deMi1w 8Md1hdjrbR80Mn0Pl1qnfiqlbEKcDn6234FvD/iZmUCKNYmKvcp7loleAR6J77+y4+Pr EdUhYFparaX0LBnygqvnldG7VpogCX0zWAE4UBRzNAzJxYOBtXQZkM3Nbu+RvGNb6rQd jZPoFU/XOTOe7Ko1/0MN9X+XlXZ6WVOGjxamj5PDvl+dOYQHfyf8uftuloPqRUhlUvJy Sy1ClVBez2J6phSwNSFOuo4qfD5RvO0BuloFFQzkAkB3fh9CAZWLT34CMnpzywujKyJ0 q5Aw== X-Gm-Message-State: AOAM531M1VU/8ayQJp6kjHlfJnVbib83hcMG/nL2Sw/4MWTlbBVB3QcB 9I3jRcg8gQAWbr9q9YO6Qf1AlqFVG0Xv X-Google-Smtp-Source: ABdhPJwCLQbUskjoObbtdir9+Ze+XkJzhwquJQAmJ0+tc6epSJ7UNq8IznwqjL85GmEsdyt0hu3l0g== X-Received: by 2002:a05:620a:d8d:b0:67b:e95:2975 with SMTP id q13-20020a05620a0d8d00b0067b0e952975mr1193551qkl.115.1650584925172; Thu, 21 Apr 2022 16:48:45 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:44 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , roman.gushchin@linux.dev, hannes@cmpxchg.org Subject: [PATCH 1/4] lib/printbuf: New data structure for heap-allocated strings Date: Thu, 21 Apr 2022 19:48:25 -0400 Message-Id: <20220421234837.3629927-2-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds printbufs: simple heap-allocated strings meant for building up structured messages, for logging/procfs/sysfs and elsewhere. They've been heavily used in bcachefs for writing .to_text() functions/methods - pretty printers, which has in turn greatly improved the overall quality of error messages. Basic usage is documented in include/linux/printbuf.h. The next patches in the series are going to be using printbufs to implement a .to_text() method for shrinkers, and improving OOM reporting. Signed-off-by: Kent Overstreet --- include/linux/printbuf.h | 140 ++++++++++++++++++++ lib/Makefile | 2 +- lib/printbuf.c | 271 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 412 insertions(+), 1 deletion(-) create mode 100644 include/linux/printbuf.h create mode 100644 lib/printbuf.c diff --git a/include/linux/printbuf.h b/include/linux/printbuf.h new file mode 100644 index 0000000000..84a271446d --- /dev/null +++ b/include/linux/printbuf.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/* Copyright (C) 2022 Kent Overstreet */ + +#ifndef _LINUX_PRINTBUF_H +#define _LINUX_PRINTBUF_H + +/* + * Printbufs: Simple heap allocated strings, with some features for struct= ered + * formatting. + * + * This code has provisions for use in userspace, to aid in making other c= ode + * portable between kernelspace and userspace. + * + * Basic example: + * + * struct printbuf buf =3D PRINTBUF; + * + * pr_buf(&buf, "foo=3D"); + * foo_to_text(&buf, foo); + * printk("%s", buf.buf); + * printbuf_exit(&buf); + * + * We can now write pretty printers instead of writing code that dumps + * everything to the kernel log buffer, and then those pretty-printers can= be + * used by other code that outputs to kernel log, sysfs, debugfs, etc. + * + * Memory allocation: Outputing to a printbuf may allocate memory. This + * allocation is done with GFP_KERNEL, by default: use the newer + * memalloc_*_(save|restore) functions as needed. + * + * Since no equivalent yet exists for GFP_ATOMIC/GFP_NOWAIT, memory alloca= tions + * will be done with GFP_ATOMIC if printbuf->atomic is nonzero. + * + * Memory allocation failures: We don't return errors directly, because on + * memory allocation failure we usually don't want to bail out and unwind = - we + * want to print what we've got, on a best-effort basis. But code that doe= s want + * to return -ENOMEM may check printbuf.allocation_failure. + * + * Indenting, tabstops: + * + * To aid is writing multi-line pretty printers spread across multiple + * functions, printbufs track the current indent level. + * + * pr_indent_push() and pr_indent_pop() increase and decrease the current = indent + * level, respectively. + * + * To use tabstops, set printbuf->tabstops[]; they are in units of spaces,= from + * start of line. Once set, pr_tab() will output spaces up to the next tab= stop. + * pr_tab_rjust() will also advance the current line of text up to the next + * tabstop, but it does so by shifting text since the previous tabstop up = to the + * next tabstop - right justifying it. + * + * Make sure you use pr_newline() instead of \n in the format string for i= ndent + * level and tabstops to work corretly. + * + * Output units: printbuf->units exists to tell pretty-printers how to out= put + * numbers: a raw value (e.g. directly from a superblock field), as bytes,= or as + * human readable bytes. pr_units() and pr_sectors() obey it. + * + * Other helpful functions: + * + * pr_human_readable_u64, pr_human_readable_s64: Print an integer with hum= an + * readable units. + * + * pr_time(): for printing a time_t with strftime in userspace, prints as = an + * integer number of seconds in the kernel. + * + * pr_string_option: Given an enumerated value and a string array with nam= es for + * each option, prints out the enum names with the selected one indicated = with + * square brackets. + * + * pr_bitflags: Given a bitflag and a string array with names for each bit, + * prints out the names of the selected bits. + */ + +#include + +enum printbuf_units { + PRINTBUF_UNITS_RAW, + PRINTBUF_UNITS_BYTES, + PRINTBUF_UNITS_HUMAN_READABLE, +}; + +struct printbuf { + char *buf; + unsigned size; + unsigned pos; + unsigned last_newline; + unsigned last_field; + unsigned indent; + enum printbuf_units units:8; + u8 atomic; + bool allocation_failure:1; + u8 tabstop; + u8 tabstops[4]; +}; + +#define PRINTBUF ((struct printbuf) { NULL }) + +/** + * printbuf_exit - exit a printbuf, freeing memory it owns and poisoning it + * against accidental use. + */ +static inline void printbuf_exit(struct printbuf *buf) +{ + kfree(buf->buf); + buf->buf =3D ERR_PTR(-EINTR); /* poison value */ +} + +/** + * printbuf_reset - re-use a printbuf without freeing and re-initializing = it: + */ +static inline void printbuf_reset(struct printbuf *buf) +{ + buf->pos =3D 0; + buf->last_newline =3D 0; + buf->last_field =3D 0; + buf->indent =3D 0; + buf->tabstop =3D 0; +} + +void pr_buf(struct printbuf *out, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +void pr_char(struct printbuf *buf, char c); +void pr_newline(struct printbuf *); +void pr_indent_push(struct printbuf *, unsigned); +void pr_indent_pop(struct printbuf *, unsigned); +void pr_tab(struct printbuf *); +void pr_tab_rjust(struct printbuf *); +void pr_human_readable_u64(struct printbuf *, u64); +void pr_human_readable_s64(struct printbuf *, s64); +void pr_units(struct printbuf *, s64, s64); +void pr_sectors(struct printbuf *, u64); +void pr_time(struct printbuf *, u64); +void pr_uuid(struct printbuf *, u8 *); +void pr_string_option(struct printbuf *, const char * const list[], size_t= ); +void pr_bitflags(struct printbuf *, const char * const list[], u64); + +#endif /* _LINUX_PRINTBUF_H */ diff --git a/lib/Makefile b/lib/Makefile index c588a126a3..31a3904eda 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -34,7 +34,7 @@ lib-y :=3D ctype.o string.o vsprintf.o cmdline.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o \ - buildid.o + buildid.o printbuf.o =20 lib-$(CONFIG_PRINTK) +=3D dump_stack.o lib-$(CONFIG_SMP) +=3D cpumask.o diff --git a/lib/printbuf.c b/lib/printbuf.c new file mode 100644 index 0000000000..1d87de787f --- /dev/null +++ b/lib/printbuf.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: LGPL-2.1+ +/* Copyright (C) 2022 Kent Overstreet */ + +#ifdef __KERNEL__ +#include +#include +#else +#define EXPORT_SYMBOL(x) +#endif + +#include +#include + +static inline size_t printbuf_remaining(struct printbuf *buf) +{ + return buf->size - buf->pos; +} + +static inline size_t printbuf_linelen(struct printbuf *buf) +{ + return buf->pos - buf->last_newline; +} + +static int printbuf_realloc(struct printbuf *out, unsigned extra) +{ + unsigned new_size; + char *buf; + + if (out->pos + extra + 1 < out->size) + return 0; + + new_size =3D roundup_pow_of_two(out->size + extra); + buf =3D krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_ATOM= IC); + + if (!buf) { + out->allocation_failure =3D true; + return -ENOMEM; + } + + out->buf =3D buf; + out->size =3D new_size; + return 0; +} + +void pr_buf(struct printbuf *out, const char *fmt, ...) +{ + va_list args; + int len; + + do { + va_start(args, fmt); + len =3D vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, arg= s); + va_end(args); + } while (len + 1 >=3D printbuf_remaining(out) && + !printbuf_realloc(out, len + 1)); + + len =3D min_t(size_t, len, + printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0); + out->pos +=3D len; +} +EXPORT_SYMBOL(pr_buf); + +void pr_char(struct printbuf *buf, char c) +{ + if (!printbuf_realloc(buf, 1)) { + buf->buf[buf->pos++] =3D c; + buf->buf[buf->pos] =3D 0; + } +} +EXPORT_SYMBOL(pr_char); + +void pr_newline(struct printbuf *buf) +{ + unsigned i; + + pr_char(buf, '\n'); + + buf->last_newline =3D buf->pos; + + for (i =3D 0; i < buf->indent; i++) + pr_char(buf, ' '); + + buf->last_field =3D buf->pos; + buf->tabstop =3D 0; +} +EXPORT_SYMBOL(pr_newline); + +void pr_indent_push(struct printbuf *buf, unsigned spaces) +{ + buf->indent +=3D spaces; + while (spaces--) + pr_char(buf, ' '); +} +EXPORT_SYMBOL(pr_indent_push); + +void pr_indent_pop(struct printbuf *buf, unsigned spaces) +{ + if (buf->last_newline + buf->indent =3D=3D buf->pos) { + buf->pos -=3D spaces; + buf->buf[buf->pos] =3D 0; + } + buf->indent -=3D spaces; +} +EXPORT_SYMBOL(pr_indent_pop); + +void pr_tab(struct printbuf *buf) +{ + BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops)); + + while (printbuf_remaining(buf) > 1 && + printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) + pr_char(buf, ' '); + + buf->last_field =3D buf->pos; + buf->tabstop++; +} +EXPORT_SYMBOL(pr_tab); + +void pr_tab_rjust(struct printbuf *buf) +{ + BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops)); + + if (printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) { + unsigned move =3D buf->pos - buf->last_field; + unsigned shift =3D buf->tabstops[buf->tabstop] - + printbuf_linelen(buf); + + printbuf_realloc(buf, shift); + + if (buf->last_field + shift + 1 < buf->size) { + move =3D min(move, buf->size - 1 - buf->last_field - shift); + + memmove(buf->buf + buf->last_field + shift, + buf->buf + buf->last_field, + move); + memset(buf->buf + buf->last_field, ' ', shift); + buf->pos +=3D shift; + buf->buf[buf->pos] =3D 0; + } + } + + buf->last_field =3D buf->pos; + buf->tabstop++; +} +EXPORT_SYMBOL(pr_tab_rjust); + +static const char si_units[] =3D "?kMGTPEZY"; + +void pr_human_readable_u64(struct printbuf *buf, u64 v) +{ + int u, t =3D 0; + + for (u =3D 0; v >=3D 1024; u++) { + t =3D v & ~(~0U << 10); + v >>=3D 10; + } + + pr_buf(buf, "%llu", v); + + /* + * 103 is magic: t is in the range [-1023, 1023] and we want + * to turn it into [-9, 9] + */ + if (u && t && v < 100 && v > -100) + pr_buf(buf, ".%i", t / 103); + if (u) + pr_char(buf, si_units[u]); +} +EXPORT_SYMBOL(pr_human_readable_u64); + +void pr_human_readable_s64(struct printbuf *buf, s64 v) +{ + if (v < 0) + pr_char(buf, '-'); + pr_human_readable_u64(buf, abs(v)); +} +EXPORT_SYMBOL(pr_human_readable_s64); + +void pr_units(struct printbuf *out, s64 raw, s64 bytes) +{ + switch (out->units) { + case PRINTBUF_UNITS_RAW: + pr_buf(out, "%llu", raw); + break; + case PRINTBUF_UNITS_BYTES: + pr_buf(out, "%llu", bytes); + break; + case PRINTBUF_UNITS_HUMAN_READABLE: + pr_human_readable_s64(out, bytes); + break; + } +} +EXPORT_SYMBOL(pr_units); + +void pr_sectors(struct printbuf *out, u64 v) +{ + pr_units(out, v, v << 9); +} +EXPORT_SYMBOL(pr_sectors); + +#ifdef __KERNEL__ + +void pr_time(struct printbuf *out, u64 time) +{ + pr_buf(out, "%llu", time); +} +EXPORT_SYMBOL(pr_time); + +void pr_uuid(struct printbuf *out, u8 *uuid) +{ + pr_buf(out, "%pUb", uuid); +} +EXPORT_SYMBOL(pr_uuid); + +#else + +#include +#include + +void pr_time(struct printbuf *out, u64 _time) +{ + char time_str[64]; + time_t time =3D _time; + struct tm *tm =3D localtime(&time); + size_t err =3D strftime(time_str, sizeof(time_str), "%c", tm); + + if (!err) + pr_buf(out, "(formatting error)"); + else + pr_buf(out, "%s", time_str); +} + +void pr_uuid(struct printbuf *out, u8 *uuid) +{ + char uuid_str[40]; + + uuid_unparse_lower(uuid, uuid_str); + pr_buf(out, uuid_str); +} + +#endif + +void pr_string_option(struct printbuf *out, + const char * const list[], + size_t selected) +{ + size_t i; + + for (i =3D 0; list[i]; i++) + pr_buf(out, i =3D=3D selected ? "[%s] " : "%s ", list[i]); +} +EXPORT_SYMBOL(pr_string_option); + +void pr_bitflags(struct printbuf *out, + const char * const list[], u64 flags) +{ + unsigned bit, nr =3D 0; + bool first =3D true; + + while (list[nr]) + nr++; + + while (flags && (bit =3D __ffs(flags)) < nr) { + if (!first) + pr_buf(out, ","); + first =3D false; + pr_buf(out, "%s", list[bit]); + flags ^=3D 1 << bit; + } +} +EXPORT_SYMBOL(pr_bitflags); --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3FDA8C433F5 for ; Thu, 21 Apr 2022 23:49:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442828AbiDUXwD (ORCPT ); Thu, 21 Apr 2022 19:52:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49376 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442782AbiDUXvq (ORCPT ); Thu, 21 Apr 2022 19:51:46 -0400 Received: from mail-qv1-xf33.google.com (mail-qv1-xf33.google.com [IPv6:2607:f8b0:4864:20::f33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4269F433B1; Thu, 21 Apr 2022 16:48:54 -0700 (PDT) Received: by mail-qv1-xf33.google.com with SMTP id n11so4906693qvl.0; Thu, 21 Apr 2022 16:48:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=5WhyHlyJy4xU6YReftUXEs5LTZutZa3HDofMmOBXTLE=; b=AQLPRW36rsBuMa8/xIUdaNbDiyRqcAQz684qwwVv5jdLQnu/zUNtGDUw/B7bFrni4C pAWeJ3oN4Pj6oXtZ5lkmXkMrHv+tbMMT1sD7mBY1yESyD9eO2i5x9amEzL1U4/DhFLbO ejC1kTWj5x5vdx4D9HqkqzSrRHXcg4r8zcPJLUJI8A+cLrh9EXaLh3Mev/xfVD1zji97 ANZPDGmBJXJb5dWzh58VEUAaFZxFgnsrJPE5oOlfVAPTmm9emNVVRm7DuIUtBZjQTFHF H0YYlZzmDAKDikd3+AF86phqxO3cd9iyh4TejHR60t/GdthAMVRNpHI9zHNQtzy+/VpA GkCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=5WhyHlyJy4xU6YReftUXEs5LTZutZa3HDofMmOBXTLE=; b=EoPnVRvfNjF9maaenmDs2gfJXobomj5la/equ+uuFqK+cL3MfcTHPppTj7Oii13BVF ixEUy/mU1eh4vhRNqxsxPhAyf6SK2c2l6B53r6CeIMKX/v5ffDti9CBHMhTGthzdrg1J WOXYa8Nderkt/6OSmeIU0pPXSi9ivJ9LK1PKN61ClqSXKYfhR9NrtScXRurtlB81B595 wC4mu4baIfH4gBvBiaMv/nPvOG34dwaKbiaCtU5NC2CqE8k9IerN4F6zx/SyKwF7LQSv veTaP0ZRjhyYWBavIcEMx5MZPyRXdz0nqwwah6zAGHpGtjYPOlkAabZVFyr9Wct/R+t4 hqaQ== X-Gm-Message-State: AOAM530UjxzCBoEcJJc/34VRxNOjljw6LIQLngZes3mRufQGp0o0RJve +sOIawHOmJT3Nn9OVAvgCVQPJRfO95br X-Google-Smtp-Source: ABdhPJzTeuKYtVKzuVMuXWGTjw9xC0J0QgXOrkVmCWcRl3U4YiWy6z27w1kaozh6EXBlAv8VPDLQqQ== X-Received: by 2002:a05:6214:21a4:b0:446:5514:82b7 with SMTP id t4-20020a05621421a400b00446551482b7mr1507048qvc.54.1650584932740; Thu, 21 Apr 2022 16:48:52 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:52 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , hch@lst.de, hannes@cmpxchg.org, akpm@linux-foundation.org, linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org, linux-input@vger.kernel.org, roman.gushchin@linux.dev Subject: [PATCH v2 1/8] lib/printbuf: New data structure for heap-allocated strings Date: Thu, 21 Apr 2022 19:48:30 -0400 Message-Id: <20220421234837.3629927-7-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds printbufs: simple heap-allocated strings meant for building up structured messages, for logging/procfs/sysfs and elsewhere. They've been heavily used in bcachefs for writing .to_text() functions/methods - pretty printers, which has in turn greatly improved the overall quality of error messages. Basic usage is documented in include/linux/printbuf.h. The next patches in the series are going to be using printbufs to implement a .to_text() method for shrinkers, and improving OOM reporting. Signed-off-by: Kent Overstreet --- include/linux/printbuf.h | 164 +++++++++++++++++++++++ lib/Makefile | 2 +- lib/printbuf.c | 274 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 439 insertions(+), 1 deletion(-) create mode 100644 include/linux/printbuf.h create mode 100644 lib/printbuf.c diff --git a/include/linux/printbuf.h b/include/linux/printbuf.h new file mode 100644 index 0000000000..276cdecf08 --- /dev/null +++ b/include/linux/printbuf.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/* Copyright (C) 2022 Kent Overstreet */ + +#ifndef _LINUX_PRINTBUF_H +#define _LINUX_PRINTBUF_H + +/* + * Printbufs: Simple heap allocated strings, with some features for struct= ered + * formatting. + * + * This code has provisions for use in userspace, to aid in making other c= ode + * portable between kernelspace and userspace. + * + * Basic example: + * + * struct printbuf buf =3D PRINTBUF; + * + * pr_buf(&buf, "foo=3D"); + * foo_to_text(&buf, foo); + * printk("%s", buf.buf); + * printbuf_exit(&buf); + * + * We can now write pretty printers instead of writing code that dumps + * everything to the kernel log buffer, and then those pretty-printers can= be + * used by other code that outputs to kernel log, sysfs, debugfs, etc. + * + * Memory allocation: Outputing to a printbuf may allocate memory. This + * allocation is done with GFP_KERNEL, by default: use the newer + * memalloc_*_(save|restore) functions as needed. + * + * Since no equivalent yet exists for GFP_ATOMIC/GFP_NOWAIT, memory alloca= tions + * will be done with GFP_ATOMIC if printbuf->atomic is nonzero. + * + * Memory allocation failures: We don't return errors directly, because on + * memory allocation failure we usually don't want to bail out and unwind = - we + * want to print what we've got, on a best-effort basis. But code that doe= s want + * to return -ENOMEM may check printbuf.allocation_failure. + * + * Indenting, tabstops: + * + * To aid is writing multi-line pretty printers spread across multiple + * functions, printbufs track the current indent level. + * + * pr_indent_push() and pr_indent_pop() increase and decrease the current = indent + * level, respectively. + * + * To use tabstops, set printbuf->tabstops[]; they are in units of spaces,= from + * start of line. Once set, pr_tab() will output spaces up to the next tab= stop. + * pr_tab_rjust() will also advance the current line of text up to the next + * tabstop, but it does so by shifting text since the previous tabstop up = to the + * next tabstop - right justifying it. + * + * Make sure you use pr_newline() instead of \n in the format string for i= ndent + * level and tabstops to work corretly. + * + * Output units: printbuf->units exists to tell pretty-printers how to out= put + * numbers: a raw value (e.g. directly from a superblock field), as bytes,= or as + * human readable bytes. pr_units() and pr_sectors() obey it. + * + * Other helpful functions: + * + * pr_human_readable_u64, pr_human_readable_s64: Print an integer with hum= an + * readable units. + * + * pr_time(): for printing a time_t with strftime in userspace, prints as = an + * integer number of seconds in the kernel. + * + * pr_string_option: Given an enumerated value and a string array with nam= es for + * each option, prints out the enum names with the selected one indicated = with + * square brackets. + * + * pr_bitflags: Given a bitflag and a string array with names for each bit, + * prints out the names of the selected bits. + */ + +#include +#include + +enum printbuf_units { + PRINTBUF_UNITS_RAW, + PRINTBUF_UNITS_BYTES, + PRINTBUF_UNITS_HUMAN_READABLE, +}; + +struct printbuf { + char *buf; + unsigned size; + unsigned pos; + unsigned last_newline; + unsigned last_field; + unsigned indent; + enum printbuf_units units:8; + /* + * If nonzero, allocations will be done with GFP_ATOMIC: + */ + u8 atomic; + bool allocation_failure:1; + /* SI units (10^3), or 2^10: */ + enum string_size_units human_readable_units:1; + u8 tabstop; + u8 tabstops[4]; +}; + +#define PRINTBUF ((struct printbuf) { .human_readable_units =3D STRING_UNI= TS_2 }) + +/** + * printbuf_exit - exit a printbuf, freeing memory it owns and poisoning it + * against accidental use. + */ +static inline void printbuf_exit(struct printbuf *buf) +{ + kfree(buf->buf); + buf->buf =3D ERR_PTR(-EINTR); /* poison value */ +} + +/** + * printbuf_reset - re-use a printbuf without freeing and re-initializing = it: + */ +static inline void printbuf_reset(struct printbuf *buf) +{ + buf->pos =3D 0; + buf->last_newline =3D 0; + buf->last_field =3D 0; + buf->indent =3D 0; + buf->tabstop =3D 0; + buf->allocation_failure =3D 0; +} + +/** + * printbuf_atomic_inc - mark as entering an atomic section + */ +static inline void printbuf_atomic_inc(struct printbuf *buf) +{ + buf->atomic++; +} + +/** + * printbuf_atomic_inc - mark as leaving an atomic section + */ +static inline void printbuf_atomic_dec(struct printbuf *buf) +{ + buf->atomic--; +} + +void pr_buf(struct printbuf *out, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +void pr_char(struct printbuf *buf, char c); +void pr_newline(struct printbuf *); +void pr_indent_push(struct printbuf *, unsigned); +void pr_indent_pop(struct printbuf *, unsigned); +void pr_tab(struct printbuf *); +void pr_tab_rjust(struct printbuf *); +void pr_human_readable_u64(struct printbuf *, u64); +void pr_human_readable_s64(struct printbuf *, s64); +void pr_units(struct printbuf *, s64, s64); +void pr_sectors(struct printbuf *, u64); +void pr_time(struct printbuf *, u64); +void pr_uuid(struct printbuf *, u8 *); +void pr_string_option(struct printbuf *, const char * const list[], size_t= ); +void pr_bitflags(struct printbuf *, const char * const list[], u64); +const char *printbuf_str(const struct printbuf *); + +#endif /* _LINUX_PRINTBUF_H */ diff --git a/lib/Makefile b/lib/Makefile index c588a126a3..31a3904eda 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -34,7 +34,7 @@ lib-y :=3D ctype.o string.o vsprintf.o cmdline.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o \ - buildid.o + buildid.o printbuf.o =20 lib-$(CONFIG_PRINTK) +=3D dump_stack.o lib-$(CONFIG_SMP) +=3D cpumask.o diff --git a/lib/printbuf.c b/lib/printbuf.c new file mode 100644 index 0000000000..e0dfa82cda --- /dev/null +++ b/lib/printbuf.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: LGPL-2.1+ +/* Copyright (C) 2022 Kent Overstreet */ + +#ifdef __KERNEL__ +#include +#include +#else +#define EXPORT_SYMBOL(x) +#endif + +#include +#include +#include + +static inline size_t printbuf_remaining(struct printbuf *buf) +{ + return buf->size - buf->pos; +} + +static inline size_t printbuf_linelen(struct printbuf *buf) +{ + return buf->pos - buf->last_newline; +} + +static int printbuf_realloc(struct printbuf *out, unsigned extra) +{ + unsigned new_size; + char *buf; + + if (out->pos + extra + 1 < out->size) + return 0; + + new_size =3D roundup_pow_of_two(out->size + extra); + buf =3D krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_ATOM= IC); + + if (!buf) { + out->allocation_failure =3D true; + return -ENOMEM; + } + + out->buf =3D buf; + out->size =3D new_size; + return 0; +} + +void pr_buf(struct printbuf *out, const char *fmt, ...) +{ + va_list args; + int len; + + do { + va_start(args, fmt); + len =3D vsnprintf(out->buf + out->pos, printbuf_remaining(out), fmt, arg= s); + va_end(args); + } while (len + 1 >=3D printbuf_remaining(out) && + !printbuf_realloc(out, len + 1)); + + len =3D min_t(size_t, len, + printbuf_remaining(out) ? printbuf_remaining(out) - 1 : 0); + out->pos +=3D len; +} +EXPORT_SYMBOL(pr_buf); + +void pr_char(struct printbuf *buf, char c) +{ + if (!printbuf_realloc(buf, 1)) { + buf->buf[buf->pos++] =3D c; + buf->buf[buf->pos] =3D 0; + } +} +EXPORT_SYMBOL(pr_char); + +void pr_newline(struct printbuf *buf) +{ + unsigned i; + + pr_char(buf, '\n'); + + buf->last_newline =3D buf->pos; + + for (i =3D 0; i < buf->indent; i++) + pr_char(buf, ' '); + + buf->last_field =3D buf->pos; + buf->tabstop =3D 0; +} +EXPORT_SYMBOL(pr_newline); + +void pr_indent_push(struct printbuf *buf, unsigned spaces) +{ + buf->indent +=3D spaces; + while (spaces--) + pr_char(buf, ' '); +} +EXPORT_SYMBOL(pr_indent_push); + +void pr_indent_pop(struct printbuf *buf, unsigned spaces) +{ + if (buf->last_newline + buf->indent =3D=3D buf->pos) { + buf->pos -=3D spaces; + buf->buf[buf->pos] =3D 0; + } + buf->indent -=3D spaces; +} +EXPORT_SYMBOL(pr_indent_pop); + +void pr_tab(struct printbuf *buf) +{ + BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops)); + + while (printbuf_remaining(buf) > 1 && + printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) + pr_char(buf, ' '); + + buf->last_field =3D buf->pos; + buf->tabstop++; +} +EXPORT_SYMBOL(pr_tab); + +void pr_tab_rjust(struct printbuf *buf) +{ + BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops)); + + if (printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) { + unsigned move =3D buf->pos - buf->last_field; + unsigned shift =3D buf->tabstops[buf->tabstop] - + printbuf_linelen(buf); + + printbuf_realloc(buf, shift); + + if (buf->last_field + shift + 1 < buf->size) { + move =3D min(move, buf->size - 1 - buf->last_field - shift); + + memmove(buf->buf + buf->last_field + shift, + buf->buf + buf->last_field, + move); + memset(buf->buf + buf->last_field, ' ', shift); + buf->pos +=3D shift; + buf->buf[buf->pos] =3D 0; + } + } + + buf->last_field =3D buf->pos; + buf->tabstop++; +} +EXPORT_SYMBOL(pr_tab_rjust); + +void pr_human_readable_u64(struct printbuf *buf, u64 v) +{ + printbuf_realloc(buf, 10); + string_get_size(v, 1, buf->human_readable_units, buf->buf + buf->pos, + printbuf_remaining(buf)); + buf->pos +=3D strlen(buf->buf + buf->pos); +} +EXPORT_SYMBOL(pr_human_readable_u64); + +void pr_human_readable_s64(struct printbuf *buf, s64 v) +{ + if (v < 0) + pr_char(buf, '-'); + pr_human_readable_u64(buf, abs(v)); +} +EXPORT_SYMBOL(pr_human_readable_s64); + +void pr_units(struct printbuf *out, s64 raw, s64 bytes) +{ + switch (out->units) { + case PRINTBUF_UNITS_RAW: + pr_buf(out, "%llu", raw); + break; + case PRINTBUF_UNITS_BYTES: + pr_buf(out, "%llu", bytes); + break; + case PRINTBUF_UNITS_HUMAN_READABLE: + pr_human_readable_s64(out, bytes); + break; + } +} +EXPORT_SYMBOL(pr_units); + +void pr_sectors(struct printbuf *out, u64 v) +{ + pr_units(out, v, v << 9); +} +EXPORT_SYMBOL(pr_sectors); + +#ifdef __KERNEL__ + +void pr_time(struct printbuf *out, u64 time) +{ + pr_buf(out, "%llu", time); +} +EXPORT_SYMBOL(pr_time); + +void pr_uuid(struct printbuf *out, u8 *uuid) +{ + pr_buf(out, "%pUb", uuid); +} +EXPORT_SYMBOL(pr_uuid); + +#else + +#include +#include + +void pr_time(struct printbuf *out, u64 _time) +{ + char time_str[64]; + time_t time =3D _time; + struct tm *tm =3D localtime(&time); + size_t err =3D strftime(time_str, sizeof(time_str), "%c", tm); + + if (!err) + pr_buf(out, "(formatting error)"); + else + pr_buf(out, "%s", time_str); +} + +void pr_uuid(struct printbuf *out, u8 *uuid) +{ + char uuid_str[40]; + + uuid_unparse_lower(uuid, uuid_str); + pr_buf(out, uuid_str); +} + +#endif + +void pr_string_option(struct printbuf *out, + const char * const list[], + size_t selected) +{ + size_t i; + + for (i =3D 0; list[i]; i++) + pr_buf(out, i =3D=3D selected ? "[%s] " : "%s ", list[i]); +} +EXPORT_SYMBOL(pr_string_option); + +void pr_bitflags(struct printbuf *out, + const char * const list[], u64 flags) +{ + unsigned bit, nr =3D 0; + bool first =3D true; + + while (list[nr]) + nr++; + + while (flags && (bit =3D __ffs(flags)) < nr) { + if (!first) + pr_buf(out, ","); + first =3D false; + pr_buf(out, "%s", list[bit]); + flags ^=3D 1 << bit; + } +} +EXPORT_SYMBOL(pr_bitflags); + +/** + * printbuf_str - returns printbuf's buf as a C string, guaranteed to be n= ull + * terminated + */ +const char *printbuf_str(const struct printbuf *buf) +{ + /* + * If we've written to a printbuf then it's guaranteed to be a null + * terminated string - but if we haven't, then we might not have + * allocated a buffer at all: + */ + return buf->pos + ? buf->buf + : ""; +} +EXPORT_SYMBOL(printbuf_str); --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 956CDC43219 for ; Thu, 21 Apr 2022 23:49:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442847AbiDUXwP (ORCPT ); Thu, 21 Apr 2022 19:52:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49384 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442787AbiDUXvq (ORCPT ); Thu, 21 Apr 2022 19:51:46 -0400 Received: from mail-qv1-xf2d.google.com (mail-qv1-xf2d.google.com [IPv6:2607:f8b0:4864:20::f2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA98042EF1; Thu, 21 Apr 2022 16:48:55 -0700 (PDT) Received: by mail-qv1-xf2d.google.com with SMTP id c1so4878901qvl.3; Thu, 21 Apr 2022 16:48:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=SE94/Kbz0iYkWqSiwiZXgkxJUhacoUay8DsU/fM4rGc=; b=O+Cm9zSSCAsfuY1cv1uyHWIfLd6AHQdXHkxkvQ1owHl1q4ed7gdNQPhDpX5U39ujmv yxHn/O7exq1vCm2R4Di+f5GdGcazARxVpYR+LbOz/om50ZJUiuhNwSe/W6O8i7ARpSGQ sY60BVfp3B8pLDaUfDS918qDgPQvki6XTXv1SXJUne0mHecVCvAkhP5SeB7Jl11anPcV tOw2oSITm50Hq0EvbwOmG5qp2GC/7aihcvhgAY7xt6OtbutHsyMm6T/DKNO72WWyzLXb 2+dFGD2ybpnAYizCWKXrnWd+g1rkN8/gCfZSr+xRjYSlsTPkWNm/Ms8qB1RnC85iuZTd JJzA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=SE94/Kbz0iYkWqSiwiZXgkxJUhacoUay8DsU/fM4rGc=; b=kI9ve79GTJP9TH4fUIhtIe5rbWwpMg09m529I99NoFP92ggHBzvgDOFdVLW//LyuSI QQv/t3PTRFkcr2a0HrW+0ff+qZW8srkY6nuZ5PLLCEGSUgTQDBZM/OKrAHQ1ofdWaI6r wcFXc3c7PZ48sI+5BMBe9n///RV1ohx0dcB5h843+WoRG9Zz93zGTlRf3kkqislbh3d2 zZJ0w82kE+jRoeJtoMgmaSnIk64vU7RrdTEhzPDqNdoNKkJepVrpK7liw8R+Z2N4SKQA U6th1P+TpRPJfkHwutHbSGJHlhSpvHu6PkLrxzx9KGreOpxF6nKQT6ibVYxAXOfig0FU Wnsw== X-Gm-Message-State: AOAM530O4wDXdsjvYsqWJBZr4jAsjkAj9W0VTNP7flGuK6RKE8FdE/pJ 6z2PM2nMyyhnOLHBIBHC5wMkcVnVpzjD X-Google-Smtp-Source: ABdhPJy1Vx4dCLoAejscY+AlE0uvjsIV8mL4rJ+39tNdmbaMB3K37JbaK9DmVM8bGfz4EduxkZW3sw== X-Received: by 2002:a05:6214:c85:b0:441:2b1c:dd46 with SMTP id r5-20020a0562140c8500b004412b1cdd46mr1437161qvr.41.1650584934575; Thu, 21 Apr 2022 16:48:54 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:53 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , hch@lst.de, hannes@cmpxchg.org, akpm@linux-foundation.org, linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org, linux-input@vger.kernel.org, roman.gushchin@linux.dev Subject: [PATCH v2 2/8] Input/joystick/analog: Convert from seq_buf -> printbuf Date: Thu, 21 Apr 2022 19:48:31 -0400 Message-Id: <20220421234837.3629927-8-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" seq_buf is being deprecated, this converts to printbuf which is similar but heap allocates the string buffer. This means we have to consider memory allocation context & failure: Here we're in device initialization so GFP_KERNEL should be fine, and also as we're in device initialization returning -ENOMEM is fine. Signed-off-by: Kent Overstreet --- drivers/input/joystick/analog.c | 37 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analo= g.c index 3088c5b829..72e1e30d19 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include =20 @@ -337,26 +337,32 @@ static void analog_calibrate_timer(struct analog_port= *port) * analog_name() constructs a name for an analog joystick. */ =20 -static void analog_name(struct analog *analog) +static int analog_name(struct analog *analog) { - struct seq_buf s; + struct printbuf buf =3D PRINTBUF; + int ret =3D 0; =20 - seq_buf_init(&s, analog->name, sizeof(analog->name)); - seq_buf_printf(&s, "Analog %d-axis %d-button", - hweight8(analog->mask & ANALOG_AXES_STD), - hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTN= S_CHF) * 2 + - hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALO= G_HBTN_CHF) * 4); + pr_buf(&buf, "Analog %d-axis %d-button", + hweight8(analog->mask & ANALOG_AXES_STD), + hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALO= G_BTNS_CHF) * 2 + + hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & = ANALOG_HBTN_CHF) * 4); =20 if (analog->mask & ANALOG_HATS_ALL) - seq_buf_printf(&s, " %d-hat", - hweight16(analog->mask & ANALOG_HATS_ALL)); + pr_buf(&buf, " %d-hat", + hweight16(analog->mask & ANALOG_HATS_ALL)); =20 if (analog->mask & ANALOG_HAT_FCS) - seq_buf_printf(&s, " FCS"); + pr_buf(&buf, " FCS"); if (analog->mask & ANALOG_ANY_CHF) - seq_buf_printf(&s, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF"); + pr_buf(&buf, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF"); =20 - seq_buf_printf(&s, (analog->mask & ANALOG_GAMEPAD) ? " gamepad" : " joyst= ick"); + pr_buf(&buf, (analog->mask & ANALOG_GAMEPAD) ? " gamepad" : " joystick"); + + ret =3D buf.allocation_failure ? -ENOMEM : 0; + if (!ret) + strlcpy(analog->name, buf.buf, sizeof(analog->name)); + printbuf_exit(&buf); + return ret; } =20 /* @@ -369,7 +375,10 @@ static int analog_init_device(struct analog_port *port= , struct analog *analog, i int i, j, t, v, w, x, y, z; int error; =20 - analog_name(analog); + error =3D analog_name(analog); + if (error) + return error; + snprintf(analog->phys, sizeof(analog->phys), "%s/input%d", port->gameport->phys, index); analog->buttons =3D (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : an= alog_joy_btn; --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 782F3C4332F for ; Thu, 21 Apr 2022 23:49:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442816AbiDUXv4 (ORCPT ); Thu, 21 Apr 2022 19:51:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49296 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442774AbiDUXvj (ORCPT ); Thu, 21 Apr 2022 19:51:39 -0400 Received: from mail-qk1-x72f.google.com (mail-qk1-x72f.google.com [IPv6:2607:f8b0:4864:20::72f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0803535A9C; Thu, 21 Apr 2022 16:48:48 -0700 (PDT) Received: by mail-qk1-x72f.google.com with SMTP id j6so4752975qkp.9; Thu, 21 Apr 2022 16:48:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=eAsTyebn2Y4pYis3+WZXuPp8TzH7j4PwV2amK3FTGx8=; b=OOmnTYCAoQCRnBz8ZGchOn9i8U2hOeNPorJb87M3/pnKbf8r4wczk8AvZCUmTkG3mo xGWgYzNqWvYNey8z+NvJMhfgd1eg+nk1HGXrD25zDFPAUgk72Sa+LB7v6gfUO57Dvvme PUKAn+DVRz1g0IvpX6xC/IKenendQESOW7zlAWGHCNmpC2LVNI+AasWrGx5DlnqpEhuH GBs/HApRFPWfFJP9NkeR/a/P7ve/PSSxLMXaBDwU6FpPrKr9LlUltYvmFz5OWhNH5XKG T9QQFV9TmX/Y3Wc645Fpqp/Pqb4neHuqNYITdF61bPOzKiNfbMor6CQBRbRA0xBGNKNF hC3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=eAsTyebn2Y4pYis3+WZXuPp8TzH7j4PwV2amK3FTGx8=; b=7DrS0+Z3mThWH+nQRLrzh6PdMedrZOjHURx5Rx5y4t2ET3SAO4ziFe2f0RYFM8VyG3 qSlYr3Ek70PnEv7cgcuvalIfWDas/Imv7z11eNgW3aXTuNfEdgEkBBnUbtf6o2ZKBgzM HfUWwSYuw4+3B0TzdKtMOk4RpbdXK3bciGSFtBu9SznZwgAR4CMTp+QP8F1RsN1Oyjqm I3D9zaX0QPY4J7MKfWwV1f7h1hSOS8ste2qB7vcgDSrmwZlGgrC/8fNwd66zkiHZ+Mj3 DwBBoMbKnq45riI/qt/FUgrfpipsty4jwwD7mCtllnKDvTLObl24kTtcpGmBbVEoYYpJ WHpg== X-Gm-Message-State: AOAM5332H2udxrushDNYsfFxAj7yTT6O/mNwdGb+3f0fkcC+q5SxYsme f8dCnWFLpHHLPt4DETQKnswMdWEZy1K5 X-Google-Smtp-Source: ABdhPJznB8ohPd49EoVGQUtsW/9dkOtNQzD1SuXVh4IxjthK+x2h94gl7xGMY9HG+LZtHfOVU1TYjw== X-Received: by 2002:a05:620a:4001:b0:69e:d9cf:d957 with SMTP id h1-20020a05620a400100b0069ed9cfd957mr1185369qko.678.1650584926675; Thu, 21 Apr 2022 16:48:46 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:46 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , roman.gushchin@linux.dev, hannes@cmpxchg.org Subject: [PATCH 2/4] mm: Add a .to_text() method for shrinkers Date: Thu, 21 Apr 2022 19:48:26 -0400 Message-Id: <20220421234837.3629927-3-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds a new callback method to shrinkers which they can use to describe anything relevant to memory reclaim about their internal state, for example object dirtyness. This uses the new printbufs to output to heap allocated strings, so that the .to_text() methods can be used both for messages logged to the console, and also sysfs/debugfs. This patch also adds shrinkers_to_text(), which reports on the top 10 shrinkers - by object count - in sorted order, to be used in OOM reporting. Signed-off-by: Kent Overstreet --- include/linux/shrinker.h | 5 +++ mm/vmscan.c | 75 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index 76fbf92b04..b5f411768b 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -2,6 +2,8 @@ #ifndef _LINUX_SHRINKER_H #define _LINUX_SHRINKER_H =20 +struct printbuf; + /* * This struct is used to pass information from page reclaim to the shrink= ers. * We consolidate the values for easier extension later. @@ -58,10 +60,12 @@ struct shrink_control { * @flags determine the shrinker abilities, like numa awareness */ struct shrinker { + char name[32]; unsigned long (*count_objects)(struct shrinker *, struct shrink_control *sc); unsigned long (*scan_objects)(struct shrinker *, struct shrink_control *sc); + void (*to_text)(struct printbuf *, struct shrinker *); =20 long batch; /* reclaim batch size, 0 =3D default */ int seeks; /* seeks to recreate an obj */ @@ -94,4 +98,5 @@ extern int register_shrinker(struct shrinker *shrinker); extern void unregister_shrinker(struct shrinker *shrinker); extern void free_prealloced_shrinker(struct shrinker *shrinker); extern void synchronize_shrinkers(void); +void shrinkers_to_text(struct printbuf *); #endif diff --git a/mm/vmscan.c b/mm/vmscan.c index 59b14e0d69..09c483dfd3 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -50,6 +50,7 @@ #include #include #include +#include =20 #include #include @@ -702,6 +703,80 @@ void synchronize_shrinkers(void) } EXPORT_SYMBOL(synchronize_shrinkers); =20 +/** + * shrinkers_to_text - Report on shrinkers with highest usage + * + * This reports on the top 10 shrinkers, by object counts, in sorted order: + * intended to be used for OOM reporting. + */ +void shrinkers_to_text(struct printbuf *out) +{ + struct shrinker *shrinker; + struct shrinker_by_mem { + struct shrinker *shrinker; + unsigned long mem; + } shrinkers_by_mem[10]; + int i, nr =3D 0; + + if (!down_read_trylock(&shrinker_rwsem)) { + pr_buf(out, "(couldn't take shrinker lock)"); + return; + } + + list_for_each_entry(shrinker, &shrinker_list, list) { + struct shrink_control sc =3D { .gfp_mask =3D GFP_KERNEL, }; + unsigned long mem =3D shrinker->count_objects(shrinker, &sc); + + if (!mem || mem =3D=3D SHRINK_STOP || mem =3D=3D SHRINK_EMPTY) + continue; + + for (i =3D 0; i < nr; i++) + if (mem < shrinkers_by_mem[i].mem) + break; + + if (nr < ARRAY_SIZE(shrinkers_by_mem)) { + memmove(&shrinkers_by_mem[i + 1], + &shrinkers_by_mem[i], + sizeof(shrinkers_by_mem[0]) * (nr - i)); + nr++; + } else if (i) { + i--; + memmove(&shrinkers_by_mem[0], + &shrinkers_by_mem[1], + sizeof(shrinkers_by_mem[0]) * i); + } else { + continue; + } + + shrinkers_by_mem[i] =3D (struct shrinker_by_mem) { + .shrinker =3D shrinker, + .mem =3D mem, + }; + } + + for (i =3D nr - 1; i >=3D 0; --i) { + struct shrink_control sc =3D { .gfp_mask =3D GFP_KERNEL, }; + shrinker =3D shrinkers_by_mem[i].shrinker; + + if (shrinker->name[0]) + pr_buf(out, "%s", shrinker->name); + else + pr_buf(out, "%ps:", shrinker->scan_objects); + + pr_buf(out, " objects: %lu", shrinker->count_objects(shrinker, &sc)); + pr_newline(out); + + if (shrinker->to_text) { + pr_indent_push(out, 2); + shrinker->to_text(out, shrinker); + pr_indent_pop(out, 2); + pr_newline(out); + } + } + + up_read(&shrinker_rwsem); +} + #define SHRINK_BATCH 128 =20 static unsigned long do_shrink_slab(struct shrink_control *shrinkctl, --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 09105C433EF for ; Thu, 21 Apr 2022 23:49:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442853AbiDUXwU (ORCPT ); Thu, 21 Apr 2022 19:52:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49400 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442779AbiDUXvs (ORCPT ); Thu, 21 Apr 2022 19:51:48 -0400 Received: from mail-qk1-x72b.google.com (mail-qk1-x72b.google.com [IPv6:2607:f8b0:4864:20::72b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7565C42A1E; Thu, 21 Apr 2022 16:48:57 -0700 (PDT) Received: by mail-qk1-x72b.google.com with SMTP id j6so4753186qkp.9; Thu, 21 Apr 2022 16:48:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=e+6QqEX2/fgk530CjQfyw22ixS6gH/22/NxatjEsE7U=; b=Piq4cGEnKIYkeK5yEy1v2UexgRA+klnfryaBWZhkBupuYhBIN2XFcsCr/AaH52FE8d 0JEeXqf4Zq7HsG13fmFy4/2mFPqqz7rKZatDWMCYVdnRBHgG6rgfOgrOQHT/GVvIvdUf wsU28fJ4WSETTWK8Qg0O8saCEIIie3SaDaIHYbYAvz6DgcuMPQ3p71RE6tc8leNehciN mRO85fjyes4oVWSJFVlSIAnLK9flxPklVtPhoULVPgaguai70ROKTnCM/ymp+zIfWIfT Sc7Bv4DgOO1Af7Llus43kg4AUlS9Uw0odTji6nK7vtAut6O7Z76r0LJ651UVN/paMo0b 1RhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=e+6QqEX2/fgk530CjQfyw22ixS6gH/22/NxatjEsE7U=; b=XvSzxHpmnPiz/Izt/odwH9KfS3YkciS4zNMkBwnZbuDiIRnAR1PYNW6Mf5fc4ugGhF JoXZnH4hepo+QMH9ff3wGfAjXiqT/738VEv/tU7NZsKUD+lMdBASReMwzGkpm+0tRToB EPQo1cTU3HWkYh/mYY9ladEjC154WMe/DkZJ99QrANLWHlpuGJVp1MCSE+usjnhyAVs6 hLwXmU+wJhXkJin1Tk3GGyZtaWywKr3PYuKhEHkY62ohc8eq1wxBqucMO4YREPUz9tX+ GgT4HDLUkokx9bWkop1lAoKiy+c9N8S32qn6z6GSqOHOKCOPTGLEQGVyWKUbji+oWjfq wDfw== X-Gm-Message-State: AOAM530JBgetKWHO3h31512mhXQNTZ+Xos53qDE13svUtiLis5oGQT7Y /R+TJKBxhLvSFgn4g0OcY98gZiMDkaqk X-Google-Smtp-Source: ABdhPJxpYT8g1HdDWANIVxroce92VLtnIjLTEtakAXl78RZEeLWPyMTLx9X4IHkCH/A+O9FtQPwCpQ== X-Received: by 2002:a05:620a:17a0:b0:69e:e769:48fd with SMTP id ay32-20020a05620a17a000b0069ee76948fdmr1213264qkb.382.1650584936061; Thu, 21 Apr 2022 16:48:56 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:55 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , hch@lst.de, hannes@cmpxchg.org, akpm@linux-foundation.org, linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org, linux-input@vger.kernel.org, roman.gushchin@linux.dev Subject: [PATCH v2 3/8] mm/memcontrol.c: Convert to printbuf Date: Thu, 21 Apr 2022 19:48:32 -0400 Message-Id: <20220421234837.3629927-9-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This converts memory_stat_format() from seq_buf to printbuf. Printbuf is simalar to seq_buf except that it heap allocates the string buffer: here, we were already heap allocating the buffer with kmalloc() so the conversion is trivial. Signed-off-by: Kent Overstreet --- mm/memcontrol.c | 68 ++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 36e9f38c91..4cb0b7bc1c 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -61,7 +61,7 @@ #include #include #include -#include +#include #include "internal.h" #include #include @@ -1436,13 +1436,9 @@ static inline unsigned long memcg_page_state_output(= struct mem_cgroup *memcg, =20 static char *memory_stat_format(struct mem_cgroup *memcg) { - struct seq_buf s; + struct printbuf buf =3D PRINTBUF; int i; =20 - seq_buf_init(&s, kmalloc(PAGE_SIZE, GFP_KERNEL), PAGE_SIZE); - if (!s.buffer) - return NULL; - /* * Provide statistics on the state of the memory subsystem as * well as cumulative event counters that show past behavior. @@ -1459,49 +1455,51 @@ static char *memory_stat_format(struct mem_cgroup *= memcg) u64 size; =20 size =3D memcg_page_state_output(memcg, memory_stats[i].idx); - seq_buf_printf(&s, "%s %llu\n", memory_stats[i].name, size); + pr_buf(&buf, "%s %llu\n", memory_stats[i].name, size); =20 if (unlikely(memory_stats[i].idx =3D=3D NR_SLAB_UNRECLAIMABLE_B)) { size +=3D memcg_page_state_output(memcg, NR_SLAB_RECLAIMABLE_B); - seq_buf_printf(&s, "slab %llu\n", size); + pr_buf(&buf, "slab %llu\n", size); } } =20 /* Accumulated memory events */ =20 - seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGFAULT), - memcg_events(memcg, PGFAULT)); - seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGMAJFAULT), - memcg_events(memcg, PGMAJFAULT)); - seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGREFILL), - memcg_events(memcg, PGREFILL)); - seq_buf_printf(&s, "pgscan %lu\n", - memcg_events(memcg, PGSCAN_KSWAPD) + - memcg_events(memcg, PGSCAN_DIRECT)); - seq_buf_printf(&s, "pgsteal %lu\n", - memcg_events(memcg, PGSTEAL_KSWAPD) + - memcg_events(memcg, PGSTEAL_DIRECT)); - seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGACTIVATE), - memcg_events(memcg, PGACTIVATE)); - seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGDEACTIVATE), - memcg_events(memcg, PGDEACTIVATE)); - seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGLAZYFREE), - memcg_events(memcg, PGLAZYFREE)); - seq_buf_printf(&s, "%s %lu\n", vm_event_name(PGLAZYFREED), - memcg_events(memcg, PGLAZYFREED)); + pr_buf(&buf, "%s %lu\n", vm_event_name(PGFAULT), + memcg_events(memcg, PGFAULT)); + pr_buf(&buf, "%s %lu\n", vm_event_name(PGMAJFAULT), + memcg_events(memcg, PGMAJFAULT)); + pr_buf(&buf, "%s %lu\n", vm_event_name(PGREFILL), + memcg_events(memcg, PGREFILL)); + pr_buf(&buf, "pgscan %lu\n", + memcg_events(memcg, PGSCAN_KSWAPD) + + memcg_events(memcg, PGSCAN_DIRECT)); + pr_buf(&buf, "pgsteal %lu\n", + memcg_events(memcg, PGSTEAL_KSWAPD) + + memcg_events(memcg, PGSTEAL_DIRECT)); + pr_buf(&buf, "%s %lu\n", vm_event_name(PGACTIVATE), + memcg_events(memcg, PGACTIVATE)); + pr_buf(&buf, "%s %lu\n", vm_event_name(PGDEACTIVATE), + memcg_events(memcg, PGDEACTIVATE)); + pr_buf(&buf, "%s %lu\n", vm_event_name(PGLAZYFREE), + memcg_events(memcg, PGLAZYFREE)); + pr_buf(&buf, "%s %lu\n", vm_event_name(PGLAZYFREED), + memcg_events(memcg, PGLAZYFREED)); =20 #ifdef CONFIG_TRANSPARENT_HUGEPAGE - seq_buf_printf(&s, "%s %lu\n", vm_event_name(THP_FAULT_ALLOC), - memcg_events(memcg, THP_FAULT_ALLOC)); - seq_buf_printf(&s, "%s %lu\n", vm_event_name(THP_COLLAPSE_ALLOC), - memcg_events(memcg, THP_COLLAPSE_ALLOC)); + pr_buf(&buf, "%s %lu\n", vm_event_name(THP_FAULT_ALLOC), + memcg_events(memcg, THP_FAULT_ALLOC)); + pr_buf(&buf, "%s %lu\n", vm_event_name(THP_COLLAPSE_ALLOC), + memcg_events(memcg, THP_COLLAPSE_ALLOC)); #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ =20 - /* The above should easily fit into one page */ - WARN_ON_ONCE(seq_buf_has_overflowed(&s)); + if (buf.allocation_failure) { + printbuf_exit(&buf); + return NULL; + } =20 - return s.buffer; + return buf.buf; } =20 #define K(x) ((x) << (PAGE_SHIFT-10)) --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 82E41C433EF for ; Thu, 21 Apr 2022 23:49:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1377074AbiDUXwJ (ORCPT ); Thu, 21 Apr 2022 19:52:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49338 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1381619AbiDUXvl (ORCPT ); Thu, 21 Apr 2022 19:51:41 -0400 Received: from mail-qk1-x730.google.com (mail-qk1-x730.google.com [IPv6:2607:f8b0:4864:20::730]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A59C943AC0; Thu, 21 Apr 2022 16:48:49 -0700 (PDT) Received: by mail-qk1-x730.google.com with SMTP id b189so4743205qkf.11; Thu, 21 Apr 2022 16:48:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=hiSsrCjlwcoYpl0/USGlx4MhgXt3RiZFVish54MSnok=; b=RhU5SczM7MVxuNqxZsysmmyBQLNaVLb/iEEH6obfC/a+trx9CedfZtJBll0IWekfih tuXO0eYVjBPdozagT3PrGnVNP8+XjxRjuR9WLfymxj+0Xua835Q13Gw8Lpni5Io2OEmI b1bn/4zKQFkNEU3LLPoUKMFik3eBOJePUJ1x6G2jrK6itl1IAIa4rl7ySv4bP4evNGXT AErbwlrchxqc9UBwE2MEpLDhgcphNu5M1F4hviCtf/mrA9756zSZ5wseB6rbk2SwIL2t 6ukPAOCy90+zZIZfiWPuyhv9GPPVm9C3ICs5PJhv6LFGh3/qIz6/ZNt8Eq04DVVBw3OO nwKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=hiSsrCjlwcoYpl0/USGlx4MhgXt3RiZFVish54MSnok=; b=djnKYsgwkmM0Ba2KAHoZ0vn0nd9qcXxPdz1weC5vHKknVtiSAdosj+X/2iKJY11W0n VIG8+cY0vNw9OhWL8Gj80fdCs35drBi60RQxLFghMzUGypWQOAH1piy4JodVjlikEbGZ zTPADbndg2txB5fsYRsGlhjwexpBRJUqHEfxLcXjeiJTKAxn94y64a4Sxt5VYXAtu/uT Kj8AgMspEmayDodGDt907Xt+eDyFbOXft170w5VM9LmxsXk+JntWxNJQAj+eROGhOogX wZ19L8S+3V651DeQ5NPJQD9kZR55JFlMZzhlYUtE+t27xwtwjTVTnqNvP1V8R5XKYq28 WFwg== X-Gm-Message-State: AOAM530BIW8GzFG8sGacCq0eKlV9HDBwtU85hQ3yZRgsjJVnsxb9Uxx9 FKV8xe8FX1A3Mr0jCMHSTB308oVlgffd X-Google-Smtp-Source: ABdhPJzdKXxkO6fb4T06NqccHoQlgynEHMHYXfdQlfuIRpxfcMHi3GVv+ul+UsxLxNvOJg/4zsKRuA== X-Received: by 2002:a05:620a:4504:b0:69e:eb76:1d83 with SMTP id t4-20020a05620a450400b0069eeb761d83mr1211556qkp.92.1650584928386; Thu, 21 Apr 2022 16:48:48 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:47 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , roman.gushchin@linux.dev, hannes@cmpxchg.org Subject: [PATCH 3/4] mm: Centralize & improve oom reporting in show_mem.c Date: Thu, 21 Apr 2022 19:48:27 -0400 Message-Id: <20220421234837.3629927-4-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This patch: - Moves lib/show_mem.c to mm/show_mem.c - Changes show_mem() to always report on slab usage - Instead of reporting on all slabs, we only report on top 10 slabs, and in sorted order - Also reports on shrinkers, with the new shrinkers_to_text(). More OOM reporting can be moved to show_mem.c and improved, this patch is only a small start. Signed-off-by: Kent Overstreet --- lib/Makefile | 2 +- mm/Makefile | 2 +- mm/oom_kill.c | 23 ------------------ {lib =3D> mm}/show_mem.c | 14 +++++++++++ mm/slab.h | 6 +++-- mm/slab_common.c | 53 +++++++++++++++++++++++++++++++++++------- 6 files changed, 65 insertions(+), 35 deletions(-) rename {lib =3D> mm}/show_mem.c (78%) diff --git a/lib/Makefile b/lib/Makefile index 31a3904eda..c5041d33d0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -30,7 +30,7 @@ endif lib-y :=3D ctype.o string.o vsprintf.o cmdline.o \ rbtree.o radix-tree.o timerqueue.o xarray.o \ idr.o extable.o sha1.o irq_regs.o argv_split.o \ - flex_proportions.o ratelimit.o show_mem.o \ + flex_proportions.o ratelimit.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o \ diff --git a/mm/Makefile b/mm/Makefile index 70d4309c9c..97c0be12f3 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -54,7 +54,7 @@ obj-y :=3D filemap.o mempool.o oom_kill.o fadvise.o \ mm_init.o percpu.o slab_common.o \ compaction.o vmacache.o \ interval_tree.o list_lru.o workingset.o \ - debug.o gup.o mmap_lock.o $(mmu-y) + debug.o gup.o mmap_lock.o show_mem.o $(mmu-y) =20 # Give 'page_alloc' its own module-parameter namespace page-alloc-y :=3D page_alloc.o diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 832fb33037..659c7d6376 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -171,27 +171,6 @@ static bool oom_unkillable_task(struct task_struct *p) return false; } =20 -/* - * Check whether unreclaimable slab amount is greater than - * all user memory(LRU pages). - * dump_unreclaimable_slab() could help in the case that - * oom due to too much unreclaimable slab used by kernel. -*/ -static bool should_dump_unreclaim_slab(void) -{ - unsigned long nr_lru; - - nr_lru =3D global_node_page_state(NR_ACTIVE_ANON) + - global_node_page_state(NR_INACTIVE_ANON) + - global_node_page_state(NR_ACTIVE_FILE) + - global_node_page_state(NR_INACTIVE_FILE) + - global_node_page_state(NR_ISOLATED_ANON) + - global_node_page_state(NR_ISOLATED_FILE) + - global_node_page_state(NR_UNEVICTABLE); - - return (global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B) > nr_lru); -} - /** * oom_badness - heuristic function to determine which candidate task to k= ill * @p: task struct of which task we should calculate @@ -465,8 +444,6 @@ static void dump_header(struct oom_control *oc, struct = task_struct *p) mem_cgroup_print_oom_meminfo(oc->memcg); else { show_mem(SHOW_MEM_FILTER_NODES, oc->nodemask); - if (should_dump_unreclaim_slab()) - dump_unreclaimable_slab(); } if (sysctl_oom_dump_tasks) dump_tasks(oc); diff --git a/lib/show_mem.c b/mm/show_mem.c similarity index 78% rename from lib/show_mem.c rename to mm/show_mem.c index 1c26c14ffb..c9f37f13d6 100644 --- a/lib/show_mem.c +++ b/mm/show_mem.c @@ -7,11 +7,15 @@ =20 #include #include +#include + +#include "slab.h" =20 void show_mem(unsigned int filter, nodemask_t *nodemask) { pg_data_t *pgdat; unsigned long total =3D 0, reserved =3D 0, highmem =3D 0; + struct printbuf buf =3D PRINTBUF; =20 printk("Mem-Info:\n"); show_free_areas(filter, nodemask); @@ -41,4 +45,14 @@ void show_mem(unsigned int filter, nodemask_t *nodemask) #ifdef CONFIG_MEMORY_FAILURE printk("%lu pages hwpoisoned\n", atomic_long_read(&num_poisoned_pages)); #endif + + pr_info("Unreclaimable slab info:\n"); + dump_unreclaimable_slab(&buf); + printk("%s", buf.buf); + printbuf_reset(&buf); + + printk("Shrinkers:\n"); + shrinkers_to_text(&buf); + printk("%s", buf.buf); + printbuf_exit(&buf); } diff --git a/mm/slab.h b/mm/slab.h index c7f2abc2b1..abefbf7674 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -788,10 +788,12 @@ static inline struct kmem_cache_node *get_node(struct= kmem_cache *s, int node) =20 #endif =20 +struct printbuf; + #if defined(CONFIG_SLAB) || defined(CONFIG_SLUB_DEBUG) -void dump_unreclaimable_slab(void); +void dump_unreclaimable_slab(struct printbuf *); #else -static inline void dump_unreclaimable_slab(void) +static inline void dump_unreclaimable_slab(struct printbuf *out) { } #endif diff --git a/mm/slab_common.c b/mm/slab_common.c index 23f2ab0713..cb1c548c73 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -24,6 +24,7 @@ #include #include #include +#include =20 #define CREATE_TRACE_POINTS #include @@ -1084,10 +1085,15 @@ static int slab_show(struct seq_file *m, void *p) return 0; } =20 -void dump_unreclaimable_slab(void) +void dump_unreclaimable_slab(struct printbuf *out) { struct kmem_cache *s; struct slabinfo sinfo; + struct slab_by_mem { + struct kmem_cache *s; + size_t total, active; + } slabs_by_mem[10], n; + int i, nr =3D 0; =20 /* * Here acquiring slab_mutex is risky since we don't prefer to get @@ -1097,12 +1103,11 @@ void dump_unreclaimable_slab(void) * without acquiring the mutex. */ if (!mutex_trylock(&slab_mutex)) { - pr_warn("excessive unreclaimable slab but cannot dump stats\n"); + pr_buf(out, "excessive unreclaimable slab but cannot dump stats\n"); return; } =20 - pr_info("Unreclaimable slab info:\n"); - pr_info("Name Used Total\n"); + buf->atomic++; =20 list_for_each_entry(s, &slab_caches, list) { if (s->flags & SLAB_RECLAIM_ACCOUNT) @@ -1110,11 +1115,43 @@ void dump_unreclaimable_slab(void) =20 get_slabinfo(s, &sinfo); =20 - if (sinfo.num_objs > 0) - pr_info("%-17s %10luKB %10luKB\n", s->name, - (sinfo.active_objs * s->size) / 1024, - (sinfo.num_objs * s->size) / 1024); + if (!sinfo.num_objs) + continue; + + n.s =3D s; + n.total =3D sinfo.num_objs * s->size; + n.active =3D sinfo.active_objs * s->size; + + for (i =3D 0; i < nr; i++) + if (n.total < slabs_by_mem[i].total) + break; + + if (nr < ARRAY_SIZE(slabs_by_mem)) { + memmove(&slabs_by_mem[i + 1], + &slabs_by_mem[i], + sizeof(slabs_by_mem[0]) * (nr - i)); + nr++; + } else if (i) { + i--; + memmove(&slabs_by_mem[0], + &slabs_by_mem[1], + sizeof(slabs_by_mem[0]) * i); + } else { + continue; + } + + slabs_by_mem[i] =3D n; + } + + for (i =3D nr - 1; i >=3D 0; --i) { + pr_buf(out, "%-17s total: ", slabs_by_mem[i].s->name); + pr_human_readable_u64(out, slabs_by_mem[i].total); + pr_buf(out, " active: "); + pr_human_readable_u64(out, slabs_by_mem[i].active); + pr_newline(out); } + + --buf->atomic; mutex_unlock(&slab_mutex); } =20 --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EB6F5C433F5 for ; Thu, 21 Apr 2022 23:49:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442832AbiDUXwG (ORCPT ); Thu, 21 Apr 2022 19:52:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49340 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442778AbiDUXvm (ORCPT ); Thu, 21 Apr 2022 19:51:42 -0400 Received: from mail-qk1-x72a.google.com (mail-qk1-x72a.google.com [IPv6:2607:f8b0:4864:20::72a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EB4BD43EC5; Thu, 21 Apr 2022 16:48:50 -0700 (PDT) Received: by mail-qk1-x72a.google.com with SMTP id a186so4750158qkc.10; Thu, 21 Apr 2022 16:48:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=OJODyF/ajH9xOJK+4CIgokrEBufAgT0uT/ipe+iH5NU=; b=iMIgPJ5erku/7c7HhXsIctg1kxrza0LuvC2QEIAcGT7wBu0OauFCACWenk2xffUDR8 XvSO6KpoUrlwK8MsoRjIvhQGG3zVynFJa5Gw7Fnwvxb3RBVaVSIlGsbNQsUo5Ggj+g2m F3zt7/xN30ltoNSguXjheaeHJTLuicb+L99c5ETzfEAHShhj8+y7XTpzRhK1h/NwV1jP 1RdSjlkCUTKXhQ+pScjWL/hQfIrvKW6R9iBUMiwKnX/QQ4H696tdz7Sf3PD2st3851z7 hwHwA2cDiSaz5zzTGDVOXyaBFkRTNpPOx/O+/F4tLvIWQswTUThlV4CaqLNTB+5KykNb ovFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=OJODyF/ajH9xOJK+4CIgokrEBufAgT0uT/ipe+iH5NU=; b=dT7YDNQAogKLFLm0MaZIsSL/fsSRQRybj8UEbxoyR2g0El5Bf3ztULqTP2gMWHU5Ju IyEFFbl75Q+D/FRff2V3i9Bim102XNE3JSVsZ7qbSP9L/a5rfFMKemDEeQtE+94JeNIZ WUkeZPBPe62MWe7IUnMAcMHyRpcUqlKPqIvSzMsAZjQt1ccfqmzWCbOT5BVnNkTO0NIR 5FKl9hcRcEhSQBucBqKTCqUWdPvwqTiwek34KSVjA/JuzTdBXf7FdCCpi5lClmJy5ym1 pWFsGm2h88DugVG+pzINlh8cTtw4LhHlOGB7b1NrS9qEnvvwiN+KNrn5F7rUQNKkXi4K 1HfA== X-Gm-Message-State: AOAM5314cmTiOBDOL8QxjJR2rvAafXPGbulZXOc4UA5SqaYTHMzpbtAG /e3eHzKnVoUtghCsXqPm0Ae58YmBJlJt X-Google-Smtp-Source: ABdhPJxI32XeTa41Ms2HZb8peaWuFEExEtNfe16DFYhZQ/thdpSwM/dy7gUZcuantPPXtVlOJX7YeA== X-Received: by 2002:a05:620a:4488:b0:69e:bf0f:42be with SMTP id x8-20020a05620a448800b0069ebf0f42bemr1112891qkp.663.1650584929641; Thu, 21 Apr 2022 16:48:49 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:49 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , roman.gushchin@linux.dev Subject: [PATCH 4/4] bcachefs: shrinker.to_text() methods Date: Thu, 21 Apr 2022 19:48:28 -0400 Message-Id: <20220421234837.3629927-5-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Signed-off-by: Kent Overstreet --- fs/bcachefs/btree_cache.c | 18 +++++++++++++++--- fs/bcachefs/btree_key_cache.c | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/fs/bcachefs/btree_cache.c b/fs/bcachefs/btree_cache.c index 72f0587e4d..75ef3b5462 100644 --- a/fs/bcachefs/btree_cache.c +++ b/fs/bcachefs/btree_cache.c @@ -394,6 +394,14 @@ static unsigned long bch2_btree_cache_count(struct shr= inker *shrink, return btree_cache_can_free(bc); } =20 +static void bch2_btree_cache_shrinker_to_text(struct printbuf *out, struct= shrinker *shrink) +{ + struct bch_fs *c =3D container_of(shrink, struct bch_fs, + btree_cache.shrink); + + bch2_btree_cache_to_text(out, c); +} + void bch2_fs_btree_cache_exit(struct bch_fs *c) { struct btree_cache *bc =3D &c->btree_cache; @@ -477,6 +485,7 @@ int bch2_fs_btree_cache_init(struct bch_fs *c) =20 bc->shrink.count_objects =3D bch2_btree_cache_count; bc->shrink.scan_objects =3D bch2_btree_cache_scan; + bc->shrink.to_text =3D bch2_btree_cache_shrinker_to_text; bc->shrink.seeks =3D 4; ret =3D register_shrinker(&bc->shrink); out: @@ -1147,7 +1156,10 @@ void bch2_btree_node_to_text(struct printbuf *out, s= truct bch_fs *c, =20 void bch2_btree_cache_to_text(struct printbuf *out, struct bch_fs *c) { - pr_buf(out, "nr nodes:\t\t%u\n", c->btree_cache.used); - pr_buf(out, "nr dirty:\t\t%u\n", atomic_read(&c->btree_cache.dirty)); - pr_buf(out, "cannibalize lock:\t%p\n", c->btree_cache.alloc_lock); + pr_buf(out, "nr nodes: %u", c->btree_cache.used); + pr_newline(out); + pr_buf(out, "nr dirty: %u", atomic_read(&c->btree_cache.dirty)); + pr_newline(out); + pr_buf(out, "cannibalize lock: %p", c->btree_cache.alloc_lock); + pr_newline(out); } diff --git a/fs/bcachefs/btree_key_cache.c b/fs/bcachefs/btree_key_cache.c index a575189f35..32b5cb6042 100644 --- a/fs/bcachefs/btree_key_cache.c +++ b/fs/bcachefs/btree_key_cache.c @@ -711,6 +711,14 @@ void bch2_fs_btree_key_cache_init_early(struct btree_k= ey_cache *c) INIT_LIST_HEAD(&c->freed); } =20 +static void bch2_btree_key_cache_shrinker_to_text(struct printbuf *out, st= ruct shrinker *shrink) +{ + struct btree_key_cache *bc =3D + container_of(shrink, struct btree_key_cache, shrink); + + bch2_btree_key_cache_to_text(out, bc); +} + int bch2_fs_btree_key_cache_init(struct btree_key_cache *c) { int ret; @@ -724,14 +732,18 @@ int bch2_fs_btree_key_cache_init(struct btree_key_cac= he *c) c->shrink.seeks =3D 1; c->shrink.count_objects =3D bch2_btree_key_cache_count; c->shrink.scan_objects =3D bch2_btree_key_cache_scan; + c->shrink.to_text =3D bch2_btree_key_cache_shrinker_to_text; return register_shrinker(&c->shrink); } =20 void bch2_btree_key_cache_to_text(struct printbuf *out, struct btree_key_c= ache *c) { - pr_buf(out, "nr_freed:\t%zu\n", c->nr_freed); - pr_buf(out, "nr_keys:\t%lu\n", atomic_long_read(&c->nr_keys)); - pr_buf(out, "nr_dirty:\t%lu\n", atomic_long_read(&c->nr_dirty)); + pr_buf(out, "nr_freed: %zu", c->nr_freed); + pr_newline(out); + pr_buf(out, "nr_keys: %zu", atomic_long_read(&c->nr_keys)); + pr_newline(out); + pr_buf(out, "nr_dirty: %zu", atomic_long_read(&c->nr_dirty)); + pr_newline(out); } =20 void bch2_btree_key_cache_exit(void) --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 458C4C43219 for ; Thu, 21 Apr 2022 23:50:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442878AbiDUXw3 (ORCPT ); Thu, 21 Apr 2022 19:52:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49428 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442776AbiDUXvu (ORCPT ); Thu, 21 Apr 2022 19:51:50 -0400 Received: from mail-qv1-xf35.google.com (mail-qv1-xf35.google.com [IPv6:2607:f8b0:4864:20::f35]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 222B2434A5; Thu, 21 Apr 2022 16:48:59 -0700 (PDT) Received: by mail-qv1-xf35.google.com with SMTP id hu11so4859464qvb.7; Thu, 21 Apr 2022 16:48:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=PF/Z8BQ8fxOBlrER2fv/400ai3CQSf3kzChsoC/3ncM=; b=Fmg9GchsDQjutgHrWM/IG+EZhv+HiZ+dEvnMEDFKb+T+r+Q/Xm1YYliGP71kb6HN+W GLqoDr61dXwsDzPdRECJYcQarmk+T6H4rug3ZFdmtLaQYy7lzYaMsCU6dX3rUj64pGr7 difeOIk+oQYdWGlmXufNianxRUrB5l5qg89ze9Jteco8L9yFCLmSBz6753W5U7GVkTFf KV2WBL3T5cbnVEjKBJAhLxSEDGc8wbP1WK3nKE6ceGRyVxh4RU72LEeojkTBoTQAuVll 0zLDqezyxdzSEYDpBh/5eBMG/x+TQe220iuYVtOgctc18dzhEdeyciNQwMdPaIo0yI2x DdwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=PF/Z8BQ8fxOBlrER2fv/400ai3CQSf3kzChsoC/3ncM=; b=P6i+gA/DsL+XmEyamtFY0jBIIrN9d/kl+qiz2uyV9VCwfCe/xNOeG8YgU4n4nTf1Xa JRbxqcuLGqAC1wIrNEU+SW7KmBimKFoCxbCBN37paIJoDmsA3SskzygGTRIxSoT7tQQm 6serWAq3j8c6aCID7x8cr//OLzx88IImOnckVMlkc1dTD6caljaX3GgHK0hcVpcX/A6R xi/Oa4jekRBgIRvbpFFrmB4RY3bleooJAlY9HWbW5hMJdhvI8zNONzHfXULKKrRzqa3p D55xzESMxviBxVBNZ3hil/UmnjfejmeG709wyVbzB2c+XZYHvSZWDQRmnZMy1s9fSHh8 vOsA== X-Gm-Message-State: AOAM533GR4sKfLgLxU1pZavK/8APAiGi3ROe6u2cggbwrJsDdHcmxsPz Jz9qjlWVBMrn0OGPai209rZdhviLkHGb X-Google-Smtp-Source: ABdhPJwDhIK3eHTLsewAwF5FpbZ4NbS8mVZfkNqfhh2q7YLtu3tIrgjsNLqW2nO1uAxRcg8T77R/yw== X-Received: by 2002:ad4:5caa:0:b0:446:54ef:60d4 with SMTP id q10-20020ad45caa000000b0044654ef60d4mr1790926qvh.86.1650584937815; Thu, 21 Apr 2022 16:48:57 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:56 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , hch@lst.de, hannes@cmpxchg.org, akpm@linux-foundation.org, linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org, linux-input@vger.kernel.org, roman.gushchin@linux.dev Subject: [PATCH v2 4/8] clk: tegra: bpmp: Convert to printbuf Date: Thu, 21 Apr 2022 19:48:33 -0400 Message-Id: <20220421234837.3629927-10-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This converts from seq_buf to printbuf, which is similar but heap allocates the string buffer. Previously in this code the string buffer was allocated on the stack; this means we've added a new potential memory allocation failure. This is fine though since it's only for a dev_printk() message. Memory allocation context: printbuf doesn't take gfp flags, instead we prefer the new memalloc_no*_(save|restore) interfaces to be used. Here the surrounding code is already allocating with GFP_KERNEL, so everything is fine. Signed-off-by: Kent Overstreet --- drivers/clk/tegra/clk-bpmp.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index 6ecf18f71c..77a8c47806 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -5,7 +5,7 @@ =20 #include #include -#include +#include #include =20 #include @@ -360,39 +360,38 @@ static void tegra_bpmp_clk_info_dump(struct tegra_bpm= p *bpmp, const struct tegra_bpmp_clk_info *info) { const char *prefix =3D ""; - struct seq_buf buf; + struct printbuf buf =3D PRINTBUF; unsigned int i; - char flags[64]; - - seq_buf_init(&buf, flags, sizeof(flags)); =20 if (info->flags) - seq_buf_printf(&buf, "("); + pr_buf(&buf, "("); =20 if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) { - seq_buf_printf(&buf, "%smux", prefix); + pr_buf(&buf, "%smux", prefix); prefix =3D ", "; } =20 if ((info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE) =3D=3D 0) { - seq_buf_printf(&buf, "%sfixed", prefix); + pr_buf(&buf, "%sfixed", prefix); prefix =3D ", "; } =20 if (info->flags & TEGRA_BPMP_CLK_IS_ROOT) { - seq_buf_printf(&buf, "%sroot", prefix); + pr_buf(&buf, "%sroot", prefix); prefix =3D ", "; } =20 if (info->flags) - seq_buf_printf(&buf, ")"); + pr_buf(&buf, ")"); =20 dev_printk(level, bpmp->dev, "%03u: %s\n", info->id, info->name); - dev_printk(level, bpmp->dev, " flags: %lx %s\n", info->flags, flags); + dev_printk(level, bpmp->dev, " flags: %lx %s\n", info->flags, printbuf_s= tr(&buf)); dev_printk(level, bpmp->dev, " parents: %u\n", info->num_parents); =20 for (i =3D 0; i < info->num_parents; i++) dev_printk(level, bpmp->dev, " %03u\n", info->parents[i]); + + printbuf_exit(&buf); } =20 static int tegra_bpmp_probe_clocks(struct tegra_bpmp *bpmp, --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 123A2C433FE for ; Thu, 21 Apr 2022 23:50:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442859AbiDUXxg (ORCPT ); Thu, 21 Apr 2022 19:53:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442809AbiDUXvw (ORCPT ); Thu, 21 Apr 2022 19:51:52 -0400 Received: from mail-qv1-xf33.google.com (mail-qv1-xf33.google.com [IPv6:2607:f8b0:4864:20::f33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 97AE8434B5; Thu, 21 Apr 2022 16:49:00 -0700 (PDT) Received: by mail-qv1-xf33.google.com with SMTP id ke5so2635997qvb.5; Thu, 21 Apr 2022 16:49:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gx/pEzK/Si3DJxK25M0+mRodztZR2hxnPp00eWVAa1k=; b=Md/LjYEF9f+pRuz8KZH8oR8ODzAl6LE1NdwDO9B7yhhTbHjC1XjY6StBiio3j2Nvo1 JelKkMUZhH6wK9SIieCBlHRjkPiXecMX7lbXfg/XqFWogYyaitQ4MdWK8BXZq7mkhu1O OFnyhM+ibntll36tPPZSueMUXCwouOzvP6eHH1utH55G/gzIVvvomUfh32hDdsmMbf5j ior9XaGlQzyXxpuadInYd2sY51uzIco7yCLiu8jNyncc1IUMQD2y1/lU0BMZz4BOsCG/ YfI4zjIBitflaOo7HONdKt45CVTiopIOyKsTTpjmD6y0c5WL8ulhg5/2E53m0J0N/wOI +Qdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gx/pEzK/Si3DJxK25M0+mRodztZR2hxnPp00eWVAa1k=; b=SpsmedleUlNsICzdnEvYumm35OBa5oSpxxBCG6LU4eWfN8S43dnrXBYaHIksYEMEsA /X4o6rdX2gPDDmnEoFDV0dBg+AdFSDXACyLFWI0N4F3Ox73rShQCBx+Er+9zsvAHsYfc A+aDTgqGeGLXVoM5MOizIeMvcBhcyrbstOX7fLPBIZAIb4JKLd6Mu/iaDyj4YeEXW+Vo KjK/q/NtODtV0opmODsmLBU3XIiXj28ZgSJQHYlurNfjaC1iJcPyy9ctcQVVrgvJLPr8 dIKyNPUrdFtanfi5Fn7IxHoRkEwrJGuIg9f+oH/zz0MCAm5EyD+4FobyB8mDSnjYTth8 6Xug== X-Gm-Message-State: AOAM530a89CvO2mrP+SMOw2boDCMYmnTAIdImUV4P8GWf1ft5+Hx5lNR 1LaPy1F+AxsoXyz/T7qaO2EhMUo3ytFZ X-Google-Smtp-Source: ABdhPJy1nyPXDBoL0+vXyPBBH/+kX8pkeabBh3Ms+kkb3pWns3FlAR3mANJ7k+SatBCK1YhmRDDm8g== X-Received: by 2002:a05:6214:262c:b0:446:3464:57cd with SMTP id gv12-20020a056214262c00b00446346457cdmr1758402qvb.89.1650584939257; Thu, 21 Apr 2022 16:48:59 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:48:58 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , hch@lst.de, hannes@cmpxchg.org, akpm@linux-foundation.org, linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org, linux-input@vger.kernel.org, roman.gushchin@linux.dev Subject: [PATCH v2 5/8] mm: Add a .to_text() method for shrinkers Date: Thu, 21 Apr 2022 19:48:34 -0400 Message-Id: <20220421234837.3629927-11-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This adds a new callback method to shrinkers which they can use to describe anything relevant to memory reclaim about their internal state, for example object dirtyness. This uses the new printbufs to output to heap allocated strings, so that the .to_text() methods can be used both for messages logged to the console, and also sysfs/debugfs. This patch also adds shrinkers_to_text(), which reports on the top 10 shrinkers - by object count - in sorted order, to be used in OOM reporting. Signed-off-by: Kent Overstreet --- include/linux/shrinker.h | 5 +++ mm/vmscan.c | 78 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index 76fbf92b04..b5f411768b 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -2,6 +2,8 @@ #ifndef _LINUX_SHRINKER_H #define _LINUX_SHRINKER_H =20 +struct printbuf; + /* * This struct is used to pass information from page reclaim to the shrink= ers. * We consolidate the values for easier extension later. @@ -58,10 +60,12 @@ struct shrink_control { * @flags determine the shrinker abilities, like numa awareness */ struct shrinker { + char name[32]; unsigned long (*count_objects)(struct shrinker *, struct shrink_control *sc); unsigned long (*scan_objects)(struct shrinker *, struct shrink_control *sc); + void (*to_text)(struct printbuf *, struct shrinker *); =20 long batch; /* reclaim batch size, 0 =3D default */ int seeks; /* seeks to recreate an obj */ @@ -94,4 +98,5 @@ extern int register_shrinker(struct shrinker *shrinker); extern void unregister_shrinker(struct shrinker *shrinker); extern void free_prealloced_shrinker(struct shrinker *shrinker); extern void synchronize_shrinkers(void); +void shrinkers_to_text(struct printbuf *); #endif diff --git a/mm/vmscan.c b/mm/vmscan.c index 59b14e0d69..905bc23800 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -50,6 +50,7 @@ #include #include #include +#include =20 #include #include @@ -702,6 +703,83 @@ void synchronize_shrinkers(void) } EXPORT_SYMBOL(synchronize_shrinkers); =20 +void shrinker_to_text(struct printbuf *out, struct shrinker *shrinker) +{ + struct shrink_control sc =3D { .gfp_mask =3D GFP_KERNEL, }; + + if (shrinker->name[0]) + pr_buf(out, "%s", shrinker->name); + else + pr_buf(out, "%ps:", shrinker->scan_objects); + + pr_buf(out, " objects: %lu", shrinker->count_objects(shrinker, &sc)); + pr_newline(out); + + if (shrinker->to_text) { + pr_indent_push(out, 2); + shrinker->to_text(out, shrinker); + pr_indent_pop(out, 2); + pr_newline(out); + } +} + +/** + * shrinkers_to_text - Report on shrinkers with highest usage + * + * This reports on the top 10 shrinkers, by object counts, in sorted order: + * intended to be used for OOM reporting. + */ +void shrinkers_to_text(struct printbuf *out) +{ + struct shrinker *shrinker; + struct shrinker_by_mem { + struct shrinker *shrinker; + unsigned long mem; + } shrinkers_by_mem[10]; + int i, nr =3D 0; + + if (!down_read_trylock(&shrinker_rwsem)) { + pr_buf(out, "(couldn't take shrinker lock)"); + return; + } + + list_for_each_entry(shrinker, &shrinker_list, list) { + struct shrink_control sc =3D { .gfp_mask =3D GFP_KERNEL, }; + unsigned long mem =3D shrinker->count_objects(shrinker, &sc); + + if (!mem || mem =3D=3D SHRINK_STOP || mem =3D=3D SHRINK_EMPTY) + continue; + + for (i =3D 0; i < nr; i++) + if (mem < shrinkers_by_mem[i].mem) + break; + + if (nr < ARRAY_SIZE(shrinkers_by_mem)) { + memmove(&shrinkers_by_mem[i + 1], + &shrinkers_by_mem[i], + sizeof(shrinkers_by_mem[0]) * (nr - i)); + nr++; + } else if (i) { + i--; + memmove(&shrinkers_by_mem[0], + &shrinkers_by_mem[1], + sizeof(shrinkers_by_mem[0]) * i); + } else { + continue; + } + + shrinkers_by_mem[i] =3D (struct shrinker_by_mem) { + .shrinker =3D shrinker, + .mem =3D mem, + }; + } + + for (i =3D nr - 1; i >=3D 0; --i) + shrinker_to_text(out, shrinkers_by_mem[i].shrinker); + + up_read(&shrinker_rwsem); +} + #define SHRINK_BATCH 128 =20 static unsigned long do_shrink_slab(struct shrink_control *shrinkctl, --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E579EC433F5 for ; Thu, 21 Apr 2022 23:50:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442903AbiDUXxs (ORCPT ); Thu, 21 Apr 2022 19:53:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49906 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442779AbiDUXwW (ORCPT ); Thu, 21 Apr 2022 19:52:22 -0400 Received: from mail-qv1-xf2c.google.com (mail-qv1-xf2c.google.com [IPv6:2607:f8b0:4864:20::f2c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 163C047385; Thu, 21 Apr 2022 16:49:02 -0700 (PDT) Received: by mail-qv1-xf2c.google.com with SMTP id n11so4906889qvl.0; Thu, 21 Apr 2022 16:49:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=FeM5bqJiQrm2rh3JILkdt+BZf3iQXt3DndJ5kJUH6VM=; b=n/KPNGWJXcs0GJJTYwzELGdDRU26YZeN+AFBdrfivcUmDTFgoEKIyrauqulst14dH0 VIawqwx2mO79s0OxciEEIzbn1FvG1bH8bG3uS1fw7LT5ALzrMm7yM+uw93vItLfT2nW0 6vW0ixWFbUjKGZzE54v1t/I3Bb56898l1K1XBAcQabLQzanStxI9UkxPRziU7gkhloaO BPYvgr1vJyyfoY4JXraylWH6PYW9y9v+u6E5dvL1U4gTfbVtPd5b01hz0ZuIgSBkAYal 2vHqlPuenxkKGGJ237DRh/3jonP/A8fdnfy/nV7yUnNdSgA4uOcGoslhIzZ4kevfjAKu LBBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=FeM5bqJiQrm2rh3JILkdt+BZf3iQXt3DndJ5kJUH6VM=; b=nOAPxG8xFKfc88RtTdPQ1SPFgF2adwipG9fL2+cI3+G2jrJ5mLdFyvE5GdxI62CAyD ldLwHngqJUTsDDh8otfdcKrIH6tphDBANDtcgpVNLLaTaMkmC7cbP+3etELttkaQ5/Iz 8E9m2u0f11rn7hZFaIh8xdZG3g2ONbcVizl3vc1UnzhFTew/QH9g22ylLG7VQyxSYsWu s3/wuxoNZk5R1+/9y3rXySVq4HAP+ig0MxmsAXS91/S8vSl3Ny4/i57/9gW6hdkZT1Pd D8kYxwQCwrewL0pIl1nH7g29LHXkMXGcdcDMWUIBZ0fZkossO3sH74G77eq8AwLYL5lu 3uKg== X-Gm-Message-State: AOAM530EKcXeKhcShHjP2rVI9zKP+uEYnwlc1kPd9qDWo6YQ5CsZDqUJ qgarRLmTkHoYPGIf9GesEzJI0neeXczI X-Google-Smtp-Source: ABdhPJwIwwSIi9BX9ueYR8W3xLzPDKzGU08fb3TSCEvxc7eNfeoVsUdKsvEsHwvgXeKxMCM8QFg4Jg== X-Received: by 2002:a05:6214:3006:b0:444:2fa9:9849 with SMTP id ke6-20020a056214300600b004442fa99849mr1462717qvb.101.1650584940771; Thu, 21 Apr 2022 16:49:00 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.48.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:49:00 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , hch@lst.de, hannes@cmpxchg.org, akpm@linux-foundation.org, linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org, linux-input@vger.kernel.org, roman.gushchin@linux.dev Subject: [PATCH v2 6/8] mm: Count requests to free & nr freed per shrinker Date: Thu, 21 Apr 2022 19:48:35 -0400 Message-Id: <20220421234837.3629927-12-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The next step in this patch series for improving debugging of shrinker related issues: keep counts of number of objects we request to free vs. actually freed, and prints them in shrinker_to_text(). Shrinkers won't necessarily free all objects requested for a variety of reasons, but if the two counts are wildly different something is likely amiss. Signed-off-by: Kent Overstreet --- include/linux/shrinker.h | 3 +++ mm/vmscan.c | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index b5f411768b..12967748f9 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -79,6 +79,9 @@ struct shrinker { #endif /* objs pending delete, per node */ atomic_long_t *nr_deferred; + + atomic_long_t objects_requested_to_free; + atomic_long_t objects_freed; }; #define DEFAULT_SEEKS 2 /* A good number if you don't know better. */ =20 diff --git a/mm/vmscan.c b/mm/vmscan.c index 905bc23800..12562546a7 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -711,16 +711,22 @@ void shrinker_to_text(struct printbuf *out, struct sh= rinker *shrinker) pr_buf(out, "%s", shrinker->name); else pr_buf(out, "%ps:", shrinker->scan_objects); + pr_newline(out); + pr_indent_push(out, 2); =20 - pr_buf(out, " objects: %lu", shrinker->count_objects(shrinker, &sc)); + pr_buf(out, "objects: %lu", shrinker->count_objects(shrinker, &= sc)); + pr_newline(out); + pr_buf(out, "requested to free: %lu", atomic_long_read(&shrinker->objects= _requested_to_free)); + pr_newline(out); + pr_buf(out, "objects freed: %lu", atomic_long_read(&shrinker->objects= _freed)); pr_newline(out); =20 if (shrinker->to_text) { - pr_indent_push(out, 2); shrinker->to_text(out, shrinker); - pr_indent_pop(out, 2); pr_newline(out); } + + pr_indent_pop(out, 2); } =20 /** @@ -846,12 +852,16 @@ static unsigned long do_shrink_slab(struct shrink_con= trol *shrinkctl, unsigned long ret; unsigned long nr_to_scan =3D min(batch_size, total_scan); =20 + atomic_long_add(nr_to_scan, &shrinker->objects_requested_to_free); + shrinkctl->nr_to_scan =3D nr_to_scan; shrinkctl->nr_scanned =3D nr_to_scan; ret =3D shrinker->scan_objects(shrinker, shrinkctl); if (ret =3D=3D SHRINK_STOP) break; + freed +=3D ret; + atomic_long_add(ret, &shrinker->objects_freed); =20 count_vm_events(SLABS_SCANNED, shrinkctl->nr_scanned); total_scan -=3D shrinkctl->nr_scanned; --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 89C16C433EF for ; Thu, 21 Apr 2022 23:50:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1442895AbiDUXxn (ORCPT ); Thu, 21 Apr 2022 19:53:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49904 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442855AbiDUXwW (ORCPT ); Thu, 21 Apr 2022 19:52:22 -0400 Received: from mail-qk1-x731.google.com (mail-qk1-x731.google.com [IPv6:2607:f8b0:4864:20::731]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8E76347541; Thu, 21 Apr 2022 16:49:03 -0700 (PDT) Received: by mail-qk1-x731.google.com with SMTP id b68so4762799qkc.4; Thu, 21 Apr 2022 16:49:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=OX+ZZxfUCa6AeznhtMYBa3lbAYkGql05KEYmpApGJvc=; b=fWoFdNFoTzuTeyd37gJBh3UEJqZnL5c7olLDqlVchiUDB4EfzgpzArPgDksaoxFYSV lFcwfvuY2O4d+01Q5Zj7FApRfnsx10MrvqIQjieDrYqKS8oTMogkpDCLe6b+tIvGeoDg oZ25deodeMYYdcb4msCQZ95tNwqLOpZL1GqFWlCJbzyzHA0RXWkB1OWPmvNGxWqOFk0Z NMobe8u2+R7aXU1cBxhn6C/5a3nl/GRTkhDG3IY39MAnvrmCeWGVgd8OH0FEk9JXcTV+ sT/ZRPNX+2nh2YnvFSNMks5fpzsFDvBjYXVsugVKFszq5lRjdggcfrPmLI1vTlpoRedw R7eg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=OX+ZZxfUCa6AeznhtMYBa3lbAYkGql05KEYmpApGJvc=; b=nMilll6iPLoM+F+QT3W8u2m/mt9pOQQ+r+uClq6+uxtqAsTZHZsi3mubEJq80i/3rW 92p/R1IxcuNU3NOxPJLFta3QIlZ5FXa0+yW9lfj6Pob7UadwO6veTKjz0ESnboTA7oRz K0cUUazZ8jEAPuMiFqwFwqqtypPDCZAQKFE0Cw+9MRC+5qqAvgESV3rO0OV02zyOvuVf 7OYo3zvhSr2/j7rgAYhCxzohUrpuXhTXzyTuX2Ph8kw6T3R5VPZ2wcv6xQsTAflE4TDY s8pPm0unxCaDvIbQEfpW3qZUrtFlhT8f6+rpoPf4umy2GChXQmnUJm6a1IUuHv/IZR8W VYvg== X-Gm-Message-State: AOAM532Kk/qKbRjROAObwT3eLJ8R7VN8CV0T+ouaAkDKc3i6ZMwyJzMM rpseF8w2ZwpqEb4uiWXBlsUPfsyodICm X-Google-Smtp-Source: ABdhPJy4AfRMSM5fE/ShUTn41jLAMSbQ5zXgowJp+WmfgN33q5UIkYcEB9ug5C7qJVU5PFjSL7Hzbg== X-Received: by 2002:a05:620a:2805:b0:67d:5c7e:c43a with SMTP id f5-20020a05620a280500b0067d5c7ec43amr1216746qkp.84.1650584942298; Thu, 21 Apr 2022 16:49:02 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.49.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:49:01 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , hch@lst.de, hannes@cmpxchg.org, akpm@linux-foundation.org, linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org, linux-input@vger.kernel.org, roman.gushchin@linux.dev Subject: [PATCH v2 7/8] mm: Move lib/show_mem.c to mm/ Date: Thu, 21 Apr 2022 19:48:36 -0400 Message-Id: <20220421234837.3629927-13-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" show_mem.c is really mm specific, and the next patch in the series is going to require mm/slab.h, so let's move it before doing more work on it. Signed-off-by: Kent Overstreet Acked-by: Michal Hocko --- lib/Makefile | 2 +- mm/Makefile | 2 +- {lib =3D> mm}/show_mem.c | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename {lib =3D> mm}/show_mem.c (100%) diff --git a/lib/Makefile b/lib/Makefile index 31a3904eda..c5041d33d0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -30,7 +30,7 @@ endif lib-y :=3D ctype.o string.o vsprintf.o cmdline.o \ rbtree.o radix-tree.o timerqueue.o xarray.o \ idr.o extable.o sha1.o irq_regs.o argv_split.o \ - flex_proportions.o ratelimit.o show_mem.o \ + flex_proportions.o ratelimit.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o siphash.o dec_and_lock.o \ nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o \ diff --git a/mm/Makefile b/mm/Makefile index 70d4309c9c..97c0be12f3 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -54,7 +54,7 @@ obj-y :=3D filemap.o mempool.o oom_kill.o fadvise.o \ mm_init.o percpu.o slab_common.o \ compaction.o vmacache.o \ interval_tree.o list_lru.o workingset.o \ - debug.o gup.o mmap_lock.o $(mmu-y) + debug.o gup.o mmap_lock.o show_mem.o $(mmu-y) =20 # Give 'page_alloc' its own module-parameter namespace page-alloc-y :=3D page_alloc.o diff --git a/lib/show_mem.c b/mm/show_mem.c similarity index 100% rename from lib/show_mem.c rename to mm/show_mem.c --=20 2.35.2 From nobody Mon May 11 00:45:15 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D360CC433F5 for ; Thu, 21 Apr 2022 23:51:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1387034AbiDUXxx (ORCPT ); Thu, 21 Apr 2022 19:53:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49914 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442861AbiDUXwW (ORCPT ); Thu, 21 Apr 2022 19:52:22 -0400 Received: from mail-qk1-x734.google.com (mail-qk1-x734.google.com [IPv6:2607:f8b0:4864:20::734]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 363F947AE9; Thu, 21 Apr 2022 16:49:05 -0700 (PDT) Received: by mail-qk1-x734.google.com with SMTP id q75so4758029qke.6; Thu, 21 Apr 2022 16:49:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=aaKcIjNjF3IwQgxs7vyEXb42UUHeDaL+RKW940GYuHE=; b=a0tjhmKMatzGt0SztAxbHSgi9tkuoq0b0Avq27VcC+kWC+951h6K4afxy78BlImIme 8hwewDxQUByXhjBpdf3GRogZFMXghbYddWPYGObWHaKwar6ZutgSnbKNT7F3FZLqk7wN iZppyKJc9qP3jlBDtQPTyi/5r/om31TNT0840qZqtz+vuCG6AlUZg0IcBuGtOpb3ubGg NNKJgJqrfumSUdnk3c04fo5WdiHypYP0u2zJ040DG42b0Ps/eBSB7PE57jCggeofy1rQ bctqg3CeHEwk/dvoUnReNkmfYLTGm+Cqm1k45E9NSblGTm2QEP4vBQwsNvO+VemICgy1 gcCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=aaKcIjNjF3IwQgxs7vyEXb42UUHeDaL+RKW940GYuHE=; b=dYZl1j8JBv8yxudvoLOWi6OljcuD7nl/yvdxg/qHKI9RY8GDlNmHt9wFbn9Xgw9U3C /xWkVll8r730WR+10+14ABANnANpqhZJ246diEe6DqJl/1c01mg3POSvM1PVwT0/AsyQ 9iMEYw+9vZVEc58zYbFh/qCrRsApn9BTWCmlUlJtWUT/fmpqSR2onKxrtUZSK0+E0UR8 LwUeOfogJTNvGdFbgjm36h64qISwpkwXjYBZh6ZOW5vnbQQUNpGao6i2dEY157m0+rbK NrXaF2ph0XooiBen763ZP6xzify+2Q4EKGRnM2eYSMqIQExAtfATCmyC1T59XoO+oR05 UqBQ== X-Gm-Message-State: AOAM532NdbS+QfEKz26gVlhymAL70KGPTANwuAhsYcfV/+oR+8/35kKE 1hBKT6cE2ugIaZXOSk/zReM6kd7iHL7J X-Google-Smtp-Source: ABdhPJwtXpdd8XMsi8NfAgNi48EgWOzVYdEawLNA8H89/n1HqY3g/ULD/amWov5SbJzrqfz2xmZ8eQ== X-Received: by 2002:a05:620a:bd5:b0:67d:15ed:2fcd with SMTP id s21-20020a05620a0bd500b0067d15ed2fcdmr1185692qki.81.1650584943898; Thu, 21 Apr 2022 16:49:03 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id a1-20020a05622a02c100b002f342ccc1c5sm287372qtx.72.2022.04.21.16.49.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 21 Apr 2022 16:49:03 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org Cc: Kent Overstreet , hch@lst.de, hannes@cmpxchg.org, akpm@linux-foundation.org, linux-clk@vger.kernel.org, linux-tegra@vger.kernel.org, linux-input@vger.kernel.org, roman.gushchin@linux.dev Subject: [PATCH v2 8/8] mm: Centralize & improve oom reporting in show_mem.c Date: Thu, 21 Apr 2022 19:48:37 -0400 Message-Id: <20220421234837.3629927-14-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220421234837.3629927-1-kent.overstreet@gmail.com> References: <20220421234837.3629927-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This patch: - Changes show_mem() to always report on slab usage - Instead of reporting on all slabs, we only report on top 10 slabs, and in sorted order - Also reports on shrinkers, with the new shrinkers_to_text(). Shrinkers need to be included in OOM/allocation failure reporting because they're responsible for memory reclaim - if a shrinker isn't giving up its memory, we need to know which one and why. More OOM reporting can be moved to show_mem.c and improved, this patch is only a start. New example output on OOM/memory allocation failure: 00177 Mem-Info: 00177 active_anon:13706 inactive_anon:32266 isolated_anon:16 00177 active_file:1653 inactive_file:1822 isolated_file:0 00177 unevictable:0 dirty:0 writeback:0 00177 slab_reclaimable:6242 slab_unreclaimable:11168 00177 mapped:3824 shmem:3 pagetables:1266 bounce:0 00177 kernel_misc_reclaimable:0 00177 free:4362 free_pcp:35 free_cma:0 00177 Node 0 active_anon:54824kB inactive_anon:129064kB active_file:6612kB = inactive_file:7288kB unevictable:0kB isolated(anon):64kB isolated(file):0kB= mapped:15296kB dirty:0kB writeback:0kB shmem:12kB writeback_tmp:0kB kernel= _stack:3392kB pagetables:5064kB all_unreclaimable? no 00177 DMA free:2232kB boost:0kB min:88kB low:108kB high:128kB reserved_high= atomic:0KB active_anon:2924kB inactive_anon:6596kB active_file:428kB inacti= ve_file:384kB unevictable:0kB writepending:0kB present:15992kB managed:1536= 0kB mlocked:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB 00177 lowmem_reserve[]: 0 426 426 426 00177 DMA32 free:15092kB boost:5836kB min:8432kB low:9080kB high:9728kB res= erved_highatomic:0KB active_anon:52196kB inactive_anon:122392kB active_file= :6176kB inactive_file:7068kB unevictable:0kB writepending:0kB present:50776= 0kB managed:441816kB mlocked:0kB bounce:0kB free_pcp:72kB local_pcp:0kB fre= e_cma:0kB 00177 lowmem_reserve[]: 0 0 0 0 00177 DMA: 284*4kB (UM) 53*8kB (UM) 21*16kB (U) 11*32kB (U) 0*64kB 0*128kB = 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB =3D 2248kB 00177 DMA32: 2765*4kB (UME) 375*8kB (UME) 57*16kB (UM) 5*32kB (U) 0*64kB 0*= 128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB =3D 15132kB 00177 4656 total pagecache pages 00177 1031 pages in swap cache 00177 Swap cache stats: add 6572399, delete 6572173, find 488603/3286476 00177 Free swap =3D 509112kB 00177 Total swap =3D 2097148kB 00177 130938 pages RAM 00177 0 pages HighMem/MovableOnly 00177 16644 pages reserved 00177 Unreclaimable slab info: 00177 9p-fcall-cache total: 8.25 MiB active: 8.25 MiB 00177 kernfs_node_cache total: 2.15 MiB active: 2.15 MiB 00177 kmalloc-64 total: 2.08 MiB active: 2.07 MiB 00177 task_struct total: 1.95 MiB active: 1.95 MiB 00177 kmalloc-4k total: 1.50 MiB active: 1.50 MiB 00177 signal_cache total: 1.34 MiB active: 1.34 MiB 00177 kmalloc-2k total: 1.16 MiB active: 1.16 MiB 00177 bch_inode_info total: 1.02 MiB active: 922 KiB 00177 perf_event total: 1.02 MiB active: 1.02 MiB 00177 biovec-max total: 992 KiB active: 960 KiB 00177 Shrinkers: 00177 super_cache_scan: objects: 127 00177 super_cache_scan: objects: 106 00177 jbd2_journal_shrink_scan: objects: 32 00177 ext4_es_scan: objects: 32 00177 bch2_btree_cache_scan: objects: 8 00177 nr nodes: 24 00177 nr dirty: 0 00177 cannibalize lock: 0000000000000000 00177 00177 super_cache_scan: objects: 8 00177 super_cache_scan: objects: 1 Signed-off-by: Kent Overstreet --- mm/oom_kill.c | 23 --------------------- mm/show_mem.c | 14 +++++++++++++ mm/slab.h | 6 ++++-- mm/slab_common.c | 53 ++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 63 insertions(+), 33 deletions(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 832fb33037..659c7d6376 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -171,27 +171,6 @@ static bool oom_unkillable_task(struct task_struct *p) return false; } =20 -/* - * Check whether unreclaimable slab amount is greater than - * all user memory(LRU pages). - * dump_unreclaimable_slab() could help in the case that - * oom due to too much unreclaimable slab used by kernel. -*/ -static bool should_dump_unreclaim_slab(void) -{ - unsigned long nr_lru; - - nr_lru =3D global_node_page_state(NR_ACTIVE_ANON) + - global_node_page_state(NR_INACTIVE_ANON) + - global_node_page_state(NR_ACTIVE_FILE) + - global_node_page_state(NR_INACTIVE_FILE) + - global_node_page_state(NR_ISOLATED_ANON) + - global_node_page_state(NR_ISOLATED_FILE) + - global_node_page_state(NR_UNEVICTABLE); - - return (global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B) > nr_lru); -} - /** * oom_badness - heuristic function to determine which candidate task to k= ill * @p: task struct of which task we should calculate @@ -465,8 +444,6 @@ static void dump_header(struct oom_control *oc, struct = task_struct *p) mem_cgroup_print_oom_meminfo(oc->memcg); else { show_mem(SHOW_MEM_FILTER_NODES, oc->nodemask); - if (should_dump_unreclaim_slab()) - dump_unreclaimable_slab(); } if (sysctl_oom_dump_tasks) dump_tasks(oc); diff --git a/mm/show_mem.c b/mm/show_mem.c index 1c26c14ffb..24b662f64d 100644 --- a/mm/show_mem.c +++ b/mm/show_mem.c @@ -7,11 +7,15 @@ =20 #include #include +#include + +#include "slab.h" =20 void show_mem(unsigned int filter, nodemask_t *nodemask) { pg_data_t *pgdat; unsigned long total =3D 0, reserved =3D 0, highmem =3D 0; + struct printbuf buf =3D PRINTBUF; =20 printk("Mem-Info:\n"); show_free_areas(filter, nodemask); @@ -41,4 +45,14 @@ void show_mem(unsigned int filter, nodemask_t *nodemask) #ifdef CONFIG_MEMORY_FAILURE printk("%lu pages hwpoisoned\n", atomic_long_read(&num_poisoned_pages)); #endif + + pr_info("Unreclaimable slab info:\n"); + dump_unreclaimable_slab(&buf); + printk("%s", printbuf_str(&buf)); + printbuf_reset(&buf); + + printk("Shrinkers:\n"); + shrinkers_to_text(&buf); + printk("%s", printbuf_str(&buf)); + printbuf_exit(&buf); } diff --git a/mm/slab.h b/mm/slab.h index c7f2abc2b1..abefbf7674 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -788,10 +788,12 @@ static inline struct kmem_cache_node *get_node(struct= kmem_cache *s, int node) =20 #endif =20 +struct printbuf; + #if defined(CONFIG_SLAB) || defined(CONFIG_SLUB_DEBUG) -void dump_unreclaimable_slab(void); +void dump_unreclaimable_slab(struct printbuf *); #else -static inline void dump_unreclaimable_slab(void) +static inline void dump_unreclaimable_slab(struct printbuf *out) { } #endif diff --git a/mm/slab_common.c b/mm/slab_common.c index 23f2ab0713..1209480797 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -24,6 +24,7 @@ #include #include #include +#include =20 #define CREATE_TRACE_POINTS #include @@ -1084,10 +1085,15 @@ static int slab_show(struct seq_file *m, void *p) return 0; } =20 -void dump_unreclaimable_slab(void) +void dump_unreclaimable_slab(struct printbuf *out) { struct kmem_cache *s; struct slabinfo sinfo; + struct slab_by_mem { + struct kmem_cache *s; + size_t total, active; + } slabs_by_mem[10], n; + int i, nr =3D 0; =20 /* * Here acquiring slab_mutex is risky since we don't prefer to get @@ -1097,12 +1103,11 @@ void dump_unreclaimable_slab(void) * without acquiring the mutex. */ if (!mutex_trylock(&slab_mutex)) { - pr_warn("excessive unreclaimable slab but cannot dump stats\n"); + pr_buf(out, "excessive unreclaimable slab but cannot dump stats\n"); return; } =20 - pr_info("Unreclaimable slab info:\n"); - pr_info("Name Used Total\n"); + printbuf_atomic_inc(out); =20 list_for_each_entry(s, &slab_caches, list) { if (s->flags & SLAB_RECLAIM_ACCOUNT) @@ -1110,11 +1115,43 @@ void dump_unreclaimable_slab(void) =20 get_slabinfo(s, &sinfo); =20 - if (sinfo.num_objs > 0) - pr_info("%-17s %10luKB %10luKB\n", s->name, - (sinfo.active_objs * s->size) / 1024, - (sinfo.num_objs * s->size) / 1024); + if (!sinfo.num_objs) + continue; + + n.s =3D s; + n.total =3D sinfo.num_objs * s->size; + n.active =3D sinfo.active_objs * s->size; + + for (i =3D 0; i < nr; i++) + if (n.total < slabs_by_mem[i].total) + break; + + if (nr < ARRAY_SIZE(slabs_by_mem)) { + memmove(&slabs_by_mem[i + 1], + &slabs_by_mem[i], + sizeof(slabs_by_mem[0]) * (nr - i)); + nr++; + } else if (i) { + i--; + memmove(&slabs_by_mem[0], + &slabs_by_mem[1], + sizeof(slabs_by_mem[0]) * i); + } else { + continue; + } + + slabs_by_mem[i] =3D n; + } + + for (i =3D nr - 1; i >=3D 0; --i) { + pr_buf(out, "%-17s total: ", slabs_by_mem[i].s->name); + pr_human_readable_u64(out, slabs_by_mem[i].total); + pr_buf(out, " active: "); + pr_human_readable_u64(out, slabs_by_mem[i].active); + pr_newline(out); } + + printbuf_atomic_dec(out); mutex_unlock(&slab_mutex); } =20 --=20 2.35.2