From nobody Sat Sep 26 23:51:54 2026 Received: from mail-m12741.qiye.163.com (mail-m12741.qiye.163.com [115.236.127.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1D8AE39D6D5; Fri, 28 Aug 2026 03:19:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.236.127.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887158; cv=none; b=cycJWfpiyLMSsMu2ZmKNmGOEMvESf0oeNi27YRWbd5fcOM+y0E+koesrcfQVU3ixQKgF7MktuodGVtqpNCeO29pdO8Mtn6KKv+eqi2pv6sl/SexJuNzL3T5stAuqVgduGMvTw/fNYgXqeU7lDSTC/s5aY3Y2Zm0OA/Wc3REiOBY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887158; c=relaxed/simple; bh=4IVelvh4nv33eUyLJApCYIUwSgl3KIZ519p+aJxLldo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=U5W7SP047AV1M5qkEYbeS7YXZP/YRekaJjacnTl33xT6SPjxtzqxLZCKLJjR6+D8OvDyGB62pZE2dV+auTs+JkySRMMKZEI4yRvvnax5ia0VsYknmhbGMQZsC9kiiTSkUBjiCZ/mJKr+d88lDsR2bY0uSB4+y/ih28N50Yr0iCk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn; spf=pass smtp.mailfrom=easystack.cn; arc=none smtp.client-ip=115.236.127.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=easystack.cn Received: from localhost.localdomain (unknown [218.94.118.90]) by smtp.qiye.163.com (Hmail) with ESMTP id 1e6a20d93; Fri, 28 Aug 2026 11:13:53 +0800 (GMT+08:00) From: Zhen Ni To: Andrew Morton Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jonathan Corbet , Shuah Khan , Randy Dunlap , Brendan Jackman , Johannes Weiner , Zi Yan , linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Zhen Ni Subject: [PATCH 1/8] mm/page_owner: Add PID filtering support Date: Fri, 28 Aug 2026 11:13:32 +0800 Message-Id: <20260828031339.1270699-2-zhen.ni@easystack.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20260828031339.1270699-1-zhen.ni@easystack.cn> References: <20260828031339.1270699-1-zhen.ni@easystack.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa0465c0d6c0229kunma81ef96712a329 X-HM-MType: 1 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFJQjdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVkZTRgaVkMfQk8dTkkZTE8aGlYVFA kWGhdVGRETFhoSFyQUDg9ZV1kYEgtZQVlJSkNVQk9VSkpDVUJLWVdZFhoPEhUdFFlBWU9LSFVKS0 lPT09IVUpLS1VKQktLWQY+ Content-Type: text/plain; charset="utf-8" Add PID filtering support. Users can filter page_owner output by process IDs using the "pid=3D" command format. The filter supports up to 16 PIDs specified as a comma-separated list. PIDs are stored in sorted order for efficient binary search matching during page owner iteration. Signed-off-by: Zhen Ni --- mm/page_owner.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/mm/page_owner.c b/mm/page_owner.c index fbbda7ba914b..33b9e12a019b 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include =20 #include "page_alloc.h" =20 @@ -66,12 +68,24 @@ static const char * const page_owner_print_mode_strings= [] =3D { [PAGE_OWNER_PRINT_STACK_HANDLE] =3D "stack_handle", }; =20 +/* PID_MAX_LIMIT =3D 4,194,304 (7 decimal digits) */ +#define PID_MAX_DIGITS 7 +#define MAX_FILTER_PIDS 16 + struct page_owner_filter_state { enum page_owner_print_mode print_mode; - nodemask_t nid_filter; bool nid_filter_enabled; + bool proc_filter_enabled; + nodemask_t nid_filter; + int pid_count; + pid_t pid_list[MAX_FILTER_PIDS]; }; =20 +static int cmp_pid_t(const void *a, const void *b) +{ + return *(pid_t *)a - *(pid_t *)b; +} + static bool page_owner_enabled __initdata; DEFINE_STATIC_KEY_FALSE(page_owner_inited); =20 @@ -820,6 +834,19 @@ read_page_owner(struct file *file, char __user *buf, s= ize_t count, loff_t *ppos) goto ext_put_continue; } =20 + if (state->proc_filter_enabled) { + bool proc_match =3D false; + + proc_match =3D bsearch(&page_owner->pid, + state->pid_list, + state->pid_count, + sizeof(pid_t), + cmp_pid_t) !=3D NULL; + + if (!proc_match) + goto ext_put_continue; + } + /* Record the next PFN to read in the file offset */ *ppos =3D pfn + 1; =20 @@ -927,6 +954,7 @@ static int page_owner_open(struct inode *inode, struct = file *file) state->print_mode =3D PAGE_OWNER_PRINT_STACK; nodes_clear(state->nid_filter); state->nid_filter_enabled =3D false; + state->proc_filter_enabled =3D false; file->private_data =3D state; return 0; } @@ -937,6 +965,37 @@ static int page_owner_release(struct inode *inode, str= uct file *file) return 0; } =20 +static int parse_pid_t_list(const char *str, pid_t *list, int *count) +{ + char *str_copy, *token; + int i =3D 0; + unsigned int pid; + int ret =3D 0; + + str_copy =3D kstrdup(str, GFP_KERNEL); + if (!str_copy) + return -ENOMEM; + + while ((token =3D strsep(&str_copy, ",")) !=3D NULL) { + if (*token =3D=3D '\0') + continue; + if (i >=3D MAX_FILTER_PIDS) { + ret =3D -E2BIG; + goto out_free; + } + if (kstrtouint(token, 10, &pid) !=3D 0) { + ret =3D -EINVAL; + goto out_free; + } + list[i++] =3D (pid_t)pid; + } + + *count =3D i; +out_free: + kfree(str_copy); + return ret; +} + static ssize_t page_owner_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) @@ -949,6 +1008,9 @@ static ssize_t page_owner_write(struct file *file, enum page_owner_print_mode new_print_mode; nodemask_t new_nid_filter; bool new_nid_filter_enabled; + bool new_proc_filter_enabled; + pid_t new_pid_list[MAX_FILTER_PIDS]; + int new_pid_count =3D 0; =20 /* * Maximum input length for filter commands: @@ -956,8 +1018,10 @@ static ssize_t page_owner_write(struct file *file, * with sufficient buffer * - 6 * MAX_NUMNODES: worst case for nid list * Worst case per node: ",NNNNN" (comma + 5-digit node number) =3D 6 by= tes + * - For list filters: (digit+comma) * count + prefix */ - if (count > 32 + 6 * MAX_NUMNODES) + if (count > 32 + 6 * MAX_NUMNODES + + (PID_MAX_DIGITS + 1) * MAX_FILTER_PIDS + 4) return -EINVAL; =20 kbuf =3D memdup_user_nul(buf, count); @@ -969,6 +1033,11 @@ static ssize_t page_owner_write(struct file *file, new_print_mode =3D state->print_mode; new_nid_filter =3D state->nid_filter; new_nid_filter_enabled =3D state->nid_filter_enabled; + new_proc_filter_enabled =3D state->proc_filter_enabled; + if (state->pid_count > 0) { + memcpy(new_pid_list, state->pid_list, sizeof(state->pid_list)); + new_pid_count =3D state->pid_count; + } =20 while ((token =3D strsep(&kbuf, " \t\n")) !=3D NULL) { if (*token =3D=3D '\0') @@ -1000,6 +1069,10 @@ static ssize_t page_owner_write(struct file *file, } =20 new_nid_filter_enabled =3D true; + } else if (!strncmp(token, "pid=3D", 4)) { + ret =3D parse_pid_t_list(token + 4, new_pid_list, &new_pid_count); + if (ret < 0) + goto out_free; } else { ret =3D -EINVAL; goto out_free; @@ -1010,6 +1083,14 @@ static ssize_t page_owner_write(struct file *file, state->print_mode =3D new_print_mode; state->nid_filter =3D new_nid_filter; state->nid_filter_enabled =3D new_nid_filter_enabled; + state->proc_filter_enabled =3D new_pid_count > 0; + if (new_pid_count > 0) { + memcpy(state->pid_list, new_pid_list, sizeof(state->pid_list)); + state->pid_count =3D new_pid_count; + } + if (state->pid_count > 1) + sort(state->pid_list, state->pid_count, sizeof(pid_t), + cmp_pid_t, NULL); =20 ret =3D count; =20 --=20 2.20.1 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-m3284.qiye.163.com (mail-m3284.qiye.163.com [220.197.32.84]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7C7D338AC68; Fri, 28 Aug 2026 03:19:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.32.84 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887160; cv=none; b=tXSFW3WJFCZ5xEurh9N+SPR3J3DHSzWVMcO/5ttv/LCqYsmvr/H56xbHg/vFEF4qmjOxMnPd01XM6CoPmPliPy6q9afc28Cq5SB1dqnTvTq5kky5TJu+rtxRJhwWzd8USluxA/2o+TCd5cx06QJYKrYKi+yhun9k4WuJu91FgCI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887160; c=relaxed/simple; bh=dOA2CLreTGapet+ozgio/gFEInLVcWqQDCAMPQusI6c=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=bRy9BvTqIQpvWQbYKwyQi932e9OqKrCxE4I4c9tJ/KZyWBBI5txnHhPmkPjWcFclrDmN+X4Fcak12DoustUh5FHH8h9YvWAZ0K7awazZlWM5SQCxBG9RzYL1ozuPnIDA+jo6CVxk/eKagtfE6RThncKsjZm/6dyKDeJ4NdUg4sU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn; spf=pass smtp.mailfrom=easystack.cn; arc=none smtp.client-ip=220.197.32.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=easystack.cn Received: from localhost.localdomain (unknown [218.94.118.90]) by smtp.qiye.163.com (Hmail) with ESMTP id 1e6a20d97; Fri, 28 Aug 2026 11:13:54 +0800 (GMT+08:00) From: Zhen Ni To: Andrew Morton Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jonathan Corbet , Shuah Khan , Randy Dunlap , Brendan Jackman , Johannes Weiner , Zi Yan , linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Zhen Ni Subject: [PATCH 2/8] mm/page_owner: Add TGID filtering support Date: Fri, 28 Aug 2026 11:13:33 +0800 Message-Id: <20260828031339.1270699-3-zhen.ni@easystack.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20260828031339.1270699-1-zhen.ni@easystack.cn> References: <20260828031339.1270699-1-zhen.ni@easystack.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa0465c12fe0229kunma81ef96712a32f X-HM-MType: 1 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFJQjdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVlDQ0MdVhofS0NMTRoaTRpDS1YVFA kWGhdVGRETFhoSFyQUDg9ZV1kYEgtZQVlJSkNVQk9VSkpDVUJLWVdZFhoPEhUdFFlBWU9LSFVKS0 lPT09IVUpLS1VKQktLWQY+ Content-Type: text/plain; charset="utf-8" Extend filter to support thread group ID (TGID) filtering alongside PID filtering. Reuses existing PID parsing and binary search infrastructure with separate TGID list and count fields. Signed-off-by: Zhen Ni --- mm/page_owner.c | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/mm/page_owner.c b/mm/page_owner.c index 33b9e12a019b..077867e9e572 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -71,6 +71,7 @@ static const char * const page_owner_print_mode_strings[]= =3D { /* PID_MAX_LIMIT =3D 4,194,304 (7 decimal digits) */ #define PID_MAX_DIGITS 7 #define MAX_FILTER_PIDS 16 +#define MAX_FILTER_TGIDS 16 =20 struct page_owner_filter_state { enum page_owner_print_mode print_mode; @@ -78,7 +79,9 @@ struct page_owner_filter_state { bool proc_filter_enabled; nodemask_t nid_filter; int pid_count; + int tgid_count; pid_t pid_list[MAX_FILTER_PIDS]; + pid_t tgid_list[MAX_FILTER_TGIDS]; }; =20 static int cmp_pid_t(const void *a, const void *b) @@ -837,11 +840,19 @@ read_page_owner(struct file *file, char __user *buf, = size_t count, loff_t *ppos) if (state->proc_filter_enabled) { bool proc_match =3D false; =20 - proc_match =3D bsearch(&page_owner->pid, - state->pid_list, - state->pid_count, - sizeof(pid_t), - cmp_pid_t) !=3D NULL; + if (state->pid_count > 0) + proc_match =3D bsearch(&page_owner->pid, + state->pid_list, + state->pid_count, + sizeof(pid_t), + cmp_pid_t) !=3D NULL; + + if (!proc_match && state->tgid_count > 0) + proc_match =3D bsearch(&page_owner->tgid, + state->tgid_list, + state->tgid_count, + sizeof(pid_t), + cmp_pid_t) !=3D NULL; =20 if (!proc_match) goto ext_put_continue; @@ -1010,7 +1021,9 @@ static ssize_t page_owner_write(struct file *file, bool new_nid_filter_enabled; bool new_proc_filter_enabled; pid_t new_pid_list[MAX_FILTER_PIDS]; + pid_t new_tgid_list[MAX_FILTER_TGIDS]; int new_pid_count =3D 0; + int new_tgid_count =3D 0; =20 /* * Maximum input length for filter commands: @@ -1021,7 +1034,8 @@ static ssize_t page_owner_write(struct file *file, * - For list filters: (digit+comma) * count + prefix */ if (count > 32 + 6 * MAX_NUMNODES + - (PID_MAX_DIGITS + 1) * MAX_FILTER_PIDS + 4) + (PID_MAX_DIGITS + 1) * MAX_FILTER_PIDS + 4 + + (PID_MAX_DIGITS + 1) * MAX_FILTER_TGIDS + 5) return -EINVAL; =20 kbuf =3D memdup_user_nul(buf, count); @@ -1038,6 +1052,10 @@ static ssize_t page_owner_write(struct file *file, memcpy(new_pid_list, state->pid_list, sizeof(state->pid_list)); new_pid_count =3D state->pid_count; } + if (state->tgid_count > 0) { + memcpy(new_tgid_list, state->tgid_list, sizeof(state->tgid_list)); + new_tgid_count =3D state->tgid_count; + } =20 while ((token =3D strsep(&kbuf, " \t\n")) !=3D NULL) { if (*token =3D=3D '\0') @@ -1073,6 +1091,10 @@ static ssize_t page_owner_write(struct file *file, ret =3D parse_pid_t_list(token + 4, new_pid_list, &new_pid_count); if (ret < 0) goto out_free; + } else if (!strncmp(token, "tgid=3D", 5)) { + ret =3D parse_pid_t_list(token + 5, new_tgid_list, &new_tgid_count); + if (ret < 0) + goto out_free; } else { ret =3D -EINVAL; goto out_free; @@ -1083,7 +1105,7 @@ static ssize_t page_owner_write(struct file *file, state->print_mode =3D new_print_mode; state->nid_filter =3D new_nid_filter; state->nid_filter_enabled =3D new_nid_filter_enabled; - state->proc_filter_enabled =3D new_pid_count > 0; + state->proc_filter_enabled =3D new_pid_count > 0 || new_tgid_count > 0; if (new_pid_count > 0) { memcpy(state->pid_list, new_pid_list, sizeof(state->pid_list)); state->pid_count =3D new_pid_count; @@ -1091,6 +1113,13 @@ static ssize_t page_owner_write(struct file *file, if (state->pid_count > 1) sort(state->pid_list, state->pid_count, sizeof(pid_t), cmp_pid_t, NULL); + if (new_tgid_count > 0) { + memcpy(state->tgid_list, new_tgid_list, sizeof(state->tgid_list)); + state->tgid_count =3D new_tgid_count; + } + if (state->tgid_count > 1) + sort(state->tgid_list, state->tgid_count, sizeof(pid_t), + cmp_pid_t, NULL); =20 ret =3D count; =20 --=20 2.20.1 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-m12766.qiye.163.com (mail-m12766.qiye.163.com [115.236.127.66]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12AD630FC0F; Fri, 28 Aug 2026 03:29:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.236.127.66 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887761; cv=none; b=Sz0eZ9YhhcA67T27gWRJpTFlTPjr0NT+eOySiYDeFbWIPThjzVmfSYdHNzmuxG2xgQGvjI3oaDogD1Qj+2cpW1xzjV0UOTCAbja59hPXShqinqaaAl3/uHgHPI5XrYh3TkkZv2Nvf2xN63Xcw9cVYY2TArvKpKK0uQ4yY25+jtg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887761; c=relaxed/simple; bh=KmGCl8M6y4QiHYVSPZJfZzZRpwmqrCFnQIvcBARhz3c=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=b9sTmgnkOrn3qSKlCPofEHQxdv6Jw2l71BTwNufESwGW/13myTggH/4cOG76Ls2T/9V9k12WI42dpTH51V1f5yTiF1M8qxsiLOWjehwz/VwEa444D6AAJOd6f9y3Rqt/dH08In8M6L1CmASnnxCY2asM27kEDEr5U6g2nOF0m5I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn; spf=pass smtp.mailfrom=easystack.cn; arc=none smtp.client-ip=115.236.127.66 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=easystack.cn Received: from localhost.localdomain (unknown [218.94.118.90]) by smtp.qiye.163.com (Hmail) with ESMTP id 1e6a20da3; Fri, 28 Aug 2026 11:13:55 +0800 (GMT+08:00) From: Zhen Ni To: Andrew Morton Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jonathan Corbet , Shuah Khan , Randy Dunlap , Brendan Jackman , Johannes Weiner , Zi Yan , linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Zhen Ni Subject: [PATCH 3/8] mm/page_owner: Add COMM filtering with wildcard support Date: Fri, 28 Aug 2026 11:13:34 +0800 Message-Id: <20260828031339.1270699-4-zhen.ni@easystack.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20260828031339.1270699-1-zhen.ni@easystack.cn> References: <20260828031339.1270699-1-zhen.ni@easystack.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa0465c18480229kunma81ef96712a33b X-HM-MType: 1 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFJQjdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVkZT0JOVkJMSRkeH04dTENPGVYVFA kWGhdVGRETFhoSFyQUDg9ZV1kYEgtZQVlJSkNVQk9VSkpDVUJLWVdZFhoPEhUdFFlBWU9LSFVKS0 lPT09IVUpLS1VKQktLWQY+ Content-Type: text/plain; charset="utf-8" Add process name (COMM) filtering to page_owner with glob-style wildcard pattern matching support. Users can now filter page_owner output by process names using flexible patterns. Supported wildcards: * : matches any sequence of characters ? : matches any single character [abc]: matches any character in the set [a-z]: matches any character in the range Examples: comm=3Dpython* : matches python, python3, python3.9, etc. comm=3D*sh : matches bash, zsh, dash, etc. Signed-off-by: Zhen Ni --- mm/page_owner.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/mm/page_owner.c b/mm/page_owner.c index 077867e9e572..7cd533682054 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -14,6 +14,7 @@ #include #include #include +#include =20 #include "page_alloc.h" =20 @@ -72,6 +73,7 @@ static const char * const page_owner_print_mode_strings[]= =3D { #define PID_MAX_DIGITS 7 #define MAX_FILTER_PIDS 16 #define MAX_FILTER_TGIDS 16 +#define MAX_FILTER_COMMS 8 =20 struct page_owner_filter_state { enum page_owner_print_mode print_mode; @@ -80,8 +82,10 @@ struct page_owner_filter_state { nodemask_t nid_filter; int pid_count; int tgid_count; + int comm_count; pid_t pid_list[MAX_FILTER_PIDS]; pid_t tgid_list[MAX_FILTER_TGIDS]; + char comm_list[MAX_FILTER_COMMS][TASK_COMM_LEN]; }; =20 static int cmp_pid_t(const void *a, const void *b) @@ -854,6 +858,20 @@ read_page_owner(struct file *file, char __user *buf, s= ize_t count, loff_t *ppos) sizeof(pid_t), cmp_pid_t) !=3D NULL; =20 + if (!proc_match && state->comm_count > 0) { + bool comm_match =3D false; + int i; + + for (i =3D 0; i < state->comm_count; i++) { + if (glob_match(state->comm_list[i], + page_owner->comm)) { + comm_match =3D true; + break; + } + } + proc_match =3D comm_match; + } + if (!proc_match) goto ext_put_continue; } @@ -1007,6 +1025,38 @@ static int parse_pid_t_list(const char *str, pid_t *= list, int *count) return ret; } =20 +static int parse_comm_list(const char *str, char (*list)[TASK_COMM_LEN], i= nt *count) +{ + char *str_copy, *token; + int i =3D 0; + int ret =3D 0; + + str_copy =3D kstrdup(str, GFP_KERNEL); + if (!str_copy) + return -ENOMEM; + + while ((token =3D strsep(&str_copy, ",")) !=3D NULL) { + token =3D strstrip(token); + if (*token =3D=3D '\0') + continue; + if (i >=3D MAX_FILTER_COMMS) { + ret =3D -E2BIG; + goto out_free; + } + strscpy(list[i], token, TASK_COMM_LEN); + i++; + } + + *count =3D i; + + if (i =3D=3D 0) + ret =3D -EINVAL; + +out_free: + kfree(str_copy); + return ret; +} + static ssize_t page_owner_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) @@ -1022,8 +1072,10 @@ static ssize_t page_owner_write(struct file *file, bool new_proc_filter_enabled; pid_t new_pid_list[MAX_FILTER_PIDS]; pid_t new_tgid_list[MAX_FILTER_TGIDS]; + char (*new_comm_list)[TASK_COMM_LEN] =3D NULL; int new_pid_count =3D 0; int new_tgid_count =3D 0; + int new_comm_count =3D 0; =20 /* * Maximum input length for filter commands: @@ -1035,12 +1087,19 @@ static ssize_t page_owner_write(struct file *file, */ if (count > 32 + 6 * MAX_NUMNODES + (PID_MAX_DIGITS + 1) * MAX_FILTER_PIDS + 4 + - (PID_MAX_DIGITS + 1) * MAX_FILTER_TGIDS + 5) + (PID_MAX_DIGITS + 1) * MAX_FILTER_TGIDS + 5 + + TASK_COMM_LEN * MAX_FILTER_COMMS + 5) return -EINVAL; =20 + new_comm_list =3D kmalloc_array(MAX_FILTER_COMMS, TASK_COMM_LEN, GFP_KERN= EL); + if (!new_comm_list) + return -ENOMEM; + kbuf =3D memdup_user_nul(buf, count); - if (IS_ERR(kbuf)) + if (IS_ERR(kbuf)) { + kfree(new_comm_list); return PTR_ERR(kbuf); + } =20 orig =3D kbuf; =20 @@ -1056,6 +1115,11 @@ static ssize_t page_owner_write(struct file *file, memcpy(new_tgid_list, state->tgid_list, sizeof(state->tgid_list)); new_tgid_count =3D state->tgid_count; } + if (state->comm_count > 0) { + memcpy(new_comm_list, state->comm_list, + state->comm_count * TASK_COMM_LEN); + new_comm_count =3D state->comm_count; + } =20 while ((token =3D strsep(&kbuf, " \t\n")) !=3D NULL) { if (*token =3D=3D '\0') @@ -1095,6 +1159,10 @@ static ssize_t page_owner_write(struct file *file, ret =3D parse_pid_t_list(token + 5, new_tgid_list, &new_tgid_count); if (ret < 0) goto out_free; + } else if (!strncmp(token, "comm=3D", 5)) { + ret =3D parse_comm_list(token + 5, new_comm_list, &new_comm_count); + if (ret < 0) + goto out_free; } else { ret =3D -EINVAL; goto out_free; @@ -1105,7 +1173,9 @@ static ssize_t page_owner_write(struct file *file, state->print_mode =3D new_print_mode; state->nid_filter =3D new_nid_filter; state->nid_filter_enabled =3D new_nid_filter_enabled; - state->proc_filter_enabled =3D new_pid_count > 0 || new_tgid_count > 0; + state->proc_filter_enabled =3D new_pid_count > 0 || + new_tgid_count > 0 || + new_comm_count > 0; if (new_pid_count > 0) { memcpy(state->pid_list, new_pid_list, sizeof(state->pid_list)); state->pid_count =3D new_pid_count; @@ -1120,10 +1190,16 @@ static ssize_t page_owner_write(struct file *file, if (state->tgid_count > 1) sort(state->tgid_list, state->tgid_count, sizeof(pid_t), cmp_pid_t, NULL); + if (new_comm_count > 0) { + memcpy(state->comm_list, new_comm_list, + new_comm_count * TASK_COMM_LEN); + state->comm_count =3D new_comm_count; + } =20 ret =3D count; =20 out_free: + kfree(new_comm_list); kfree(orig); return ret; } --=20 2.20.1 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-m15572.qiye.163.com (mail-m15572.qiye.163.com [101.71.155.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C79DE1684B0; Fri, 28 Aug 2026 03:49:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=101.71.155.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787888977; cv=none; b=iuogS/EptXS8OehzrO/0F+27+S6mCN6iNOxvu+RiyJcg6O1x1v0PSyjnOTwxFbxtnLD06TdcTc+ZLV3zvXBUMZ9wc+9YkReFBFbKACaNYRnBDzuze01Y187mh4SK7fMjdNsNkebw5Um4MJyu1klAS+ZGCDpvonkcgFoErT2J4Ao= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787888977; c=relaxed/simple; bh=xK5AniTkiNlM8WCrPaWuzkP15+yNQb1EBVA4yZ9y9D0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=uHX/yvcpzzVYsFkRoZVvGF4CUgGywqHBIwL928G+pHxF/tQ9Q/8jADLE8dy4C9nNv4Ktf2PXCvv1iSqm34J09Od0ZATtRpEoFd1wo36xb4NbUI5ruLgZ04COgTLKOIhAGO7/KgrQuISOizWeurlUoy08WWpekUVNFPxVQoo4Epk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn; spf=pass smtp.mailfrom=easystack.cn; arc=none smtp.client-ip=101.71.155.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=easystack.cn Received: from localhost.localdomain (unknown [218.94.118.90]) by smtp.qiye.163.com (Hmail) with ESMTP id 1e6a20da8; Fri, 28 Aug 2026 11:13:56 +0800 (GMT+08:00) From: Zhen Ni To: Andrew Morton Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jonathan Corbet , Shuah Khan , Randy Dunlap , Brendan Jackman , Johannes Weiner , Zi Yan , linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Zhen Ni Subject: [PATCH 4/8] mm/page_owner: Refactor memcg handling for cgroup filter support Date: Fri, 28 Aug 2026 11:13:35 +0800 Message-Id: <20260828031339.1270699-5-zhen.ni@easystack.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20260828031339.1270699-1-zhen.ni@easystack.cn> References: <20260828031339.1270699-1-zhen.ni@easystack.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa0465c1cf80229kunma81ef96712a344 X-HM-MType: 1 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFJQjdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVkZHh4YVhlPSh9OT05JHh9PHVYVFA kWGhdVGRETFhoSFyQUDg9ZV1kYEgtZQVlJSkNVQk9VSkpDVUJLWVdZFhoPEhUdFFlBWU9LSFVKS0 lPT09IVUpLS1VKQktLWQY+ Content-Type: text/plain; charset="utf-8" Extract memcg information retrieval from printing logic to prepare for cgroup filtering support. Introduce struct memcg_info to hold cgroup data that can be reused for both display output and filtering decisions. No functional change - output behavior unchanged. Signed-off-by: Zhen Ni --- mm/page_owner.c | 62 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/mm/page_owner.c b/mm/page_owner.c index 7cd533682054..09cfad10a7df 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -69,6 +69,13 @@ static const char * const page_owner_print_mode_strings[= ] =3D { [PAGE_OWNER_PRINT_STACK_HANDLE] =3D "stack_handle", }; =20 +struct memcg_info { + char name[80]; + bool is_slab; + bool is_objcg; + bool is_online; +}; + /* PID_MAX_LIMIT =3D 4,194,304 (7 decimal digits) */ #define PID_MAX_DIGITS 7 #define MAX_FILTER_PIDS 16 @@ -573,16 +580,13 @@ void pagetypeinfo_showmixedcount_print(struct seq_fil= e *m, =20 #ifdef CONFIG_MEMCG /* - * Looking for memcg information and print it out + * Get memcg information from page */ -static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret, - struct page *page) +static void get_page_memcg_info(struct page *page, struct memcg_info *info) { unsigned long memcg_data; struct obj_cgroup *objcg; struct mem_cgroup *memcg; - bool online; - char name[80]; =20 rcu_read_lock(); memcg_data =3D READ_ONCE(page->memcg_data); @@ -590,8 +594,7 @@ static inline int print_page_owner_memcg(char *kbuf, si= ze_t count, int ret, goto out_unlock; =20 if (memcg_data & MEMCG_DATA_OBJEXTS) { - ret +=3D scnprintf(kbuf + ret, count - ret, - "Slab cache page\n"); + info->is_slab =3D true; goto out_unlock; } =20 @@ -600,21 +603,38 @@ static inline int print_page_owner_memcg(char *kbuf, = size_t count, int ret, if (!memcg) goto out_unlock; =20 - online =3D css_is_online(&memcg->css); - cgroup_name(memcg->css.cgroup, name, sizeof(name)); - ret +=3D scnprintf(kbuf + ret, count - ret, - "Charged %sto %smemcg %s\n", - (memcg_data & MEMCG_DATA_KMEM) ? "(via objcg) " : "", - online ? "" : "offline ", - name); + info->is_objcg =3D (memcg_data & MEMCG_DATA_KMEM) !=3D 0; + info->is_online =3D css_is_online(&memcg->css); + cgroup_name(memcg->css.cgroup, info->name, sizeof(info->name)); out_unlock: rcu_read_unlock(); +} + +/* + * Print memcg information from memcg_info + */ +static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret, + const struct memcg_info *info) +{ + if (!info) + return ret; + + if (info->is_slab) + ret +=3D scnprintf(kbuf + ret, count - ret, + "Slab cache page\n"); + + if (info->name[0]) + ret +=3D scnprintf(kbuf + ret, count - ret, + "Charged %sto %smemcg %s\n", + info->is_objcg ? "(via objcg) " : "", + info->is_online ? "" : "offline ", + info->name); =20 return ret; } #else static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret, - struct page *page) + const struct memcg_info *info) { return ret; } @@ -624,7 +644,8 @@ static ssize_t print_page_owner(char __user *buf, size_t count, unsigned long pfn, struct page *page, struct page_owner *page_owner, depot_stack_handle_t handle, - struct page_owner_filter_state *state) + struct page_owner_filter_state *state, + const struct memcg_info *memcg_info) { int ret, pageblock_mt, page_mt; char *kbuf; @@ -674,7 +695,7 @@ print_page_owner(char __user *buf, size_t count, unsign= ed long pfn, migrate_reason_names[page_owner->last_migrate_reason]); } =20 - ret =3D print_page_owner_memcg(kbuf, count, ret, page); + ret =3D print_page_owner_memcg(kbuf, count, ret, memcg_info); =20 ret +=3D snprintf(kbuf + ret, count - ret, "\n"); if (ret >=3D count) @@ -777,6 +798,7 @@ read_page_owner(struct file *file, char __user *buf, si= ze_t count, loff_t *ppos) * user through copy_to_user() or GFP_KERNEL allocations. */ struct page_owner page_owner_tmp; + struct memcg_info memcg_info =3D {}; =20 /* * If the new page is in a new MAX_ORDER_NR_PAGES area, @@ -876,13 +898,17 @@ read_page_owner(struct file *file, char __user *buf, = size_t count, loff_t *ppos) goto ext_put_continue; } =20 +#ifdef CONFIG_MEMCG + get_page_memcg_info(page, &memcg_info); +#endif + /* Record the next PFN to read in the file offset */ *ppos =3D pfn + 1; =20 page_owner_tmp =3D *page_owner; page_ext_put(page_ext); return print_page_owner(buf, count, pfn, page, - &page_owner_tmp, handle, state); + &page_owner_tmp, handle, state, &memcg_info); ext_put_continue: page_ext_put(page_ext); cond_resched(); --=20 2.20.1 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-m32116.qiye.163.com (mail-m32116.qiye.163.com [220.197.32.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 27014331EB2; Fri, 28 Aug 2026 03:29:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.32.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887763; cv=none; b=eLuF7khinllXQB+9fU9SD+pJnY5EuyYIx3gpluR+9QC+bbzysp8iJ+pZSi7qbtj9xQElOKehvK/q0MHDtU+Wuc/IdaBwKOTsxa1DnnAaq/rn8bozuXQwYk4u8sdy2TVD2NxqtvtnrAuzudh9M42R1nl49hwiXlJ/Jru5SB+jbMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887763; c=relaxed/simple; bh=itGv/jJIDnFVFSAhWDNAY/d524buIqJyjfKJN9E5kRQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=s/2cvkGx4OXNwfbxD4RFwhu9wrsR1fXLneDHJmAfwme/FjaLzQS4R8Restm/ZtCdlIgx2Fl2bXj5mJAw7F6zsLr5m1DTv+J8LhQruqqoT8oiuHGfwPc7AMw2tenMhJglcirvbPvIY2ofoi/7kB+wA9c3XEQfw56JkpT5IsZ+nsY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn; spf=pass smtp.mailfrom=easystack.cn; arc=none smtp.client-ip=220.197.32.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=easystack.cn Received: from localhost.localdomain (unknown [218.94.118.90]) by smtp.qiye.163.com (Hmail) with ESMTP id 1e6a20dae; Fri, 28 Aug 2026 11:13:58 +0800 (GMT+08:00) From: Zhen Ni To: Andrew Morton Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jonathan Corbet , Shuah Khan , Randy Dunlap , Brendan Jackman , Johannes Weiner , Zi Yan , linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Zhen Ni Subject: [PATCH 5/8] mm/page_owner: Add memcg filter support Date: Fri, 28 Aug 2026 11:13:36 +0800 Message-Id: <20260828031339.1270699-6-zhen.ni@easystack.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20260828031339.1270699-1-zhen.ni@easystack.cn> References: <20260828031339.1270699-1-zhen.ni@easystack.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa0465c21b00229kunma81ef96712a34c X-HM-MType: 1 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFJQjdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVkaGhofVhgeH01JSEgfSkNMGFYVFA kWGhdVGRETFhoSFyQUDg9ZV1kYEgtZQVlJSkNVQk9VSkpDVUJLWVdZFhoPEhUdFFlBWU9LSFVKS0 lPT09IVUpLS1VKQktLWQY+ Content-Type: text/plain; charset="utf-8" Add memory cgroup filtering to page_owner to allow filtering pages by their memcg path. This helps debug memory usage patterns for specific cgroups. Users can now filter page_owner output to show only pages belonging to a particular memory cgroup. Collect cgroup path in memcg_info using cgroup_path() and store the filter state in page_owner_filter_state. When the user sets memcg filter via "memcg=3D" command, compare each page's cgroup path against the specified path and skip non-matching pages using strcmp. Signed-off-by: Zhen Ni --- mm/page_owner.c | 79 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/mm/page_owner.c b/mm/page_owner.c index 09cfad10a7df..21b82e927eaf 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -71,6 +71,7 @@ static const char * const page_owner_print_mode_strings[]= =3D { =20 struct memcg_info { char name[80]; + char *path; bool is_slab; bool is_objcg; bool is_online; @@ -86,6 +87,7 @@ struct page_owner_filter_state { enum page_owner_print_mode print_mode; bool nid_filter_enabled; bool proc_filter_enabled; + bool memcg_filter_enabled; nodemask_t nid_filter; int pid_count; int tgid_count; @@ -93,6 +95,7 @@ struct page_owner_filter_state { pid_t pid_list[MAX_FILTER_PIDS]; pid_t tgid_list[MAX_FILTER_TGIDS]; char comm_list[MAX_FILTER_COMMS][TASK_COMM_LEN]; + char *memcg_path; }; =20 static int cmp_pid_t(const void *a, const void *b) @@ -582,12 +585,21 @@ void pagetypeinfo_showmixedcount_print(struct seq_fil= e *m, /* * Get memcg information from page */ -static void get_page_memcg_info(struct page *page, struct memcg_info *info) +static void get_page_memcg_info(struct page *page, struct memcg_info *info, + bool need_path) { unsigned long memcg_data; struct obj_cgroup *objcg; struct mem_cgroup *memcg; =20 + if (need_path) { + info->path =3D kzalloc(PATH_MAX, GFP_KERNEL); + if (!info->path) + return; + } else { + info->path =3D NULL; + } + rcu_read_lock(); memcg_data =3D READ_ONCE(page->memcg_data); if (!memcg_data || PageTail(page)) @@ -606,8 +618,14 @@ static void get_page_memcg_info(struct page *page, str= uct memcg_info *info) info->is_objcg =3D (memcg_data & MEMCG_DATA_KMEM) !=3D 0; info->is_online =3D css_is_online(&memcg->css); cgroup_name(memcg->css.cgroup, info->name, sizeof(info->name)); + if (need_path) + cgroup_path(memcg->css.cgroup, info->path, PATH_MAX); out_unlock: rcu_read_unlock(); + if (info->path && !info->path[0]) { + kfree(info->path); + info->path =3D NULL; + } } =20 /* @@ -776,6 +794,7 @@ read_page_owner(struct file *file, char __user *buf, si= ze_t count, loff_t *ppos) struct page_owner *page_owner; depot_stack_handle_t handle; struct page_owner_filter_state *state =3D file->private_data; + ssize_t ret; =20 if (!static_branch_unlikely(&page_owner_inited)) return -EINVAL; @@ -899,7 +918,12 @@ read_page_owner(struct file *file, char __user *buf, s= ize_t count, loff_t *ppos) } =20 #ifdef CONFIG_MEMCG - get_page_memcg_info(page, &memcg_info); + get_page_memcg_info(page, &memcg_info, + state->memcg_filter_enabled); + if (state->memcg_filter_enabled) + if (!memcg_info.path || + strcmp(memcg_info.path, state->memcg_path) !=3D 0) + goto ext_put_continue; #endif =20 /* Record the next PFN to read in the file offset */ @@ -907,9 +931,12 @@ read_page_owner(struct file *file, char __user *buf, s= ize_t count, loff_t *ppos) =20 page_owner_tmp =3D *page_owner; page_ext_put(page_ext); - return print_page_owner(buf, count, pfn, page, + ret =3D print_page_owner(buf, count, pfn, page, &page_owner_tmp, handle, state, &memcg_info); + kfree(memcg_info.path); + return ret; ext_put_continue: + kfree(memcg_info.path); page_ext_put(page_ext); cond_resched(); } @@ -1016,7 +1043,10 @@ static int page_owner_open(struct inode *inode, stru= ct file *file) =20 static int page_owner_release(struct inode *inode, struct file *file) { - kfree(file->private_data); + struct page_owner_filter_state *state =3D file->private_data; + + kfree(state->memcg_path); + kfree(state); return 0; } =20 @@ -1096,9 +1126,11 @@ static ssize_t page_owner_write(struct file *file, nodemask_t new_nid_filter; bool new_nid_filter_enabled; bool new_proc_filter_enabled; + bool new_memcg_filter_enabled; pid_t new_pid_list[MAX_FILTER_PIDS]; pid_t new_tgid_list[MAX_FILTER_TGIDS]; char (*new_comm_list)[TASK_COMM_LEN] =3D NULL; + char *new_memcg_path; int new_pid_count =3D 0; int new_tgid_count =3D 0; int new_comm_count =3D 0; @@ -1114,16 +1146,24 @@ static ssize_t page_owner_write(struct file *file, if (count > 32 + 6 * MAX_NUMNODES + (PID_MAX_DIGITS + 1) * MAX_FILTER_PIDS + 4 + (PID_MAX_DIGITS + 1) * MAX_FILTER_TGIDS + 5 + - TASK_COMM_LEN * MAX_FILTER_COMMS + 5) + TASK_COMM_LEN * MAX_FILTER_COMMS + 5 + + PATH_MAX + 6) return -EINVAL; =20 new_comm_list =3D kmalloc_array(MAX_FILTER_COMMS, TASK_COMM_LEN, GFP_KERN= EL); if (!new_comm_list) return -ENOMEM; =20 + new_memcg_path =3D kmalloc(PATH_MAX, GFP_KERNEL); + if (!new_memcg_path) { + kfree(new_comm_list); + return -ENOMEM; + } + kbuf =3D memdup_user_nul(buf, count); if (IS_ERR(kbuf)) { kfree(new_comm_list); + kfree(new_memcg_path); return PTR_ERR(kbuf); } =20 @@ -1146,6 +1186,9 @@ static ssize_t page_owner_write(struct file *file, state->comm_count * TASK_COMM_LEN); new_comm_count =3D state->comm_count; } + new_memcg_filter_enabled =3D state->memcg_filter_enabled; + if (state->memcg_filter_enabled && state->memcg_path) + strscpy(new_memcg_path, state->memcg_path, PATH_MAX); =20 while ((token =3D strsep(&kbuf, " \t\n")) !=3D NULL) { if (*token =3D=3D '\0') @@ -1189,12 +1232,33 @@ static ssize_t page_owner_write(struct file *file, ret =3D parse_comm_list(token + 5, new_comm_list, &new_comm_count); if (ret < 0) goto out_free; + } else if (!strncmp(token, "memcg=3D", 6)) { + if (token[6] =3D=3D '\0') { + ret =3D -EINVAL; + goto out_free; + } + ret =3D strscpy(new_memcg_path, token + 6, PATH_MAX); + if (ret < 0) + goto out_free; + new_memcg_filter_enabled =3D true; } else { ret =3D -EINVAL; goto out_free; } } =20 + if (new_memcg_filter_enabled) { + if (!state->memcg_path) { + state->memcg_path =3D kzalloc(PATH_MAX, GFP_KERNEL); + if (!state->memcg_path) { + ret =3D -ENOMEM; + goto out_free; + } + } else { + memset(state->memcg_path, 0, PATH_MAX); + } + } + /* Commit all filter changes */ state->print_mode =3D new_print_mode; state->nid_filter =3D new_nid_filter; @@ -1221,11 +1285,16 @@ static ssize_t page_owner_write(struct file *file, new_comm_count * TASK_COMM_LEN); state->comm_count =3D new_comm_count; } + if (new_memcg_filter_enabled) { + strscpy(state->memcg_path, new_memcg_path, PATH_MAX); + state->memcg_filter_enabled =3D true; + } =20 ret =3D count; =20 out_free: kfree(new_comm_list); + kfree(new_memcg_path); kfree(orig); return ret; } --=20 2.20.1 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-m127102.qiye.163.com (mail-m127102.qiye.163.com [115.236.127.102]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8AF8841C6A; Fri, 28 Aug 2026 06:43:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.236.127.102 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899414; cv=none; b=firQQKUZU9RtKGd9QNZHeuWyjKqUyvMhJkTjknjMD3woHc2x5UoUZlipQLJoVePCkloHIB1V774KVyH3FevP7xmqSPDyq6vrFF/1d6O0rIB8+cjbV77fiRa8Gk3wngpg+OD0y23/in/PNl7QhlZEdXbNqNjlOmLzndFV3T/X9fc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787899414; c=relaxed/simple; bh=UPYRdrqZC5mlJ1hnd5tW0tIDT8J030CHtWUSM3IIiTo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=jHPxaNQhV7JEUPRB31JfS5USDYmKvzPUZktiKsjd0cgyVahOsDJPk5glarP7sOHWYDDf/qQzugkTvvrD8QJ2bn9SwFUhWDhgGjOdut42UNcfNTAlnTfoAoA8FukIQ1e8+ZiHoDaPJOUO58/Dtd8eaTCNaufZ/YLGIyeOcsjyddw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn; spf=pass smtp.mailfrom=easystack.cn; arc=none smtp.client-ip=115.236.127.102 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=easystack.cn Received: from localhost.localdomain (unknown [218.94.118.90]) by smtp.qiye.163.com (Hmail) with ESMTP id 1e6a20db2; Fri, 28 Aug 2026 11:13:59 +0800 (GMT+08:00) From: Zhen Ni To: Andrew Morton Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jonathan Corbet , Shuah Khan , Randy Dunlap , Brendan Jackman , Johannes Weiner , Zi Yan , linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Zhen Ni Subject: [PATCH 6/8] tools/mm: Add PID/TGID/COMM filtering support to page_owner_filter Date: Fri, 28 Aug 2026 11:13:37 +0800 Message-Id: <20260828031339.1270699-7-zhen.ni@easystack.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20260828031339.1270699-1-zhen.ni@easystack.cn> References: <20260828031339.1270699-1-zhen.ni@easystack.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa0465c26f60229kunma81ef96712a352 X-HM-MType: 1 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFJQjdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVkZSxlPVkMaTxhITBkeShkZTVYVFA kWGhdVGRETFhoSFyQUDg9ZV1kYEgtZQVlJSkNVQk9VSkpDVUJLWVdZFhoPEhUdFFlBWU9LSFVKS0 lPT09IVUpLS1VKQktLWQY+ Content-Type: text/plain; charset="utf-8" Add command-line options for filtering by process ID (PID), thread group ID (TGID), and process name (COMM) to the page_owner_filter userspace tool. New options: -p, --pid PID_LIST : Process IDs (comma-separated, max 16) -t, --tgid TGID_LIST : Thread Group IDs (comma-separated, max 16) -c, --comm COMM_LIST : Process names (comma-separated, max 8) Supports wildcards: * ? [a-z] Usage examples: page_owner_filter -p 1234,5678 page_owner_filter -c "python*" page_owner_filter -n 0 -c kworker* -o output.txt Signed-off-by: Zhen Ni --- tools/mm/page_owner_filter.c | 168 ++++++++++++++++++++++++++++++----- 1 file changed, 147 insertions(+), 21 deletions(-) diff --git a/tools/mm/page_owner_filter.c b/tools/mm/page_owner_filter.c index 1d1f0a38678a..9256ffad4939 100644 --- a/tools/mm/page_owner_filter.c +++ b/tools/mm/page_owner_filter.c @@ -21,22 +21,24 @@ #include =20 #define MAX_CMD_LEN 512 +#define TASK_COMM_LEN 16 =20 static void usage(const char *prog) { fprintf(stderr, "Usage: %s [OPTIONS]\n", prog); fprintf(stderr, "\nOptions:\n"); - fprintf(stderr, " -m, --mode MODE : print_mode (stack, handle, or s= tack_handle)\n"); - fprintf(stderr, " -n, --nid NID_LIST : NUMA node IDs (comma-separated = or ranges)\n"); - fprintf(stderr, " -o, --output FILE : output file (default: stdout)\n= "); - fprintf(stderr, " -h, --help : show this help message\n"); + fprintf(stderr, " -m, --mode MODE : print_mode (stack, handle, sta= ck_handle)\n"); + fprintf(stderr, " -n, --nid NID_LIST : NUMA nodes (comma-separated or= ranges)\n"); + fprintf(stderr, " -p, --pid PID_LIST : Process IDs (comma-separated, = max 16)\n"); + fprintf(stderr, " -t, --tgid TGID_LIST : Thread Group IDs (comma-separa= ted, max 16)\n"); + fprintf(stderr, " -c, --comm COMM_LIST : Process names (comma-separated= , max 8)\n"); + fprintf(stderr, " Supports wildcards: * ? [a-z]\= n"); + fprintf(stderr, " -o, --output FILE : output file (default: stdout)\= n"); + fprintf(stderr, " -h, --help : show this help message\n"); fprintf(stderr, "\nExamples:\n"); - fprintf(stderr, " %s -m stack\n", prog); - fprintf(stderr, " %s -m handle\n", prog); - fprintf(stderr, " %s -m stack_handle\n", prog); - fprintf(stderr, " %s -m stack -o output.txt\n", prog); - fprintf(stderr, " %s -n 0,1,2\n", prog); - fprintf(stderr, " %s -m stack -n 0\n", prog); + fprintf(stderr, " %s -m handle -o output.txt\n", prog); + fprintf(stderr, " %s -n 0,1 -c bash\n", prog); + fprintf(stderr, " %s -c \"python*\" -t 1\n", prog); } =20 static int validate_mode(const char *mode) @@ -132,6 +134,93 @@ static int validate_nid_list(const char *nid_list) return 0; } =20 +static int validate_pid_list(const char *pid_list) +{ + const char *p; + int count =3D 0; + + if (!pid_list || strlen(pid_list) =3D=3D 0) + return -1; + + for (p =3D pid_list; *p; p++) { + if (*p =3D=3D ',') { + count++; + continue; + } + if (!isdigit((unsigned char)*p)) { + fprintf(stderr, + "Error: Invalid character '%c' in pid_list (only digits allowed)\n", + *p); + return -1; + } + } + + if (++count > 16) { + fprintf(stderr, "Error: Too many PIDs (max 16)\n"); + return -1; + } + + return 0; +} + +static int validate_tgid_list(const char *tgid_list) +{ + return validate_pid_list(tgid_list); +} + +static int validate_comm_list(const char *comm_list) +{ + const char *p; + const char *comm_start; + int count =3D 0; + int comm_len =3D 0; + + if (!comm_list || strlen(comm_list) =3D=3D 0) + return -1; + + comm_start =3D comm_list; + for (p =3D comm_list; *p; p++) { + if (*p =3D=3D ',') { + /* Check COMM length before separator */ + if (comm_len =3D=3D 0) { + fprintf(stderr, "Error: Empty COMM in list\n"); + return -1; + } + if (comm_len >=3D TASK_COMM_LEN) { + fprintf(stderr, + "Error: COMM too long (max %d chars)\n", + TASK_COMM_LEN - 1); + fprintf(stderr, " Near: %.15s...\n", comm_start); + return -1; + } + count++; + comm_len =3D 0; + comm_start =3D p + 1; + continue; + } + comm_len++; + } + + /* Check last COMM */ + if (comm_len =3D=3D 0) { + fprintf(stderr, "Error: Empty COMM at end of list\n"); + return -1; + } + if (comm_len >=3D TASK_COMM_LEN) { + fprintf(stderr, "Error: COMM too long (max %d chars)\n", + TASK_COMM_LEN - 1); + fprintf(stderr, " Near: %.15s...\n", comm_start); + return -1; + } + + if (++count > 8) { + fprintf(stderr, "Error: Too many COMMs (max 8)\n"); + return -1; + } + + return 0; +} + int main(int argc, char *argv[]) { const char *output_file =3D NULL; @@ -148,6 +237,9 @@ int main(int argc, char *argv[]) static struct option long_options[] =3D { {"mode", required_argument, 0, 'm'}, {"nid", required_argument, 0, 'n'}, + {"pid", required_argument, 0, 'p'}, + {"tgid", required_argument, 0, 't'}, + {"comm", required_argument, 0, 'c'}, {"output", required_argument, 0, 'o'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} @@ -174,7 +266,7 @@ int main(int argc, char *argv[]) return 1; } =20 - while ((opt =3D getopt_long(argc, argv, "m:n:o:h", long_options, NULL)) != =3D -1) { + while ((opt =3D getopt_long(argc, argv, "m:n:p:t:c:o:h", long_options, NU= LL)) !=3D -1) { int len; =20 switch (opt) { @@ -206,6 +298,48 @@ int main(int argc, char *argv[]) cmd_len +=3D len; break; } + case 'p': { + const char *pid_list =3D optarg; + + if (validate_pid_list(pid_list) < 0) + return 1; + len =3D snprintf(filter_cmd + cmd_len, MAX_CMD_LEN - cmd_len, + "%spid=3D%s", cmd_len > 0 ? " " : "", pid_list); + if (len < 0 || cmd_len + len >=3D MAX_CMD_LEN) { + fprintf(stderr, "Error: Command too long\n"); + return 1; + } + cmd_len +=3D len; + break; + } + case 't': { + const char *tgid_list =3D optarg; + + if (validate_tgid_list(tgid_list) < 0) + return 1; + len =3D snprintf(filter_cmd + cmd_len, MAX_CMD_LEN - cmd_len, + "%stgid=3D%s", cmd_len > 0 ? " " : "", tgid_list); + if (len < 0 || cmd_len + len >=3D MAX_CMD_LEN) { + fprintf(stderr, "Error: Command too long\n"); + return 1; + } + cmd_len +=3D len; + break; + } + case 'c': { + const char *comm_list =3D optarg; + + if (validate_comm_list(comm_list) < 0) + return 1; + len =3D snprintf(filter_cmd + cmd_len, MAX_CMD_LEN - cmd_len, + "%scomm=3D%s", cmd_len > 0 ? " " : "", comm_list); + if (len < 0 || cmd_len + len >=3D MAX_CMD_LEN) { + fprintf(stderr, "Error: Command too long\n"); + return 1; + } + cmd_len +=3D len; + break; + } case 'o': output_file =3D optarg; break; @@ -220,7 +354,7 @@ int main(int argc, char *argv[]) =20 /* At least one filter must be specified */ if (cmd_len =3D=3D 0) { - fprintf(stderr, "Error: At least one filter (-m or -n) must be specified= \n\n"); + fprintf(stderr, "Error: At least one filter must be specified\n\n"); usage(argv[0]); return 1; } @@ -255,15 +389,7 @@ int main(int argc, char *argv[]) ret =3D write(fd, filter_cmd, strlen(filter_cmd)); =20 if (ret < 0) { - if (errno =3D=3D EINVAL) { - fprintf(stderr, "Error: Kernel rejected the filter command.\n"); - fprintf(stderr, "Possible causes:\n"); - fprintf(stderr, " - Kernel does not support per-fd filtering\n"); - fprintf(stderr, " - NUMA node has no memory\n"); - fprintf(stderr, " - Unknown reason\n"); - } else { - perror("write filter command"); - } + perror("write filter command"); goto out; } =20 --=20 2.20.1 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-m12739.qiye.163.com (mail-m12739.qiye.163.com [115.236.127.39]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7C1DD39BFF2; Fri, 28 Aug 2026 03:19:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.236.127.39 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887165; cv=none; b=BrdzcvcTqq2OEJha1kyY573lxoSxe0z6QNHIeu67s8n+MmbD2vbDkSspGzO7eW+MxqueNgOpIGrL5EWvNGgXXuRVIb+jXhTQgrabGQWQgSSBpdCo6LBAN6ezgUign+CpRTCEe4k99rfZiUOMchkdCBnBUYyszQGwiP8+izQNgDw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787887165; c=relaxed/simple; bh=3/vUaMKK3pIlYXKxw06c1SsYKUK53h42nctrWLZR4kk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kpwnkytCSW8koXPBJQ6OsV9GDMcLWcfj0lvFcRzS88pu66p34mtX75ck7AATX9EHveyBdS1kLU0BH4sBpw3wJuVOEFDs+LDZ8d0ebqWfS7DnYrrnWaW1CIynWVTEXYMMGzZNYRk70YKgJc9DdDwNnFhTaGUXTN98W1ceDsnroXk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn; spf=pass smtp.mailfrom=easystack.cn; arc=none smtp.client-ip=115.236.127.39 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=easystack.cn Received: from localhost.localdomain (unknown [218.94.118.90]) by smtp.qiye.163.com (Hmail) with ESMTP id 1e6a20db8; Fri, 28 Aug 2026 11:14:00 +0800 (GMT+08:00) From: Zhen Ni To: Andrew Morton Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jonathan Corbet , Shuah Khan , Randy Dunlap , Brendan Jackman , Johannes Weiner , Zi Yan , linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Zhen Ni Subject: [PATCH 7/8] tools/mm: Add memory cgroup filtering support to page_owner_filter Date: Fri, 28 Aug 2026 11:13:38 +0800 Message-Id: <20260828031339.1270699-8-zhen.ni@easystack.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20260828031339.1270699-1-zhen.ni@easystack.cn> References: <20260828031339.1270699-1-zhen.ni@easystack.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa0465c2c190229kunma81ef96712a35a X-HM-MType: 1 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFJQjdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVlCGR8eVkxNHh8YHR5IQkxKGlYVFA kWGhdVGRETFhoSFyQUDg9ZV1kYEgtZQVlJSkNVQk9VSkpDVUJLWVdZFhoPEhUdFFlBWU9LSFVKS0 lPT09IVUpLS1VKQktLWQY+ Content-Type: text/plain; charset="utf-8" Add filtering capability for page_owner to allow filtering by memory cgroup path. Filter page_owner output by cgroup path: ./page_owner_filter -g / ./page_owner_filter -g /user.slice ./page_owner_filter -g /user.slice -c systemd Signed-off-by: Zhen Ni --- tools/mm/page_owner_filter.c | 56 ++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/tools/mm/page_owner_filter.c b/tools/mm/page_owner_filter.c index 9256ffad4939..1ffbe4387854 100644 --- a/tools/mm/page_owner_filter.c +++ b/tools/mm/page_owner_filter.c @@ -20,7 +20,7 @@ #include #include =20 -#define MAX_CMD_LEN 512 +#define MAX_CMD_LEN 2048 #define TASK_COMM_LEN 16 =20 static void usage(const char *prog) @@ -33,12 +33,13 @@ static void usage(const char *prog) fprintf(stderr, " -t, --tgid TGID_LIST : Thread Group IDs (comma-separa= ted, max 16)\n"); fprintf(stderr, " -c, --comm COMM_LIST : Process names (comma-separated= , max 8)\n"); fprintf(stderr, " Supports wildcards: * ? [a-z]\= n"); + fprintf(stderr, " -g, --cgroup PATH : Memory cgroup path\n"); fprintf(stderr, " -o, --output FILE : output file (default: stdout)\= n"); fprintf(stderr, " -h, --help : show this help message\n"); fprintf(stderr, "\nExamples:\n"); fprintf(stderr, " %s -m handle -o output.txt\n", prog); fprintf(stderr, " %s -n 0,1 -c bash\n", prog); - fprintf(stderr, " %s -c \"python*\" -t 1\n", prog); + fprintf(stderr, " %s -c \"python*\" -g user.slice\n", prog); } =20 static int validate_mode(const char *mode) @@ -221,6 +222,38 @@ static int validate_comm_list(const char *comm_list) return 0; } =20 +static int validate_cgroup_path(const char *path) +{ + char cgroup_path[512]; + const char *input_path =3D path; + int is_cgroup_v2 =3D 0; + + if (!path || strlen(path) =3D=3D 0) + return -1; + + if (path[0] =3D=3D '/') + input_path++; + + /* Check if v1 memory controller exists */ + if (access("/sys/fs/cgroup/memory", F_OK) !=3D 0) + is_cgroup_v2 =3D 1; + + if (is_cgroup_v2) + snprintf(cgroup_path, sizeof(cgroup_path), + "/sys/fs/cgroup/%s/memory.stat", input_path); + else + snprintf(cgroup_path, sizeof(cgroup_path), + "/sys/fs/cgroup/memory/%s/memory.stat", input_path); + + if (access(cgroup_path, F_OK) !=3D 0) { + fprintf(stderr, "Error: Cgroup path '%s': not found or no memory control= ler\n", + path); + return -1; + } + + return 0; +} + int main(int argc, char *argv[]) { const char *output_file =3D NULL; @@ -240,6 +273,7 @@ int main(int argc, char *argv[]) {"pid", required_argument, 0, 'p'}, {"tgid", required_argument, 0, 't'}, {"comm", required_argument, 0, 'c'}, + {"cgroup", required_argument, 0, 'g'}, {"output", required_argument, 0, 'o'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} @@ -266,7 +300,7 @@ int main(int argc, char *argv[]) return 1; } =20 - while ((opt =3D getopt_long(argc, argv, "m:n:p:t:c:o:h", long_options, NU= LL)) !=3D -1) { + while ((opt =3D getopt_long(argc, argv, "m:n:p:t:c:g:o:h", long_options, = NULL)) !=3D -1) { int len; =20 switch (opt) { @@ -340,6 +374,22 @@ int main(int argc, char *argv[]) cmd_len +=3D len; break; } + case 'g': { + const char *cgroup_path =3D optarg; + + if (validate_cgroup_path(cgroup_path) < 0) + return 1; + const char *path =3D (cgroup_path[0] =3D=3D '/') ? cgroup_path + 1 : cg= roup_path; + + len =3D snprintf(filter_cmd + cmd_len, MAX_CMD_LEN - cmd_len, + "%smemcg=3D/%s", cmd_len > 0 ? " " : "", path); + if (len < 0 || cmd_len + len >=3D MAX_CMD_LEN) { + fprintf(stderr, "Error: Command too long\n"); + return 1; + } + cmd_len +=3D len; + break; + } case 'o': output_file =3D optarg; break; --=20 2.20.1 From nobody Sat Sep 26 23:51:54 2026 Received: from mail-m15571.qiye.163.com (mail-m15571.qiye.163.com [101.71.155.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE5DD21767D; Fri, 28 Aug 2026 03:49:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=101.71.155.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787888977; cv=none; b=cX3h9bOF6jBkC9Mngsc0tnbGUEAWbXLY2Jnf9yap/8pxs3X9J2nom0lbIWQGhBbb2ZmbpVgn5dXu1kso4yj0vSTQBEuclD3JRbCQc0UkDAtpNNtWU94kqnkXMK3NNHDzdjZs52j0DDiXyOoNXOzKG9UcolgXwsJqds90qVCW+9U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787888977; c=relaxed/simple; bh=0RDdhaNY7DbsgRfHuXjuEykk+p8NlJvJuNNFqZdbZSc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=lGkvxx9RwZ9ORrjbvSZoPm6GzwRVjJZdkGlTzCywgsoWMTOdZiXAeMpQmUtGbNp0a+N+BAmziK0raMnT9dLYKzj9KBmZX2JEkm3ZFLbzsBTxQaIYj4bEXa4to5G3q8KO5IYoot7+r+WzRdefKR7DgY2Cw1UFMocuCvB8qTCZrH0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn; spf=pass smtp.mailfrom=easystack.cn; arc=none smtp.client-ip=101.71.155.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=easystack.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=easystack.cn Received: from localhost.localdomain (unknown [218.94.118.90]) by smtp.qiye.163.com (Hmail) with ESMTP id 1e6a20dbd; Fri, 28 Aug 2026 11:14:02 +0800 (GMT+08:00) From: Zhen Ni To: Andrew Morton Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jonathan Corbet , Shuah Khan , Randy Dunlap , Brendan Jackman , Johannes Weiner , Zi Yan , linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Zhen Ni Subject: [PATCH 8/8] Documentation: page_owner: Document PID/TGID/COMM and cgroup filters Date: Fri, 28 Aug 2026 11:13:39 +0800 Message-Id: <20260828031339.1270699-9-zhen.ni@easystack.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20260828031339.1270699-1-zhen.ni@easystack.cn> References: <20260828031339.1270699-1-zhen.ni@easystack.cn> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-HM-Tid: 0aa0465c31140229kunma81ef96712a363 X-HM-MType: 1 X-HM-Spam-Status: e1kfGhgUHx5ZQUpXWQgPGg8OCBgUHx5ZQUlOS1dZFg8aDwILHllBWSg2Ly tZV1koWUFJQjdXWRgWCB1ZQUpXWS1ZQUlXWQ8JGhUIEh9ZQVkaTEpLVkpMS0pKT0tNTkJNSFYVFA kWGhdVGRETFhoSFyQUDg9ZV1kYEgtZQVlJSkNVQk9VSkpDVUJLWVdZFhoPEhUdFFlBWU9LSFVKS0 lPT09IVUpLS1VKQktLWQY+ Content-Type: text/plain; charset="utf-8" Update page_owner.rst to document process and cgroup filtering support in page_owner_filter tool. Add usage examples for PID, TGID, COMM (with wildcard support), and cgroup filters along with their respective limits. Signed-off-by: Zhen Ni --- Documentation/mm/page_owner.rst | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Documentation/mm/page_owner.rst b/Documentation/mm/page_owner.= rst index a6bd3fe6423a..c8a7e6c242c5 100644 --- a/Documentation/mm/page_owner.rst +++ b/Documentation/mm/page_owner.rst @@ -283,7 +283,7 @@ page_owner supports filtering output at the kernel leve= l before reading, which reduces the amount of data that needs to be processed in userspace. =20 The page_owner_filter tool provides a convenient interface for this filter= ing -capability. It supports two types of filters: +capability. It supports the following types of filters: =20 1. **print_mode filter**: Control what information is printed for each page - ``stack``: Print full stack traces (default, compatible with existing u= sage) @@ -300,6 +300,16 @@ capability. It supports two types of filters: - Ranges: ``-n 0-3`` - Mixed format: ``-n 0,2-3,5`` =20 +3. **Process filters**: Filter pages by process identifiers + - Filter by process ID: ``-p PID_LIST`` (comma-separated, max 16) + - Filter by thread group ID: ``-t TGID_LIST`` (comma-separated, max 16) + - Filter by task command name: ``-c COMM_LIST`` (comma-separated, max 8) + - Name matching supports wildcards: ``*``, ``?``, ``[a-z]`` + +4. **Cgroup (memcg) filter**: Filter pages by memory cgroup + - Filter by cgroup path: ``-g CGROUP`` + - Useful for containerized environments and multi-tenant systems + Usage examples:: =20 # Filter by print mode @@ -310,9 +320,19 @@ Usage examples:: ./page_owner_filter -n 0 ./page_owner_filter -n 0-3 =20 + # Filter by process + ./page_owner_filter -p 1234 + ./page_owner_filter -t 1,2,3 + ./page_owner_filter -c python* + + # Filter by cgroup + ./page_owner_filter -g system.slice + ./page_owner_filter -g kubepods/besteffort/pod123 + # Combined filters ./page_owner_filter -m stack -n 0,1,2 ./page_owner_filter -m handle -n 0,2-3 + ./page_owner_filter -g user.slice -c bash -n 0 =20 # Save to file ./page_owner_filter -m handle -o filtered_output.txt @@ -323,6 +343,9 @@ reduce output size by ~66% (84MB vs 244MB) and improve = read performance by ~4.4x compared to full stack output. =20 The NUMA node filter is useful for NUMA-aware memory allocation analysis a= nd debugging. +Process filters help isolate memory allocations for specific processes or = tasks. +The cgroup filter is essential for containerized environments where you ne= ed to +analyze memory usage per container or service. =20 Behind the scenes, page_owner_filter opens /sys/kernel/debug/page_owner and writes filter commands before reading the filtered output. The filtering u= ses --=20 2.20.1