From mboxrd@z Thu Jan 1 00:00:00 1970 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]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 15B93C9832A for ; Tue, 29 Sep 2026 08:20:54 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 13FFF6B00B1; Tue, 29 Sep 2026 04:20:53 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 117616B00B2; Tue, 29 Sep 2026 04:20:53 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 054296B00B3; Tue, 29 Sep 2026 04:20:53 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id CEAFA6B00B1 for ; Tue, 29 Sep 2026 04:20:52 -0400 (EDT) Received: from smtpin06.hostedemail.com (lb01a-stub [10.200.18.249]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 6546B1A0435 for ; Tue, 29 Sep 2026 08:20:52 +0000 (UTC) X-FDA: 85266103944.06.5F3FCE0 Received: from mta0.migadu.com (out-208.mta0.migadu.com [91.218.175.208]) by imf20.hostedemail.com (Postfix) with ESMTP id 7AD351C0002 for ; Tue, 29 Sep 2026 08:20:50 +0000 (UTC) Authentication-Results: imf20.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=glyp3+EF; dmarc=pass (policy=none) header.from=linux.dev; spf=pass (imf20.hostedemail.com: domain of hao.ge@linux.dev designates 91.218.175.208 as permitted sender) smtp.mailfrom=hao.ge@linux.dev ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1790670050; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=V29ad4x/WAIi1Mgv7OdMw0FrCocgUTy3KoT/uQuUj6U=; b=5N9OoRPSgTUKljyHQNbGCwsaISUhRCcelu2HnqRsYI621XiHZs3wLcGmyrmXN0AOeBiQMd WPHeQRjLIX8EYdIDvC5TbDBk6iMGIL2qtG+FD/PWEF987hiBpAt49OXD1BQGYJBzvmwUXB 9jZulEqU6lfPO1TscIT4pwe71aq6Ai4= ARC-Authentication-Results: i=1; imf20.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=glyp3+EF; dmarc=pass (policy=none) header.from=linux.dev; spf=pass (imf20.hostedemail.com: domain of hao.ge@linux.dev designates 91.218.175.208 as permitted sender) smtp.mailfrom=hao.ge@linux.dev ARC-Seal: i=1; a=rsa-sha256; d=hostedemail.com; s=arc-20220608; cv=none; t=1790670050; b=lPB7Bd6RmjYe0m7rQe7a6DjvXUpCA9hBC2YnE/LX5TAWkRftkUK122lKEyRXLKAnS9HZfb qNx91kfIN54x/oTwG56ECAwzsiI+qxHGOfK30zN223IzVHbsU3VrbLpnwcnJXBRRf/Qirj KNER9NMSuSafOp9rTRdwWTjPCPhOTww= X-Envelope-To: linux-mm@kvack.org DKIM-Signature: a=rsa-sha256; bh=fpRNa2I+DmBqaF8ZhHQ4c09SGKG5OLX8LlAhVqaV/kE=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1790670049; v=1; x=1791274849; b=glyp3+EFt2xA249QLipx0o4Z7hV5tkYJbIBdAt3wUA7AmaMta84VUzxn3uWJQmcuNqyYB5TP Sp2N8yIBjLj4t8glm3zfxX6R3890/CfZzvCRX7o+AMe7NFp9tf+PP+iHmuwV8akdU0mRqeO9idp uPgJTUrEupOLubAdSgOYaN/I= X-Envelope-To: linux-mm@kvack.org Received: by smtp.migadu.com with ESMTPS id 9af9c7f7ec312c14; Tue, 29 Sep 2026 08:20:49 +0000 X-Mizu-Trace-ID: 9af9c7f7ec312c14 X-Migadu-Flow: FLOW_OUT From: Hao Ge To: Suren Baghdasaryan , =Kent Overstreet , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , Aaron Tomlin , Andrew Morton , Alexander Potapenko , Marco Elver , Dmitry Vyukov , Vlastimil Babka , Michal Hocko , Brendan Jackman , Johannes Weiner , Zi Yan , Uladzislau Rezki Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, kasan-dev@googlegroups.com, Hao Ge , Sashiko , stable@vger.kernel.org Subject: [PATCH v11 7/7] alloc_tag: fix the /proc/allocinfo lifecycle Date: Tue, 29 Sep 2026 16:20:14 +0800 Message-Id: <20260929082014.160587-8-hao.ge@linux.dev> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260929082014.160587-1-hao.ge@linux.dev> References: <20260929082014.160587-1-hao.ge@linux.dev> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Stat-Signature: cknajdsm9e96bp9o6zh8emmuf48yhqe8 X-Rspam-User: X-Rspamd-Server: rspam10 X-Rspamd-Queue-Id: 7AD351C0002 X-HE-Tag: 1790670050-784003 X-HE-Meta: U2FsdGVkX190MYibaXtVLO1HfRvAzjWKvFh1h1vknHND8U22DQiNKQGtjr9d2MQi1vHqfBBqH8pmCz5zBGyuVUUz5vG7i7/rmitF4eYuMaVV7n4kYvxTJ9N3Yzj2Z2qEFIajY+QirPlSUWvLfKiQnXsBGrGHjKExVUZ9OQxLxerXpUaeHy7T10PHo4MEWesdXkTEJwWvUquPOvXXdVrv6ui/yATq5DonLpzP6otk3NzuCGKRBMTpGC/HwLyo13PBuwkP9T5roBCmsVeZwLtRVXbd/2h6IvNaPb7Q3attIPfgI3B+I+UZLoKgnGtVdwJtJMd3wiZaR73nhbge000zFpTcnRqosdtX2pI48pTThCKJt+1t88i72ReEnLBQbZLzDt2wYCdXI0XhqgA9g6ivVdJS3noehZi9Z6NvfqFsCkBzELmxtwal+YXNjF9e0yKxh9h7Pr42sMhHeiWECQyatHVwcbbzKlcIXkY9Tm1YGX609Z53alro5UCaUbNH+WRd/h3xuPXouSTHpsnbzcymqBXf4aBnIb+qnxp4DhWuYyYOsdctIlDC4BW3fcM6KZf6ObvbMANxovD21l7iA9aN0Th4qd3tEyMgGRbNQn48LoN0jvNX0Pansecv/M03mcW05f4IA8hbWhYbJtqHuF/TcUkHrg48jPJwwww9CF1guCVywN/q3MuNevSjXXMWvgsRn2udDSbxk0dYmSEYONazCh9hM66jz9mrAVwjLR1Rw8nVLuBqZbfbw66y0IllWnV7deiNQV7Xwn8MZwBpvvC6CX2kPuq2bEyBgdxg5+CCHW8H3S/YkfUhI8qgImc+HFhjIotVOJy0gvltTIeC9bHclg//GvnBNQsXnVN/YXtj9+ClD56aw2JMUGLZIeqeiMjslCQebDV+LBtypf9La13zKpxeB39mjMU/RvFXPioV+NXAzBbJ2nDfk5mSrKQZDpT6VzYIH/mYxe7OhfWcj7P Y/3hP2sp myKZkcn0Rl9NA8SGby8VpHV+tI5KY3jXhlx/NxIor+xC2lML/3JBq8ErcwsU5Ko3zJvdo1prqtE+XnmLIRuBP3z/j2XuHhPD3OaQqbvUfI1BEYoUvuHa2Ic+CCgIYGKJEF2bKKB5PR03LPlZ0PZmw1fOotsxXo8jFdlfRkiR1Q8LYqF18kyY6F92QabFEj4Vzysz/wEnOKj4c0NRApChO2w9HxiponGH8Ae81Q8tACUzY+V5oLDEJsgxlez28t2XzIvdj3QsiEc11S2nEGtsU2BMWLFhhwdvSSZwIFin1wRauOPY= Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: shutdown_mem_profiling() calls remove_proc_entry() from reserve_module_tags(), which runs under mod_lock held for write. remove_proc_entry() waits for readers, and a reader takes mod_lock for read in allocinfo_start(): CPU0 (insmod) CPU1 (read /proc/allocinfo) ---------------- ---------------------------- reserve_module_tags() down_write(&mod_lock) [held] use_pde() [in_use++] allocinfo_start() down_read(&mod_lock) <- blocks shutdown_mem_profiling() remove_proc_entry() wait for in_use == 0 <- blocks Move remove_proc_entry() to a workqueue. The deferred removal also affects alloc_tag_init(). The file is created before the type, so on a failure it is still there with alloc_tag_cttype NULL or an error pointer, and a reader panics in allocinfo_start(). Create the file at the end of alloc_tag_init() instead, a failed init leaves nothing behind. If proc_create() fails, the codetag type and the module tags memory leak. Call codetag_unregister_type() and free the memory. alloc_tag_cttype can now be freed at runtime. alloc_tag_top_users() reads it from __show_mem() without locks, read the pointer under rcu_read_lock() and take mod_lock before dropping the RCU lock, the type stays alive until then. The only caller never sleeps, drop the can_sleep argument. Reported-by: Sashiko Fixes: 4835f747d3ed ("alloc_tag: support for page allocation tag compression") Cc: stable@vger.kernel.org Signed-off-by: Hao Ge --- include/linux/alloc_tag.h | 2 +- include/linux/codetag.h | 2 ++ lib/codetag.c | 26 ++++++++++++++++++++ mm/alloc_tag.c | 52 +++++++++++++++++++++++++++------------ mm/show_mem.c | 2 +- 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/include/linux/alloc_tag.h b/include/linux/alloc_tag.h index 7f2d80a59792..852dc10c00ee 100644 --- a/include/linux/alloc_tag.h +++ b/include/linux/alloc_tag.h @@ -81,7 +81,7 @@ struct codetag_bytes { s64 bytes; }; -size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep); +size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count); static inline struct alloc_tag *ct_to_alloc_tag(struct codetag *ct) { diff --git a/include/linux/codetag.h b/include/linux/codetag.h index a25a085c2df1..0c4e0337b474 100644 --- a/include/linux/codetag.h +++ b/include/linux/codetag.h @@ -87,6 +87,8 @@ void codetag_to_text(struct seq_buf *out, struct codetag *ct); struct codetag_type * codetag_register_type(const struct codetag_type_desc *desc); +void codetag_unregister_type(struct codetag_type *cttype); + #if defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES) bool codetag_needs_module_section(struct module *mod, const char *name, diff --git a/lib/codetag.c b/lib/codetag.c index a0b600720afc..46d0904b08b3 100644 --- a/lib/codetag.c +++ b/lib/codetag.c @@ -429,3 +429,29 @@ codetag_register_type(const struct codetag_type_desc *desc) return cttype; } + +/** + * codetag_unregister_type - unregister a codetag type + * @cttype: the codetag type to unregister + * + * Undo codetag_register_type() and free @cttype. The caller must make + * sure no lockless reader still uses @cttype, e.g. clear the pointer + * to it and wait for an RCU grace period first. + */ +void __init codetag_unregister_type(struct codetag_type *cttype) +{ + struct codetag_module *cmod; + unsigned long id, tmp; + + mutex_lock(&codetag_lock); + list_del(&cttype->link); + mutex_unlock(&codetag_lock); + + down_write(&cttype->mod_lock); + idr_for_each_entry_ul(&cttype->mod_idr, cmod, tmp, id) + kfree(cmod); + idr_destroy(&cttype->mod_idr); + up_write(&cttype->mod_lock); + + kfree(cttype); +} diff --git a/mm/alloc_tag.c b/mm/alloc_tag.c index ba8a651769e3..b9af5fe5bba2 100644 --- a/mm/alloc_tag.c +++ b/mm/alloc_tag.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -484,22 +485,28 @@ static const struct proc_ops allocinfo_proc_ops = { #endif }; -size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sleep) +size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count) { struct codetag_iterator iter; + struct codetag_type *cttype; struct codetag *ct; struct codetag_bytes n; unsigned int i, nr = 0; + bool locked; - if (IS_ERR_OR_NULL(alloc_tag_cttype)) + rcu_read_lock(); + cttype = READ_ONCE(alloc_tag_cttype); + if (IS_ERR_OR_NULL(cttype)) { + rcu_read_unlock(); return 0; + } - if (can_sleep) - codetag_lock_module_list(alloc_tag_cttype); - else if (!codetag_trylock_module_list(alloc_tag_cttype)) + locked = codetag_trylock_module_list(cttype); + rcu_read_unlock(); + if (!locked) return 0; - iter = codetag_get_ct_iter(alloc_tag_cttype); + iter = codetag_get_ct_iter(cttype); while ((ct = codetag_next_ct(&iter))) { struct alloc_tag_counters counter = alloc_tag_read(ct_to_alloc_tag(ct)); @@ -520,7 +527,7 @@ size_t alloc_tag_top_users(struct codetag_bytes *tags, size_t count, bool can_sl } } - codetag_unlock_module_list(alloc_tag_cttype); + codetag_unlock_module_list(cttype); return nr; } @@ -591,6 +598,13 @@ void pgalloc_tag_swap(struct folio *new, struct folio *old) put_page_tag_ref(handle_new); } +static void remove_allocinfo_file(struct work_struct *work) +{ + remove_proc_entry(ALLOCINFO_FILE_NAME, NULL); +} + +static DECLARE_WORK(remove_allocinfo_work, remove_allocinfo_file); + static void shutdown_mem_profiling(bool remove_file) { if (mem_alloc_profiling_enabled()) @@ -600,7 +614,7 @@ static void shutdown_mem_profiling(bool remove_file) return; if (remove_file) - remove_proc_entry(ALLOCINFO_FILE_NAME, NULL); + schedule_work(&remove_allocinfo_work); mem_profiling_support = false; } @@ -1351,16 +1365,10 @@ static int __init alloc_tag_init(void) return 0; } - if (!proc_create(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_proc_ops)) { - pr_err("Failed to create %s file\n", ALLOCINFO_FILE_NAME); - shutdown_mem_profiling(false); - return -ENOMEM; - } - res = alloc_mod_tags_mem(); if (res) { pr_err("Failed to reserve address space for module tags, errno = %d\n", res); - shutdown_mem_profiling(true); + shutdown_mem_profiling(false); return res; } @@ -1368,10 +1376,22 @@ static int __init alloc_tag_init(void) if (IS_ERR(alloc_tag_cttype)) { pr_err("Allocation tags registration failed, errno = %pe\n", alloc_tag_cttype); free_mod_tags_mem(); - shutdown_mem_profiling(true); + shutdown_mem_profiling(false); return PTR_ERR(alloc_tag_cttype); } + if (!proc_create(ALLOCINFO_FILE_NAME, 0400, NULL, &allocinfo_proc_ops)) { + struct codetag_type *cttype = alloc_tag_cttype; + + pr_err("Failed to create %s file\n", ALLOCINFO_FILE_NAME); + shutdown_mem_profiling(false); + WRITE_ONCE(alloc_tag_cttype, NULL); + synchronize_rcu(); + codetag_unregister_type(cttype); + free_mod_tags_mem(); + return -ENOMEM; + } + return 0; } module_init(alloc_tag_init); diff --git a/mm/show_mem.c b/mm/show_mem.c index b938cbcd774a..a2e710404a48 100644 --- a/mm/show_mem.c +++ b/mm/show_mem.c @@ -439,7 +439,7 @@ void __show_mem(unsigned int filter, const nodemask_t *nodemask, struct codetag_bytes tags[10]; size_t i, nr; - nr = alloc_tag_top_users(tags, ARRAY_SIZE(tags), false); + nr = alloc_tag_top_users(tags, ARRAY_SIZE(tags)); if (nr) { pr_notice("Memory allocations (profiling is currently turned %s):\n", mem_alloc_profiling_enabled() ? "on" : "off"); -- 2.25.1