mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 22:09:30 +02:00
Merge tag 'mm-hotfixes-stable-2026-09-13-21-50' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull misc fixes from Andrew Morton: "14 hotfixes. 10 are cc:stable. 11 are for MM. All are singletons - please see the changelogs for details" * tag 'mm-hotfixes-stable-2026-09-13-21-50' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: mm/folio: EXPORT_SYMBOL_FOR_KVM(lru_cache_drain_for_folio) mm/shrinker: fix bogus set_shrinker_bit() with cgroup.memory=nokmem mm/vma: correctly unaccount on mmap_prepare() failure mm/mlock: use the IRQ-safe accessor for NR_MLOCK in __munlock_folio() remove old lib/alloc_tag.c fs/dax: check zero or empty entry before converting xarray entry fs: fix missed removal of super_fs_objects_eligible() mm: filemap: retain mapped dropbehind folios mailmap: update entry for Christopher Obbard memcg: avoid charging the root memcg from obj_cgroup_charge_pages() mm, swap: fix SWAP_USAGE_OFFLIST_BIT collision with real usage count mailmap: map Coiby Xu's address mm/mremap: account mm->locked_vm correctly for MREMAP_DONTUNMAP mm/huge_memory: bypass THP tuneables for huge pfnmap mappings
This commit is contained in:
@@ -211,7 +211,8 @@ Christophe Leroy <chleroy@kernel.org> <christophe.leroy@c-s.fr>
|
||||
Christophe Leroy <chleroy@kernel.org> <christophe.leroy@csgroup.eu>
|
||||
Christophe Leroy <chleroy@kernel.org> <christophe.leroy2@cs-soprasteria.com>
|
||||
Christophe Ricard <christophe.ricard@gmail.com>
|
||||
Christopher Obbard <christopher.obbard@linaro.org> <chris.obbard@collabora.com>
|
||||
Christopher Obbard <chris.obbard@oss.qualcomm.com> <chris.obbard@collabora.com>
|
||||
Christopher Obbard <chris.obbard@oss.qualcomm.com> <christopher.obbard@linaro.org>
|
||||
Christoph Hellwig <hch@lst.de>
|
||||
Christoph Manszewski <c.manszewski@gmail.com> <christoph.manszewski@intel.com>
|
||||
Christoph Paasch <cpaasch@openai.com> <christoph.paasch@gmail.com>
|
||||
@@ -222,6 +223,7 @@ Chuck Lever <cel@kernel.org> <chuck.lever@oracle.com>
|
||||
Chuck Lever <cel@kernel.org> <cel@netapp.com>
|
||||
Chuck Lever <cel@kernel.org> <cel@citi.umich.edu>
|
||||
Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com>
|
||||
Coiby Xu <coiby.xu@gmail.com> <coxu@redhat.com>
|
||||
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
|
||||
Corey Minyard <minyard@acm.org>
|
||||
Damian Hobson-Garcia <dhobsong@igel.co.jp>
|
||||
|
||||
@@ -480,11 +480,12 @@ static void dax_associate_entry(void *entry, struct address_space *mapping,
|
||||
unsigned long address, bool shared)
|
||||
{
|
||||
unsigned long size = dax_entry_size(entry), index;
|
||||
struct folio *folio = dax_to_folio(entry);
|
||||
struct folio *folio;
|
||||
|
||||
if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry))
|
||||
return;
|
||||
|
||||
folio = dax_to_folio(entry);
|
||||
index = linear_page_index(vma, address & ~(size - 1));
|
||||
if (shared && (folio->mapping || dax_folio_is_shared(folio))) {
|
||||
if (folio->mapping)
|
||||
@@ -505,21 +506,23 @@ static void dax_associate_entry(void *entry, struct address_space *mapping,
|
||||
static void dax_disassociate_entry(void *entry, struct address_space *mapping,
|
||||
bool trunc)
|
||||
{
|
||||
struct folio *folio = dax_to_folio(entry);
|
||||
struct folio *folio;
|
||||
|
||||
if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry))
|
||||
return;
|
||||
|
||||
folio = dax_to_folio(entry);
|
||||
dax_folio_put(folio);
|
||||
}
|
||||
|
||||
static struct page *dax_busy_page(void *entry)
|
||||
{
|
||||
struct folio *folio = dax_to_folio(entry);
|
||||
struct folio *folio;
|
||||
|
||||
if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry))
|
||||
return NULL;
|
||||
|
||||
folio = dax_to_folio(entry);
|
||||
if (folio_ref_count(folio) - folio_mapcount(folio))
|
||||
return &folio->page;
|
||||
else
|
||||
|
||||
+2
-16
@@ -171,19 +171,6 @@ static void super_wake(struct super_block *sb, unsigned int flag)
|
||||
wake_up_var(&sb->s_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* The s_op->nr_cached_objects hooks (used for example by btrfs and xfs)
|
||||
* operate on filesystem-global state and ignore sc->memcg. Driving them
|
||||
* from per-memcg shrink_slab_memcg() invocations only burns CPU walking
|
||||
* per-cpu counters and queueing duplicate work: the actual reclaim happens on
|
||||
* the global path (kswapd or root direct reclaim) regardless. Restrict them
|
||||
* to that path.
|
||||
*/
|
||||
static inline bool super_fs_objects_eligible(struct shrink_control *sc)
|
||||
{
|
||||
return !sc->memcg || mem_cgroup_is_root(sc->memcg);
|
||||
}
|
||||
|
||||
/*
|
||||
* One thing we have to be careful of with a per-sb shrinker is that we don't
|
||||
* drop the last active reference to the superblock from within the shrinker.
|
||||
@@ -213,7 +200,7 @@ static unsigned long super_cache_scan(struct shrinker *shrink,
|
||||
if (!super_trylock_shared(sb))
|
||||
return SHRINK_STOP;
|
||||
|
||||
if (sb->s_op->nr_cached_objects && super_fs_objects_eligible(sc))
|
||||
if (sb->s_op->nr_cached_objects)
|
||||
fs_objects = sb->s_op->nr_cached_objects(sb, sc);
|
||||
|
||||
inodes = list_lru_shrink_count(&sb->s_inode_lru, sc);
|
||||
@@ -274,8 +261,7 @@ static unsigned long super_cache_count(struct shrinker *shrink,
|
||||
return 0;
|
||||
smp_rmb();
|
||||
|
||||
if (sb->s_op && sb->s_op->nr_cached_objects &&
|
||||
super_fs_objects_eligible(sc))
|
||||
if (sb->s_op && sb->s_op->nr_cached_objects)
|
||||
total_objects = sb->s_op->nr_cached_objects(sb, sc);
|
||||
|
||||
total_objects += list_lru_shrink_count(&sb->s_dentry_lru, sc);
|
||||
|
||||
-1029
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1616,7 +1616,7 @@ static void filemap_end_dropbehind(struct folio *folio)
|
||||
return;
|
||||
if (!folio_test_clear_dropbehind(folio))
|
||||
return;
|
||||
if (mapping)
|
||||
if (mapping && !folio_mapped(folio))
|
||||
folio_unmap_invalidate(mapping, folio, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <linux/page_idle.h>
|
||||
#include <linux/local_lock.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/kvm_types.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "page_alloc.h"
|
||||
@@ -926,6 +927,7 @@ void lru_cache_drain_for_folio(const struct folio *folio,
|
||||
*drained = LRU_CACHE_DRAINED_ALL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_FOR_KVM(lru_cache_drain_for_folio);
|
||||
|
||||
atomic_t lru_disable_count = ATOMIC_INIT(0);
|
||||
|
||||
|
||||
+64
-22
@@ -92,7 +92,7 @@ unsigned long huge_anon_orders_madvise __read_mostly;
|
||||
unsigned long huge_anon_orders_inherit __read_mostly;
|
||||
static bool anon_orders_configured __initdata;
|
||||
|
||||
static inline bool file_thp_enabled(struct vm_area_struct *vma)
|
||||
static inline bool file_thp_enabled(const struct vm_area_struct *vma)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
@@ -118,6 +118,67 @@ static bool vma_is_special_huge(const struct vm_area_struct *vma)
|
||||
return vma_test_any(vma, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT);
|
||||
}
|
||||
|
||||
static bool vma_file_bypass_thp_tuneables(const struct vm_area_struct *vma,
|
||||
enum tva_type type)
|
||||
{
|
||||
const bool has_huge_fault = vma->vm_ops->huge_fault;
|
||||
|
||||
/* MADV_COLLAPSE ignores tuneables. */
|
||||
if (type == TVA_FORCED_COLLAPSE)
|
||||
return true;
|
||||
/* Huge PFN mappings are uncompactable so the policy doesn't apply. */
|
||||
if (vma_test(vma, VMA_PFNMAP_BIT) && has_huge_fault)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool vma_file_allow_thp_tuneables(vm_flags_t vm_flags)
|
||||
{
|
||||
/* THP=always? */
|
||||
if (hugepage_global_always())
|
||||
return true;
|
||||
/* THP=madvise and marked MADV_HUGEPAGE? */
|
||||
if (hugepage_global_enabled() && (vm_flags & VM_HUGEPAGE))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool vma_file_check_thp_tuneables(const struct vm_area_struct *vma,
|
||||
vm_flags_t vm_flags, enum tva_type type)
|
||||
{
|
||||
return vma_file_bypass_thp_tuneables(vma, type) ||
|
||||
vma_file_allow_thp_tuneables(vm_flags);
|
||||
}
|
||||
|
||||
static bool vma_can_map_huge_file(const struct vm_area_struct *vma,
|
||||
vm_flags_t vm_flags, enum tva_type type)
|
||||
{
|
||||
const bool has_huge_fault = vma->vm_ops->huge_fault;
|
||||
|
||||
/*
|
||||
* Enforce THP collapse requirements as necessary. Anonymous vmas
|
||||
* were already handled in thp_vma_allowable_orders().
|
||||
*/
|
||||
if (!vma_file_check_thp_tuneables(vma, vm_flags, type))
|
||||
return false;
|
||||
|
||||
switch (type) {
|
||||
case TVA_PAGEFAULT:
|
||||
/*
|
||||
* Trust that ->huge_fault() handlers know what they are doing
|
||||
* in fault path.
|
||||
*/
|
||||
return has_huge_fault;
|
||||
case TVA_SMAPS:
|
||||
if (has_huge_fault)
|
||||
return true;
|
||||
fallthrough;
|
||||
default:
|
||||
/* Only regular file is valid in collapse path. */
|
||||
return file_thp_enabled(vma);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
|
||||
vm_flags_t vm_flags,
|
||||
enum tva_type type,
|
||||
@@ -190,27 +251,8 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
|
||||
vma, vma_start_pgoff(vma), 0,
|
||||
forced_collapse);
|
||||
|
||||
if (!vma_is_anonymous(vma)) {
|
||||
/*
|
||||
* Enforce THP collapse requirements as necessary. Anonymous vmas
|
||||
* were already handled in thp_vma_allowable_orders().
|
||||
*/
|
||||
if (!forced_collapse &&
|
||||
(!hugepage_global_enabled() || (!(vm_flags & VM_HUGEPAGE) &&
|
||||
!hugepage_global_always())))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Trust that ->huge_fault() handlers know what they are doing
|
||||
* in fault path.
|
||||
*/
|
||||
if (((in_pf || smaps)) && vma->vm_ops->huge_fault)
|
||||
return orders;
|
||||
/* Only regular file is valid in collapse path */
|
||||
if (((!in_pf || smaps)) && file_thp_enabled(vma))
|
||||
return orders;
|
||||
return 0;
|
||||
}
|
||||
if (!vma_is_anonymous(vma))
|
||||
return vma_can_map_huge_file(vma, vm_flags, type) ? orders : 0;
|
||||
|
||||
if (vma_is_temporary_stack(vma))
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -3158,7 +3158,7 @@ static int obj_cgroup_charge_pages(struct obj_cgroup *objcg, gfp_t gfp,
|
||||
|
||||
memcg = get_mem_cgroup_from_objcg(objcg);
|
||||
|
||||
ret = try_charge_memcg(memcg, gfp, nr_pages);
|
||||
ret = try_charge(memcg, gfp, nr_pages);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ static struct lruvec *__munlock_folio(struct folio *folio, struct lruvec *lruvec
|
||||
|
||||
munlock:
|
||||
if (folio_test_clear_mlocked(folio)) {
|
||||
__zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
|
||||
zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
|
||||
if (isolated || !folio_test_unevictable(folio))
|
||||
__count_vm_events(UNEVICTABLE_PGMUNLOCKED, nr_pages);
|
||||
else
|
||||
|
||||
+4
-5
@@ -1355,12 +1355,11 @@ static void dontunmap_complete(struct vma_remap_struct *vrm,
|
||||
if (vma_is_anonymous(vma) && !vma->vm_file)
|
||||
vma_set_pgoff(vma, pgoff_unfaulted);
|
||||
}
|
||||
|
||||
/* Because we won't unmap we don't need to touch locked_vm. */
|
||||
}
|
||||
|
||||
static unsigned long move_vma(struct vma_remap_struct *vrm)
|
||||
{
|
||||
const bool is_dontunmap = vrm->flags & MREMAP_DONTUNMAP;
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *new_vma;
|
||||
unsigned long hiwater_vm;
|
||||
@@ -1401,10 +1400,10 @@ static unsigned long move_vma(struct vma_remap_struct *vrm)
|
||||
*/
|
||||
hiwater_vm = mm->hiwater_vm;
|
||||
|
||||
vrm_stat_account(vrm, vrm->new_len);
|
||||
if (unlikely(!err && (vrm->flags & MREMAP_DONTUNMAP)))
|
||||
if (unlikely(is_dontunmap && !err))
|
||||
dontunmap_complete(vrm, new_vma);
|
||||
else
|
||||
vrm_stat_account(vrm, vrm->new_len);
|
||||
if (!is_dontunmap || err)
|
||||
unmap_source_vma(vrm);
|
||||
|
||||
mm->hiwater_vm = hiwater_vm;
|
||||
|
||||
@@ -227,6 +227,8 @@ static int shrinker_memcg_alloc(struct shrinker *shrinker)
|
||||
{
|
||||
int id;
|
||||
|
||||
shrinker->id = -1;
|
||||
|
||||
if (mem_cgroup_disabled())
|
||||
return -ENOSYS;
|
||||
if (mem_cgroup_kmem_disabled() && !(shrinker->flags & SHRINKER_NONSLAB))
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ static struct swap_info_struct *swap_entry_to_info(swp_entry_t entry)
|
||||
* This bit will be set if the device is not on the plist and not
|
||||
* usable, will be cleared if the device is on the plist.
|
||||
*/
|
||||
#define SWAP_USAGE_OFFLIST_BIT (1UL << (BITS_PER_TYPE(atomic_t) - 2))
|
||||
#define SWAP_USAGE_OFFLIST_BIT (1UL << (BITS_PER_TYPE(atomic_long_t) - 2))
|
||||
#define SWAP_USAGE_COUNTER_MASK (~SWAP_USAGE_OFFLIST_BIT)
|
||||
static long swap_usage_in_pages(struct swap_info_struct *si)
|
||||
{
|
||||
|
||||
@@ -2859,10 +2859,12 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr,
|
||||
map.check_ksm_early = can_set_ksm_flags_early(&map);
|
||||
|
||||
error = __mmap_setup(&map, &desc, uf);
|
||||
if (!error && have_mmap_prepare)
|
||||
error = call_mmap_prepare(&map, &desc);
|
||||
if (error)
|
||||
goto abort_munmap;
|
||||
if (have_mmap_prepare)
|
||||
error = call_mmap_prepare(&map, &desc);
|
||||
if (error)
|
||||
goto unacct_error;
|
||||
|
||||
if (map.check_ksm_early)
|
||||
update_ksm_flags(&map);
|
||||
|
||||
Reference in New Issue
Block a user