mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
Merge tag 'mm-hotfixes-stable-2026-08-19-21-33' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull hotfixes from Andrew Morton: "8 hotfixes. 5 are cc:stable. 5 are for MM. All are singletons, please see their changelogs for details" * tag 'mm-hotfixes-stable-2026-08-19-21-33' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: mm/pagewalk: fix stale walk->action escaping walk_pmd_range() mm, swap: don't free a hibernation slot that is in the swap cache mm: memcg-v1: fix memsw and TCP failcnt accounting mm/vmscan: report RCU-tasks quiescent states in shrink_lruvec() mailmap: add entries for Guodong Xu MAINTAINERS, mailmap: update email address for JP Kobryn MAINTAINERS: remove git URL for Squashfs memcg: keep folio's objcg same as its node
This commit is contained in:
@@ -331,6 +331,8 @@ Gokul Sriram Palanisamy <quic_gokulsri@quicinc.com> <gokulsri@codeaurora.org>
|
||||
Govindaraj Saminathan <quic_gsamin@quicinc.com> <gsamin@codeaurora.org>
|
||||
Guo Ren <guoren@kernel.org> <guoren@linux.alibaba.com>
|
||||
Guo Ren <guoren@kernel.org> <ren_guo@c-sky.com>
|
||||
Guodong Xu <docular.xu@gmail.com> <guodong.xu@linaro.org>
|
||||
Guodong Xu <docular.xu@gmail.com> <guodong@riscstar.com>
|
||||
Guru Das Srinagesh <linux@gurudas.dev>
|
||||
Guru Das Srinagesh <linux@gurudas.dev> <quic_gurus@quicinc.com>
|
||||
Guru Das Srinagesh <linux@gurudas.dev> <gurus@codeaurora.org>
|
||||
@@ -465,6 +467,7 @@ Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com> <jorge.ramirez-ortiz@linaro
|
||||
Josh Poimboeuf <jpoimboe@kernel.org> <jpoimboe@redhat.com>
|
||||
Josh Poimboeuf <jpoimboe@kernel.org> <jpoimboe@us.ibm.com>
|
||||
Jouni Malinen <quic_jouni@quicinc.com> <jouni@codeaurora.org>
|
||||
JP Kobryn <jp.kobryn@linux.dev> <inwardvessel@gmail.com>
|
||||
Juha Yrjola <at solidboot.com>
|
||||
Juha Yrjola <juha.yrjola@nokia.com>
|
||||
Juha Yrjola <juha.yrjola@solidboot.com>
|
||||
|
||||
+1
-2
@@ -4985,7 +4985,7 @@ F: tools/lib/bpf/
|
||||
|
||||
BPF [MEMORY MANAGEMENT EXTENSIONS]
|
||||
M: Roman Gushchin <roman.gushchin@linux.dev>
|
||||
M: JP Kobryn <inwardvessel@gmail.com>
|
||||
M: JP Kobryn <jp.kobryn@linux.dev>
|
||||
M: Shakeel Butt <shakeel.butt@linux.dev>
|
||||
L: bpf@vger.kernel.org
|
||||
L: linux-mm@kvack.org
|
||||
@@ -25672,7 +25672,6 @@ M: Phillip Lougher <phillip@squashfs.org.uk>
|
||||
L: squashfs-devel@lists.sourceforge.net (subscribers-only)
|
||||
S: Maintained
|
||||
W: http://squashfs.org.uk
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-next.git
|
||||
F: Documentation/filesystems/squashfs.rst
|
||||
F: fs/squashfs/
|
||||
|
||||
|
||||
+85
-17
@@ -2912,10 +2912,9 @@ struct mem_cgroup *mem_cgroup_from_virt(void *p)
|
||||
return folio_memcg_check(virt_to_folio(p));
|
||||
}
|
||||
|
||||
static struct obj_cgroup *__get_obj_cgroup_from_memcg(struct mem_cgroup *memcg)
|
||||
static struct obj_cgroup *__get_obj_cgroup_from_memcg(struct mem_cgroup *memcg,
|
||||
int nid)
|
||||
{
|
||||
int nid = numa_node_id();
|
||||
|
||||
for (; memcg; memcg = parent_mem_cgroup(memcg)) {
|
||||
struct obj_cgroup *objcg = rcu_dereference(memcg->nodeinfo[nid]->objcg);
|
||||
|
||||
@@ -2926,12 +2925,13 @@ static struct obj_cgroup *__get_obj_cgroup_from_memcg(struct mem_cgroup *memcg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct obj_cgroup *get_obj_cgroup_from_memcg(struct mem_cgroup *memcg)
|
||||
static inline struct obj_cgroup *get_obj_cgroup_from_memcg(struct mem_cgroup *memcg,
|
||||
int nid)
|
||||
{
|
||||
struct obj_cgroup *objcg;
|
||||
|
||||
rcu_read_lock();
|
||||
objcg = __get_obj_cgroup_from_memcg(memcg);
|
||||
objcg = __get_obj_cgroup_from_memcg(memcg, nid);
|
||||
rcu_read_unlock();
|
||||
|
||||
return objcg;
|
||||
@@ -2975,7 +2975,7 @@ static struct obj_cgroup *current_objcg_update(void)
|
||||
|
||||
rcu_read_lock();
|
||||
memcg = mem_cgroup_from_task(current);
|
||||
objcg = __get_obj_cgroup_from_memcg(memcg);
|
||||
objcg = __get_obj_cgroup_from_memcg(memcg, numa_node_id());
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
@@ -4182,9 +4182,11 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
|
||||
page_counter_init(&memcg->swap, &parent->swap, false);
|
||||
#ifdef CONFIG_MEMCG_V1
|
||||
memcg->memory.track_failcnt = !memcg_on_dfl;
|
||||
memcg->memsw.track_failcnt = !memcg_on_dfl;
|
||||
WRITE_ONCE(memcg->oom_kill_disable, READ_ONCE(parent->oom_kill_disable));
|
||||
page_counter_init(&memcg->kmem, &parent->kmem, false);
|
||||
page_counter_init(&memcg->tcpmem, &parent->tcpmem, false);
|
||||
memcg->tcpmem.track_failcnt = !memcg_on_dfl;
|
||||
#endif
|
||||
} else {
|
||||
init_memcg_stats();
|
||||
@@ -5138,7 +5140,7 @@ static int charge_memcg(struct folio *folio, struct mem_cgroup *memcg,
|
||||
int ret = 0;
|
||||
struct obj_cgroup *objcg;
|
||||
|
||||
objcg = get_obj_cgroup_from_memcg(memcg);
|
||||
objcg = get_obj_cgroup_from_memcg(memcg, folio_nid(folio));
|
||||
/* Do not account at the root objcg level. */
|
||||
if (!obj_cgroup_is_root(objcg))
|
||||
ret = try_charge_memcg(memcg, gfp, folio_nr_pages(folio));
|
||||
@@ -5337,6 +5339,46 @@ void __mem_cgroup_uncharge_folios(struct folio_batch *folios)
|
||||
uncharge_batch(&ug);
|
||||
}
|
||||
|
||||
/*
|
||||
* An LRU folio must hold the objcg belonging to its own node.
|
||||
*
|
||||
* memcg_reparent_objcgs() reparents a dying cgroup one node at a time: the
|
||||
* folios on that node's LRU lists move to the parent and that node's objcg is
|
||||
* redirected to the parent, atomically under the node's lru_lock.
|
||||
* folio_lruvec_lock() relies on this to provide a stable folio<->lruvec
|
||||
* binding. If a folio holds another node's objcg, its list membership and its
|
||||
* lruvec resolution change in separate lock sections, and an LRU operation in
|
||||
* between can re-add the folio to, and strand it on, the LRU list of a dead
|
||||
* memcg.
|
||||
*
|
||||
* So when migration transfers the memcg state to a folio on another node,
|
||||
* re-derive the objcg for the destination node. If the memcg is dying and the
|
||||
* destination node has already been reparented, the lookup walks up to the
|
||||
* nearest live ancestor - which is also where that node's LRU lists went.
|
||||
*
|
||||
* Returns the objcg to commit to @new, with a reference for the caller.
|
||||
*/
|
||||
static struct obj_cgroup *get_migration_objcg(struct folio *old,
|
||||
struct folio *new)
|
||||
{
|
||||
struct obj_cgroup *old_objcg, *new_objcg;
|
||||
int new_nid = folio_nid(new);
|
||||
|
||||
old_objcg = get_obj_cgroup_from_folio(old);
|
||||
|
||||
if (folio_nid(old) == new_nid)
|
||||
return old_objcg;
|
||||
|
||||
rcu_read_lock();
|
||||
new_objcg = __get_obj_cgroup_from_memcg(obj_cgroup_memcg(old_objcg),
|
||||
new_nid);
|
||||
rcu_read_unlock();
|
||||
|
||||
obj_cgroup_put(old_objcg);
|
||||
|
||||
return new_objcg;
|
||||
}
|
||||
|
||||
/**
|
||||
* mem_cgroup_replace_folio - Charge a folio's replacement.
|
||||
* @old: Currently circulating folio.
|
||||
@@ -5365,21 +5407,28 @@ void mem_cgroup_replace_folio(struct folio *old, struct folio *new)
|
||||
if (folio_memcg_charged(new))
|
||||
return;
|
||||
|
||||
objcg = folio_objcg(old);
|
||||
VM_WARN_ON_ONCE_FOLIO(!objcg, old);
|
||||
if (!objcg)
|
||||
VM_WARN_ON_ONCE_FOLIO(!folio_objcg(old), old);
|
||||
if (!folio_objcg(old))
|
||||
return;
|
||||
|
||||
objcg = get_migration_objcg(old, new);
|
||||
|
||||
rcu_read_lock();
|
||||
memcg = obj_cgroup_memcg(objcg);
|
||||
/* Force-charge the new page. The old one will be freed soon */
|
||||
|
||||
/*
|
||||
* Force-charge the new page. The old one will be freed soon.
|
||||
*
|
||||
* The rootness of the committed objcg decides whether the final
|
||||
* uncharge of @new goes through the page counters (see
|
||||
* uncharge_folio()); charge them only if the uncharge will.
|
||||
*/
|
||||
if (!obj_cgroup_is_root(objcg)) {
|
||||
page_counter_charge(&memcg->memory, nr_pages);
|
||||
if (do_memsw_account())
|
||||
page_counter_charge(&memcg->memsw, nr_pages);
|
||||
}
|
||||
|
||||
obj_cgroup_get(objcg);
|
||||
commit_charge(new, objcg);
|
||||
memcg1_commit_charge(new, memcg);
|
||||
rcu_read_unlock();
|
||||
@@ -5391,14 +5440,15 @@ void mem_cgroup_replace_folio(struct folio *old, struct folio *new)
|
||||
* @new: Replacement folio.
|
||||
*
|
||||
* Transfer the memcg data from the old folio to the new folio for migration.
|
||||
* The old folio's data info will be cleared. Note that the memory counters
|
||||
* will remain unchanged throughout the process.
|
||||
* The old folio's data info will be cleared. The memory counters remain
|
||||
* unchanged, unless the charge moves out of a fully reparented ancestry
|
||||
* and has to be settled (see below).
|
||||
*
|
||||
* Both folios must be locked, @new->mapping must be set up.
|
||||
*/
|
||||
void mem_cgroup_migrate(struct folio *old, struct folio *new)
|
||||
{
|
||||
struct obj_cgroup *objcg;
|
||||
struct obj_cgroup *objcg, *new_objcg;
|
||||
|
||||
VM_BUG_ON_FOLIO(!folio_test_locked(old), old);
|
||||
VM_BUG_ON_FOLIO(!folio_test_locked(new), new);
|
||||
@@ -5419,12 +5469,30 @@ void mem_cgroup_migrate(struct folio *old, struct folio *new)
|
||||
if (!objcg)
|
||||
return;
|
||||
|
||||
/* Transfer the charge and the objcg ref */
|
||||
commit_charge(new, objcg);
|
||||
new_objcg = get_migration_objcg(old, new);
|
||||
|
||||
/*
|
||||
* @old was charged through a non-root objcg, so its charge is in the
|
||||
* page counters. If the re-derivation walked up to the root objcg -
|
||||
* @old's entire ancestry is dying and already reparented - the final
|
||||
* uncharge of @new will skip the page counters (see uncharge_folio()).
|
||||
* Settle them now: this is @old's eventual uncharge, moved up to the
|
||||
* point where its charge record ends.
|
||||
*/
|
||||
if (obj_cgroup_is_root(new_objcg) && !obj_cgroup_is_root(objcg)) {
|
||||
rcu_read_lock();
|
||||
memcg_uncharge(obj_cgroup_memcg(objcg), folio_nr_pages(old));
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
commit_charge(new, new_objcg);
|
||||
|
||||
/* Warning should never happen, so don't worry about refcount non-0 */
|
||||
WARN_ON_ONCE(folio_unqueue_deferred_split(old));
|
||||
old->memcg_data = 0;
|
||||
|
||||
/* @new holds its own reference now, drop @old's */
|
||||
obj_cgroup_put(objcg);
|
||||
}
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(memcg_sockets_enabled_key);
|
||||
|
||||
+2
-4
@@ -126,6 +126,7 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end,
|
||||
pmd = pmd_offset(pud, addr);
|
||||
do {
|
||||
again:
|
||||
walk->action = ACTION_SUBTREE;
|
||||
next = pmd_addr_end(addr, end);
|
||||
if (pmd_none(*pmd)) {
|
||||
if (has_install)
|
||||
@@ -138,8 +139,6 @@ again:
|
||||
continue;
|
||||
}
|
||||
|
||||
walk->action = ACTION_SUBTREE;
|
||||
|
||||
/*
|
||||
* This implies that each ->pmd_entry() handler
|
||||
* needs to know about pmd_trans_huge() pmds
|
||||
@@ -196,6 +195,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end,
|
||||
pud = pud_offset(p4d, addr);
|
||||
do {
|
||||
again:
|
||||
walk->action = ACTION_SUBTREE;
|
||||
next = pud_addr_end(addr, end);
|
||||
if (pud_none(*pud)) {
|
||||
if (has_install)
|
||||
@@ -208,8 +208,6 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end,
|
||||
continue;
|
||||
}
|
||||
|
||||
walk->action = ACTION_SUBTREE;
|
||||
|
||||
if (ops->pud_entry)
|
||||
err = ops->pud_entry(pud, addr, next, walk);
|
||||
if (err)
|
||||
|
||||
+8
-1
@@ -2202,7 +2202,14 @@ void swap_free_hibernation_slot(swp_entry_t entry)
|
||||
|
||||
ci = swap_cluster_lock(si, offset);
|
||||
__swap_cluster_put_entry(ci, offset % SWAPFILE_CLUSTER);
|
||||
__swap_cluster_free_entries(si, ci, offset % SWAPFILE_CLUSTER, 1);
|
||||
/*
|
||||
* A slot with a folio in the swap cache is freed when the folio
|
||||
* leaves the cache, the same rule swap_put_entries_cluster() follows.
|
||||
* Readahead can put a folio here, and freeing the slot now would
|
||||
* leave that folio with no entry behind it.
|
||||
*/
|
||||
if (!swp_tb_is_folio(__swap_table_get(ci, offset % SWAPFILE_CLUSTER)))
|
||||
__swap_cluster_free_entries(si, ci, offset % SWAPFILE_CLUSTER, 1);
|
||||
swap_cluster_unlock(ci);
|
||||
|
||||
/* In theory readahead might add it to the swap cache by accident */
|
||||
|
||||
+1
-1
@@ -5948,7 +5948,7 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
|
||||
}
|
||||
}
|
||||
|
||||
cond_resched();
|
||||
cond_resched_tasks_rcu_qs();
|
||||
|
||||
if (nr_reclaimed < nr_to_reclaim || proportional_reclaim)
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user