Skip to content

[Deepin-Kernel-SIG] [linux 6.6.y] [Upstream] mm/list_lru: Split list_lru lock into per-cgroup scope - #2026

Merged
opsiff merged 8 commits into
deepin-community:linux-6.6.yfrom
opsiff:linux-6.6.y-2026-07-30-update
Jul 30, 2026
Merged

[Deepin-Kernel-SIG] [linux 6.6.y] [Upstream] mm/list_lru: Split list_lru lock into per-cgroup scope#2026
opsiff merged 8 commits into
deepin-community:linux-6.6.yfrom
opsiff:linux-6.6.y-2026-07-30-update

Conversation

@opsiff

@opsiff opsiff commented Jul 30, 2026

Copy link
Copy Markdown
Member

Commits(8):
mm: zswap: fix objcg use-after-free in entry destruction
mm/list_lru: simplify reparenting and initial allocation
mm/list_lru: code clean up for reparenting
mm/list_lru: don't export list_lru_add
mm/list_lru: don't pass unnecessary key parameters
mm: list_lru: remove unused macro list_lru_init_key()
mm: workingset: dynamically allocate the mm-shadow shrinker
zswap: make shrinking memcg-aware

Link: https://lore.kernel.org/all/20241104175257.60853-1-ryncsn@gmail.com/T/#u
From: Kairui Song kasong@tencent.com

Currently, every list_lru has a per-node lock that protects adding,
deletion, isolation, and reparenting of all list_lru_one instances
belonging to this list_lru on this node. This lock contention is heavy
when multiple cgroups modify the same list_lru.

This can be alleviated by splitting the lock into per-cgroup scope.

To achieve this, this series reworked and optimized the reparenting
process step by step, making it possible to have a stable list_lru_one,
and making it possible to pin the list_lru_one. Then split the lock
into per-cgroup scope.

The result is ~15% performance gain for simple multi-cgroup tar test
of small files, and reduced LOC. See PATCH 5/6 for test details.

V2: https://lore.kernel.org/linux-mm/20240925171020.32142-1-ryncsn@gmail.com/
Updates from V2:

V1: https://lore.kernel.org/linux-mm/20240624175313.47329-1-ryncsn@gmail.com/
Updates from V1:

  • Collect Review-by.
  • Fix a race of initialization issue that may lead to mem leak [Muchun
    Song]
  • Drop a unrelated and incorrect fix [Shakeel Butt]
  • Use VM_WARN_ON instead of WARN_ON for several sanity checks.

Kairui Song (6):
mm/list_lru: don't pass unnecessary key parameters
mm/list_lru: don't export list_lru_add
mm/list_lru: code clean up for reparenting
mm/list_lru: simplify reparenting and initial allocation
mm/list_lru: split the lock to per-cgroup scope
mm/list_lru: simplify the list_lru walk callback function

drivers/android/binder_alloc.c | 8 +-
drivers/android/binder_alloc.h | 2 +-
fs/dcache.c | 4 +-
fs/gfs2/quota.c | 2 +-
fs/inode.c | 5 +-
fs/nfs/nfs42xattr.c | 4 +-
fs/nfsd/filecache.c | 5 +-
fs/xfs/xfs_buf.c | 2 -
fs/xfs/xfs_qm.c | 6 +-
include/linux/list_lru.h | 26 ++-
mm/list_lru.c | 383 ++++++++++++++++-----------------
mm/memcontrol.c | 10 +-
mm/workingset.c | 20 +-
mm/zswap.c | 12 +-
14 files changed, 241 insertions(+), 248 deletions(-)

--
2.47.0

Summary by Sourcery

Integrate memcg-aware list_lru support into zswap and core MM infrastructure to enable cgroup-aware zswap reclaim and robust handling of memcg offlining and swap cache recursion.

New Features:

  • Add memcg-aware list_lru integration for zswap entries to support per-memcg LRU accounting and reclaim.
  • Introduce cgroup-aware zswap reclaim that walks memcg-specific LRUs and selects memcgs in a round-robin fashion for global reclaim.
  • Provide zswap_memcg_offline_cleanup to keep pool state consistent during memcg offlining and reparenting.

Bug Fixes:

  • Prevent potential deadlock/recursion in __read_swap_cache_async by allowing callers to skip waiting when the swap cache entry already exists but is not yet attached.
  • Avoid reclaiming from offlined (zombie) memory cgroups during zswap reclaim to prevent stale references and incorrect accounting.

Enhancements:

  • Convert zswap’s per-pool LRU from a simple list+lock to the generic list_lru infrastructure with memcg awareness.
  • Charge and allocate zswap entries on the appropriate NUMA node and attach them to the correct memcg-aware list_lru instance.
  • Rework list_lru’s memcg integration, including reparenting and allocation paths, to use list_lru_one and Xarray-based tracking more safely under concurrent operations.
  • Update workingset shadow node shrinker initialization to use the new list_lru memcg+lockdep helpers and dynamic shrinker allocation/registration.
  • Refine memcg offlining paths to reparent list_lru data structures safely and invoke zswap-specific cleanup before kmem and shrinker reparenting.

@sourcery-ai

sourcery-ai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

Make zswap reclaim and list_lru fully memcg-aware, switching zswap pool LRU management from a manual list + spinlock to the generic list_lru infrastructure, updating memcg list_lru reparenting/allocation, and fixing a swap cache recursion hazard during zswap-triggered reclaim.

Sequence diagram for memcg-aware zswap reclaim and swap cache recursion protection

sequenceDiagram
    participant Task as task
    participant ZS as zswap_store
    participant SM as shrink_memcg
    participant LL as list_lru_walk_one
    participant CB as shrink_memcg_cb
    participant WB as zswap_writeback_entry
    participant SC as __read_swap_cache_async

    Task->>ZS: zswap_store(folio)
    ZS->>ZS: get_obj_cgroup_from_folio(folio)
    ZS->>ZS: obj_cgroup_may_zswap(objcg)?
    alt objcg not allowed
        ZS->>ZS: get_mem_cgroup_from_objcg(objcg)
        ZS->>SM: shrink_memcg(memcg)
        SM->>SM: zswap_pool_current_get()
        SM->>LL: list_lru_walk_one(pool->list_lru, nid, memcg, shrink_memcg_cb)
        LL-->>CB: shrink_memcg_cb(item, lru_one, lock, arg)
        CB->>WB: zswap_writeback_entry(entry, tree)
        WB->>SC: __read_swap_cache_async(swpentry, GFP_KERNEL, mpol, NO_INTERLEAVE_INDEX, &page_was_allocated, true)
        SC-->>WB: page or error
        WB-->>CB: writeback_result
        CB-->>LL: LRU_REMOVED_RETRY or LRU_RETRY
        SM-->>ZS: ret (0 or error)
    end
    ZS-->>Task: store result / reject
Loading

File-Level Changes

Change Details Files
Refactor zswap entry LRU management to use memcg-aware list_lru instead of a per-pool list_head + spinlock, and make reclaim operate per memcg with proper RCU and node-awareness.
  • Include linux/list_lru.h and replace zswap_pool lru/list + spinlock fields with struct list_lru and a mem_cgroup *next_shrink cursor.
  • Add helper functions to derive mem_cgroup and NUMA node from zswap entries, and implement zswap_lru_add/zswap_lru_del/zswap_lru_putback wrappers using list_lru APIs under RCU.
  • Introduce zswap_memcg_offline_cleanup to advance next_shrink when a memcg is offlined and hook it into mem_cgroup_css_offline.
  • Change zswap_entry allocation to be NUMA-aware via kmem_cache_alloc_node.
  • Ensure zswap_free_entry/uncharge paths use list_lru_del and update ordering of objcg uncharge/put.
  • Replace zswap_reclaim_entry with shrink_memcg_cb + shrink_memcg + round-robin shrink_worker that iterates memcgs, uses mem_cgroup_iter and mem_cgroup_tryget_online, and walks list_lru per-node via list_lru_walk_one.
  • Initialize and destroy zswap_pool list_lru using list_lru_init_memcg/list_lru_destroy, and clean up next_shrink/mem_cgroup_iter on pool destroy.
  • Update zswap_store/zswap_load to allocate memcg list_lru state (memcg_list_lru_alloc), add entries to list_lru, and perform targeted shrink_memcg when obj_cgroup_may_zswap() rejects the store.
mm/zswap.c
Evolve list_lru memcg support to work on mem_cgroup pointers instead of raw kmemcg_id indices, improve reparenting semantics, and simplify allocation of list_lru_memcg structures.
  • Add list_lru_from_memcg helper (CONFIG_MEMCG_KMEM and non-MEMCG variants) that resolves the appropriate list_lru_one for a memcg, reparenting up the hierarchy when necessary.
  • Change list_lru_add/list_lru_del to call list_lru_from_memcg instead of list_lru_from_memcg_idx, and drop EXPORT_SYMBOL_GPL(list_lru_add).
  • Remove memcg_list_lru_free and the old memcg_reparent_list_lru/memcg_reparent_list_lrus implementation that relied on kmemcg_id updates and post-reparent freeing of per-memcg list_lrus.
  • Introduce a new memcg_reparent_list_lrus that iterates memcg_list_lrus, clears the xarray entry for the memcg, reparenting per-node lists under lru->node[i].lock and freeing the list_lru_memcg via kvfree_rcu.
  • Rewrite memcg_list_lru_alloc to allocate and publish list_lru_memcg structures incrementally for the farthest ancestor without list_lru state, using xarray locking, css_is_dying checks, and simplified error/nomem handling.
  • Adjust __list_lru_init lockdep integration to use a key stored in struct list_lru (under CONFIG_LOCKDEP) instead of passing a key into the initializer.
mm/list_lru.c
include/linux/list_lru.h
Rework workingset shadow node shrinker initialization to use the new shrinker/list_lru APIs and lockdep key storage.
  • Remove the static workingset_shadow_shrinker struct and legacy prealloc_shrinker/register_shrinker_prepared usage.
  • In workingset_init, allocate a shrinker via shrinker_alloc with NUMA+MEMCG flags, then initialize the shadow_nodes list_lru using list_lru_init_memcg_key with a lock_class_key stored on the list_lru.
  • Set shrinker callbacks (count_shadow_nodes, scan_shadow_nodes), seeks=0, and register via shrinker_register; on error, teardown with shrinker_free.
mm/workingset.c
include/linux/list_lru.h
Extend swap cache async read to guard against recursion when zswap-triggered reclaim calls back into __read_swap_cache_async for the same entry.
  • Add a skip_if_exists boolean parameter to __read_swap_cache_async and to its declaration in mm/swap.h.
  • Within __read_swap_cache_async, after a failed add_to_swap_cache with -EEXIST, bail out early if skip_if_exists is true to avoid waiting for a folio that is not yet in swap cache.
  • Update all existing call sites (read_swap_cache_async, swap_cluster_readahead, swap_vma_readahead) to pass skip_if_exists=false, and change zswap_writeback_entry to pass skip_if_exists=true when reading swap cache for writeback.
mm/swap_state.c
mm/swap.h
mm/zswap.c
Hook zswap into memcg offlining and provide a stub for non-memcg builds so the new cleanup call is always available.
  • Declare zswap_memcg_offline_cleanup in include/linux/zswap.h with a no-op inline stub for !CONFIG_ZSWAP.
  • Implement zswap_memcg_offline_cleanup in mm/zswap.c to advance pool->next_shrink when the current memcg is offlined, under zswap_pools_lock.
  • Call zswap_memcg_offline_cleanup from mem_cgroup_css_offline before memcg_offline_kmem/reparenting to keep zswap’s memcg iteration state consistent.
include/linux/zswap.h
mm/zswap.c
mm/memcontrol.c
Add a helper for deriving mem_cgroup from obj_cgroup in memcontrol headers, with a stub in the non-memcg configuration.
  • Declare get_mem_cgroup_from_objcg in include/linux/memcontrol.h, returning NULL in the non-memcg case, for use in zswap_store when performing memcg-aware reclaim decisions.
include/linux/memcontrol.h

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@dongert
dongert requested a review from Copilot July 30, 2026 08:13
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please ask for approval from opsiff. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In the !CONFIG_MEMCG_KMEM path, the new list_lru_from_memcg() helper still takes an int parameter but is now called with a struct mem_cgroup * in list_lru_add/list_lru_del, which will cause unsafe pointer-to-int coercions; consider aligning the prototype and call sites to avoid type mismatches in non-memcg-kmem builds.
  • The new shrink_memcg() path is invoked from zswap_store() when obj_cgroup_may_zswap() fails; it would be useful to double-check that this reclaim-on-store behavior cannot lead to unexpected reentrancy or long latencies in hot paths, e.g. by guarding against nested zswap reclaim calls or imposing tighter bounds on the reclaim work done synchronously.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the !CONFIG_MEMCG_KMEM path, the new list_lru_from_memcg() helper still takes an int parameter but is now called with a struct mem_cgroup * in list_lru_add/list_lru_del, which will cause unsafe pointer-to-int coercions; consider aligning the prototype and call sites to avoid type mismatches in non-memcg-kmem builds.
- The new shrink_memcg() path is invoked from zswap_store() when obj_cgroup_may_zswap() fails; it would be useful to double-check that this reclaim-on-store behavior cannot lead to unexpected reentrancy or long latencies in hot paths, e.g. by guarding against nested zswap reclaim calls or imposing tighter bounds on the reclaim work done synchronously.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR backports mainline MM changes to make zswap’s reclaim and accounting memcg-aware by integrating zswap entries with the generic list_lru infrastructure, while also updating core list_lru memcg/reparenting logic and tightening swap-cache behavior to avoid recursion hazards.

Changes:

  • Convert zswap’s per-pool LRU to list_lru with memcg-aware accounting and implement memcg round-robin reclaim.
  • Rework list_lru memcg integration/reparenting and update workingset shadow shrinker initialization to the newer shrinker/list_lru helpers.
  • Extend __read_swap_cache_async() with a “skip if exists” mode to prevent recursive wait/lock scenarios during zswap-triggered reclaim.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
mm/zswap.c Switches zswap LRU to list_lru, adds memcg-aware reclaim and memcg offline cleanup integration.
mm/workingset.c Migrates workingset shadow shrinker init to dynamically allocated shrinker + new list_lru init helper.
mm/swap.h Extends __read_swap_cache_async() signature to add skip_if_exists.
mm/swap_state.c Implements the skip_if_exists behavior to avoid recursive wait/lock behavior.
mm/memcontrol.c Hooks zswap memcg offline cleanup into memcg offline sequence.
mm/list_lru.c Refactors list_lru memcg lookup/reparenting/allocation and lockdep plumbing.
include/linux/zswap.h Exposes zswap memcg offline cleanup API.
include/linux/memcontrol.h Provides get_mem_cgroup_from_objcg() (and stub when !MEMCG).
include/linux/list_lru.h Adjusts list_lru init APIs and adds memcg+lockdep key helper.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread mm/list_lru.c
Comment on lines +101 to +105
static inline struct list_lru_one *
list_lru_from_memcg(struct list_lru *lru, int nid, int idx)
{
return &lru->node[nid].lru;
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread mm/zswap.c
Comment on lines +752 to 756
if (writeback_result) {
zswap_reject_reclaim_fail++;
zswap_lru_putback(&entry->pool->list_lru, entry);
ret = LRU_RETRY;
goto put_unlock;
Comment thread include/linux/zswap.h
void zswap_invalidate(int type, pgoff_t offset);
void zswap_swapon(int type);
void zswap_swapoff(int type);
void zswap_memcg_offline_cleanup(struct mem_cgroup *memcg);
@opsiff
opsiff force-pushed the linux-6.6.y-2026-07-30-update branch from ab5c512 to fc0c4bf Compare July 30, 2026 09:21
lelloman and others added 8 commits July 30, 2026 18:23
mainline inclusion
from mainline-v6.8-rc1
category: performance

Currently, we only have a single global LRU for zswap.  This makes it
impossible to perform worload-specific shrinking - an memcg cannot
determine which pages in the pool it owns, and often ends up writing pages
from other memcgs.  This issue has been previously observed in practice
and mitigated by simply disabling memcg-initiated shrinking:

https://lore.kernel.org/all/20230530232435.3097106-1-nphamcs@gmail.com/T/#u

This patch fully resolves the issue by replacing the global zswap LRU
with memcg- and NUMA-specific LRUs, and modify the reclaim logic:

a) When a store attempt hits an memcg limit, it now triggers a
   synchronous reclaim attempt that, if successful, allows the new
   hotter page to be accepted by zswap.
b) If the store attempt instead hits the global zswap limit, it will
   trigger an asynchronous reclaim attempt, in which an memcg is
   selected for reclaim in a round-robin-like fashion.

[nphamcs@gmail.com: use correct function for the onlineness check, use mem_cgroup_iter_break()]
  Link: https://lkml.kernel.org/r/20231205195419.2563217-1-nphamcs@gmail.com
[nphamcs@gmail.com: drop the pool's reference at the end of the writeback step]
  Link: https://lkml.kernel.org/r/20231206030627.4155634-1-nphamcs@gmail.com
Link: https://lkml.kernel.org/r/20231130194023.4102148-4-nphamcs@gmail.com
Signed-off-by: Domenico Cerasuolo <cerasuolodomenico@gmail.com>
Co-developed-by: Nhat Pham <nphamcs@gmail.com>
Signed-off-by: Nhat Pham <nphamcs@gmail.com>
Tested-by: Bagas Sanjaya <bagasdotme@gmail.com>
Cc: Chris Li <chrisl@kernel.org>
Cc: Dan Streetman <ddstreet@ieee.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Seth Jennings <sjenning@redhat.com>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Vitaly Wool <vitaly.wool@konsulko.com>
Cc: Yosry Ahmed <yosryahmed@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Conflicts:
	mm/zswap.c
[call to zswap_memcg_offline_cleanup() in mem_cgroup_css_offline(),
but mm/memcontrol.c does not include linux/zswap.h where the function
is declared, causing:
    mm/memcontrol.c:5654:9: error: implicit declaration of function
    'zswap_memcg_offline_cleanup' [-Werror=implicit-function-declaration]
Upstream gets the declaration transitively: include/linux/mmzone.h
includes linux/zswap.h since commit b5ba474 ("zswap: shrink
zswap pool based on memory pressure"), which is not (yet) backported
to this branch.  Add the include directly, matching what upstream
achieves via mmzone.h.]
(cherry picked from commit a65b0e7)
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.7-rc1
category: performance

Use new APIs to dynamically allocate the mm-shadow shrinker.

Link: https://lkml.kernel.org/r/20230911094444.68966-20-zhengqi.arch@bytedance.com
Signed-off-by: Qi Zheng <zhengqi.arch@bytedance.com>
Acked-by: Muchun Song <songmuchun@bytedance.com>
Cc: Abhinav Kumar <quic_abhinavk@quicinc.com>
Cc: Alasdair Kergon <agk@redhat.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Cc: Andreas Dilger <adilger.kernel@dilger.ca>
Cc: Andreas Gruenbacher <agruenba@redhat.com>
Cc: Anna Schumaker <anna@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Bob Peterson <rpeterso@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Carlos Llamas <cmllamas@google.com>
Cc: Chandan Babu R <chandan.babu@oracle.com>
Cc: Chao Yu <chao@kernel.org>
Cc: Chris Mason <clm@fb.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Chuck Lever <cel@kernel.org>
Cc: Coly Li <colyli@suse.de>
Cc: Dai Ngo <Dai.Ngo@oracle.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: "Darrick J. Wong" <djwong@kernel.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Airlie <airlied@gmail.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Sterba <dsterba@suse.com>
Cc: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Cc: Gao Xiang <hsiangkao@linux.alibaba.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Huang Rui <ray.huang@amd.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Jason Wang <jasowang@redhat.com>
Cc: Jeff Layton <jlayton@kernel.org>
Cc: Jeffle Xu <jefflexu@linux.alibaba.com>
Cc: Joel Fernandes (Google) <joel@joelfernandes.org>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Josef Bacik <josef@toxicpanda.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Kent Overstreet <kent.overstreet@gmail.com>
Cc: Kirill Tkhai <tkhai@ya.ru>
Cc: Marijn Suijten <marijn.suijten@somainline.org>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Mike Snitzer <snitzer@kernel.org>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Nadav Amit <namit@vmware.com>
Cc: Neil Brown <neilb@suse.de>
Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
Cc: Olga Kornievskaia <kolga@netapp.com>
Cc: Paul E. McKenney <paulmck@kernel.org>
Cc: Richard Weinberger <richard@nod.at>
Cc: Rob Clark <robdclark@gmail.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Sean Paul <sean@poorly.run>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: Song Liu <song@kernel.org>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Steven Price <steven.price@arm.com>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Trond Myklebust <trond.myklebust@hammerspace.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Cc: Yue Hu <huyue2@coolpad.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
(cherry picked from commit 219c666)
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.9-rc1
category: performance

commit a02b8bf upstream.

list_lru_init_key() isn't used by anyone, remove it to clean up.

Link: https://lkml.kernel.org/r/20231228062715.338672-2-haifeng.xu@shopee.com
Signed-off-by: Haifeng Xu <haifeng.xu@shopee.com>
Acked-by: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Shakeel Butt <shakeelb@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.13-rc1
category: performance

commit 3f28bbe upstream.

Patch series "mm/list_lru: Split list_lru lock into per-cgroup scope".

When LOCKDEP is not enabled, lock_class_key is an empty struct that is
never used.  But the list_lru initialization function still takes a
placeholder pointer as parameter, and the compiler cannot optimize it
because the function is not static and exported.

Remove this parameter and move it inside the list_lru struct.  Only use it
when LOCKDEP is enabled.  Kernel builds with LOCKDEP will be slightly
larger, while !LOCKDEP builds without it will be slightly smaller (the
common case).

Link: https://lkml.kernel.org/r/20241104175257.60853-1-ryncsn@gmail.com
Link: https://lkml.kernel.org/r/20241104175257.60853-2-ryncsn@gmail.com
Signed-off-by: Kairui Song <kasong@tencent.com>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Chengming Zhou <zhouchengming@bytedance.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Qi Zheng <zhengqi.arch@bytedance.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Waiman Long <longman@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.13-rc1
category: performance

commit 78c0ed0 upstream.

It's no longer used by any module, just remove it.

Link: https://lkml.kernel.org/r/20241104175257.60853-3-ryncsn@gmail.com
Signed-off-by: Kairui Song <kasong@tencent.com>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Chengming Zhou <zhouchengming@bytedance.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Qi Zheng <zhengqi.arch@bytedance.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Waiman Long <longman@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.13-rc1
category: performance

commit 8d42abb upstream.

No feature change, just change of code structure and fix comment.

The list lrus are not empty until memcg_reparent_list_lru_node() calls are
all done, so the comments in memcg_offline_kmem were slightly inaccurate.

Link: https://lkml.kernel.org/r/20241104175257.60853-4-ryncsn@gmail.com
Signed-off-by: Kairui Song <kasong@tencent.com>
Reviewed-by: Muchun Song <muchun.song@linux.dev>
Acked-by: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Chengming Zhou <zhouchengming@bytedance.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Qi Zheng <zhengqi.arch@bytedance.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Waiman Long <longman@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.13-rc1
category: performance

commit 28e9802 upstream.

Currently, there is a lot of code for detecting reparent racing using
kmemcg_id as the synchronization flag.  And an intermediate table is
required to record and compare the kmemcg_id.

We can simplify this by just checking the cgroup css status, skip if
cgroup is being offlined.  On the reparenting side, ensure no more
allocation is on going and no further allocation will occur by using the
XArray lock as barrier.

Combined with a O(n^2) top-down walk for the allocation, we get rid of the
intermediate table allocation completely.  Despite being O(n^2), it should
be actually faster because it's not practical to have a very deep cgroup
level, and in most cases the parent cgroup should have been allocated
already.

This also avoided changing kmemcg_id before reparenting, making cgroups
have a stable index for list_lru_memcg.  After this change it's possible
that a dying cgroup will see a NULL value in XArray corresponding to the
kmemcg_id, because the kmemcg_id will point to an empty slot.  In such
case, just fallback to use its parent.

As a result the code is simpler, following test also showed a very slight
performance gain (12 test runs):

prepare() {
        mkdir /tmp/test-fs
        modprobe brd rd_nr=1 rd_size=16777216
        mkfs.xfs -f /dev/ram0
        mount -t xfs /dev/ram0 /tmp/test-fs
        for i in $(seq 10000); do
                seq 8000 > "/tmp/test-fs/$i"
        done
        mkdir -p /sys/fs/cgroup/system.slice/bench/test/1
        echo +memory > /sys/fs/cgroup/system.slice/bench/cgroup.subtree_control
        echo +memory > /sys/fs/cgroup/system.slice/bench/test/cgroup.subtree_control
        echo +memory > /sys/fs/cgroup/system.slice/bench/test/1/cgroup.subtree_control
        echo 768M > /sys/fs/cgroup/system.slice/bench/memory.max
}

do_test() {
        read_worker() {
                mkdir -p "/sys/fs/cgroup/system.slice/bench/test/1/$1"
                echo $BASHPID > "/sys/fs/cgroup/system.slice/bench/test/1/$1/cgroup.procs"
                read -r __TMP < "/tmp/test-fs/$1";
        }
        read_in_all() {
                for i in $(seq 10000); do
                        read_worker "$i" &
                done; wait
        }
        echo 3 > /proc/sys/vm/drop_caches
        time read_in_all
        for i in $(seq 1 10000); do
                rmdir "/sys/fs/cgroup/system.slice/bench/test/1/$i" &>/dev/null
        done
}

Before:
real    0m3.498s   user    0m11.037s  sys     0m35.872s
real    1m33.860s  user    0m11.593s  sys     3m1.169s
real    1m31.883s  user    0m11.265s  sys     2m59.198s
real    1m32.394s  user    0m11.294s  sys     3m1.616s
real    1m31.017s  user    0m11.379s  sys     3m1.349s
real    1m31.931s  user    0m11.295s  sys     2m59.863s
real    1m32.758s  user    0m11.254s  sys     2m59.538s
real    1m35.198s  user    0m11.145s  sys     3m1.123s
real    1m30.531s  user    0m11.393s  sys     2m58.089s
real    1m31.142s  user    0m11.333s  sys     3m0.549s

After:
real    0m3.489s   user    0m10.943s  sys     0m36.036s
real    1m10.893s  user    0m11.495s  sys     2m38.545s
real    1m29.129s  user    0m11.382s  sys     3m1.601s
real    1m29.944s  user    0m11.494s  sys     3m1.575s
real    1m31.208s  user    0m11.451s  sys     2m59.693s
real    1m25.944s  user    0m11.327s  sys     2m56.394s
real    1m28.599s  user    0m11.312s  sys     3m0.162s
real    1m26.746s  user    0m11.538s  sys     2m55.462s
real    1m30.668s  user    0m11.475s  sys     3m2.075s
real    1m29.258s  user    0m11.292s  sys     3m0.780s

Which is slightly faster in real time.

Link: https://lkml.kernel.org/r/20241104175257.60853-5-ryncsn@gmail.com
Signed-off-by: Kairui Song <kasong@tencent.com>
Cc: Chengming Zhou <zhouchengming@bytedance.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Qi Zheng <zhengqi.arch@bytedance.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Waiman Long <longman@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Conflicts:
       mm/list_lru.c
       mm/zswap.c
[mm/list_lru: fix !CONFIG_MEMCG_KMEM build for list_lru_from_memcg()
Commit 2e60fe3 ("mm/list_lru: simplify reparenting and initial
allocation") added a !CONFIG_MEMCG fallback stub:
    list_lru_from_memcg(struct list_lru *lru, int nid, int idx)
but all callers pass a struct mem_cgroup pointer.  With
CONFIG_MEMCG_KMEM disabled this fails to build:
    mm/list_lru.c:117:51: error: passing argument 3 of
    'list_lru_from_memcg' makes integer from pointer without a cast
    [-Werror=int-conversion]
Make the stub take struct mem_cgroup * like its CONFIG_MEMCG_KMEM
counterpart, so both variants share one signature.  Same end state as
upstream commit fb56fdf ("mm/list_lru: split the lock to
per-cgroup scope"), which incidentally resolved the same mismatch.]
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
mainline inclusion
from mainline-v6.8-rc4
category: bugfix

In the per-memcg LRU universe, LRU removal uses entry->objcg to determine
which list count needs to be decreased.  Drop the objcg reference after
updating the LRU, to fix a possible use-after-free.

Link: https://lkml.kernel.org/r/20240130013438.565167-1-hannes@cmpxchg.org
Fixes: a65b0e7 ("zswap: make shrinking memcg-aware")
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Yosry Ahmed <yosryahmed@google.com>
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Reviewed-by: Chengming Zhou <zhouchengming@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
(cherry picked from commit 2e601e1)
Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
@opsiff
opsiff force-pushed the linux-6.6.y-2026-07-30-update branch from fc0c4bf to b52c223 Compare July 30, 2026 10:25
@dongert
dongert requested a review from Copilot July 30, 2026 10:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

include/linux/zswap.h:18

  • include/linux/zswap.h now declares zswap_memcg_offline_cleanup(struct mem_cgroup *), but this header doesn’t declare/forward-declare struct mem_cgroup or include <linux/memcontrol.h>. This breaks compilation for includers like fs/proc/meminfo.c and mm/page_io.c that include <linux/zswap.h> without pulling in memcontrol definitions (unknown type name ‘struct mem_cgroup’). Add a forward declaration to keep the header self-contained.
void zswap_memcg_offline_cleanup(struct mem_cgroup *memcg);

mm/zswap.c:394

  • zswap_lru_putback() calls list_lru_putback() after dropping the list_lru walk lock. However, list_lru_putback() currently uses list_lru_from_memcg_idx() and does not fall back to a parent memcg when the per-memcg list has been erased during memcg offlining/reparenting (xa_load can return NULL). That can race with memcg offline (memcg_reparent_list_lrus() erases the xarray entry), leading to a NULL dereference when trying to put an isolated entry back. Consider updating list_lru_putback() (mm/list_lru.c) to use the new list_lru_from_memcg() helper (parent fallback) or otherwise guarantee a non-NULL list during offlining.
	rcu_read_lock();
	memcg = mem_cgroup_from_entry(entry);
	spin_lock(lock);
	/* we cannot use list_lru_add here, because it increments node's lru count */
	list_lru_putback(list_lru, &entry->lru, nid, memcg);

@opsiff
opsiff merged commit 2a88130 into deepin-community:linux-6.6.y Jul 30, 2026
14 of 16 checks passed
@opsiff opsiff changed the title [Deepin-Kernel-SIG] [linux 6.6.y] [Upstream] continue sync mm list_lru update from mainline [Deepin-Kernel-SIG] [linux 6.6.y] [Upstream] mm/list_lru: Split list_lru lock into per-cgroup scope Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants