From patchwork Fri Apr 22 01:58:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Gushchin X-Patchwork-Id: 12822657 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8E046C433F5 for ; Fri, 22 Apr 2022 01:59:05 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 212756B0074; Thu, 21 Apr 2022 21:59:05 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 124E06B0075; Thu, 21 Apr 2022 21:59:05 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id EE3F96B0078; Thu, 21 Apr 2022 21:59:04 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (relay.hostedemail.com [64.99.140.25]) by kanga.kvack.org (Postfix) with ESMTP id DFE5D6B0074 for ; Thu, 21 Apr 2022 21:59:04 -0400 (EDT) Received: from smtpin02.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id B87686076E for ; Fri, 22 Apr 2022 01:59:04 +0000 (UTC) X-FDA: 79382857008.02.A7D0C61 Received: from out0.migadu.com (out0.migadu.com [94.23.1.103]) by imf26.hostedemail.com (Postfix) with ESMTP id B7E0B140011 for ; Fri, 22 Apr 2022 01:59:02 +0000 (UTC) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1650592742; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=urcY4KpR6Y/rKfU1Exf0ylTVTWbC0tQ2e4XTZHXE3Ec=; b=bn9gcaOdhr5Jh87xq/5Eau4lhsgSb90keirrmftLOnUYbpNc2pyqKHUbZIo4OYudiKhb62 w9iU8/vl0G+7K0ZQDkQRw66f/uELFSXnOw5lFOsKDZL13OAyA7KCEkmF5hqFfm3K/jYiTs LFJwRFlht9vfDFwg7fEuBMe4qRxK0lg= From: Roman Gushchin To: Andrew Morton , linux-mm@kvack.org Cc: Dave Chinner , linux-kernel@vger.kernel.org, Yang Shi , Kent Overstreet , Hillf Danton , Roman Gushchin Subject: [PATCH v1 1/5] mm: introduce debugfs interface for kernel memory shrinkers Date: Thu, 21 Apr 2022 18:58:49 -0700 Message-Id: <20220422015853.748291-2-roman.gushchin@linux.dev> In-Reply-To: <20220422015853.748291-1-roman.gushchin@linux.dev> References: <20220422015853.748291-1-roman.gushchin@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-Migadu-Auth-User: linux.dev Authentication-Results: imf26.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=bn9gcaOd; dmarc=pass (policy=none) header.from=linux.dev; spf=pass (imf26.hostedemail.com: domain of roman.gushchin@linux.dev designates 94.23.1.103 as permitted sender) smtp.mailfrom=roman.gushchin@linux.dev X-Rspam-User: X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: B7E0B140011 X-Stat-Signature: ath1k75cytf3zs94iboyquswhkueokue X-HE-Tag: 1650592742-642707 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: This commit introduces the /sys/kernel/debug/shrinker debugfs interface which provides an ability to observe the state and interact with individual kernel memory shrinkers. Because the feature is oriented on kernel developers and adds some memory overhead (which shouldn't be large unless there is a huge amount of registered shrinkers), it's guarded by a config option (disabled by default). This commit introduces "count" and "scan" interfaces for each shrinker registered in the system. Basic usage: 1) Get the number of objects $ cat count 2) Try to reclaim 500 objects $ echo "500" > scan Following commits in the series will add memcg- and numa-specific features. This commit gives debugfs entries simple numeric names, which are not very convenient. The following commit in the series will provide shrinkers with more meaningful names. Signed-off-by: Roman Gushchin --- include/linux/shrinker.h | 19 +++- lib/Kconfig.debug | 9 ++ mm/Makefile | 1 + mm/shrinker_debug.c | 214 +++++++++++++++++++++++++++++++++++++++ mm/vmscan.c | 6 +- 5 files changed, 246 insertions(+), 3 deletions(-) create mode 100644 mm/shrinker_debug.c diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index 76fbf92b04d9..17985a890887 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -72,6 +72,10 @@ struct shrinker { #ifdef CONFIG_MEMCG /* ID in shrinker_idr */ int id; +#endif +#ifdef CONFIG_SHRINKER_DEBUG + int debugfs_id; + struct dentry *debugfs_entry; #endif /* objs pending delete, per node */ atomic_long_t *nr_deferred; @@ -94,4 +98,17 @@ 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); -#endif + +#ifdef CONFIG_SHRINKER_DEBUG +int shrinker_debugfs_add(struct shrinker *shrinker); +void shrinker_debugfs_remove(struct shrinker *shrinker); +#else /* CONFIG_SHRINKER_DEBUG */ +static inline int shrinker_debugfs_add(struct shrinker *shrinker) +{ + return 0; +} +static inline void shrinker_debugfs_remove(struct shrinker *shrinker) +{ +} +#endif /* CONFIG_SHRINKER_DEBUG */ +#endif /* _LINUX_SHRINKER_H */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 6bf9cceb7d20..51910b291b81 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -733,6 +733,15 @@ config SLUB_STATS out which slabs are relevant to a particular load. Try running: slabinfo -DA +config SHRINKER_DEBUG + default n + bool "Enable shrinker debugging support" + depends on DEBUG_FS + help + Say Y to enable the shrinker debugfs interface which provides + visibility into the kernel memory shrinkers subsystem. + Disable it to avoid an extra memory footprint. + config HAVE_DEBUG_KMEMLEAK bool diff --git a/mm/Makefile b/mm/Makefile index 6f9ffa968a1a..9a564f836403 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -133,3 +133,4 @@ obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o obj-$(CONFIG_IO_MAPPING) += io-mapping.o obj-$(CONFIG_HAVE_BOOTMEM_INFO_NODE) += bootmem_info.o obj-$(CONFIG_GENERIC_IOREMAP) += ioremap.o +obj-$(CONFIG_SHRINKER_DEBUG) += shrinker_debug.o diff --git a/mm/shrinker_debug.c b/mm/shrinker_debug.c new file mode 100644 index 000000000000..4df7382a0737 --- /dev/null +++ b/mm/shrinker_debug.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include + +/* defined in vmscan.c */ +extern struct rw_semaphore shrinker_rwsem; +extern struct list_head shrinker_list; + +static DEFINE_IDA(shrinker_debugfs_ida); +static struct dentry *shrinker_debugfs_root; + +static int shrinker_debugfs_count_show(struct seq_file *m, void *v) +{ + struct shrinker *shrinker = (struct shrinker *)m->private; + unsigned long nr, total = 0; + int ret, nid; + + ret = down_read_killable(&shrinker_rwsem); + if (ret) + return ret; + + for_each_node(nid) { + struct shrink_control sc = { + .gfp_mask = GFP_KERNEL, + .nid = nid, + }; + + nr = shrinker->count_objects(shrinker, &sc); + if (nr == SHRINK_EMPTY) + nr = 0; + total += nr; + + if (!(shrinker->flags & SHRINKER_NUMA_AWARE)) + break; + + cond_resched(); + } + up_read(&shrinker_rwsem); + + seq_printf(m, "%lu\n", total); + + return ret; +} +DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count); + +static ssize_t shrinker_debugfs_scan_write(struct file *file, + const char __user *buf, + size_t size, loff_t *pos) +{ + struct shrinker *shrinker = (struct shrinker *)file->private_data; + unsigned long nr, total = 0, nr_to_scan; + unsigned long *count_per_node = NULL; + int nid; + char kbuf[24]; + int read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1); + ssize_t ret; + + if (copy_from_user(kbuf, buf, read_len)) + return -EFAULT; + kbuf[read_len] = '\0'; + + if (kstrtoul(kbuf, 10, &nr_to_scan)) + return -EINVAL; + + ret = down_read_killable(&shrinker_rwsem); + if (ret) + return ret; + + if (shrinker->flags & SHRINKER_NUMA_AWARE) { + /* + * If the shrinker is numa aware, distribute nr_to_scan + * proportionally. + */ + count_per_node = kcalloc(nr_node_ids, sizeof(unsigned long), + GFP_KERNEL); + if (!count_per_node) { + ret = -ENOMEM; + goto out; + } + + for_each_node(nid) { + struct shrink_control sc = { + .gfp_mask = GFP_KERNEL, + .nid = nid, + }; + + nr = shrinker->count_objects(shrinker, &sc); + if (nr == SHRINK_EMPTY) + nr = 0; + count_per_node[nid] = nr; + total += nr; + + cond_resched(); + } + } + + for_each_node(nid) { + struct shrink_control sc = { + .gfp_mask = GFP_KERNEL, + .nid = nid, + }; + + if (shrinker->flags & SHRINKER_NUMA_AWARE) { + sc.nr_to_scan = nr_to_scan * count_per_node[nid] / + (total ? total : 1); + sc.nr_scanned = sc.nr_to_scan; + } else { + sc.nr_to_scan = nr_to_scan; + sc.nr_scanned = sc.nr_to_scan; + } + + nr = shrinker->scan_objects(shrinker, &sc); + if (nr == SHRINK_STOP) + break; + + if (!(shrinker->flags & SHRINKER_NUMA_AWARE)) + break; + + cond_resched(); + + } + ret = size; +out: + up_read(&shrinker_rwsem); + kfree(count_per_node); + return ret; +} + +static int shrinker_debugfs_scan_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return nonseekable_open(inode, file); +} + +static const struct file_operations shrinker_debugfs_scan_fops = { + .owner = THIS_MODULE, + .open = shrinker_debugfs_scan_open, + .write = shrinker_debugfs_scan_write, +}; + +int shrinker_debugfs_add(struct shrinker *shrinker) +{ + struct dentry *entry; + char buf[256]; + int id; + + lockdep_assert_held(&shrinker_rwsem); + + /* debugfs isn't initialized yet, add debugfs entries later. */ + if (!shrinker_debugfs_root) + return 0; + + id = ida_alloc(&shrinker_debugfs_ida, GFP_KERNEL); + if (id < 0) + return id; + shrinker->debugfs_id = id; + + snprintf(buf, sizeof(buf), "%d", id); + + /* create debugfs entry */ + entry = debugfs_create_dir(buf, shrinker_debugfs_root); + if (IS_ERR(entry)) { + ida_free(&shrinker_debugfs_ida, id); + return PTR_ERR(entry); + } + shrinker->debugfs_entry = entry; + + /* create generic interfaces */ + debugfs_create_file("count", 0220, entry, shrinker, + &shrinker_debugfs_count_fops); + debugfs_create_file("scan", 0440, entry, shrinker, + &shrinker_debugfs_scan_fops); + + return 0; +} + +void shrinker_debugfs_remove(struct shrinker *shrinker) +{ + lockdep_assert_held(&shrinker_rwsem); + + if (!shrinker->debugfs_entry) + return; + + debugfs_remove_recursive(shrinker->debugfs_entry); + ida_free(&shrinker_debugfs_ida, shrinker->debugfs_id); +} + +static int __init shrinker_debugfs_init(void) +{ + struct shrinker *shrinker; + int ret; + + if (!debugfs_initialized()) + return -ENODEV; + + shrinker_debugfs_root = debugfs_create_dir("shrinker", NULL); + if (!shrinker_debugfs_root) + return -ENOMEM; + + /* Create debugfs entries for shrinkers registered at boot */ + ret = down_write_killable(&shrinker_rwsem); + if (ret) + return ret; + + list_for_each_entry(shrinker, &shrinker_list, list) + if (!shrinker->debugfs_entry) + ret = shrinker_debugfs_add(shrinker); + up_write(&shrinker_rwsem); + + return ret; +} +late_initcall(shrinker_debugfs_init); diff --git a/mm/vmscan.c b/mm/vmscan.c index 99a572f01cb4..121a54a1602b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -190,8 +190,8 @@ static void set_task_reclaim_state(struct task_struct *task, task->reclaim_state = rs; } -static LIST_HEAD(shrinker_list); -static DECLARE_RWSEM(shrinker_rwsem); +LIST_HEAD(shrinker_list); +DECLARE_RWSEM(shrinker_rwsem); #ifdef CONFIG_MEMCG static int shrinker_nr_max; @@ -655,6 +655,7 @@ void register_shrinker_prepared(struct shrinker *shrinker) down_write(&shrinker_rwsem); list_add_tail(&shrinker->list, &shrinker_list); shrinker->flags |= SHRINKER_REGISTERED; + WARN_ON_ONCE(shrinker_debugfs_add(shrinker)); up_write(&shrinker_rwsem); } @@ -682,6 +683,7 @@ void unregister_shrinker(struct shrinker *shrinker) shrinker->flags &= ~SHRINKER_REGISTERED; if (shrinker->flags & SHRINKER_MEMCG_AWARE) unregister_memcg_shrinker(shrinker); + shrinker_debugfs_remove(shrinker); up_write(&shrinker_rwsem); kfree(shrinker->nr_deferred); From patchwork Fri Apr 22 01:58:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Gushchin X-Patchwork-Id: 12822658 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0E806C433EF for ; Fri, 22 Apr 2022 01:59:10 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 916F46B0075; Thu, 21 Apr 2022 21:59:09 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 8C81A6B0078; Thu, 21 Apr 2022 21:59:09 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 78E526B007B; Thu, 21 Apr 2022 21:59:09 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (relay.a.hostedemail.com [64.99.140.24]) by kanga.kvack.org (Postfix) with ESMTP id 6A8AD6B0075 for ; Thu, 21 Apr 2022 21:59:09 -0400 (EDT) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id 6B5DA230DE for ; Fri, 22 Apr 2022 01:59:07 +0000 (UTC) X-FDA: 79382857134.27.A7C064E Received: from out0.migadu.com (out0.migadu.com [94.23.1.103]) by imf13.hostedemail.com (Postfix) with ESMTP id 3A52820013 for ; Fri, 22 Apr 2022 01:59:04 +0000 (UTC) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1650592745; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=YJ7iyWPMUBRHOLQYsDGfDGb0YRmFrOq96IBzMGKKov4=; b=A+vAvPAvLUxpshxpsMFxiGzlhWXtwExNth63kuvG8pyzaeEFKFO49viIu4eG/STpNH3IZ3 uqZpYGbilxKBsT1DkapuFzgJd56xr3au73odv2GW7EVDrpAlQybjTWHVi6KHi9rmIPTPmC xURhXwuwskDQXdLi2rAaqlhVoYu1+/E= From: Roman Gushchin To: Andrew Morton , linux-mm@kvack.org Cc: Dave Chinner , linux-kernel@vger.kernel.org, Yang Shi , Kent Overstreet , Hillf Danton , Roman Gushchin Subject: [PATCH v1 2/5] mm: memcontrol: introduce mem_cgroup_ino() and mem_cgroup_get_from_ino() Date: Thu, 21 Apr 2022 18:58:50 -0700 Message-Id: <20220422015853.748291-3-roman.gushchin@linux.dev> In-Reply-To: <20220422015853.748291-1-roman.gushchin@linux.dev> References: <20220422015853.748291-1-roman.gushchin@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-Migadu-Auth-User: linux.dev X-Stat-Signature: r8shdxf1wdgzumhy6hqwwrq9xzkynr88 X-Rspam-User: Authentication-Results: imf13.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=A+vAvPAv; dmarc=pass (policy=none) header.from=linux.dev; spf=pass (imf13.hostedemail.com: domain of roman.gushchin@linux.dev designates 94.23.1.103 as permitted sender) smtp.mailfrom=roman.gushchin@linux.dev X-Rspamd-Server: rspam02 X-Rspamd-Queue-Id: 3A52820013 X-HE-Tag: 1650592744-352087 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Shrinker debugfs requires a way to represent memory cgroups without using full paths, both for displaying information and getting input from a user. Cgroup inode number is a perfect way, already used by e.g. bpf. This commit adds a couple of helper functions which will be used to represent and interact with memcg-aware shrinkers. Signed-off-by: Roman Gushchin --- include/linux/memcontrol.h | 9 +++++++++ mm/memcontrol.c | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 89b14729d59f..27a91dd210c9 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -831,6 +831,15 @@ static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg) } struct mem_cgroup *mem_cgroup_from_id(unsigned short id); +#ifdef CONFIG_SHRINKER_DEBUG +static inline unsigned long mem_cgroup_ino(struct mem_cgroup *memcg) +{ + return cgroup_ino(memcg->css.cgroup); +} + +struct mem_cgroup *mem_cgroup_get_from_ino(unsigned long ino); +#endif + static inline struct mem_cgroup *mem_cgroup_from_seq(struct seq_file *m) { return mem_cgroup_from_css(seq_css(m)); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 08cbe23a8b94..a508979177a2 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5022,6 +5022,29 @@ struct mem_cgroup *mem_cgroup_from_id(unsigned short id) return idr_find(&mem_cgroup_idr, id); } +#ifdef CONFIG_SHRINKER_DEBUG +struct mem_cgroup *mem_cgroup_get_from_ino(unsigned long ino) +{ + struct cgroup *cgrp; + struct cgroup_subsys_state *css; + struct mem_cgroup *memcg; + + cgrp = cgroup_get_from_id(ino); + if (!cgrp) + return ERR_PTR(-ENOENT); + + css = cgroup_get_e_css(cgrp, &memory_cgrp_subsys); + if (css) + memcg = container_of(css, struct mem_cgroup, css); + else + memcg = ERR_PTR(-ENOENT); + + cgroup_put(cgrp); + + return memcg; +} +#endif + static int alloc_mem_cgroup_per_node_info(struct mem_cgroup *memcg, int node) { struct mem_cgroup_per_node *pn; From patchwork Fri Apr 22 01:58:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Gushchin X-Patchwork-Id: 12822659 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4805DC433F5 for ; Fri, 22 Apr 2022 01:59:11 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id D5BDB6B0078; Thu, 21 Apr 2022 21:59:10 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id CE3AE6B007B; Thu, 21 Apr 2022 21:59:10 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B119E6B007D; Thu, 21 Apr 2022 21:59:10 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (relay.a.hostedemail.com [64.99.140.24]) by kanga.kvack.org (Postfix) with ESMTP id 9DA336B0078 for ; Thu, 21 Apr 2022 21:59:10 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 7BFE1477 for ; Fri, 22 Apr 2022 01:59:10 +0000 (UTC) X-FDA: 79382857260.21.D5E38C0 Received: from out0.migadu.com (out0.migadu.com [94.23.1.103]) by imf26.hostedemail.com (Postfix) with ESMTP id 7B729140012 for ; Fri, 22 Apr 2022 01:59:08 +0000 (UTC) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1650592748; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LVUES9M+BRrqRRSLg84CbnN5OMz4VRT3o7tg8BkXGPA=; b=Bgi/Cka/PsllPmJPhZipUVfhIBOKl29UgM2UqplAf96Uu/F5JYFQmiPZleCOM0PHM6FDXO XM3k6L00CKCUAzrDqXE4IYBOrUz9n+sdGEEdUhZhd7BXJyfGDcMJWdZXQm85PNTfFxoSsz ya8r4u4ZqydRGRDaP5rDWlKgFdlT5DQ= From: Roman Gushchin To: Andrew Morton , linux-mm@kvack.org Cc: Dave Chinner , linux-kernel@vger.kernel.org, Yang Shi , Kent Overstreet , Hillf Danton , Roman Gushchin Subject: [PATCH v1 3/5] mm: introduce memcg interfaces for shrinker debugfs Date: Thu, 21 Apr 2022 18:58:51 -0700 Message-Id: <20220422015853.748291-4-roman.gushchin@linux.dev> In-Reply-To: <20220422015853.748291-1-roman.gushchin@linux.dev> References: <20220422015853.748291-1-roman.gushchin@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-Migadu-Auth-User: linux.dev X-Rspam-User: X-Rspamd-Server: rspam11 X-Rspamd-Queue-Id: 7B729140012 X-Stat-Signature: joggnbjqtz9n5bwyt57z3pqwjjbna4wn Authentication-Results: imf26.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b="Bgi/Cka/"; spf=pass (imf26.hostedemail.com: domain of roman.gushchin@linux.dev designates 94.23.1.103 as permitted sender) smtp.mailfrom=roman.gushchin@linux.dev; dmarc=pass (policy=none) header.from=linux.dev X-HE-Tag: 1650592748-669810 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: This commit introduces "count_memcg" and "scan_memcg" interfaces for memcg-aware shrinkers. Count_memcg using the following format: ... Memory cgroups with 0 associated objects are skipped. Signed-off-by: Roman Gushchin --- mm/shrinker_debug.c | 186 +++++++++++++++++++++++++++++++++----------- 1 file changed, 139 insertions(+), 47 deletions(-) diff --git a/mm/shrinker_debug.c b/mm/shrinker_debug.c index 4df7382a0737..002d44d6ad56 100644 --- a/mm/shrinker_debug.c +++ b/mm/shrinker_debug.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include #include +#include /* defined in vmscan.c */ extern struct rw_semaphore shrinker_rwsem; @@ -11,25 +13,25 @@ extern struct list_head shrinker_list; static DEFINE_IDA(shrinker_debugfs_ida); static struct dentry *shrinker_debugfs_root; -static int shrinker_debugfs_count_show(struct seq_file *m, void *v) +static unsigned long shrinker_count_objects(struct shrinker *shrinker, + struct mem_cgroup *memcg, + unsigned long *count_per_node) { - struct shrinker *shrinker = (struct shrinker *)m->private; unsigned long nr, total = 0; - int ret, nid; - - ret = down_read_killable(&shrinker_rwsem); - if (ret) - return ret; + int nid; for_each_node(nid) { struct shrink_control sc = { .gfp_mask = GFP_KERNEL, .nid = nid, + .memcg = memcg, }; nr = shrinker->count_objects(shrinker, &sc); if (nr == SHRINK_EMPTY) nr = 0; + if (count_per_node) + count_per_node[nid] = nr; total += nr; if (!(shrinker->flags & SHRINKER_NUMA_AWARE)) @@ -37,32 +39,17 @@ static int shrinker_debugfs_count_show(struct seq_file *m, void *v) cond_resched(); } - up_read(&shrinker_rwsem); - - seq_printf(m, "%lu\n", total); - return ret; + return total; } -DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count); -static ssize_t shrinker_debugfs_scan_write(struct file *file, - const char __user *buf, - size_t size, loff_t *pos) +static int shrinker_scan_objects(struct shrinker *shrinker, + struct mem_cgroup *memcg, + unsigned long nr_to_scan) { - struct shrinker *shrinker = (struct shrinker *)file->private_data; - unsigned long nr, total = 0, nr_to_scan; - unsigned long *count_per_node = NULL; - int nid; - char kbuf[24]; - int read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1); - ssize_t ret; - - if (copy_from_user(kbuf, buf, read_len)) - return -EFAULT; - kbuf[read_len] = '\0'; - - if (kstrtoul(kbuf, 10, &nr_to_scan)) - return -EINVAL; + unsigned long *count_per_node; + unsigned long total, nr; + int ret, nid; ret = down_read_killable(&shrinker_rwsem); if (ret) @@ -80,20 +67,7 @@ static ssize_t shrinker_debugfs_scan_write(struct file *file, goto out; } - for_each_node(nid) { - struct shrink_control sc = { - .gfp_mask = GFP_KERNEL, - .nid = nid, - }; - - nr = shrinker->count_objects(shrinker, &sc); - if (nr == SHRINK_EMPTY) - nr = 0; - count_per_node[nid] = nr; - total += nr; - - cond_resched(); - } + total = shrinker_count_objects(shrinker, memcg, count_per_node); } for_each_node(nid) { @@ -102,13 +76,13 @@ static ssize_t shrinker_debugfs_scan_write(struct file *file, .nid = nid, }; - if (shrinker->flags & SHRINKER_NUMA_AWARE) { + if (count_per_node) { sc.nr_to_scan = nr_to_scan * count_per_node[nid] / (total ? total : 1); sc.nr_scanned = sc.nr_to_scan; } else { sc.nr_to_scan = nr_to_scan; - sc.nr_scanned = sc.nr_to_scan; + sc.nr_scanned = nr_to_scan; } nr = shrinker->scan_objects(shrinker, &sc); @@ -119,15 +93,51 @@ static ssize_t shrinker_debugfs_scan_write(struct file *file, break; cond_resched(); - } - ret = size; out: up_read(&shrinker_rwsem); kfree(count_per_node); return ret; } +static int shrinker_debugfs_count_show(struct seq_file *m, void *v) +{ + struct shrinker *shrinker = (struct shrinker *)m->private; + int ret; + + ret = down_read_killable(&shrinker_rwsem); + if (!ret) { + unsigned long total = shrinker_count_objects(shrinker, NULL, NULL); + + up_read(&shrinker_rwsem); + seq_printf(m, "%lu\n", total); + } + return ret; +} +DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count); + +static ssize_t shrinker_debugfs_scan_write(struct file *file, + const char __user *buf, + size_t size, loff_t *pos) +{ + struct shrinker *shrinker = (struct shrinker *)file->private_data; + unsigned long nr_to_scan; + char kbuf[24]; + int read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1); + ssize_t ret; + + if (copy_from_user(kbuf, buf, read_len)) + return -EFAULT; + kbuf[read_len] = '\0'; + + if (kstrtoul(kbuf, 10, &nr_to_scan)) + return -EINVAL; + + ret = shrinker_scan_objects(shrinker, NULL, nr_to_scan); + + return ret ? ret : size; +} + static int shrinker_debugfs_scan_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -140,6 +150,78 @@ static const struct file_operations shrinker_debugfs_scan_fops = { .write = shrinker_debugfs_scan_write, }; +#ifdef CONFIG_MEMCG +static int shrinker_debugfs_count_memcg_show(struct seq_file *m, void *v) +{ + struct shrinker *shrinker = (struct shrinker *)m->private; + struct mem_cgroup *memcg; + unsigned long total; + int ret; + + ret = down_read_killable(&shrinker_rwsem); + if (ret) + return ret; + rcu_read_lock(); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + if (!mem_cgroup_online(memcg)) + continue; + + total = shrinker_count_objects(shrinker, memcg, NULL); + if (!total) + continue; + + seq_printf(m, "%lu %lu\n", mem_cgroup_ino(memcg), total); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL); + + rcu_read_unlock(); + up_read(&shrinker_rwsem); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count_memcg); + +static ssize_t shrinker_debugfs_scan_memcg_write(struct file *file, + const char __user *buf, + size_t size, loff_t *pos) +{ + struct shrinker *shrinker = (struct shrinker *)file->private_data; + unsigned long nr_to_scan, ino; + struct mem_cgroup *memcg; + char kbuf[48]; + int read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1); + ssize_t ret; + + if (copy_from_user(kbuf, buf, read_len)) + return -EFAULT; + kbuf[read_len] = '\0'; + + if (sscanf(kbuf, "%lu %lu", &ino, &nr_to_scan) < 2) + return -EINVAL; + + memcg = mem_cgroup_get_from_ino(ino); + if (!memcg || IS_ERR(memcg)) + return -ENOENT; + + if (!mem_cgroup_online(memcg)) { + mem_cgroup_put(memcg); + return -ENOENT; + } + + ret = shrinker_scan_objects(shrinker, memcg, nr_to_scan); + mem_cgroup_put(memcg); + + return ret ? ret : size; +} + +static const struct file_operations shrinker_debugfs_scan_memcg_fops = { + .owner = THIS_MODULE, + .open = shrinker_debugfs_scan_open, + .write = shrinker_debugfs_scan_memcg_write, +}; +#endif + int shrinker_debugfs_add(struct shrinker *shrinker) { struct dentry *entry; @@ -173,6 +255,16 @@ int shrinker_debugfs_add(struct shrinker *shrinker) debugfs_create_file("scan", 0440, entry, shrinker, &shrinker_debugfs_scan_fops); +#ifdef CONFIG_MEMCG + /* create memcg interfaces */ + if (shrinker->flags & SHRINKER_MEMCG_AWARE) { + debugfs_create_file("count_memcg", 0220, entry, shrinker, + &shrinker_debugfs_count_memcg_fops); + debugfs_create_file("scan_memcg", 0440, entry, shrinker, + &shrinker_debugfs_scan_memcg_fops); + } +#endif + return 0; } From patchwork Fri Apr 22 01:58:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Gushchin X-Patchwork-Id: 12822660 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 15FC3C433F5 for ; Fri, 22 Apr 2022 01:59:14 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id A9FC06B007B; Thu, 21 Apr 2022 21:59:13 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id A25886B007D; Thu, 21 Apr 2022 21:59:13 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 8EE866B007E; Thu, 21 Apr 2022 21:59:13 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (relay.hostedemail.com [64.99.140.26]) by kanga.kvack.org (Postfix) with ESMTP id 7EE0B6B007B for ; Thu, 21 Apr 2022 21:59:13 -0400 (EDT) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 5DA3E22E5C for ; Fri, 22 Apr 2022 01:59:13 +0000 (UTC) X-FDA: 79382857386.27.E936913 Received: from out0.migadu.com (out0.migadu.com [94.23.1.103]) by imf26.hostedemail.com (Postfix) with ESMTP id 4FCF2140011 for ; Fri, 22 Apr 2022 01:59:11 +0000 (UTC) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1650592751; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zzvvA3SXvofoJHZNbBulanDIE6i4rnzYjcD9jlw7cIA=; b=drtHT1Ewzu6/crw875L0g+fzthtUNItM+1hYvpl0gtM6fOVI4zCGubfzJu2dO4nINPkuGh XAQIt1/o+VtjUMrIEmVcejVK7ernJVF71xiNYFRFsvSe4tj5btsWV1XtAmp3xzLZSJuiae tRIQaxo5czwvAXOBJoML3ehI16vlU+g= From: Roman Gushchin To: Andrew Morton , linux-mm@kvack.org Cc: Dave Chinner , linux-kernel@vger.kernel.org, Yang Shi , Kent Overstreet , Hillf Danton , Roman Gushchin Subject: [PATCH v1 4/5] mm: introduce numa interfaces for shrinker debugfs Date: Thu, 21 Apr 2022 18:58:52 -0700 Message-Id: <20220422015853.748291-5-roman.gushchin@linux.dev> In-Reply-To: <20220422015853.748291-1-roman.gushchin@linux.dev> References: <20220422015853.748291-1-roman.gushchin@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-Migadu-Auth-User: linux.dev Authentication-Results: imf26.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=drtHT1Ew; spf=pass (imf26.hostedemail.com: domain of roman.gushchin@linux.dev designates 94.23.1.103 as permitted sender) smtp.mailfrom=roman.gushchin@linux.dev; dmarc=pass (policy=none) header.from=linux.dev X-Stat-Signature: fzmb8ih6ziuwk7a4h3hfir5mq6e8yzeb X-Rspamd-Queue-Id: 4FCF2140011 X-Rspamd-Server: rspam04 X-Rspam-User: X-HE-Tag: 1650592751-724042 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: This commit introduces "count_node", "scan_node", "count_memcg_node" and "scan_memcg_node" interfaces for numa-aware and numa- and memcg-aware shrinkers. Usage examples: 1) Get per-node and per-memcg per-node counts: $ cat count_node 209 3 $ cat count_memcg_node 1 209 3 20 96 0 53 810 7 2297 2 0 218 13 0 581 30 0 911 124 0 2) Scan individual node: $ echo "1 200" > scan_node $ cat scan_node 2 3) Scan individual memcg and node: $ echo "1868 0 500" > scan_memcg_node $ cat scan_memcg_node 435 Signed-off-by: Roman Gushchin --- mm/shrinker_debug.c | 200 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/mm/shrinker_debug.c b/mm/shrinker_debug.c index 002d44d6ad56..81350b64bf01 100644 --- a/mm/shrinker_debug.c +++ b/mm/shrinker_debug.c @@ -222,6 +222,185 @@ static const struct file_operations shrinker_debugfs_scan_memcg_fops = { }; #endif +#ifdef CONFIG_NUMA +static int shrinker_debugfs_count_node_show(struct seq_file *m, void *v) +{ + struct shrinker *shrinker = (struct shrinker *)m->private; + unsigned long nr; + int ret, nid; + + ret = down_read_killable(&shrinker_rwsem); + if (ret) + return ret; + + for_each_node(nid) { + struct shrink_control sc = { + .gfp_mask = GFP_KERNEL, + .nid = nid, + }; + + nr = shrinker->count_objects(shrinker, &sc); + if (nr == SHRINK_EMPTY) + nr = 0; + + seq_printf(m, "%s%lu", nid ? " " : "", nr); + cond_resched(); + } + up_read(&shrinker_rwsem); + seq_puts(m, "\n"); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count_node); + +static ssize_t shrinker_debugfs_scan_node_write(struct file *file, + const char __user *buf, + size_t size, loff_t *pos) +{ + struct shrinker *shrinker = (struct shrinker *)file->private_data; + unsigned long nr_to_scan = 0; + int nid; + struct shrink_control sc = { + .gfp_mask = GFP_KERNEL, + }; + char kbuf[48]; + int read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1); + ssize_t ret; + + if (copy_from_user(kbuf, buf, read_len)) + return -EFAULT; + kbuf[read_len] = '\0'; + + if (sscanf(kbuf, "%d %lu", &nid, &nr_to_scan) < 2) + return -EINVAL; + + if (nid < 0 || nid >= nr_node_ids) + return -EINVAL; + + ret = down_read_killable(&shrinker_rwsem); + if (ret) + return ret; + + sc.nid = nid; + sc.nr_to_scan = nr_to_scan; + sc.nr_scanned = nr_to_scan; + + shrinker->scan_objects(shrinker, &sc); + + up_read(&shrinker_rwsem); + + return ret ? ret : size; +} + +static const struct file_operations shrinker_debugfs_scan_node_fops = { + .owner = THIS_MODULE, + .open = shrinker_debugfs_scan_open, + .write = shrinker_debugfs_scan_node_write, +}; + +#ifdef CONFIG_MEMCG +static int shrinker_debugfs_count_memcg_node_show(struct seq_file *m, void *v) +{ + struct shrinker *shrinker = (struct shrinker *)m->private; + unsigned long *count_per_node = NULL; + struct mem_cgroup *memcg; + unsigned long total; + int ret, nid; + + count_per_node = kcalloc(nr_node_ids, sizeof(unsigned long), GFP_KERNEL); + if (!count_per_node) + return -ENOMEM; + + ret = down_read_killable(&shrinker_rwsem); + if (ret) { + kfree(count_per_node); + return ret; + } + rcu_read_lock(); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + if (!mem_cgroup_online(memcg)) + continue; + + total = shrinker_count_objects(shrinker, memcg, count_per_node); + if (!total) + continue; + + seq_printf(m, "%lu", mem_cgroup_ino(memcg)); + for_each_node(nid) + seq_printf(m, " %lu", count_per_node[nid]); + seq_puts(m, "\n"); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL); + + rcu_read_unlock(); + up_read(&shrinker_rwsem); + + kfree(count_per_node); + return ret; +} +DEFINE_SHOW_ATTRIBUTE(shrinker_debugfs_count_memcg_node); + +static ssize_t shrinker_debugfs_scan_memcg_node_write(struct file *file, + const char __user *buf, + size_t size, loff_t *pos) +{ + struct shrinker *shrinker = (struct shrinker *)file->private_data; + unsigned long nr_to_scan = 0, ino; + struct shrink_control sc = { + .gfp_mask = GFP_KERNEL, + }; + struct mem_cgroup *memcg; + int nid; + char kbuf[72]; + int read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1); + ssize_t ret; + + if (copy_from_user(kbuf, buf, read_len)) + return -EFAULT; + kbuf[read_len] = '\0'; + + if (sscanf(kbuf, "%lu %d %lu", &ino, &nid, &nr_to_scan) < 2) + return -EINVAL; + + if (nid < 0 || nid >= nr_node_ids) + return -EINVAL; + + memcg = mem_cgroup_get_from_ino(ino); + if (!memcg || IS_ERR(memcg)) + return -ENOENT; + + if (!mem_cgroup_online(memcg)) { + mem_cgroup_put(memcg); + return -ENOENT; + } + + ret = down_read_killable(&shrinker_rwsem); + if (ret) { + mem_cgroup_put(memcg); + return ret; + } + + sc.nid = nid; + sc.memcg = memcg; + sc.nr_to_scan = nr_to_scan; + sc.nr_scanned = nr_to_scan; + + shrinker->scan_objects(shrinker, &sc); + + up_read(&shrinker_rwsem); + mem_cgroup_put(memcg); + + return ret ? ret : size; +} + +static const struct file_operations shrinker_debugfs_scan_memcg_node_fops = { + .owner = THIS_MODULE, + .open = shrinker_debugfs_scan_open, + .write = shrinker_debugfs_scan_memcg_node_write, +}; +#endif /* CONFIG_MEMCG */ +#endif /* CONFIG_NUMA */ + int shrinker_debugfs_add(struct shrinker *shrinker) { struct dentry *entry; @@ -265,6 +444,27 @@ int shrinker_debugfs_add(struct shrinker *shrinker) } #endif +#ifdef CONFIG_NUMA + /* create numa and memcg/numa interfaces */ + if ((shrinker->flags & SHRINKER_NUMA_AWARE) && nr_node_ids > 1) { + debugfs_create_file("count_node", 0220, entry, shrinker, + &shrinker_debugfs_count_node_fops); + debugfs_create_file("scan_node", 0440, entry, shrinker, + &shrinker_debugfs_scan_node_fops); + +#ifdef CONFIG_MEMCG + if (shrinker->flags & SHRINKER_MEMCG_AWARE) { + debugfs_create_file("count_memcg_node", 0220, entry, + shrinker, + &shrinker_debugfs_count_memcg_node_fops); + debugfs_create_file("scan_memcg_node", 0440, entry, + shrinker, + &shrinker_debugfs_scan_memcg_node_fops); + } +#endif /* CONFIG_MEMCG */ + } +#endif /* CONFIG_NUMA */ + return 0; } From patchwork Fri Apr 22 01:58:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Gushchin X-Patchwork-Id: 12822661 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1989AC433EF for ; Fri, 22 Apr 2022 01:59:17 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id A006B6B007D; Thu, 21 Apr 2022 21:59:16 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 98A3D6B007E; Thu, 21 Apr 2022 21:59:16 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 7DDB06B0080; Thu, 21 Apr 2022 21:59:16 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (relay.a.hostedemail.com [64.99.140.24]) by kanga.kvack.org (Postfix) with ESMTP id 65AD16B007D for ; Thu, 21 Apr 2022 21:59:16 -0400 (EDT) Received: from smtpin31.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 432E520484 for ; Fri, 22 Apr 2022 01:59:16 +0000 (UTC) X-FDA: 79382857512.31.08E18E7 Received: from out0.migadu.com (out0.migadu.com [94.23.1.103]) by imf19.hostedemail.com (Postfix) with ESMTP id 60EF71A0021 for ; Fri, 22 Apr 2022 01:59:13 +0000 (UTC) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1650592754; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5P4GrUpvY4QIe8HXGHTCPSIp+2Gb48+q63e1fJU3hTM=; b=tiTYmDSQWJfqouzFDcn+FaB0E7HL5rbnJnl97J313ygC3wf8MIebndpKEmAUx/XyEBT8dc rMOZM2iSAtvejOSUQcUnhPtCSgjGEK6SfWN845tLiHFJ6rTtshnaL08nog/GOZGXNgaaZf 1ACb1pFeTLi4VvHwQArOnLyv+oSs4SU= From: Roman Gushchin To: Andrew Morton , linux-mm@kvack.org Cc: Dave Chinner , linux-kernel@vger.kernel.org, Yang Shi , Kent Overstreet , Hillf Danton , Roman Gushchin Subject: [PATCH v1 5/5] mm: provide shrinkers with names Date: Thu, 21 Apr 2022 18:58:53 -0700 Message-Id: <20220422015853.748291-6-roman.gushchin@linux.dev> In-Reply-To: <20220422015853.748291-1-roman.gushchin@linux.dev> References: <20220422015853.748291-1-roman.gushchin@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-Migadu-Auth-User: linux.dev X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 60EF71A0021 X-Rspam-User: Authentication-Results: imf19.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=tiTYmDSQ; spf=pass (imf19.hostedemail.com: domain of roman.gushchin@linux.dev designates 94.23.1.103 as permitted sender) smtp.mailfrom=roman.gushchin@linux.dev; dmarc=pass (policy=none) header.from=linux.dev X-Stat-Signature: i8o8ucku7ur8octy4gyhoywzqeuanjge X-HE-Tag: 1650592753-778531 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Currently shrinkers are anonymous objects. For debugging purposes they can be identified by count/scan function names, but it's not always useful: e.g. for superblock's shrinkers it's nice to have at least an idea of to which superblock the shrinker belongs. This commit adds names to shrinkers. register_shrinker() and prealloc_shrinker() functions are extended to take a format and arguments to master a name. If CONFIG_SHRINKER_DEBUG is on, the name is saved until the corresponding kobject is created, otherwise it's simple ignored. After this change the shrinker debugfs directory looks like: $ cd /sys/kernel/debug/shrinker/ $ ls dqcache-16 sb-cgroup2-30 sb-hugetlbfs-33 sb-proc-41 sb-selinuxfs-22 sb-tmpfs-40 sb-zsmalloc-19 kfree_rcu-0 sb-configfs-23 sb-iomem-12 sb-proc-44 sb-sockfs-8 sb-tmpfs-42 shadow-18 sb-aio-20 sb-dax-11 sb-mqueue-21 sb-proc-45 sb-sysfs-26 sb-tmpfs-43 thp_deferred_split-10 sb-anon_inodefs-15 sb-debugfs-7 sb-nsfs-4 sb-proc-47 sb-tmpfs-1 sb-tmpfs-46 thp_zero-9 sb-bdev-3 sb-devpts-28 sb-pipefs-14 sb-pstore-31 sb-tmpfs-27 sb-tmpfs-49 xfs_buf-37 sb-bpf-32 sb-devtmpfs-5 sb-proc-25 sb-rootfs-2 sb-tmpfs-29 sb-tracefs-13 xfs_inodegc-38 sb-btrfs-24 sb-hugetlbfs-17 sb-proc-39 sb-securityfs-6 sb-tmpfs-35 sb-xfs-36 zspool-34 Signed-off-by: Roman Gushchin --- arch/x86/kvm/mmu/mmu.c | 2 +- drivers/android/binder_alloc.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_shrinker.c | 3 +- drivers/gpu/drm/msm/msm_gem_shrinker.c | 2 +- .../gpu/drm/panfrost/panfrost_gem_shrinker.c | 2 +- drivers/gpu/drm/ttm/ttm_pool.c | 2 +- drivers/md/bcache/btree.c | 2 +- drivers/md/dm-bufio.c | 2 +- drivers/md/dm-zoned-metadata.c | 2 +- drivers/md/raid5.c | 2 +- drivers/misc/vmw_balloon.c | 2 +- drivers/virtio/virtio_balloon.c | 2 +- drivers/xen/xenbus/xenbus_probe_backend.c | 2 +- fs/erofs/utils.c | 2 +- fs/ext4/extents_status.c | 3 +- fs/f2fs/super.c | 2 +- fs/gfs2/glock.c | 2 +- fs/gfs2/main.c | 2 +- fs/jbd2/journal.c | 2 +- fs/mbcache.c | 2 +- fs/nfs/nfs42xattr.c | 7 ++- fs/nfs/super.c | 2 +- fs/nfsd/filecache.c | 2 +- fs/nfsd/nfscache.c | 2 +- fs/quota/dquot.c | 2 +- fs/super.c | 2 +- fs/ubifs/super.c | 2 +- fs/xfs/xfs_buf.c | 2 +- fs/xfs/xfs_icache.c | 2 +- fs/xfs/xfs_qm.c | 2 +- include/linux/shrinker.h | 5 +- kernel/rcu/tree.c | 2 +- mm/huge_memory.c | 4 +- mm/shrinker_debug.c | 7 ++- mm/vmscan.c | 60 ++++++++++++++++++- mm/workingset.c | 2 +- mm/zsmalloc.c | 2 +- net/sunrpc/auth.c | 2 +- 38 files changed, 106 insertions(+), 45 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index c623019929a7..8cfabdd63406 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -6283,7 +6283,7 @@ int kvm_mmu_vendor_module_init(void) if (percpu_counter_init(&kvm_total_used_mmu_pages, 0, GFP_KERNEL)) goto out; - ret = register_shrinker(&mmu_shrinker); + ret = register_shrinker(&mmu_shrinker, "mmu"); if (ret) goto out; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 2ac1008a5f39..951343c41ba8 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -1084,7 +1084,7 @@ int binder_alloc_shrinker_init(void) int ret = list_lru_init(&binder_alloc_lru); if (ret == 0) { - ret = register_shrinker(&binder_shrinker); + ret = register_shrinker(&binder_shrinker, "binder"); if (ret) list_lru_destroy(&binder_alloc_lru); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c index 6a6ff98a8746..85524ef92ea4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c @@ -426,7 +426,8 @@ void i915_gem_driver_register__shrinker(struct drm_i915_private *i915) i915->mm.shrinker.count_objects = i915_gem_shrinker_count; i915->mm.shrinker.seeks = DEFAULT_SEEKS; i915->mm.shrinker.batch = 4096; - drm_WARN_ON(&i915->drm, register_shrinker(&i915->mm.shrinker)); + drm_WARN_ON(&i915->drm, register_shrinker(&i915->mm.shrinker, + "drm_i915_gem")); i915->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom; drm_WARN_ON(&i915->drm, register_oom_notifier(&i915->mm.oom_notifier)); diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 086dacf2f26a..2d3cf4f13dfd 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -221,7 +221,7 @@ void msm_gem_shrinker_init(struct drm_device *dev) priv->shrinker.count_objects = msm_gem_shrinker_count; priv->shrinker.scan_objects = msm_gem_shrinker_scan; priv->shrinker.seeks = DEFAULT_SEEKS; - WARN_ON(register_shrinker(&priv->shrinker)); + WARN_ON(register_shrinker(&priv->shrinker, "drm_msm_gem")); priv->vmap_notifier.notifier_call = msm_gem_shrinker_vmap; WARN_ON(register_vmap_purge_notifier(&priv->vmap_notifier)); diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c index 77e7cb6d1ae3..0d028266ee9e 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c @@ -103,7 +103,7 @@ void panfrost_gem_shrinker_init(struct drm_device *dev) pfdev->shrinker.count_objects = panfrost_gem_shrinker_count; pfdev->shrinker.scan_objects = panfrost_gem_shrinker_scan; pfdev->shrinker.seeks = DEFAULT_SEEKS; - WARN_ON(register_shrinker(&pfdev->shrinker)); + WARN_ON(register_shrinker(&pfdev->shrinker, "drm_panfrost")); } /** diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c index 1bba0a0ed3f9..b8b41d242197 100644 --- a/drivers/gpu/drm/ttm/ttm_pool.c +++ b/drivers/gpu/drm/ttm/ttm_pool.c @@ -722,7 +722,7 @@ int ttm_pool_mgr_init(unsigned long num_pages) mm_shrinker.count_objects = ttm_pool_shrinker_count; mm_shrinker.scan_objects = ttm_pool_shrinker_scan; mm_shrinker.seeks = 1; - return register_shrinker(&mm_shrinker); + return register_shrinker(&mm_shrinker, "drm_ttm_pool"); } /** diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index ad9f16689419..c1f734ab86b3 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -812,7 +812,7 @@ int bch_btree_cache_alloc(struct cache_set *c) c->shrink.seeks = 4; c->shrink.batch = c->btree_pages * 2; - if (register_shrinker(&c->shrink)) + if (register_shrinker(&c->shrink, "btree")) pr_warn("bcache: %s: could not register shrinker\n", __func__); diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 5ffa1dcf84cf..bcc95898c341 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -1806,7 +1806,7 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign c->shrinker.scan_objects = dm_bufio_shrink_scan; c->shrinker.seeks = 1; c->shrinker.batch = 0; - r = register_shrinker(&c->shrinker); + r = register_shrinker(&c->shrinker, "dm_bufio"); if (r) goto bad; diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c index d1ea66114d14..05f2fd12066b 100644 --- a/drivers/md/dm-zoned-metadata.c +++ b/drivers/md/dm-zoned-metadata.c @@ -2944,7 +2944,7 @@ int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev, zmd->mblk_shrinker.seeks = DEFAULT_SEEKS; /* Metadata cache shrinker */ - ret = register_shrinker(&zmd->mblk_shrinker); + ret = register_shrinker(&zmd->mblk_shrinker, "md_meta"); if (ret) { dmz_zmd_err(zmd, "Register metadata cache shrinker failed"); goto err; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 59f91e392a2a..1b326b93155c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -7383,7 +7383,7 @@ static struct r5conf *setup_conf(struct mddev *mddev) conf->shrinker.count_objects = raid5_cache_count; conf->shrinker.batch = 128; conf->shrinker.flags = 0; - if (register_shrinker(&conf->shrinker)) { + if (register_shrinker(&conf->shrinker, "md")) { pr_warn("md/raid:%s: couldn't register shrinker.\n", mdname(mddev)); goto abort; diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index f1d8ba6d4857..6c9ddf1187dd 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -1587,7 +1587,7 @@ static int vmballoon_register_shrinker(struct vmballoon *b) b->shrinker.count_objects = vmballoon_shrinker_count; b->shrinker.seeks = DEFAULT_SEEKS; - r = register_shrinker(&b->shrinker); + r = register_shrinker(&b->shrinker, "vmw_balloon"); if (r == 0) b->shrinker_registered = true; diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index f4c34a2a6b8e..093e06e19d0e 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -875,7 +875,7 @@ static int virtio_balloon_register_shrinker(struct virtio_balloon *vb) vb->shrinker.count_objects = virtio_balloon_shrinker_count; vb->shrinker.seeks = DEFAULT_SEEKS; - return register_shrinker(&vb->shrinker); + return register_shrinker(&vb->shrinker, "virtio_valloon"); } static int virtballoon_probe(struct virtio_device *vdev) diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index 5abded97e1a7..a6c5e344017d 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c @@ -305,7 +305,7 @@ static int __init xenbus_probe_backend_init(void) register_xenstore_notifier(&xenstore_notifier); - if (register_shrinker(&backend_memory_shrinker)) + if (register_shrinker(&backend_memory_shrinker, "xen_backend")) pr_warn("shrinker registration failed\n"); return 0; diff --git a/fs/erofs/utils.c b/fs/erofs/utils.c index ec9a1d780dc1..67eb64fadd4f 100644 --- a/fs/erofs/utils.c +++ b/fs/erofs/utils.c @@ -282,7 +282,7 @@ static struct shrinker erofs_shrinker_info = { int __init erofs_init_shrinker(void) { - return register_shrinker(&erofs_shrinker_info); + return register_shrinker(&erofs_shrinker_info, "erofs"); } void erofs_exit_shrinker(void) diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index 9a3a8996aacf..a7aa79d580e5 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c @@ -1650,11 +1650,10 @@ int ext4_es_register_shrinker(struct ext4_sb_info *sbi) err = percpu_counter_init(&sbi->s_es_stats.es_stats_shk_cnt, 0, GFP_KERNEL); if (err) goto err3; - sbi->s_es_shrinker.scan_objects = ext4_es_scan; sbi->s_es_shrinker.count_objects = ext4_es_count; sbi->s_es_shrinker.seeks = DEFAULT_SEEKS; - err = register_shrinker(&sbi->s_es_shrinker); + err = register_shrinker(&sbi->s_es_shrinker, "ext4_es"); if (err) goto err4; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 4368f90571bd..2fc40a1635f3 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -4579,7 +4579,7 @@ static int __init init_f2fs_fs(void) err = f2fs_init_sysfs(); if (err) goto free_garbage_collection_cache; - err = register_shrinker(&f2fs_shrinker_info); + err = register_shrinker(&f2fs_shrinker_info, "f2fs"); if (err) goto free_sysfs; err = register_filesystem(&f2fs_fs_type); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 26169cedcefc..791c23d9f7e7 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -2549,7 +2549,7 @@ int __init gfs2_glock_init(void) return -ENOMEM; } - ret = register_shrinker(&glock_shrinker); + ret = register_shrinker(&glock_shrinker, "gfs2_glock"); if (ret) { destroy_workqueue(gfs2_delete_workqueue); destroy_workqueue(glock_workqueue); diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 28d0eb23e18e..dde981b78488 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -150,7 +150,7 @@ static int __init init_gfs2_fs(void) if (!gfs2_trans_cachep) goto fail_cachep8; - error = register_shrinker(&gfs2_qd_shrinker); + error = register_shrinker(&gfs2_qd_shrinker, "gfs2_qd"); if (error) goto fail_shrinker; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index c0cbeeaec2d1..e7786445ecc1 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1418,7 +1418,7 @@ static journal_t *journal_init_common(struct block_device *bdev, if (percpu_counter_init(&journal->j_checkpoint_jh_count, 0, GFP_KERNEL)) goto err_cleanup; - if (register_shrinker(&journal->j_shrinker)) { + if (register_shrinker(&journal->j_shrinker, "jbd2_journal")) { percpu_counter_destroy(&journal->j_checkpoint_jh_count); goto err_cleanup; } diff --git a/fs/mbcache.c b/fs/mbcache.c index 97c54d3a2227..379dc5b0b6ad 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -367,7 +367,7 @@ struct mb_cache *mb_cache_create(int bucket_bits) cache->c_shrink.count_objects = mb_cache_count; cache->c_shrink.scan_objects = mb_cache_scan; cache->c_shrink.seeks = DEFAULT_SEEKS; - if (register_shrinker(&cache->c_shrink)) { + if (register_shrinker(&cache->c_shrink, "mb_cache")) { kfree(cache->c_hash); kfree(cache); goto err_out; diff --git a/fs/nfs/nfs42xattr.c b/fs/nfs/nfs42xattr.c index e7b34f7e0614..147b8a2f2dc6 100644 --- a/fs/nfs/nfs42xattr.c +++ b/fs/nfs/nfs42xattr.c @@ -1017,15 +1017,16 @@ int __init nfs4_xattr_cache_init(void) if (ret) goto out2; - ret = register_shrinker(&nfs4_xattr_cache_shrinker); + ret = register_shrinker(&nfs4_xattr_cache_shrinker, "nfs_xattr_cache"); if (ret) goto out1; - ret = register_shrinker(&nfs4_xattr_entry_shrinker); + ret = register_shrinker(&nfs4_xattr_entry_shrinker, "nfs_xattr_entry"); if (ret) goto out; - ret = register_shrinker(&nfs4_xattr_large_entry_shrinker); + ret = register_shrinker(&nfs4_xattr_large_entry_shrinker, + "nfs_xattr_large_entry"); if (!ret) return 0; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 6ab5eeb000dc..c7a2aef911f1 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -149,7 +149,7 @@ int __init register_nfs_fs(void) ret = nfs_register_sysctl(); if (ret < 0) goto error_2; - ret = register_shrinker(&acl_shrinker); + ret = register_shrinker(&acl_shrinker, "nfs_acl"); if (ret < 0) goto error_3; #ifdef CONFIG_NFS_V4_2 diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index 2c1b027774d4..9c2879a3c3c0 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -666,7 +666,7 @@ nfsd_file_cache_init(void) goto out_err; } - ret = register_shrinker(&nfsd_file_shrinker); + ret = register_shrinker(&nfsd_file_shrinker, "nfsd_filecache"); if (ret) { pr_err("nfsd: failed to register nfsd_file_shrinker: %d\n", ret); goto out_lru; diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 0b3f12aa37ff..f1cfb06d0be5 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -176,7 +176,7 @@ int nfsd_reply_cache_init(struct nfsd_net *nn) nn->nfsd_reply_cache_shrinker.scan_objects = nfsd_reply_cache_scan; nn->nfsd_reply_cache_shrinker.count_objects = nfsd_reply_cache_count; nn->nfsd_reply_cache_shrinker.seeks = 1; - status = register_shrinker(&nn->nfsd_reply_cache_shrinker); + status = register_shrinker(&nn->nfsd_reply_cache_shrinker, "nfsd_reply"); if (status) goto out_stats_destroy; diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index a74aef99bd3d..854d2b1d0914 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -2985,7 +2985,7 @@ static int __init dquot_init(void) pr_info("VFS: Dquot-cache hash table entries: %ld (order %ld," " %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order)); - if (register_shrinker(&dqcache_shrinker)) + if (register_shrinker(&dqcache_shrinker, "dqcache")) panic("Cannot register dquot shrinker"); return 0; diff --git a/fs/super.c b/fs/super.c index 60f57c7bc0a6..5776a3dbaf10 100644 --- a/fs/super.c +++ b/fs/super.c @@ -265,7 +265,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, s->s_shrink.count_objects = super_cache_count; s->s_shrink.batch = 1024; s->s_shrink.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE; - if (prealloc_shrinker(&s->s_shrink)) + if (prealloc_shrinker(&s->s_shrink, "sb-%s", type->name)) goto fail; if (list_lru_init_memcg(&s->s_dentry_lru, &s->s_shrink)) goto fail; diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index bad67455215f..a3663d201f64 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -2430,7 +2430,7 @@ static int __init ubifs_init(void) if (!ubifs_inode_slab) return -ENOMEM; - err = register_shrinker(&ubifs_shrinker_info); + err = register_shrinker(&ubifs_shrinker_info, "ubifs"); if (err) goto out_slab; diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index e1afb9e503e1..5645e92df0c9 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1986,7 +1986,7 @@ xfs_alloc_buftarg( btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan; btp->bt_shrinker.seeks = DEFAULT_SEEKS; btp->bt_shrinker.flags = SHRINKER_NUMA_AWARE; - if (register_shrinker(&btp->bt_shrinker)) + if (register_shrinker(&btp->bt_shrinker, "xfs_buf")) goto error_pcpu; return btp; diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index bffd6eb0b298..d0c4e74ff763 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -2198,5 +2198,5 @@ xfs_inodegc_register_shrinker( shrink->flags = SHRINKER_NONSLAB; shrink->batch = XFS_INODEGC_SHRINKER_BATCH; - return register_shrinker(shrink); + return register_shrinker(shrink, "xfs_inodegc"); } diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index f165d1a3de1d..93ded9e81f49 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -686,7 +686,7 @@ xfs_qm_init_quotainfo( qinf->qi_shrinker.seeks = DEFAULT_SEEKS; qinf->qi_shrinker.flags = SHRINKER_NUMA_AWARE; - error = register_shrinker(&qinf->qi_shrinker); + error = register_shrinker(&qinf->qi_shrinker, "xfs_qm"); if (error) goto out_free_inos; diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index 17985a890887..8dffe56d6ad1 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -75,6 +75,7 @@ struct shrinker { #endif #ifdef CONFIG_SHRINKER_DEBUG int debugfs_id; + char *name; struct dentry *debugfs_entry; #endif /* objs pending delete, per node */ @@ -92,9 +93,9 @@ struct shrinker { */ #define SHRINKER_NONSLAB (1 << 3) -extern int prealloc_shrinker(struct shrinker *shrinker); +extern int prealloc_shrinker(struct shrinker *shrinker, const char *fmt, ...); extern void register_shrinker_prepared(struct shrinker *shrinker); -extern int register_shrinker(struct shrinker *shrinker); +extern int register_shrinker(struct shrinker *shrinker, const char *fmt, ...); extern void unregister_shrinker(struct shrinker *shrinker); extern void free_prealloced_shrinker(struct shrinker *shrinker); extern void synchronize_shrinkers(void); diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 5c587e00811c..b4c66916bea9 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -4978,7 +4978,7 @@ static void __init kfree_rcu_batch_init(void) INIT_DELAYED_WORK(&krcp->page_cache_work, fill_page_cache_func); krcp->initialized = true; } - if (register_shrinker(&kfree_rcu_shrinker)) + if (register_shrinker(&kfree_rcu_shrinker, "kfree_rcu")) pr_err("Failed to register kfree_rcu() shrinker!\n"); } diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 541c1eba072f..76086984347f 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -423,10 +423,10 @@ static int __init hugepage_init(void) if (err) goto err_slab; - err = register_shrinker(&huge_zero_page_shrinker); + err = register_shrinker(&huge_zero_page_shrinker, "thp_zero"); if (err) goto err_hzp_shrinker; - err = register_shrinker(&deferred_split_shrinker); + err = register_shrinker(&deferred_split_shrinker, "thp_deferred_split"); if (err) goto err_split_shrinker; diff --git a/mm/shrinker_debug.c b/mm/shrinker_debug.c index 81350b64bf01..e2f7ef5fecfc 100644 --- a/mm/shrinker_debug.c +++ b/mm/shrinker_debug.c @@ -418,7 +418,7 @@ int shrinker_debugfs_add(struct shrinker *shrinker) return id; shrinker->debugfs_id = id; - snprintf(buf, sizeof(buf), "%d", id); + snprintf(buf, sizeof(buf), "%s-%d", shrinker->name, id); /* create debugfs entry */ entry = debugfs_create_dir(buf, shrinker_debugfs_root); @@ -465,6 +465,10 @@ int shrinker_debugfs_add(struct shrinker *shrinker) } #endif /* CONFIG_NUMA */ + /* shrinker->name is not needed anymore, free it */ + kfree(shrinker->name); + shrinker->name = NULL; + return 0; } @@ -477,6 +481,7 @@ void shrinker_debugfs_remove(struct shrinker *shrinker) debugfs_remove_recursive(shrinker->debugfs_entry); ida_free(&shrinker_debugfs_ida, shrinker->debugfs_id); + WARN_ON_ONCE(shrinker->name); } static int __init shrinker_debugfs_init(void) diff --git a/mm/vmscan.c b/mm/vmscan.c index 121a54a1602b..6025cfda4932 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -613,7 +613,7 @@ static unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, /* * Add a shrinker callback to be called from the vm. */ -int prealloc_shrinker(struct shrinker *shrinker) +static int __prealloc_shrinker(struct shrinker *shrinker) { unsigned int size; int err; @@ -637,6 +637,34 @@ int prealloc_shrinker(struct shrinker *shrinker) return 0; } +#ifdef CONFIG_SHRINKER_DEBUG +int prealloc_shrinker(struct shrinker *shrinker, const char *fmt, ...) +{ + int err; + char buf[64]; + va_list ap; + + va_start(ap, fmt); + vscnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + shrinker->name = kstrdup(buf, GFP_KERNEL); + if (!shrinker->name) + return -ENOMEM; + + err = __prealloc_shrinker(shrinker); + if (err) + kfree(shrinker->name); + + return err; +} +#else +int prealloc_shrinker(struct shrinker *shrinker, const char *fmt, ...) +{ + return __prealloc_shrinker(shrinker); +} +#endif + void free_prealloced_shrinker(struct shrinker *shrinker) { if (shrinker->flags & SHRINKER_MEMCG_AWARE) { @@ -648,6 +676,9 @@ void free_prealloced_shrinker(struct shrinker *shrinker) kfree(shrinker->nr_deferred); shrinker->nr_deferred = NULL; +#ifdef CONFIG_SHRINKER_DEBUG + kfree(shrinker->name); +#endif } void register_shrinker_prepared(struct shrinker *shrinker) @@ -659,15 +690,38 @@ void register_shrinker_prepared(struct shrinker *shrinker) up_write(&shrinker_rwsem); } -int register_shrinker(struct shrinker *shrinker) +static int __register_shrinker(struct shrinker *shrinker) { - int err = prealloc_shrinker(shrinker); + int err = __prealloc_shrinker(shrinker); if (err) return err; register_shrinker_prepared(shrinker); return 0; } + +#ifdef CONFIG_SHRINKER_DEBUG +int register_shrinker(struct shrinker *shrinker, const char *fmt, ...) +{ + char buf[64]; + va_list ap; + + va_start(ap, fmt); + vscnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + shrinker->name = kstrdup(buf, GFP_KERNEL); + if (!shrinker->name) + return -ENOMEM; + + return __register_shrinker(shrinker); +} +#else +int register_shrinker(struct shrinker *shrinker, const char *fmt, ...) +{ + return __register_shrinker(shrinker); +} +#endif EXPORT_SYMBOL(register_shrinker); /* diff --git a/mm/workingset.c b/mm/workingset.c index 592569a8974c..840986179cf3 100644 --- a/mm/workingset.c +++ b/mm/workingset.c @@ -625,7 +625,7 @@ static int __init workingset_init(void) pr_info("workingset: timestamp_bits=%d max_order=%d bucket_order=%u\n", timestamp_bits, max_order, bucket_order); - ret = prealloc_shrinker(&workingset_shadow_shrinker); + ret = prealloc_shrinker(&workingset_shadow_shrinker, "shadow"); if (ret) goto err; ret = __list_lru_init(&shadow_nodes, true, &shadow_nodes_key, diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 9152fbde33b5..a19de176f604 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -2188,7 +2188,7 @@ static int zs_register_shrinker(struct zs_pool *pool) pool->shrinker.batch = 0; pool->shrinker.seeks = DEFAULT_SEEKS; - return register_shrinker(&pool->shrinker); + return register_shrinker(&pool->shrinker, "zspool"); } /** diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 682fcd24bf43..a29742a9c3f1 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -874,7 +874,7 @@ int __init rpcauth_init_module(void) err = rpc_init_authunix(); if (err < 0) goto out1; - err = register_shrinker(&rpc_cred_shrinker); + err = register_shrinker(&rpc_cred_shrinker, "rpc_cred"); if (err < 0) goto out2; return 0;