[PATCH v2] mm/zswap: publish the initial pool with list_add_rcu()

Longlong Xia posted 1 patch 2 weeks, 3 days ago
mm/zswap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[PATCH v2] mm/zswap: publish the initial pool with list_add_rcu()
Posted by Longlong Xia 2 weeks, 3 days ago
From: Longlong Xia <xialonglong@kylinos.cn>

zswap_setup() publishes the pool on the zswap_pools list with a
plain list_add(), but the list is walked by concurrent RCU readers
holding nothing but rcu_read_lock() through zswap_total_pages(), e.g.
/proc/meminfo and the shrinker count path.

    CPU 0 (writer)                          CPU 1 (reader)
    --------------                          --------------
    zswap_pool_create():
      pool->zs_pool = zs_create_pool(); (1)
    list_add() -> __list_add():
      WRITE_ONCE(zswap_pools.next,
          &pool->list);                (2)   zswap_total_pages():
                                                pool = READ_ONCE(     (a)
                                                    zswap_pools.next);
                                                zs_get_total_pages(   (b)
                                                    pool->zs_pool);

If (2) becomes visible to CPU 1 before (1), CPU 1 finds the pool at
(a) but dereferences a wild pointer at (b). Publish the node with
list_add_rcu().

Fixes: 91cdcd8d624bf ("mm: zswap: optimize zswap pool size tracking")
Cc: stable@vger.kernel.org
Assisted-by: Zcode:GLM-5.3
Reported-by: Sashiko <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260906133601.3563324-1-xialonglong2025%40163.com
Acked-by: Yosry Ahmed <yosry@kernel.org>
Signed-off-by: Longlong Xia <xialonglong@kylinos.cn>
---
Changes in v2:
- Add Reported-by: and Link: trailers pointing at the Sashiko report,
  as suggested by Yosry Ahmed.
- Collect Acked-by from Yosry Ahmed.

No code changes since v1.

 mm/zswap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/zswap.c b/mm/zswap.c
index 37f34e406c8e..cb5a0855fd2a 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -1803,7 +1803,7 @@ static int zswap_setup(void)
 	pool = __zswap_pool_create_fallback();
 	if (pool) {
 		pr_info("loaded using pool %s\n", pool->tfm_name);
-		list_add(&pool->list, &zswap_pools);
+		list_add_rcu(&pool->list, &zswap_pools);
 		zswap_has_pool = true;
 		static_branch_enable(&zswap_ever_enabled);
 	} else {
-- 
2.43.0
Re: [PATCH v2] mm/zswap: publish the initial pool with list_add_rcu()
Posted by Nhat Pham 2 weeks, 3 days ago
On Mon, Sep 7, 2026 at 6:28 PM Longlong Xia <xialonglong2025@163.com> wrote:
>
> From: Longlong Xia <xialonglong@kylinos.cn>
>
> zswap_setup() publishes the pool on the zswap_pools list with a
> plain list_add(), but the list is walked by concurrent RCU readers
> holding nothing but rcu_read_lock() through zswap_total_pages(), e.g.
> /proc/meminfo and the shrinker count path.
>
>     CPU 0 (writer)                          CPU 1 (reader)
>     --------------                          --------------
>     zswap_pool_create():
>       pool->zs_pool = zs_create_pool(); (1)
>     list_add() -> __list_add():
>       WRITE_ONCE(zswap_pools.next,
>           &pool->list);                (2)   zswap_total_pages():
>                                                 pool = READ_ONCE(     (a)
>                                                     zswap_pools.next);
>                                                 zs_get_total_pages(   (b)
>                                                     pool->zs_pool);
>
> If (2) becomes visible to CPU 1 before (1), CPU 1 finds the pool at
> (a) but dereferences a wild pointer at (b). Publish the node with
> list_add_rcu().

Acked-by: Nhat Pham <nphamcs@gmail.com>