summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-09 08:24:25 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-09 08:24:25 -0700
commit685441a6d3f17404b47087d051963bc7fb665ef0 (patch)
treec7266fb3f79a0e9fd6c4ae7feba2206afd5ca535 /mm
parentfed2efe803e014e5c419bc7592caa8633683603e (diff)
parent0c25b8734367574e21aeb8468c2e522713134da7 (diff)
Merge tag 'mm-hotfixes-stable-2026-06-08-20-51' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull misc fixes from Andrew Morton: "11 hotfixes. 9 are for MM. 8 are cc:stable and the remaining 3 address post-7.1 issues or aren't considered suitable for backporting. Thre's a two-patch series "mm/damon/{reclaim,lru_sort}: handle ctx allocation failures" from SeongJae Park which fixes a couple of DAMON -ENOMEM bloopers. The rest are singletons - please see the individual changelogs for details" * tag 'mm-hotfixes-stable-2026-06-08-20-51' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: mm/mincore: handle non-swap entries before !CONFIG_SWAP guard arm64: mm: call pagetable dtor when freeing hot-removed page tables mm/list_lru: drain before clearing xarray entry on reparent mm/huge_memory: use correct flags for device private PMD entry mm/damon/lru_sort: handle ctx allocation failure mm/damon/reclaim: handle ctx allocation failure zram: fix use-after-free in zram_bvec_write_partial() MAINTAINERS: update Baoquan He's email address tools headers UAPI: sync linux/taskstats.h for procacct.c mm/cma_sysfs: skip inactive CMA areas in sysfs ipc/shm: serialize orphan cleanup with shm_nattch updates
Diffstat (limited to 'mm')
-rw-r--r--mm/cma_sysfs.c8
-rw-r--r--mm/damon/lru_sort.c4
-rw-r--r--mm/damon/reclaim.c4
-rw-r--r--mm/huge_memory.c45
-rw-r--r--mm/list_lru.c21
-rw-r--r--mm/mincore.c10
6 files changed, 64 insertions, 28 deletions
diff --git a/mm/cma_sysfs.c b/mm/cma_sysfs.c
index f52b696bc46d..d5bf792c6245 100644
--- a/mm/cma_sysfs.c
+++ b/mm/cma_sysfs.c
@@ -117,13 +117,16 @@ static int __init cma_sysfs_init(void)
return -ENOMEM;
for (i = 0; i < cma_area_count; i++) {
+ cma = &cma_areas[i];
+ if (!test_bit(CMA_ACTIVATED, &cma->flags))
+ continue;
+
cma_kobj = kzalloc_obj(*cma_kobj);
if (!cma_kobj) {
err = -ENOMEM;
goto out;
}
- cma = &cma_areas[i];
cma->cma_kobj = cma_kobj;
cma_kobj->cma = cma;
err = kobject_init_and_add(&cma_kobj->kobj, &cma_ktype,
@@ -138,7 +141,8 @@ static int __init cma_sysfs_init(void)
out:
while (--i >= 0) {
cma = &cma_areas[i];
- kobject_put(&cma->cma_kobj->kobj);
+ if (cma->cma_kobj)
+ kobject_put(&cma->cma_kobj->kobj);
}
kobject_put(cma_kobj_root);
diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
index 8494040b1ee4..8cfe7bd3dc1d 100644
--- a/mm/damon/lru_sort.c
+++ b/mm/damon/lru_sort.c
@@ -437,6 +437,10 @@ static int damon_lru_sort_enabled_store(const char *val,
if (!damon_initialized())
return 0;
+ /* damon_modules_new_paddr_ctx_target() in the init function failed. */
+ if (!ctx)
+ return -ENOMEM;
+
return damon_lru_sort_turn(enabled);
}
diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
index fe7fce26cf6c..96f6dfc28eae 100644
--- a/mm/damon/reclaim.c
+++ b/mm/damon/reclaim.c
@@ -339,6 +339,10 @@ static int damon_reclaim_enabled_store(const char *val,
if (!damon_initialized())
return 0;
+ /* damon_modules_new_paddr_ctx_target() in the init function failed. */
+ if (!ctx)
+ return -ENOMEM;
+
return damon_reclaim_turn(enabled);
}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 653f2dc03403..b118bcd392cb 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4983,7 +4983,7 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
struct vm_area_struct *vma = pvmw->vma;
struct mm_struct *mm = vma->vm_mm;
unsigned long address = pvmw->address;
- bool anon_exclusive;
+ bool anon_exclusive, present, writable, softdirty, uffd_wp;
pmd_t pmdval;
swp_entry_t entry;
pmd_t pmdswp;
@@ -4991,12 +4991,26 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
if (!(pvmw->pmd && !pvmw->pte))
return 0;
- flush_cache_range(vma, address, address + HPAGE_PMD_SIZE);
- if (unlikely(!pmd_present(*pvmw->pmd)))
- pmdval = pmdp_huge_get_and_clear(vma->vm_mm, address, pvmw->pmd);
- else
+ present = pmd_present(*pvmw->pmd);
+ if (likely(present)) {
+ flush_cache_range(vma, address, address + HPAGE_PMD_SIZE);
+
pmdval = pmdp_invalidate(vma, address, pvmw->pmd);
+ writable = pmd_write(pmdval);
+ softdirty = pmd_soft_dirty(pmdval);
+ uffd_wp = pmd_uffd_wp(pmdval);
+ } else {
+ softleaf_t old_entry;
+
+ pmdval = pmdp_huge_get_and_clear(vma->vm_mm, address, pvmw->pmd);
+ old_entry = softleaf_from_pmd(pmdval);
+
+ writable = softleaf_is_device_private_write(old_entry);
+ softdirty = pmd_swp_soft_dirty(pmdval);
+ uffd_wp = pmd_swp_uffd_wp(pmdval);
+ }
+
/* See folio_try_share_anon_rmap_pmd(): invalidate PMD first. */
anon_exclusive = folio_test_anon(folio) && PageAnonExclusive(page);
if (anon_exclusive && folio_try_share_anon_rmap_pmd(folio, page)) {
@@ -5004,24 +5018,31 @@ int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
return -EBUSY;
}
- if (pmd_dirty(pmdval))
- folio_mark_dirty(folio);
- if (pmd_write(pmdval))
+ /* Determine type of migration entry. */
+ if (writable)
entry = make_writable_migration_entry(page_to_pfn(page));
else if (anon_exclusive)
entry = make_readable_exclusive_migration_entry(page_to_pfn(page));
else
entry = make_readable_migration_entry(page_to_pfn(page));
- if (pmd_young(pmdval))
+
+ /* Set A/D bits as necessary. */
+ if (present && pmd_young(pmdval))
entry = make_migration_entry_young(entry);
- if (pmd_dirty(pmdval))
+ if (present && pmd_dirty(pmdval)) {
+ folio_mark_dirty(folio);
entry = make_migration_entry_dirty(entry);
+ }
+
+ /* Set PMD. */
pmdswp = swp_entry_to_pmd(entry);
- if (pmd_soft_dirty(pmdval))
+ if (softdirty)
pmdswp = pmd_swp_mksoft_dirty(pmdswp);
- if (pmd_uffd_wp(pmdval))
+ if (uffd_wp)
pmdswp = pmd_swp_mkuffd_wp(pmdswp);
set_pmd_at(mm, address, pvmw->pmd, pmdswp);
+
+ /* Migration entry installed: cleanup rmap, folio. */
folio_remove_rmap_pmd(folio, page, vma);
folio_put(folio);
trace_set_migration_pmd(address, pmd_val(pmdswp));
diff --git a/mm/list_lru.c b/mm/list_lru.c
index dd29bcf8eb5f..9bf7f524796b 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -473,26 +473,29 @@ void memcg_reparent_list_lrus(struct mem_cgroup *memcg, struct mem_cgroup *paren
mutex_lock(&list_lrus_mutex);
list_for_each_entry(lru, &memcg_list_lrus, list) {
struct list_lru_memcg *mlru;
- XA_STATE(xas, &lru->xa, memcg->kmemcg_id);
/*
- * Lock the Xarray to ensure no on going list_lru_memcg
- * allocation and further allocation will see css_is_dying().
+ * css_is_dying() check in memcg_list_lru_alloc() avoids
+ * allocating a new mlru since CSS_DYING is already set for this
+ * memcg a rcu grace period ago.
*/
- xas_lock_irq(&xas);
- mlru = xas_store(&xas, NULL);
- xas_unlock_irq(&xas);
+ mlru = xa_load(&lru->xa, memcg->kmemcg_id);
if (!mlru)
continue;
/*
- * With Xarray value set to NULL, holding the lru lock below
- * prevents list_lru_{add,del,isolate} from touching the lru,
- * safe to reparent.
+ * Reparent each per-node list and mark the child dead
+ * (LONG_MIN) before clearing xarray entry otherwise a
+ * concurrent list_lru_del() may corrupt the list if it arrives
+ * after xarray clear but before reparenting as
+ * lock_list_lru_of_memcg will acquire parent's lock while the
+ * item is still on child's list.
*/
for_each_node(i)
memcg_reparent_list_lru_one(lru, i, &mlru->node[i], parent);
+ xa_erase_irq(&lru->xa, memcg->kmemcg_id);
+
/*
* Here all list_lrus corresponding to the cgroup are guaranteed
* to remain empty, we can safely free this lru, any further
diff --git a/mm/mincore.c b/mm/mincore.c
index e5d13eea9234..296f2e3922b5 100644
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -64,11 +64,6 @@ static unsigned char mincore_swap(swp_entry_t entry, bool shmem)
struct folio *folio = NULL;
unsigned char present = 0;
- if (!IS_ENABLED(CONFIG_SWAP)) {
- WARN_ON(1);
- return 0;
- }
-
/*
* Shmem mapping may contain swapin error entries, which are
* absent. Page table may contain migration or hwpoison
@@ -77,6 +72,11 @@ static unsigned char mincore_swap(swp_entry_t entry, bool shmem)
if (!softleaf_is_swap(entry))
return !shmem;
+ if (!IS_ENABLED(CONFIG_SWAP)) {
+ WARN_ON(1);
+ return 0;
+ }
+
/*
* Shmem mapping lookup is lockless, so we need to grab the swap
* device. mincore page table walk locks the PTL, and the swap