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; }