diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-09 08:24:25 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-09 08:24:25 -0700 |
| commit | 685441a6d3f17404b47087d051963bc7fb665ef0 (patch) | |
| tree | c7266fb3f79a0e9fd6c4ae7feba2206afd5ca535 | |
| parent | fed2efe803e014e5c419bc7592caa8633683603e (diff) | |
| parent | 0c25b8734367574e21aeb8468c2e522713134da7 (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
| -rw-r--r-- | .mailmap | 1 | ||||
| -rw-r--r-- | MAINTAINERS | 6 | ||||
| -rw-r--r-- | arch/arm64/mm/mmu.c | 1 | ||||
| -rw-r--r-- | drivers/block/zram/zram_drv.c | 2 | ||||
| -rw-r--r-- | ipc/shm.c | 10 | ||||
| -rw-r--r-- | mm/cma_sysfs.c | 8 | ||||
| -rw-r--r-- | mm/damon/lru_sort.c | 4 | ||||
| -rw-r--r-- | mm/damon/reclaim.c | 4 | ||||
| -rw-r--r-- | mm/huge_memory.c | 45 | ||||
| -rw-r--r-- | mm/list_lru.c | 21 | ||||
| -rw-r--r-- | mm/mincore.c | 10 | ||||
| -rw-r--r-- | tools/include/uapi/linux/acct.h | 128 |
12 files changed, 204 insertions, 36 deletions
@@ -126,6 +126,7 @@ Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@linaro.org> Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@spreadtrum.com> Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang@unisoc.com> Baolin Wang <baolin.wang@linux.alibaba.com> <baolin.wang7@gmail.com> +Baoquan He <baoquan.he@linux.dev> <bhe@redhat.com> Barry Song <baohua@kernel.org> <21cnbao@gmail.com> Barry Song <baohua@kernel.org> <v-songbaohua@oppo.com> Barry Song <baohua@kernel.org> <song.bao.hua@hisilicon.com> diff --git a/MAINTAINERS b/MAINTAINERS index e035a3be797c..355e4ab2f9e5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13865,7 +13865,7 @@ F: scripts/Makefile.kcsan KDUMP M: Andrew Morton <akpm@linux-foundation.org> -M: Baoquan He <bhe@redhat.com> +M: Baoquan He <baoquan.he@linux.dev> M: Mike Rapoport <rppt@kernel.org> M: Pasha Tatashin <pasha.tatashin@soleen.com> M: Pratyush Yadav <pratyush@kernel.org> @@ -14184,7 +14184,7 @@ F: include/linux/kernfs.h KEXEC M: Andrew Morton <akpm@linux-foundation.org> -M: Baoquan He <bhe@redhat.com> +M: Baoquan He <baoquan.he@linux.dev> M: Mike Rapoport <rppt@kernel.org> M: Pasha Tatashin <pasha.tatashin@soleen.com> M: Pratyush Yadav <pratyush@kernel.org> @@ -17037,7 +17037,7 @@ M: Chris Li <chrisl@kernel.org> M: Kairui Song <kasong@tencent.com> R: Kemeng Shi <shikemeng@huaweicloud.com> R: Nhat Pham <nphamcs@gmail.com> -R: Baoquan He <bhe@redhat.com> +R: Baoquan He <baoquan.he@linux.dev> R: Barry Song <baohua@kernel.org> R: Youngjun Park <youngjun.park@lge.com> L: linux-mm@kvack.org diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index dd85e093ffdb..8242f93f05e4 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -1441,6 +1441,7 @@ static void free_hotplug_page_range(struct page *page, size_t size, static void free_hotplug_pgtable_page(struct page *page) { + pagetable_dtor(page_ptdesc(page)); free_hotplug_page_range(page, PAGE_SIZE, NULL); } diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 07111455eecf..e11ee1ed3832 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -2337,7 +2337,7 @@ static int zram_bvec_write_partial(struct zram *zram, struct bio_vec *bvec, if (!page) return -ENOMEM; - ret = zram_read_page(zram, page, index, bio); + ret = zram_read_page(zram, page, index, NULL); if (!ret) { memcpy_from_bvec(page_address(page) + offset, bvec); ret = zram_write_page(zram, page, index); diff --git a/ipc/shm.c b/ipc/shm.c index a95dae447707..b3e8a58e177d 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -418,15 +418,17 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data) * We want to destroy segments without users and with already * exit'ed originating process. * - * As shp->* are changed under rwsem, it's safe to skip shp locking. + * shm_nattch can be changed under shm_perm.lock without holding the + * rwsem, so take the object lock before checking shm_may_destroy(). */ if (!list_empty(&shp->shm_clist)) return 0; - if (shm_may_destroy(shp)) { - shm_lock_by_ptr(shp); + shm_lock_by_ptr(shp); + if (shm_may_destroy(shp)) shm_destroy(ns, shp); - } + else + shm_unlock(shp); return 0; } 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 diff --git a/tools/include/uapi/linux/acct.h b/tools/include/uapi/linux/acct.h new file mode 100644 index 000000000000..1e2382ed4fd5 --- /dev/null +++ b/tools/include/uapi/linux/acct.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * BSD Process Accounting for Linux - Definitions + * + * Author: Marco van Wieringen (mvw@planets.elm.net) + * + * This header file contains the definitions needed to implement + * BSD-style process accounting. The kernel accounting code and all + * user-level programs that try to do something useful with the + * process accounting log must include this file. + * + * Copyright (C) 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V. + * + */ + +#ifndef _UAPI_LINUX_ACCT_H +#define _UAPI_LINUX_ACCT_H + +#include <linux/types.h> + +#include <asm/param.h> +#include <asm/byteorder.h> + +/* + * comp_t is a 16-bit "floating" point number with a 3-bit base 8 + * exponent and a 13-bit fraction. + * comp2_t is 24-bit with 5-bit base 2 exponent and 20 bit fraction + * (leading 1 not stored). + * See linux/kernel/acct.c for the specific encoding systems used. + */ + +typedef __u16 comp_t; +typedef __u32 comp2_t; + +/* + * accounting file record + * + * This structure contains all of the information written out to the + * process accounting file whenever a process exits. + */ + +#define ACCT_COMM 16 + +struct acct +{ + char ac_flag; /* Flags */ + char ac_version; /* Always set to ACCT_VERSION */ + /* for binary compatibility back until 2.0 */ + __u16 ac_uid16; /* LSB of Real User ID */ + __u16 ac_gid16; /* LSB of Real Group ID */ + __u16 ac_tty; /* Control Terminal */ + /* __u32 range means times from 1970 to 2106 */ + __u32 ac_btime; /* Process Creation Time */ + comp_t ac_utime; /* User Time */ + comp_t ac_stime; /* System Time */ + comp_t ac_etime; /* Elapsed Time */ + comp_t ac_mem; /* Average Memory Usage */ + comp_t ac_io; /* Chars Transferred */ + comp_t ac_rw; /* Blocks Read or Written */ + comp_t ac_minflt; /* Minor Pagefaults */ + comp_t ac_majflt; /* Major Pagefaults */ + comp_t ac_swaps; /* Number of Swaps */ +/* m68k had no padding here. */ +#if !defined(CONFIG_M68K) || !defined(__KERNEL__) + __u16 ac_ahz; /* AHZ */ +#endif + __u32 ac_exitcode; /* Exitcode */ + char ac_comm[ACCT_COMM + 1]; /* Command Name */ + __u8 ac_etime_hi; /* Elapsed Time MSB */ + __u16 ac_etime_lo; /* Elapsed Time LSB */ + __u32 ac_uid; /* Real User ID */ + __u32 ac_gid; /* Real Group ID */ +}; + +struct acct_v3 +{ + char ac_flag; /* Flags */ + char ac_version; /* Always set to ACCT_VERSION */ + __u16 ac_tty; /* Control Terminal */ + __u32 ac_exitcode; /* Exitcode */ + __u32 ac_uid; /* Real User ID */ + __u32 ac_gid; /* Real Group ID */ + __u32 ac_pid; /* Process ID */ + __u32 ac_ppid; /* Parent Process ID */ + /* __u32 range means times from 1970 to 2106 */ + __u32 ac_btime; /* Process Creation Time */ +#ifdef __KERNEL__ + __u32 ac_etime; /* Elapsed Time */ +#else + float ac_etime; /* Elapsed Time */ +#endif + comp_t ac_utime; /* User Time */ + comp_t ac_stime; /* System Time */ + comp_t ac_mem; /* Average Memory Usage */ + comp_t ac_io; /* Chars Transferred */ + comp_t ac_rw; /* Blocks Read or Written */ + comp_t ac_minflt; /* Minor Pagefaults */ + comp_t ac_majflt; /* Major Pagefaults */ + comp_t ac_swaps; /* Number of Swaps */ + char ac_comm[ACCT_COMM]; /* Command Name */ +}; + +/* + * accounting flags + */ + /* bit set when the process/task ... */ +#define AFORK 0x01 /* ... executed fork, but did not exec */ +#define ASU 0x02 /* ... used super-user privileges */ +#define ACOMPAT 0x04 /* ... used compatibility mode (VAX only not used) */ +#define ACORE 0x08 /* ... dumped core */ +#define AXSIG 0x10 /* ... was killed by a signal */ +#define AGROUP 0x20 /* ... was the last task of the process (task group) */ + +#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN) +#define ACCT_BYTEORDER 0x80 /* accounting file is big endian */ +#elif defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) +#define ACCT_BYTEORDER 0x00 /* accounting file is little endian */ +#else +#error unspecified endianness +#endif + +#ifndef __KERNEL__ +#define ACCT_VERSION 2 +#define AHZ (HZ) +#endif /* __KERNEL */ + + +#endif /* _UAPI_LINUX_ACCT_H */ |
