]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Merge tag 'mm-stable-2025-10-01-19-00' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Oct 2025 01:18:33 +0000 (18:18 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Oct 2025 01:18:33 +0000 (18:18 -0700)
Pull MM updates from Andrew Morton:

 - "mm, swap: improve cluster scan strategy" from Kairui Song improves
   performance and reduces the failure rate of swap cluster allocation

 - "support large align and nid in Rust allocators" from Vitaly Wool
   permits Rust allocators to set NUMA node and large alignment when
   perforning slub and vmalloc reallocs

 - "mm/damon/vaddr: support stat-purpose DAMOS" from Yueyang Pan extend
   DAMOS_STAT's handling of the DAMON operations sets for virtual
   address spaces for ops-level DAMOS filters

 - "execute PROCMAP_QUERY ioctl under per-vma lock" from Suren
   Baghdasaryan reduces mmap_lock contention during reads of
   /proc/pid/maps

 - "mm/mincore: minor clean up for swap cache checking" from Kairui Song
   performs some cleanup in the swap code

 - "mm: vm_normal_page*() improvements" from David Hildenbrand provides
   code cleanup in the pagemap code

 - "add persistent huge zero folio support" from Pankaj Raghav provides
   a block layer speedup by optionalls making the
   huge_zero_pagepersistent, instead of releasing it when its refcount
   falls to zero

 - "kho: fixes and cleanups" from Mike Rapoport adds a few touchups to
   the recently added Kexec Handover feature

 - "mm: make mm->flags a bitmap and 64-bit on all arches" from Lorenzo
   Stoakes turns mm_struct.flags into a bitmap. To end the constant
   struggle with space shortage on 32-bit conflicting with 64-bit's
   needs

 - "mm/swapfile.c and swap.h cleanup" from Chris Li cleans up some swap
   code

 - "selftests/mm: Fix false positives and skip unsupported tests" from
   Donet Tom fixes a few things in our selftests code

 - "prctl: extend PR_SET_THP_DISABLE to only provide THPs when advised"
   from David Hildenbrand "allows individual processes to opt-out of
   THP=always into THP=madvise, without affecting other workloads on the
   system".

   It's a long story - the [1/N] changelog spells out the considerations

 - "Add and use memdesc_flags_t" from Matthew Wilcox gets us started on
   the memdesc project. Please see

      https://kernelnewbies.org/MatthewWilcox/Memdescs and
      https://blogs.oracle.com/linux/post/introducing-memdesc

 - "Tiny optimization for large read operations" from Chi Zhiling
   improves the efficiency of the pagecache read path

 - "Better split_huge_page_test result check" from Zi Yan improves our
   folio splitting selftest code

 - "test that rmap behaves as expected" from Wei Yang adds some rmap
   selftests

 - "remove write_cache_pages()" from Christoph Hellwig removes that
   function and converts its two remaining callers

 - "selftests/mm: uffd-stress fixes" from Dev Jain fixes some UFFD
   selftests issues

 - "introduce kernel file mapped folios" from Boris Burkov introduces
   the concept of "kernel file pages". Using these permits btrfs to
   account its metadata pages to the root cgroup, rather than to the
   cgroups of random inappropriate tasks

 - "mm/pageblock: improve readability of some pageblock handling" from
   Wei Yang provides some readability improvements to the page allocator
   code

 - "mm/damon: support ARM32 with LPAE" from SeongJae Park teaches DAMON
   to understand arm32 highmem

 - "tools: testing: Use existing atomic.h for vma/maple tests" from
   Brendan Jackman performs some code cleanups and deduplication under
   tools/testing/

 - "maple_tree: Fix testing for 32bit compiles" from Liam Howlett fixes
   a couple of 32-bit issues in tools/testing/radix-tree.c

 - "kasan: unify kasan_enabled() and remove arch-specific
   implementations" from Sabyrzhan Tasbolatov moves KASAN arch-specific
   initialization code into a common arch-neutral implementation

 - "mm: remove zpool" from Johannes Weiner removes zspool - an
   indirection layer which now only redirects to a single thing
   (zsmalloc)

 - "mm: task_stack: Stack handling cleanups" from Pasha Tatashin makes a
   couple of cleanups in the fork code

 - "mm: remove nth_page()" from David Hildenbrand makes rather a lot of
   adjustments at various nth_page() callsites, eventually permitting
   the removal of that undesirable helper function

 - "introduce kasan.write_only option in hw-tags" from Yeoreum Yun
   creates a KASAN read-only mode for ARM, using that architecture's
   memory tagging feature. It is felt that a read-only mode KASAN is
   suitable for use in production systems rather than debug-only

 - "mm: hugetlb: cleanup hugetlb folio allocation" from Kefeng Wang does
   some tidying in the hugetlb folio allocation code

 - "mm: establish const-correctness for pointer parameters" from Max
   Kellermann makes quite a number of the MM API functions more accurate
   about the constness of their arguments. This was getting in the way
   of subsystems (in this case CEPH) when they attempt to improving
   their own const/non-const accuracy

 - "Cleanup free_pages() misuse" from Vishal Moola fixes a number of
   code sites which were confused over when to use free_pages() vs
   __free_pages()

 - "Add Rust abstraction for Maple Trees" from Alice Ryhl makes the
   mapletree code accessible to Rust. Required by nouveau and by its
   forthcoming successor: the new Rust Nova driver

 - "selftests/mm: split_huge_page_test: split_pte_mapped_thp
   improvements" from David Hildenbrand adds a fix and some cleanups to
   the thp selftesting code

 - "mm, swap: introduce swap table as swap cache (phase I)" from Chris
   Li and Kairui Song is the first step along the path to implementing
   "swap tables" - a new approach to swap allocation and state tracking
   which is expected to yield speed and space improvements. This
   patchset itself yields a 5-20% performance benefit in some situations

 - "Some ptdesc cleanups" from Matthew Wilcox utilizes the new memdesc
   layer to clean up the ptdesc code a little

 - "Fix va_high_addr_switch.sh test failure" from Chunyu Hu fixes some
   issues in our 5-level pagetable selftesting code

 - "Minor fixes for memory allocation profiling" from Suren Baghdasaryan
   addresses a couple of minor issues in relatively new memory
   allocation profiling feature

 - "Small cleanups" from Matthew Wilcox has a few cleanups in
   preparation for more memdesc work

 - "mm/damon: add addr_unit for DAMON_LRU_SORT and DAMON_RECLAIM" from
   Quanmin Yan makes some changes to DAMON in furtherance of supporting
   arm highmem

 - "selftests/mm: Add -Wunreachable-code and fix warnings" from Muhammad
   Anjum adds that compiler check to selftests code and fixes the
   fallout, by removing dead code

 - "Improvements to Victim Process Thawing and OOM Reaper Traversal
   Order" from zhongjinji makes a number of improvements in the OOM
   killer: mainly thawing a more appropriate group of victim threads so
   they can release resources

 - "mm/damon: misc fixups and improvements for 6.18" from SeongJae Park
   is a bunch of small and unrelated fixups for DAMON

 - "mm/damon: define and use DAMON initialization check function" from
   SeongJae Park implement reliability and maintainability improvements
   to a recently-added bug fix

 - "mm/damon/stat: expose auto-tuned intervals and non-idle ages" from
   SeongJae Park provides additional transparency to userspace clients
   of the DAMON_STAT information

 - "Expand scope of khugepaged anonymous collapse" from Dev Jain removes
   some constraints on khubepaged's collapsing of anon VMAs. It also
   increases the success rate of MADV_COLLAPSE against an anon vma

 - "mm: do not assume file == vma->vm_file in compat_vma_mmap_prepare()"
   from Lorenzo Stoakes moves us further towards removal of
   file_operations.mmap(). This patchset concentrates upon clearing up
   the treatment of stacked filesystems

 - "mm: Improve mlock tracking for large folios" from Kiryl Shutsemau
   provides some fixes and improvements to mlock's tracking of large
   folios. /proc/meminfo's "Mlocked" field became more accurate

 - "mm/ksm: Fix incorrect accounting of KSM counters during fork" from
   Donet Tom fixes several user-visible KSM stats inaccuracies across
   forks and adds selftest code to verify these counters

 - "mm_slot: fix the usage of mm_slot_entry" from Wei Yang addresses
   some potential but presently benign issues in KSM's mm_slot handling

* tag 'mm-stable-2025-10-01-19-00' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (372 commits)
  mm: swap: check for stable address space before operating on the VMA
  mm: convert folio_page() back to a macro
  mm/khugepaged: use start_addr/addr for improved readability
  hugetlbfs: skip VMAs without shareable locks in hugetlb_vmdelete_list
  alloc_tag: fix boot failure due to NULL pointer dereference
  mm: silence data-race in update_hiwater_rss
  mm/memory-failure: don't select MEMORY_ISOLATION
  mm/khugepaged: remove definition of struct khugepaged_mm_slot
  mm/ksm: get mm_slot by mm_slot_entry() when slot is !NULL
  hugetlb: increase number of reserving hugepages via cmdline
  selftests/mm: add fork inheritance test for ksm_merging_pages counter
  mm/ksm: fix incorrect KSM counter handling in mm_struct during fork
  drivers/base/node: fix double free in register_one_node()
  mm: remove PMD alignment constraint in execmem_vmalloc()
  mm/memory_hotplug: fix typo 'esecially' -> 'especially'
  mm/rmap: improve mlock tracking for large folios
  mm/filemap: map entire large folio faultaround
  mm/fault: try to map the entire file folio in finish_fault()
  mm/rmap: mlock large folios in try_to_unmap_one()
  mm/rmap: fix a mlock race condition in folio_referenced_one()
  ...

64 files changed:
1  2 
Documentation/filesystems/proc.rst
MAINTAINERS
arch/arm64/Kconfig
arch/arm64/kernel/cpufeature.c
arch/arm64/mm/mmu.c
arch/loongarch/Kconfig
arch/powerpc/Kconfig
arch/powerpc/include/asm/kasan.h
arch/riscv/mm/init.c
arch/s390/Kconfig
arch/s390/mm/pgalloc.c
arch/x86/Kconfig
drivers/block/zram/zram_drv.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/i915/gem/i915_gem_pages.c
drivers/memstick/core/mspro_block.c
drivers/xen/gntdev.c
fs/Kconfig
fs/aio.c
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/coredump.c
fs/exec.c
fs/fuse/dev.c
fs/hugetlbfs/inode.c
fs/pidfs.c
fs/proc/array.c
fs/proc/task_mmu.c
include/linux/blkdev.h
include/linux/fs.h
include/linux/kasan.h
include/linux/maple_tree.h
include/linux/memcontrol.h
include/linux/mm_types.h
include/linux/slab.h
include/linux/writeback.h
io_uring/zcrx.c
kernel/events/uprobes.c
kernel/fork.c
kernel/sched/fair.c
lib/maple_tree.c
lib/test_maple_tree.c
mm/Kconfig
mm/backing-dev.c
mm/damon/sysfs.c
mm/hugetlb.c
mm/internal.h
mm/kasan/common.c
mm/memcontrol.c
mm/page_alloc.c
mm/pagewalk.c
mm/shmem.c
mm/slab.h
mm/slub.c
mm/vma_init.c
rust/helpers/helpers.c
rust/kernel/alloc.rs
rust/kernel/alloc/allocator.rs
rust/kernel/alloc/kbox.rs
rust/kernel/alloc/kvec.rs
rust/kernel/lib.rs
tools/testing/radix-tree/maple.c
tools/testing/selftests/kselftest.h
tools/testing/vma/vma_internal.h

Simple merge
diff --cc MAINTAINERS
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 36700384fe6bddf6320dcaef7284d14d501a4706,f56ee9aeac83e7d654880f85edc735e4a9dcc60b..76d92069799f589123aecfd23048836fcae8fda8
  #include <asm/pgalloc.h>
  #include <asm/tlbflush.h>
  
 -unsigned long *crst_table_alloc(struct mm_struct *mm)
 +unsigned long *crst_table_alloc_noprof(struct mm_struct *mm)
  {
 -      struct ptdesc *ptdesc = pagetable_alloc(GFP_KERNEL, CRST_ALLOC_ORDER);
 +      gfp_t gfp = GFP_KERNEL_ACCOUNT;
 +      struct ptdesc *ptdesc;
        unsigned long *table;
  
 +      if (mm == &init_mm)
 +              gfp &= ~__GFP_ACCOUNT;
 +      ptdesc = pagetable_alloc_noprof(gfp, CRST_ALLOC_ORDER);
        if (!ptdesc)
                return NULL;
-       table = ptdesc_to_virt(ptdesc);
+       table = ptdesc_address(ptdesc);
        __arch_set_page_dat(table, 1UL << CRST_ALLOC_ORDER);
        return table;
  }
@@@ -121,9 -117,9 +121,9 @@@ struct ptdesc *page_table_alloc_pgste_n
        struct ptdesc *ptdesc;
        u64 *table;
  
 -      ptdesc = pagetable_alloc(GFP_KERNEL, 0);
 +      ptdesc = pagetable_alloc_noprof(GFP_KERNEL_ACCOUNT, 0);
        if (ptdesc) {
-               table = (u64 *)ptdesc_to_virt(ptdesc);
+               table = (u64 *)ptdesc_address(ptdesc);
                __arch_set_page_dat(table, 1);
                memset64(table, _PAGE_INVALID, PTRS_PER_PTE);
                memset64(table + PTRS_PER_PTE, 0, PTRS_PER_PTE);
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc fs/Kconfig
Simple merge
diff --cc fs/aio.c
Simple merge
Simple merge
Simple merge
diff --cc fs/coredump.c
Simple merge
diff --cc fs/exec.c
Simple merge
diff --cc fs/fuse/dev.c
Simple merge
Simple merge
diff --cc fs/pidfs.c
Simple merge
diff --cc fs/proc/array.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 561597dd216496467d758515986a450b11952261,6dc300bac2a12f2c31855da204d791db2401e379..cf443f064a667e39d028e9bec75ac3bf59a46eee
@@@ -496,12 -465,15 +496,16 @@@ int kmem_cache_shrink(struct kmem_cach
  /*
   * Common kmalloc functions provided by all allocators
   */
- void * __must_check krealloc_noprof(const void *objp, size_t new_size,
-                                   gfp_t flags) __realloc_size(2);
- #define krealloc(...)                         alloc_hooks(krealloc_noprof(__VA_ARGS__))
+ void * __must_check krealloc_node_align_noprof(const void *objp, size_t new_size,
+                                              unsigned long align,
+                                              gfp_t flags, int nid) __realloc_size(2);
+ #define krealloc_noprof(_o, _s, _f)   krealloc_node_align_noprof(_o, _s, 1, _f, NUMA_NO_NODE)
+ #define krealloc_node_align(...)      alloc_hooks(krealloc_node_align_noprof(__VA_ARGS__))
+ #define krealloc_node(_o, _s, _f, _n) krealloc_node_align(_o, _s, 1, _f, _n)
+ #define krealloc(...)                 krealloc_node(__VA_ARGS__, NUMA_NO_NODE)
  
  void kfree(const void *objp);
 +void kfree_nolock(const void *objp);
  void kfree_sensitive(const void *objp);
  size_t __ksize(const void *objp);
  
Simple merge
diff --cc io_uring/zcrx.c
Simple merge
Simple merge
diff --cc kernel/fork.c
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc mm/Kconfig
Simple merge
Simple merge
Simple merge
diff --cc mm/hugetlb.c
Simple merge
diff --cc mm/internal.h
Simple merge
index 3264900b942f91d268a4d00869861266012c5b9c,e3765931a31fc253b274004bb080070437d7921f..d4c14359feaf9d8fb4e92374ee9f9569c41d3574
@@@ -252,9 -261,9 +261,9 @@@ bool __kasan_slab_pre_free(struct kmem_
  }
  
  bool __kasan_slab_free(struct kmem_cache *cache, void *object, bool init,
 -                     bool still_accessible)
 +                     bool still_accessible, bool no_quarantine)
  {
-       if (!kasan_arch_is_ready() || is_kfence_address(object))
+       if (is_kfence_address(object))
                return false;
  
        /*
diff --cc mm/memcontrol.c
Simple merge
diff --cc mm/page_alloc.c
Simple merge
diff --cc mm/pagewalk.c
Simple merge
diff --cc mm/shmem.c
Simple merge
diff --cc mm/slab.h
Simple merge
diff --cc mm/slub.c
index a585d0ac45d408a8d27e1c81d3106e094416e44b,9d73cca9f1de8b0235f78a4cdd7b6356920d74a5..584a5ff1828b163220f3fb64bad15424f7ae18f1
+++ b/mm/slub.c
@@@ -3011,672 -2937,741 +3013,672 @@@ static void barn_shrink(struct kmem_cac
  }
  
  /*
 - * Get a slab from somewhere. Search in increasing NUMA distances.
 + * Slab allocation and freeing
   */
 -static struct slab *get_any_partial(struct kmem_cache *s,
 -                                  struct partial_context *pc)
 +static inline struct slab *alloc_slab_page(gfp_t flags, int node,
 +                                         struct kmem_cache_order_objects oo,
 +                                         bool allow_spin)
  {
 -#ifdef CONFIG_NUMA
 -      struct zonelist *zonelist;
 -      struct zoneref *z;
 -      struct zone *zone;
 -      enum zone_type highest_zoneidx = gfp_zone(pc->flags);
 +      struct folio *folio;
        struct slab *slab;
 -      unsigned int cpuset_mems_cookie;
 -
 -      /*
 -       * The defrag ratio allows a configuration of the tradeoffs between
 -       * inter node defragmentation and node local allocations. A lower
 -       * defrag_ratio increases the tendency to do local allocations
 -       * instead of attempting to obtain partial slabs from other nodes.
 -       *
 -       * If the defrag_ratio is set to 0 then kmalloc() always
 -       * returns node local objects. If the ratio is higher then kmalloc()
 -       * may return off node objects because partial slabs are obtained
 -       * from other nodes and filled up.
 -       *
 -       * If /sys/kernel/slab/xx/remote_node_defrag_ratio is set to 100
 -       * (which makes defrag_ratio = 1000) then every (well almost)
 -       * allocation will first attempt to defrag slab caches on other nodes.
 -       * This means scanning over all nodes to look for partial slabs which
 -       * may be expensive if we do it every time we are trying to find a slab
 -       * with available objects.
 -       */
 -      if (!s->remote_node_defrag_ratio ||
 -                      get_cycles() % 1024 > s->remote_node_defrag_ratio)
 -              return NULL;
 +      unsigned int order = oo_order(oo);
  
 -      do {
 -              cpuset_mems_cookie = read_mems_allowed_begin();
 -              zonelist = node_zonelist(mempolicy_slab_node(), pc->flags);
 -              for_each_zone_zonelist(zone, z, zonelist, highest_zoneidx) {
 -                      struct kmem_cache_node *n;
 +      if (unlikely(!allow_spin))
 +              folio = (struct folio *)alloc_frozen_pages_nolock(0/* __GFP_COMP is implied */,
 +                                                                node, order);
 +      else if (node == NUMA_NO_NODE)
 +              folio = (struct folio *)alloc_frozen_pages(flags, order);
 +      else
 +              folio = (struct folio *)__alloc_frozen_pages(flags, order, node, NULL);
  
 -                      n = get_node(s, zone_to_nid(zone));
 +      if (!folio)
 +              return NULL;
  
 -                      if (n && cpuset_zone_allowed(zone, pc->flags) &&
 -                                      n->nr_partial > s->min_partial) {
 -                              slab = get_partial_node(s, n, pc);
 -                              if (slab) {
 -                                      /*
 -                                       * Don't check read_mems_allowed_retry()
 -                                       * here - if mems_allowed was updated in
 -                                       * parallel, that was a harmless race
 -                                       * between allocation and the cpuset
 -                                       * update
 -                                       */
 -                                      return slab;
 -                              }
 -                      }
 -              }
 -      } while (read_mems_allowed_retry(cpuset_mems_cookie));
 -#endif        /* CONFIG_NUMA */
 -      return NULL;
 +      slab = folio_slab(folio);
 +      __folio_set_slab(folio);
 +      if (folio_is_pfmemalloc(folio))
 +              slab_set_pfmemalloc(slab);
 +
 +      return slab;
  }
  
 -/*
 - * Get a partial slab, lock it and return it.
 - */
 -static struct slab *get_partial(struct kmem_cache *s, int node,
 -                              struct partial_context *pc)
 +#ifdef CONFIG_SLAB_FREELIST_RANDOM
 +/* Pre-initialize the random sequence cache */
 +static int init_cache_random_seq(struct kmem_cache *s)
  {
 -      struct slab *slab;
 -      int searchnode = node;
 +      unsigned int count = oo_objects(s->oo);
 +      int err;
  
 -      if (node == NUMA_NO_NODE)
 -              searchnode = numa_mem_id();
 +      /* Bailout if already initialised */
 +      if (s->random_seq)
 +              return 0;
  
 -      slab = get_partial_node(s, get_node(s, searchnode), pc);
 -      if (slab || (node != NUMA_NO_NODE && (pc->flags & __GFP_THISNODE)))
 -              return slab;
 +      err = cache_random_seq_create(s, count, GFP_KERNEL);
 +      if (err) {
 +              pr_err("SLUB: Unable to initialize free list for %s\n",
 +                      s->name);
 +              return err;
 +      }
  
 -      return get_any_partial(s, pc);
 +      /* Transform to an offset on the set of pages */
 +      if (s->random_seq) {
 +              unsigned int i;
 +
 +              for (i = 0; i < count; i++)
 +                      s->random_seq[i] *= s->size;
 +      }
 +      return 0;
  }
  
 -#ifndef CONFIG_SLUB_TINY
 +/* Initialize each random sequence freelist per cache */
 +static void __init init_freelist_randomization(void)
 +{
 +      struct kmem_cache *s;
  
 -#ifdef CONFIG_PREEMPTION
 -/*
 - * Calculate the next globally unique transaction for disambiguation
 - * during cmpxchg. The transactions start with the cpu number and are then
 - * incremented by CONFIG_NR_CPUS.
 - */
 -#define TID_STEP  roundup_pow_of_two(CONFIG_NR_CPUS)
 -#else
 -/*
 - * No preemption supported therefore also no need to check for
 - * different cpus.
 - */
 -#define TID_STEP 1
 -#endif /* CONFIG_PREEMPTION */
 +      mutex_lock(&slab_mutex);
  
 -static inline unsigned long next_tid(unsigned long tid)
 -{
 -      return tid + TID_STEP;
 -}
 +      list_for_each_entry(s, &slab_caches, list)
 +              init_cache_random_seq(s);
  
 -#ifdef SLUB_DEBUG_CMPXCHG
 -static inline unsigned int tid_to_cpu(unsigned long tid)
 -{
 -      return tid % TID_STEP;
 +      mutex_unlock(&slab_mutex);
  }
  
 -static inline unsigned long tid_to_event(unsigned long tid)
 +/* Get the next entry on the pre-computed freelist randomized */
 +static void *next_freelist_entry(struct kmem_cache *s,
 +                              unsigned long *pos, void *start,
 +                              unsigned long page_limit,
 +                              unsigned long freelist_count)
  {
 -      return tid / TID_STEP;
 -}
 -#endif
 +      unsigned int idx;
  
 -static inline unsigned int init_tid(int cpu)
 -{
 -      return cpu;
 +      /*
 +       * If the target page allocation failed, the number of objects on the
 +       * page might be smaller than the usual size defined by the cache.
 +       */
 +      do {
 +              idx = s->random_seq[*pos];
 +              *pos += 1;
 +              if (*pos >= freelist_count)
 +                      *pos = 0;
 +      } while (unlikely(idx >= page_limit));
 +
 +      return (char *)start + idx;
  }
  
 -static inline void note_cmpxchg_failure(const char *n,
 -              const struct kmem_cache *s, unsigned long tid)
 +/* Shuffle the single linked freelist based on a random pre-computed sequence */
 +static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab)
  {
 -#ifdef SLUB_DEBUG_CMPXCHG
 -      unsigned long actual_tid = __this_cpu_read(s->cpu_slab->tid);
 +      void *start;
 +      void *cur;
 +      void *next;
 +      unsigned long idx, pos, page_limit, freelist_count;
  
 -      pr_info("%s %s: cmpxchg redo ", n, s->name);
 +      if (slab->objects < 2 || !s->random_seq)
 +              return false;
  
 -#ifdef CONFIG_PREEMPTION
 -      if (tid_to_cpu(tid) != tid_to_cpu(actual_tid))
 -              pr_warn("due to cpu change %d -> %d\n",
 -                      tid_to_cpu(tid), tid_to_cpu(actual_tid));
 -      else
 -#endif
 -      if (tid_to_event(tid) != tid_to_event(actual_tid))
 -              pr_warn("due to cpu running other code. Event %ld->%ld\n",
 -                      tid_to_event(tid), tid_to_event(actual_tid));
 -      else
 -              pr_warn("for unknown reason: actual=%lx was=%lx target=%lx\n",
 -                      actual_tid, tid, next_tid(tid));
 -#endif
 -      stat(s, CMPXCHG_DOUBLE_CPU_FAIL);
 -}
 +      freelist_count = oo_objects(s->oo);
 +      pos = get_random_u32_below(freelist_count);
  
 -static void init_kmem_cache_cpus(struct kmem_cache *s)
 -{
 -      int cpu;
 -      struct kmem_cache_cpu *c;
 +      page_limit = slab->objects * s->size;
 +      start = fixup_red_left(s, slab_address(slab));
  
 -      for_each_possible_cpu(cpu) {
 -              c = per_cpu_ptr(s->cpu_slab, cpu);
 -              local_lock_init(&c->lock);
 -              c->tid = init_tid(cpu);
 +      /* First entry is used as the base of the freelist */
 +      cur = next_freelist_entry(s, &pos, start, page_limit, freelist_count);
 +      cur = setup_object(s, cur);
 +      slab->freelist = cur;
 +
 +      for (idx = 1; idx < slab->objects; idx++) {
 +              next = next_freelist_entry(s, &pos, start, page_limit,
 +                      freelist_count);
 +              next = setup_object(s, next);
 +              set_freepointer(s, cur, next);
 +              cur = next;
        }
 +      set_freepointer(s, cur, NULL);
 +
 +      return true;
 +}
 +#else
 +static inline int init_cache_random_seq(struct kmem_cache *s)
 +{
 +      return 0;
 +}
 +static inline void init_freelist_randomization(void) { }
 +static inline bool shuffle_freelist(struct kmem_cache *s, struct slab *slab)
 +{
 +      return false;
  }
 +#endif /* CONFIG_SLAB_FREELIST_RANDOM */
  
 -/*
 - * Finishes removing the cpu slab. Merges cpu's freelist with slab's freelist,
 - * unfreezes the slabs and puts it on the proper list.
 - * Assumes the slab has been already safely taken away from kmem_cache_cpu
 - * by the caller.
 - */
 -static void deactivate_slab(struct kmem_cache *s, struct slab *slab,
 -                          void *freelist)
 +static __always_inline void account_slab(struct slab *slab, int order,
 +                                       struct kmem_cache *s, gfp_t gfp)
  {
 -      struct kmem_cache_node *n = get_node(s, slab_nid(slab));
 -      int free_delta = 0;
 -      void *nextfree, *freelist_iter, *freelist_tail;
 -      int tail = DEACTIVATE_TO_HEAD;
 -      unsigned long flags = 0;
 -      struct slab new;
 -      struct slab old;
 +      if (memcg_kmem_online() && (s->flags & SLAB_ACCOUNT))
 +              alloc_slab_obj_exts(slab, s, gfp, true);
  
 -      if (READ_ONCE(slab->freelist)) {
 -              stat(s, DEACTIVATE_REMOTE_FREES);
 -              tail = DEACTIVATE_TO_TAIL;
 -      }
 +      mod_node_page_state(slab_pgdat(slab), cache_vmstat_idx(s),
 +                          PAGE_SIZE << order);
 +}
  
 +static __always_inline void unaccount_slab(struct slab *slab, int order,
 +                                         struct kmem_cache *s)
 +{
        /*
 -       * Stage one: Count the objects on cpu's freelist as free_delta and
 -       * remember the last object in freelist_tail for later splicing.
 +       * The slab object extensions should now be freed regardless of
 +       * whether mem_alloc_profiling_enabled() or not because profiling
 +       * might have been disabled after slab->obj_exts got allocated.
         */
 -      freelist_tail = NULL;
 -      freelist_iter = freelist;
 -      while (freelist_iter) {
 -              nextfree = get_freepointer(s, freelist_iter);
 +      free_slab_obj_exts(slab);
  
 -              /*
 -               * If 'nextfree' is invalid, it is possible that the object at
 -               * 'freelist_iter' is already corrupted.  So isolate all objects
 -               * starting at 'freelist_iter' by skipping them.
 -               */
 -              if (freelist_corrupted(s, slab, &freelist_iter, nextfree))
 -                      break;
 +      mod_node_page_state(slab_pgdat(slab), cache_vmstat_idx(s),
 +                          -(PAGE_SIZE << order));
 +}
  
 -              freelist_tail = freelist_iter;
 -              free_delta++;
 +static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
 +{
 +      bool allow_spin = gfpflags_allow_spinning(flags);
 +      struct slab *slab;
 +      struct kmem_cache_order_objects oo = s->oo;
 +      gfp_t alloc_gfp;
 +      void *start, *p, *next;
 +      int idx;
 +      bool shuffle;
  
 -              freelist_iter = nextfree;
 -      }
 +      flags &= gfp_allowed_mask;
 +
 +      flags |= s->allocflags;
  
        /*
 -       * Stage two: Unfreeze the slab while splicing the per-cpu
 -       * freelist to the head of slab's freelist.
 +       * Let the initial higher-order allocation fail under memory pressure
 +       * so we fall-back to the minimum order allocation.
         */
 -      do {
 -              old.freelist = READ_ONCE(slab->freelist);
 -              old.counters = READ_ONCE(slab->counters);
 -              VM_BUG_ON(!old.frozen);
 -
 -              /* Determine target state of the slab */
 -              new.counters = old.counters;
 -              new.frozen = 0;
 -              if (freelist_tail) {
 -                      new.inuse -= free_delta;
 -                      set_freepointer(s, freelist_tail, old.freelist);
 -                      new.freelist = freelist;
 -              } else {
 -                      new.freelist = old.freelist;
 -              }
 -      } while (!slab_update_freelist(s, slab,
 -              old.freelist, old.counters,
 -              new.freelist, new.counters,
 -              "unfreezing slab"));
 +      alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL;
 +      if ((alloc_gfp & __GFP_DIRECT_RECLAIM) && oo_order(oo) > oo_order(s->min))
 +              alloc_gfp = (alloc_gfp | __GFP_NOMEMALLOC) & ~__GFP_RECLAIM;
  
        /*
 -       * Stage three: Manipulate the slab list based on the updated state.
 +       * __GFP_RECLAIM could be cleared on the first allocation attempt,
 +       * so pass allow_spin flag directly.
         */
 -      if (!new.inuse && n->nr_partial >= s->min_partial) {
 -              stat(s, DEACTIVATE_EMPTY);
 -              discard_slab(s, slab);
 -              stat(s, FREE_SLAB);
 -      } else if (new.freelist) {
 -              spin_lock_irqsave(&n->list_lock, flags);
 -              add_partial(n, slab, tail);
 -              spin_unlock_irqrestore(&n->list_lock, flags);
 -              stat(s, tail);
 -      } else {
 -              stat(s, DEACTIVATE_FULL);
 +      slab = alloc_slab_page(alloc_gfp, node, oo, allow_spin);
 +      if (unlikely(!slab)) {
 +              oo = s->min;
 +              alloc_gfp = flags;
 +              /*
 +               * Allocation may have failed due to fragmentation.
 +               * Try a lower order alloc if possible
 +               */
 +              slab = alloc_slab_page(alloc_gfp, node, oo, allow_spin);
 +              if (unlikely(!slab))
 +                      return NULL;
 +              stat(s, ORDER_FALLBACK);
        }
 -}
  
 -#ifdef CONFIG_SLUB_CPU_PARTIAL
 -static void __put_partials(struct kmem_cache *s, struct slab *partial_slab)
 -{
 -      struct kmem_cache_node *n = NULL, *n2 = NULL;
 -      struct slab *slab, *slab_to_discard = NULL;
 -      unsigned long flags = 0;
 +      slab->objects = oo_objects(oo);
 +      slab->inuse = 0;
 +      slab->frozen = 0;
 +      init_slab_obj_exts(slab);
  
 -      while (partial_slab) {
 -              slab = partial_slab;
 -              partial_slab = slab->next;
 +      account_slab(slab, oo_order(oo), s, flags);
  
 -              n2 = get_node(s, slab_nid(slab));
 -              if (n != n2) {
 -                      if (n)
 -                              spin_unlock_irqrestore(&n->list_lock, flags);
 +      slab->slab_cache = s;
  
 -                      n = n2;
 -                      spin_lock_irqsave(&n->list_lock, flags);
 -              }
 +      kasan_poison_slab(slab);
  
 -              if (unlikely(!slab->inuse && n->nr_partial >= s->min_partial)) {
 -                      slab->next = slab_to_discard;
 -                      slab_to_discard = slab;
 -              } else {
 -                      add_partial(n, slab, DEACTIVATE_TO_TAIL);
 -                      stat(s, FREE_ADD_PARTIAL);
 -              }
 -      }
 +      start = slab_address(slab);
  
 -      if (n)
 -              spin_unlock_irqrestore(&n->list_lock, flags);
 +      setup_slab_debug(s, slab, start);
  
 -      while (slab_to_discard) {
 -              slab = slab_to_discard;
 -              slab_to_discard = slab_to_discard->next;
 +      shuffle = shuffle_freelist(s, slab);
  
 -              stat(s, DEACTIVATE_EMPTY);
 -              discard_slab(s, slab);
 -              stat(s, FREE_SLAB);
 +      if (!shuffle) {
 +              start = fixup_red_left(s, start);
 +              start = setup_object(s, start);
 +              slab->freelist = start;
 +              for (idx = 0, p = start; idx < slab->objects - 1; idx++) {
 +                      next = p + s->size;
 +                      next = setup_object(s, next);
 +                      set_freepointer(s, p, next);
 +                      p = next;
 +              }
 +              set_freepointer(s, p, NULL);
        }
 +
 +      return slab;
  }
  
 -/*
 - * Put all the cpu partial slabs to the node partial list.
 - */
 -static void put_partials(struct kmem_cache *s)
 +static struct slab *new_slab(struct kmem_cache *s, gfp_t flags, int node)
  {
 -      struct slab *partial_slab;
 -      unsigned long flags;
 +      if (unlikely(flags & GFP_SLAB_BUG_MASK))
 +              flags = kmalloc_fix_flags(flags);
  
 -      local_lock_irqsave(&s->cpu_slab->lock, flags);
 -      partial_slab = this_cpu_read(s->cpu_slab->partial);
 -      this_cpu_write(s->cpu_slab->partial, NULL);
 -      local_unlock_irqrestore(&s->cpu_slab->lock, flags);
 +      WARN_ON_ONCE(s->ctor && (flags & __GFP_ZERO));
  
 -      if (partial_slab)
 -              __put_partials(s, partial_slab);
 +      return allocate_slab(s,
 +              flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
  }
  
 -static void put_partials_cpu(struct kmem_cache *s,
 -                           struct kmem_cache_cpu *c)
 +static void __free_slab(struct kmem_cache *s, struct slab *slab)
  {
 -      struct slab *partial_slab;
 -
 -      partial_slab = slub_percpu_partial(c);
 -      c->partial = NULL;
 +      struct folio *folio = slab_folio(slab);
 +      int order = folio_order(folio);
 +      int pages = 1 << order;
  
 -      if (partial_slab)
 -              __put_partials(s, partial_slab);
 +      __slab_clear_pfmemalloc(slab);
 +      folio->mapping = NULL;
 +      __folio_clear_slab(folio);
 +      mm_account_reclaimed_pages(pages);
 +      unaccount_slab(slab, order, s);
 +      free_frozen_pages(&folio->page, order);
  }
  
 -/*
 - * Put a slab into a partial slab slot if available.
 - *
 - * If we did not find a slot then simply move all the partials to the
 - * per node partial list.
 - */
 -static void put_cpu_partial(struct kmem_cache *s, struct slab *slab, int drain)
 +static void rcu_free_slab(struct rcu_head *h)
  {
 -      struct slab *oldslab;
 -      struct slab *slab_to_put = NULL;
 -      unsigned long flags;
 -      int slabs = 0;
 +      struct slab *slab = container_of(h, struct slab, rcu_head);
  
 -      local_lock_irqsave(&s->cpu_slab->lock, flags);
 +      __free_slab(slab->slab_cache, slab);
 +}
  
 -      oldslab = this_cpu_read(s->cpu_slab->partial);
 +static void free_slab(struct kmem_cache *s, struct slab *slab)
 +{
 +      if (kmem_cache_debug_flags(s, SLAB_CONSISTENCY_CHECKS)) {
 +              void *p;
  
 -      if (oldslab) {
 -              if (drain && oldslab->slabs >= s->cpu_partial_slabs) {
 -                      /*
 -                       * Partial array is full. Move the existing set to the
 -                       * per node partial list. Postpone the actual unfreezing
 -                       * outside of the critical section.
 -                       */
 -                      slab_to_put = oldslab;
 -                      oldslab = NULL;
 -              } else {
 -                      slabs = oldslab->slabs;
 -              }
 +              slab_pad_check(s, slab);
 +              for_each_object(p, s, slab_address(slab), slab->objects)
 +                      check_object(s, slab, p, SLUB_RED_INACTIVE);
        }
  
 -      slabs++;
 -
 -      slab->slabs = slabs;
 -      slab->next = oldslab;
 -
 -      this_cpu_write(s->cpu_slab->partial, slab);
 -
 -      local_unlock_irqrestore(&s->cpu_slab->lock, flags);
 -
 -      if (slab_to_put) {
 -              __put_partials(s, slab_to_put);
 -              stat(s, CPU_PARTIAL_DRAIN);
 -      }
 +      if (unlikely(s->flags & SLAB_TYPESAFE_BY_RCU))
 +              call_rcu(&slab->rcu_head, rcu_free_slab);
 +      else
 +              __free_slab(s, slab);
  }
  
 -#else /* CONFIG_SLUB_CPU_PARTIAL */
 -
 -static inline void put_partials(struct kmem_cache *s) { }
 -static inline void put_partials_cpu(struct kmem_cache *s,
 -                                  struct kmem_cache_cpu *c) { }
 -
 -#endif        /* CONFIG_SLUB_CPU_PARTIAL */
 -
 -static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
 +static void discard_slab(struct kmem_cache *s, struct slab *slab)
  {
 -      unsigned long flags;
 -      struct slab *slab;
 -      void *freelist;
 -
 -      local_lock_irqsave(&s->cpu_slab->lock, flags);
 -
 -      slab = c->slab;
 -      freelist = c->freelist;
 -
 -      c->slab = NULL;
 -      c->freelist = NULL;
 -      c->tid = next_tid(c->tid);
 -
 -      local_unlock_irqrestore(&s->cpu_slab->lock, flags);
 -
 -      if (slab) {
 -              deactivate_slab(s, slab, freelist);
 -              stat(s, CPUSLAB_FLUSH);
 -      }
 +      dec_slabs_node(s, slab_nid(slab), slab->objects);
 +      free_slab(s, slab);
  }
  
 -static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
 +static inline bool slab_test_node_partial(const struct slab *slab)
  {
-       return test_bit(SL_partial, &slab->flags);
 -      struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
 -      void *freelist = c->freelist;
 -      struct slab *slab = c->slab;
 -
 -      c->slab = NULL;
 -      c->freelist = NULL;
 -      c->tid = next_tid(c->tid);
 -
 -      if (slab) {
 -              deactivate_slab(s, slab, freelist);
 -              stat(s, CPUSLAB_FLUSH);
 -      }
++      return test_bit(SL_partial, &slab->flags.f);
 +}
  
 -      put_partials_cpu(s, c);
 +static inline void slab_set_node_partial(struct slab *slab)
 +{
-       set_bit(SL_partial, &slab->flags);
++      set_bit(SL_partial, &slab->flags.f);
  }
  
 -struct slub_flush_work {
 -      struct work_struct work;
 -      struct kmem_cache *s;
 -      bool skip;
 -};
 +static inline void slab_clear_node_partial(struct slab *slab)
 +{
-       clear_bit(SL_partial, &slab->flags);
++      clear_bit(SL_partial, &slab->flags.f);
 +}
  
  /*
 - * Flush cpu slab.
 - *
 - * Called from CPU work handler with migration disabled.
 + * Management of partially allocated slabs.
   */
 -static void flush_cpu_slab(struct work_struct *w)
 +static inline void
 +__add_partial(struct kmem_cache_node *n, struct slab *slab, int tail)
  {
 -      struct kmem_cache *s;
 -      struct kmem_cache_cpu *c;
 -      struct slub_flush_work *sfw;
 -
 -      sfw = container_of(w, struct slub_flush_work, work);
 -
 -      s = sfw->s;
 -      c = this_cpu_ptr(s->cpu_slab);
 -
 -      if (c->slab)
 -              flush_slab(s, c);
 -
 -      put_partials(s);
 +      n->nr_partial++;
 +      if (tail == DEACTIVATE_TO_TAIL)
 +              list_add_tail(&slab->slab_list, &n->partial);
 +      else
 +              list_add(&slab->slab_list, &n->partial);
 +      slab_set_node_partial(slab);
  }
  
 -static bool has_cpu_slab(int cpu, struct kmem_cache *s)
 +static inline void add_partial(struct kmem_cache_node *n,
 +                              struct slab *slab, int tail)
  {
 -      struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
 -
 -      return c->slab || slub_percpu_partial(c);
 +      lockdep_assert_held(&n->list_lock);
 +      __add_partial(n, slab, tail);
  }
  
 -static DEFINE_MUTEX(flush_lock);
 -static DEFINE_PER_CPU(struct slub_flush_work, slub_flush);
 +static inline void remove_partial(struct kmem_cache_node *n,
 +                                      struct slab *slab)
 +{
 +      lockdep_assert_held(&n->list_lock);
 +      list_del(&slab->slab_list);
 +      slab_clear_node_partial(slab);
 +      n->nr_partial--;
 +}
  
 -static void flush_all_cpus_locked(struct kmem_cache *s)
 +/*
 + * Called only for kmem_cache_debug() caches instead of remove_partial(), with a
 + * slab from the n->partial list. Remove only a single object from the slab, do
 + * the alloc_debug_processing() checks and leave the slab on the list, or move
 + * it to full list if it was the last free object.
 + */
 +static void *alloc_single_from_partial(struct kmem_cache *s,
 +              struct kmem_cache_node *n, struct slab *slab, int orig_size)
  {
 -      struct slub_flush_work *sfw;
 -      unsigned int cpu;
 +      void *object;
  
 -      lockdep_assert_cpus_held();
 -      mutex_lock(&flush_lock);
 +      lockdep_assert_held(&n->list_lock);
  
 -      for_each_online_cpu(cpu) {
 -              sfw = &per_cpu(slub_flush, cpu);
 -              if (!has_cpu_slab(cpu, s)) {
 -                      sfw->skip = true;
 -                      continue;
 +#ifdef CONFIG_SLUB_DEBUG
 +      if (s->flags & SLAB_CONSISTENCY_CHECKS) {
 +              if (!validate_slab_ptr(slab)) {
 +                      slab_err(s, slab, "Not a valid slab page");
 +                      return NULL;
                }
 -              INIT_WORK(&sfw->work, flush_cpu_slab);
 -              sfw->skip = false;
 -              sfw->s = s;
 -              queue_work_on(cpu, flushwq, &sfw->work);
        }
 +#endif
  
 -      for_each_online_cpu(cpu) {
 -              sfw = &per_cpu(slub_flush, cpu);
 -              if (sfw->skip)
 -                      continue;
 -              flush_work(&sfw->work);
 +      object = slab->freelist;
 +      slab->freelist = get_freepointer(s, object);
 +      slab->inuse++;
 +
 +      if (!alloc_debug_processing(s, slab, object, orig_size)) {
 +              remove_partial(n, slab);
 +              return NULL;
        }
  
 -      mutex_unlock(&flush_lock);
 -}
 +      if (slab->inuse == slab->objects) {
 +              remove_partial(n, slab);
 +              add_full(s, n, slab);
 +      }
  
 -static void flush_all(struct kmem_cache *s)
 -{
 -      cpus_read_lock();
 -      flush_all_cpus_locked(s);
 -      cpus_read_unlock();
 +      return object;
  }
  
 +static void defer_deactivate_slab(struct slab *slab, void *flush_freelist);
 +
  /*
 - * Use the cpu notifier to insure that the cpu slabs are flushed when
 - * necessary.
 + * Called only for kmem_cache_debug() caches to allocate from a freshly
 + * allocated slab. Allocate a single object instead of whole freelist
 + * and put the slab to the partial (or full) list.
   */
 -static int slub_cpu_dead(unsigned int cpu)
 +static void *alloc_single_from_new_slab(struct kmem_cache *s, struct slab *slab,
 +                                      int orig_size, gfp_t gfpflags)
  {
 -      struct kmem_cache *s;
 -
 -      mutex_lock(&slab_mutex);
 -      list_for_each_entry(s, &slab_caches, list)
 -              __flush_cpu_slab(s, cpu);
 -      mutex_unlock(&slab_mutex);
 -      return 0;
 -}
 +      bool allow_spin = gfpflags_allow_spinning(gfpflags);
 +      int nid = slab_nid(slab);
 +      struct kmem_cache_node *n = get_node(s, nid);
 +      unsigned long flags;
 +      void *object;
  
 -#else /* CONFIG_SLUB_TINY */
 -static inline void flush_all_cpus_locked(struct kmem_cache *s) { }
 -static inline void flush_all(struct kmem_cache *s) { }
 -static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu) { }
 -static inline int slub_cpu_dead(unsigned int cpu) { return 0; }
 -#endif /* CONFIG_SLUB_TINY */
 +      if (!allow_spin && !spin_trylock_irqsave(&n->list_lock, flags)) {
 +              /* Unlucky, discard newly allocated slab */
 +              slab->frozen = 1;
 +              defer_deactivate_slab(slab, NULL);
 +              return NULL;
 +      }
  
 -/*
 - * Check if the objects in a per cpu structure fit numa
 - * locality expectations.
 - */
 -static inline int node_match(struct slab *slab, int node)
 -{
 -#ifdef CONFIG_NUMA
 -      if (node != NUMA_NO_NODE && slab_nid(slab) != node)
 -              return 0;
 -#endif
 -      return 1;
 -}
 +      object = slab->freelist;
 +      slab->freelist = get_freepointer(s, object);
 +      slab->inuse = 1;
  
 -#ifdef CONFIG_SLUB_DEBUG
 -static int count_free(struct slab *slab)
 -{
 -      return slab->objects - slab->inuse;
 -}
 +      if (!alloc_debug_processing(s, slab, object, orig_size)) {
 +              /*
 +               * It's not really expected that this would fail on a
 +               * freshly allocated slab, but a concurrent memory
 +               * corruption in theory could cause that.
 +               * Leak memory of allocated slab.
 +               */
 +              if (!allow_spin)
 +                      spin_unlock_irqrestore(&n->list_lock, flags);
 +              return NULL;
 +      }
  
 -static inline unsigned long node_nr_objs(struct kmem_cache_node *n)
 -{
 -      return atomic_long_read(&n->total_objects);
 -}
 +      if (allow_spin)
 +              spin_lock_irqsave(&n->list_lock, flags);
  
 -/* Supports checking bulk free of a constructed freelist */
 -static inline bool free_debug_processing(struct kmem_cache *s,
 -      struct slab *slab, void *head, void *tail, int *bulk_cnt,
 -      unsigned long addr, depot_stack_handle_t handle)
 -{
 -      bool checks_ok = false;
 -      void *object = head;
 -      int cnt = 0;
 +      if (slab->inuse == slab->objects)
 +              add_full(s, n, slab);
 +      else
 +              add_partial(n, slab, DEACTIVATE_TO_HEAD);
  
 -      if (s->flags & SLAB_CONSISTENCY_CHECKS) {
 -              if (!check_slab(s, slab))
 -                      goto out;
 -      }
 +      inc_slabs_node(s, nid, slab->objects);
 +      spin_unlock_irqrestore(&n->list_lock, flags);
  
 -      if (slab->inuse < *bulk_cnt) {
 -              slab_err(s, slab, "Slab has %d allocated objects but %d are to be freed\n",
 -                       slab->inuse, *bulk_cnt);
 -              goto out;
 -      }
 +      return object;
 +}
  
 -next_object:
 +#ifdef CONFIG_SLUB_CPU_PARTIAL
 +static void put_cpu_partial(struct kmem_cache *s, struct slab *slab, int drain);
 +#else
 +static inline void put_cpu_partial(struct kmem_cache *s, struct slab *slab,
 +                                 int drain) { }
 +#endif
 +static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags);
  
 -      if (++cnt > *bulk_cnt)
 -              goto out_cnt;
 +/*
 + * Try to allocate a partial slab from a specific node.
 + */
 +static struct slab *get_partial_node(struct kmem_cache *s,
 +                                   struct kmem_cache_node *n,
 +                                   struct partial_context *pc)
 +{
 +      struct slab *slab, *slab2, *partial = NULL;
 +      unsigned long flags;
 +      unsigned int partial_slabs = 0;
  
 -      if (s->flags & SLAB_CONSISTENCY_CHECKS) {
 -              if (!free_consistency_checks(s, slab, object, addr))
 -                      goto out;
 -      }
 +      /*
 +       * Racy check. If we mistakenly see no partial slabs then we
 +       * just allocate an empty slab. If we mistakenly try to get a
 +       * partial slab and there is none available then get_partial()
 +       * will return NULL.
 +       */
 +      if (!n || !n->nr_partial)
 +              return NULL;
  
 -      if (s->flags & SLAB_STORE_USER)
 -              set_track_update(s, object, TRACK_FREE, addr, handle);
 -      trace(s, slab, object, 0);
 -      /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */
 -      init_object(s, object, SLUB_RED_INACTIVE);
 +      if (gfpflags_allow_spinning(pc->flags))
 +              spin_lock_irqsave(&n->list_lock, flags);
 +      else if (!spin_trylock_irqsave(&n->list_lock, flags))
 +              return NULL;
 +      list_for_each_entry_safe(slab, slab2, &n->partial, slab_list) {
 +              if (!pfmemalloc_match(slab, pc->flags))
 +                      continue;
  
 -      /* Reached end of constructed freelist yet? */
 -      if (object != tail) {
 -              object = get_freepointer(s, object);
 -              goto next_object;
 -      }
 -      checks_ok = true;
 +              if (IS_ENABLED(CONFIG_SLUB_TINY) || kmem_cache_debug(s)) {
 +                      void *object = alloc_single_from_partial(s, n, slab,
 +                                                      pc->orig_size);
 +                      if (object) {
 +                              partial = slab;
 +                              pc->object = object;
 +                              break;
 +                      }
 +                      continue;
 +              }
  
 -out_cnt:
 -      if (cnt != *bulk_cnt) {
 -              slab_err(s, slab, "Bulk free expected %d objects but found %d\n",
 -                       *bulk_cnt, cnt);
 -              *bulk_cnt = cnt;
 -      }
 +              remove_partial(n, slab);
  
 -out:
 +              if (!partial) {
 +                      partial = slab;
 +                      stat(s, ALLOC_FROM_PARTIAL);
  
 -      if (!checks_ok)
 -              slab_fix(s, "Object at 0x%p not freed", object);
 +                      if ((slub_get_cpu_partial(s) == 0)) {
 +                              break;
 +                      }
 +              } else {
 +                      put_cpu_partial(s, slab, 0);
 +                      stat(s, CPU_PARTIAL_NODE);
  
 -      return checks_ok;
 +                      if (++partial_slabs > slub_get_cpu_partial(s) / 2) {
 +                              break;
 +                      }
 +              }
 +      }
 +      spin_unlock_irqrestore(&n->list_lock, flags);
 +      return partial;
  }
 -#endif /* CONFIG_SLUB_DEBUG */
  
 -#if defined(CONFIG_SLUB_DEBUG) || defined(SLAB_SUPPORTS_SYSFS)
 -static unsigned long count_partial(struct kmem_cache_node *n,
 -                                      int (*get_count)(struct slab *))
 +/*
 + * Get a slab from somewhere. Search in increasing NUMA distances.
 + */
 +static struct slab *get_any_partial(struct kmem_cache *s,
 +                                  struct partial_context *pc)
  {
 -      unsigned long flags;
 -      unsigned long x = 0;
 +#ifdef CONFIG_NUMA
 +      struct zonelist *zonelist;
 +      struct zoneref *z;
 +      struct zone *zone;
 +      enum zone_type highest_zoneidx = gfp_zone(pc->flags);
        struct slab *slab;
 +      unsigned int cpuset_mems_cookie;
  
 -      spin_lock_irqsave(&n->list_lock, flags);
 -      list_for_each_entry(slab, &n->partial, slab_list)
 -              x += get_count(slab);
 -      spin_unlock_irqrestore(&n->list_lock, flags);
 -      return x;
 -}
 -#endif /* CONFIG_SLUB_DEBUG || SLAB_SUPPORTS_SYSFS */
 -
 -#ifdef CONFIG_SLUB_DEBUG
 -#define MAX_PARTIAL_TO_SCAN 10000
 +      /*
 +       * The defrag ratio allows a configuration of the tradeoffs between
 +       * inter node defragmentation and node local allocations. A lower
 +       * defrag_ratio increases the tendency to do local allocations
 +       * instead of attempting to obtain partial slabs from other nodes.
 +       *
 +       * If the defrag_ratio is set to 0 then kmalloc() always
 +       * returns node local objects. If the ratio is higher then kmalloc()
 +       * may return off node objects because partial slabs are obtained
 +       * from other nodes and filled up.
 +       *
 +       * If /sys/kernel/slab/xx/remote_node_defrag_ratio is set to 100
 +       * (which makes defrag_ratio = 1000) then every (well almost)
 +       * allocation will first attempt to defrag slab caches on other nodes.
 +       * This means scanning over all nodes to look for partial slabs which
 +       * may be expensive if we do it every time we are trying to find a slab
 +       * with available objects.
 +       */
 +      if (!s->remote_node_defrag_ratio ||
 +                      get_cycles() % 1024 > s->remote_node_defrag_ratio)
 +              return NULL;
  
 -static unsigned long count_partial_free_approx(struct kmem_cache_node *n)
 -{
 -      unsigned long flags;
 -      unsigned long x = 0;
 -      struct slab *slab;
 +      do {
 +              cpuset_mems_cookie = read_mems_allowed_begin();
 +              zonelist = node_zonelist(mempolicy_slab_node(), pc->flags);
 +              for_each_zone_zonelist(zone, z, zonelist, highest_zoneidx) {
 +                      struct kmem_cache_node *n;
  
 -      spin_lock_irqsave(&n->list_lock, flags);
 -      if (n->nr_partial <= MAX_PARTIAL_TO_SCAN) {
 -              list_for_each_entry(slab, &n->partial, slab_list)
 -                      x += slab->objects - slab->inuse;
 -      } else {
 -              /*
 -               * For a long list, approximate the total count of objects in
 -               * it to meet the limit on the number of slabs to scan.
 -               * Scan from both the list's head and tail for better accuracy.
 -               */
 -              unsigned long scanned = 0;
 +                      n = get_node(s, zone_to_nid(zone));
  
 -              list_for_each_entry(slab, &n->partial, slab_list) {
 -                      x += slab->objects - slab->inuse;
 -                      if (++scanned == MAX_PARTIAL_TO_SCAN / 2)
 -                              break;
 -              }
 -              list_for_each_entry_reverse(slab, &n->partial, slab_list) {
 -                      x += slab->objects - slab->inuse;
 -                      if (++scanned == MAX_PARTIAL_TO_SCAN)
 -                              break;
 +                      if (n && cpuset_zone_allowed(zone, pc->flags) &&
 +                                      n->nr_partial > s->min_partial) {
 +                              slab = get_partial_node(s, n, pc);
 +                              if (slab) {
 +                                      /*
 +                                       * Don't check read_mems_allowed_retry()
 +                                       * here - if mems_allowed was updated in
 +                                       * parallel, that was a harmless race
 +                                       * between allocation and the cpuset
 +                                       * update
 +                                       */
 +                                      return slab;
 +                              }
 +                      }
                }
 -              x = mult_frac(x, n->nr_partial, scanned);
 -              x = min(x, node_nr_objs(n));
 -      }
 -      spin_unlock_irqrestore(&n->list_lock, flags);
 -      return x;
 +      } while (read_mems_allowed_retry(cpuset_mems_cookie));
 +#endif        /* CONFIG_NUMA */
 +      return NULL;
  }
  
 -static noinline void
 -slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
 +/*
 + * Get a partial slab, lock it and return it.
 + */
 +static struct slab *get_partial(struct kmem_cache *s, int node,
 +                              struct partial_context *pc)
  {
 -      static DEFINE_RATELIMIT_STATE(slub_oom_rs, DEFAULT_RATELIMIT_INTERVAL,
 -                                    DEFAULT_RATELIMIT_BURST);
 -      int cpu = raw_smp_processor_id();
 -      int node;
 -      struct kmem_cache_node *n;
 +      struct slab *slab;
 +      int searchnode = node;
  
 -      if ((gfpflags & __GFP_NOWARN) || !__ratelimit(&slub_oom_rs))
 -              return;
 +      if (node == NUMA_NO_NODE)
 +              searchnode = numa_mem_id();
  
 -      pr_warn("SLUB: Unable to allocate memory on CPU %u (of node %d) on node %d, gfp=%#x(%pGg)\n",
 -              cpu, cpu_to_node(cpu), nid, gfpflags, &gfpflags);
 -      pr_warn("  cache: %s, object size: %u, buffer size: %u, default order: %u, min order: %u\n",
 -              s->name, s->object_size, s->size, oo_order(s->oo),
 -              oo_order(s->min));
 +      slab = get_partial_node(s, get_node(s, searchnode), pc);
 +      if (slab || (node != NUMA_NO_NODE && (pc->flags & __GFP_THISNODE)))
 +              return slab;
  
 -      if (oo_order(s->min) > get_order(s->object_size))
 -              pr_warn("  %s debugging increased min order, use slab_debug=O to disable.\n",
 -                      s->name);
 +      return get_any_partial(s, pc);
 +}
  
 -      for_each_kmem_cache_node(s, node, n) {
 -              unsigned long nr_slabs;
 -              unsigned long nr_objs;
 -              unsigned long nr_free;
 +#ifndef CONFIG_SLUB_TINY
  
 -              nr_free  = count_partial_free_approx(n);
 -              nr_slabs = node_nr_slabs(n);
 -              nr_objs  = node_nr_objs(n);
 +#ifdef CONFIG_PREEMPTION
 +/*
 + * Calculate the next globally unique transaction for disambiguation
 + * during cmpxchg. The transactions start with the cpu number and are then
 + * incremented by CONFIG_NR_CPUS.
 + */
 +#define TID_STEP  roundup_pow_of_two(CONFIG_NR_CPUS)
 +#else
 +/*
 + * No preemption supported therefore also no need to check for
 + * different cpus.
 + */
 +#define TID_STEP 1
 +#endif /* CONFIG_PREEMPTION */
  
 -              pr_warn("  node %d: slabs: %ld, objs: %ld, free: %ld\n",
 -                      node, nr_slabs, nr_objs, nr_free);
 -      }
 +static inline unsigned long next_tid(unsigned long tid)
 +{
 +      return tid + TID_STEP;
  }
 -#else /* CONFIG_SLUB_DEBUG */
 -static inline void
 -slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid) { }
 -#endif
  
 -static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags)
 +#ifdef SLUB_DEBUG_CMPXCHG
 +static inline unsigned int tid_to_cpu(unsigned long tid)
  {
 -      if (unlikely(slab_test_pfmemalloc(slab)))
 -              return gfp_pfmemalloc_allowed(gfpflags);
 -
 -      return true;
 +      return tid % TID_STEP;
  }
  
 -#ifndef CONFIG_SLUB_TINY
 -static inline bool
 -__update_cpu_freelist_fast(struct kmem_cache *s,
 -                         void *freelist_old, void *freelist_new,
 -                         unsigned long tid)
 +static inline unsigned long tid_to_event(unsigned long tid)
  {
 -      freelist_aba_t old = { .freelist = freelist_old, .counter = tid };
 -      freelist_aba_t new = { .freelist = freelist_new, .counter = next_tid(tid) };
 -
 -      return this_cpu_try_cmpxchg_freelist(s->cpu_slab->freelist_tid.full,
 -                                           &old.full, new.full);
 +      return tid / TID_STEP;
  }
 +#endif
  
 -/*
 - * Check the slab->freelist and either transfer the freelist to the
 - * per cpu freelist or deactivate the slab.
 - *
 - * The slab is still frozen if the return value is not NULL.
 - *
 - * If this function returns NULL then the slab has been unfrozen.
 - */
 -static inline void *get_freelist(struct kmem_cache *s, struct slab *slab)
 +static inline unsigned int init_tid(int cpu)
  {
 -      struct slab new;
 -      unsigned long counters;
 -      void *freelist;
 -
 -      lockdep_assert_held(this_cpu_ptr(&s->cpu_slab->lock));
 +      return cpu;
 +}
  
 -      do {
 -              freelist = slab->freelist;
 -              counters = slab->counters;
 +static inline void note_cmpxchg_failure(const char *n,
 +              const struct kmem_cache *s, unsigned long tid)
 +{
 +#ifdef SLUB_DEBUG_CMPXCHG
 +      unsigned long actual_tid = __this_cpu_read(s->cpu_slab->tid);
  
 -              new.counters = counters;
 +      pr_info("%s %s: cmpxchg redo ", n, s->name);
  
 -              new.inuse = slab->objects;
 -              new.frozen = freelist != NULL;
 +      if (IS_ENABLED(CONFIG_PREEMPTION) &&
 +          tid_to_cpu(tid) != tid_to_cpu(actual_tid)) {
 +              pr_warn("due to cpu change %d -> %d\n",
 +                      tid_to_cpu(tid), tid_to_cpu(actual_tid));
 +      } else if (tid_to_event(tid) != tid_to_event(actual_tid)) {
 +              pr_warn("due to cpu running other code. Event %ld->%ld\n",
 +                      tid_to_event(tid), tid_to_event(actual_tid));
 +      } else {
 +              pr_warn("for unknown reason: actual=%lx was=%lx target=%lx\n",
 +                      actual_tid, tid, next_tid(tid));
 +      }
 +#endif
 +      stat(s, CMPXCHG_DOUBLE_CPU_FAIL);
 +}
  
 -      } while (!__slab_update_freelist(s, slab,
 -              freelist, counters,
 -              NULL, new.counters,
 -              "get_freelist"));
 +static void init_kmem_cache_cpus(struct kmem_cache *s)
 +{
 +#ifdef CONFIG_PREEMPT_RT
 +      /*
 +       * Register lockdep key for non-boot kmem caches to avoid
 +       * WARN_ON_ONCE(static_obj(key))) in lockdep_register_key()
 +       */
 +      bool finegrain_lockdep = !init_section_contains(s, 1);
 +#else
 +      /*
 +       * Don't bother with different lockdep classes for each
 +       * kmem_cache, since we only use local_trylock_irqsave().
 +       */
 +      bool finegrain_lockdep = false;
 +#endif
 +      int cpu;
 +      struct kmem_cache_cpu *c;
  
 -      return freelist;
 +      if (finegrain_lockdep)
 +              lockdep_register_key(&s->lock_key);
 +      for_each_possible_cpu(cpu) {
 +              c = per_cpu_ptr(s->cpu_slab, cpu);
 +              local_trylock_init(&c->lock);
 +              if (finegrain_lockdep)
 +                      lockdep_set_class(&c->lock, &s->lock_key);
 +              c->tid = init_tid(cpu);
 +      }
  }
  
  /*
@@@ -6772,73 -4882,8 +6774,73 @@@ void kfree(const void *object
  }
  EXPORT_SYMBOL(kfree);
  
 +/*
 + * Can be called while holding raw_spinlock_t or from IRQ and NMI,
 + * but ONLY for objects allocated by kmalloc_nolock().
 + * Debug checks (like kmemleak and kfence) were skipped on allocation,
 + * hence
 + * obj = kmalloc(); kfree_nolock(obj);
 + * will miss kmemleak/kfence book keeping and will cause false positives.
 + * large_kmalloc is not supported either.
 + */
 +void kfree_nolock(const void *object)
 +{
 +      struct folio *folio;
 +      struct slab *slab;
 +      struct kmem_cache *s;
 +      void *x = (void *)object;
 +
 +      if (unlikely(ZERO_OR_NULL_PTR(object)))
 +              return;
 +
 +      folio = virt_to_folio(object);
 +      if (unlikely(!folio_test_slab(folio))) {
 +              WARN_ONCE(1, "large_kmalloc is not supported by kfree_nolock()");
 +              return;
 +      }
 +
 +      slab = folio_slab(folio);
 +      s = slab->slab_cache;
 +
 +      memcg_slab_free_hook(s, slab, &x, 1);
 +      alloc_tagging_slab_free_hook(s, slab, &x, 1);
 +      /*
 +       * Unlike slab_free() do NOT call the following:
 +       * kmemleak_free_recursive(x, s->flags);
 +       * debug_check_no_locks_freed(x, s->object_size);
 +       * debug_check_no_obj_freed(x, s->object_size);
 +       * __kcsan_check_access(x, s->object_size, ..);
 +       * kfence_free(x);
 +       * since they take spinlocks or not safe from any context.
 +       */
 +      kmsan_slab_free(s, x);
 +      /*
 +       * If KASAN finds a kernel bug it will do kasan_report_invalid_free()
 +       * which will call raw_spin_lock_irqsave() which is technically
 +       * unsafe from NMI, but take chance and report kernel bug.
 +       * The sequence of
 +       * kasan_report_invalid_free() -> raw_spin_lock_irqsave() -> NMI
 +       *  -> kfree_nolock() -> kasan_report_invalid_free() on the same CPU
 +       * is double buggy and deserves to deadlock.
 +       */
 +      if (kasan_slab_pre_free(s, x))
 +              return;
 +      /*
 +       * memcg, kasan_slab_pre_free are done for 'x'.
 +       * The only thing left is kasan_poison without quarantine,
 +       * since kasan quarantine takes locks and not supported from NMI.
 +       */
 +      kasan_slab_free(s, x, false, false, /* skip quarantine */true);
 +#ifndef CONFIG_SLUB_TINY
 +      do_slab_free(s, slab, x, x, 0, _RET_IP_);
 +#else
 +      defer_free(s, x);
 +#endif
 +}
 +EXPORT_SYMBOL_GPL(kfree_nolock);
 +
  static __always_inline __realloc_size(2) void *
- __do_krealloc(const void *p, size_t new_size, gfp_t flags)
+ __do_krealloc(const void *p, size_t new_size, unsigned long align, gfp_t flags, int nid)
  {
        void *ret;
        size_t ks = 0;
diff --cc mm/vma_init.c
Simple merge
Simple merge
index 9c154209423cb264cca1ebf82f92efc4c76550e0,b39c279236f541b7cb1088ea37e2cb419134449f..e38720349dcf7e1a8b8dc415cb8b95516360798d
@@@ -130,15 -164,7 +157,15 @@@ impl NumaNode 
  /// - Implementers must ensure that all trait functions abide by the guarantees documented in the
  ///   `# Guarantees` sections.
  pub unsafe trait Allocator {
-     /// Allocate memory based on `layout` and `flags`.
 +    /// The minimum alignment satisfied by all allocations from this allocator.
 +    ///
 +    /// # Guarantees
 +    ///
 +    /// Any pointer allocated by this allocator is guaranteed to be aligned to `MIN_ALIGN` even if
 +    /// the requested layout has a smaller alignment.
 +    const MIN_ALIGN: usize;
 +
+     /// Allocate memory based on `layout`, `flags` and `nid`.
      ///
      /// On success, returns a buffer represented as `NonNull<[u8]>` that satisfies the layout
      /// constraints (i.e. minimum size and alignment as specified by `layout`).
index 08fd31bf72d2ccee828a223262a4dcbfca9a0e32,b561e7a57bb8a3df27dc71348f4906d10ef9af64..63bfb91b36712a6fcf04b59f2fe2359ee85e3fce
@@@ -13,15 -13,8 +13,14 @@@ use core::alloc::Layout
  use core::ptr;
  use core::ptr::NonNull;
  
- use crate::alloc::{AllocError, Allocator};
+ use crate::alloc::{AllocError, Allocator, NumaNode};
  use crate::bindings;
- use crate::pr_warn;
 +use crate::page;
 +
 +const ARCH_KMALLOC_MINALIGN: usize = bindings::ARCH_KMALLOC_MINALIGN;
 +
 +mod iter;
 +pub use self::iter::VmallocPageIter;
  
  /// The contiguous kernel allocator.
  ///
index 2137c37000042b39521af84c86a742177c066ddb,1fef9beb57c81edffa349b456bb5c2f3ac58e1e7..622b3529edfcbcc7a46cd73ec14cfe7f80552656
@@@ -3,10 -3,11 +3,10 @@@
  //! Implementation of [`Box`].
  
  #[allow(unused_imports)] // Used in doc comments.
 -use super::allocator::{KVmalloc, Kmalloc, Vmalloc};
 +use super::allocator::{KVmalloc, Kmalloc, Vmalloc, VmallocPageIter};
- use super::{AllocError, Allocator, Flags};
+ use super::{AllocError, Allocator, Flags, NumaNode};
  use core::alloc::Layout;
  use core::borrow::{Borrow, BorrowMut};
 -use core::fmt;
  use core::marker::PhantomData;
  use core::mem::ManuallyDrop;
  use core::mem::MaybeUninit;
index 5c3496b31e8bd78c13f88bffc568aa2d30b64554,92d0ed3f302ef2158bf7c6cbdee379c3bf67326e..e94aebd084c83f8fc8386fa93116a8f1b6043028
@@@ -3,16 -3,13 +3,16 @@@
  //! Implementation of [`Vec`].
  
  use super::{
 -    allocator::{KVmalloc, Kmalloc, Vmalloc},
 +    allocator::{KVmalloc, Kmalloc, Vmalloc, VmallocPageIter},
      layout::ArrayLayout,
-     AllocError, Allocator, Box, Flags,
+     AllocError, Allocator, Box, Flags, NumaNode,
  };
 +use crate::{
 +    fmt,
 +    page::AsPageIter,
 +};
  use core::{
      borrow::{Borrow, BorrowMut},
 -    fmt,
      marker::PhantomData,
      mem::{ManuallyDrop, MaybeUninit},
      ops::Deref,
Simple merge
Simple merge
Simple merge
Simple merge