]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - mm/slub.c
Merge tag 'mm-stable-2024-05-17-19-19' of git://git.kernel.org/pub/scm/linux/kernel...
[thirdparty/kernel/stable.git] / mm / slub.c
index 4954999183d58ecba9d7e86f44025131934308f2..0809760cf789d11ee385f1f31da71635a455dd71 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -646,18 +646,12 @@ static inline unsigned int slub_get_cpu_partial(struct kmem_cache *s)
  */
 static __always_inline void slab_lock(struct slab *slab)
 {
-       struct page *page = slab_page(slab);
-
-       VM_BUG_ON_PAGE(PageTail(page), page);
-       bit_spin_lock(PG_locked, &page->flags);
+       bit_spin_lock(PG_locked, &slab->__page_flags);
 }
 
 static __always_inline void slab_unlock(struct slab *slab)
 {
-       struct page *page = slab_page(slab);
-
-       VM_BUG_ON_PAGE(PageTail(page), page);
-       bit_spin_unlock(PG_locked, &page->flags);
+       bit_spin_unlock(PG_locked, &slab->__page_flags);
 }
 
 static inline bool
@@ -1875,198 +1869,278 @@ static bool freelist_corrupted(struct kmem_cache *s, struct slab *slab,
 #endif
 #endif /* CONFIG_SLUB_DEBUG */
 
-static inline enum node_stat_item cache_vmstat_idx(struct kmem_cache *s)
+#ifdef CONFIG_SLAB_OBJ_EXT
+
+#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
+
+static inline void mark_objexts_empty(struct slabobj_ext *obj_exts)
 {
-       return (s->flags & SLAB_RECLAIM_ACCOUNT) ?
-               NR_SLAB_RECLAIMABLE_B : NR_SLAB_UNRECLAIMABLE_B;
+       struct slabobj_ext *slab_exts;
+       struct slab *obj_exts_slab;
+
+       obj_exts_slab = virt_to_slab(obj_exts);
+       slab_exts = slab_obj_exts(obj_exts_slab);
+       if (slab_exts) {
+               unsigned int offs = obj_to_index(obj_exts_slab->slab_cache,
+                                                obj_exts_slab, obj_exts);
+               /* codetag should be NULL */
+               WARN_ON(slab_exts[offs].ref.ct);
+               set_codetag_empty(&slab_exts[offs].ref);
+       }
 }
 
-#ifdef CONFIG_MEMCG_KMEM
-static inline void memcg_free_slab_cgroups(struct slab *slab)
+static inline void mark_failed_objexts_alloc(struct slab *slab)
 {
-       kfree(slab_objcgs(slab));
-       slab->memcg_data = 0;
+       slab->obj_exts = OBJEXTS_ALLOC_FAIL;
 }
 
-static inline size_t obj_full_size(struct kmem_cache *s)
+static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
+                       struct slabobj_ext *vec, unsigned int objects)
 {
        /*
-        * For each accounted object there is an extra space which is used
-        * to store obj_cgroup membership. Charge it too.
+        * If vector previously failed to allocate then we have live
+        * objects with no tag reference. Mark all references in this
+        * vector as empty to avoid warnings later on.
         */
-       return s->size + sizeof(struct obj_cgroup *);
+       if (obj_exts & OBJEXTS_ALLOC_FAIL) {
+               unsigned int i;
+
+               for (i = 0; i < objects; i++)
+                       set_codetag_empty(&vec[i].ref);
+       }
 }
 
+#else /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */
+
+static inline void mark_objexts_empty(struct slabobj_ext *obj_exts) {}
+static inline void mark_failed_objexts_alloc(struct slab *slab) {}
+static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
+                       struct slabobj_ext *vec, unsigned int objects) {}
+
+#endif /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */
+
 /*
- * Returns false if the allocation should fail.
+ * The allocated objcg pointers array is not accounted directly.
+ * Moreover, it should not come from DMA buffer and is not readily
+ * reclaimable. So those GFP bits should be masked off.
  */
-static bool __memcg_slab_pre_alloc_hook(struct kmem_cache *s,
-                                       struct list_lru *lru,
-                                       struct obj_cgroup **objcgp,
-                                       size_t objects, gfp_t flags)
+#define OBJCGS_CLEAR_MASK      (__GFP_DMA | __GFP_RECLAIMABLE | \
+                               __GFP_ACCOUNT | __GFP_NOFAIL)
+
+int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
+                       gfp_t gfp, bool new_slab)
+{
+       unsigned int objects = objs_per_slab(s, slab);
+       unsigned long new_exts;
+       unsigned long old_exts;
+       struct slabobj_ext *vec;
+
+       gfp &= ~OBJCGS_CLEAR_MASK;
+       /* Prevent recursive extension vector allocation */
+       gfp |= __GFP_NO_OBJ_EXT;
+       vec = kcalloc_node(objects, sizeof(struct slabobj_ext), gfp,
+                          slab_nid(slab));
+       if (!vec) {
+               /* Mark vectors which failed to allocate */
+               if (new_slab)
+                       mark_failed_objexts_alloc(slab);
+
+               return -ENOMEM;
+       }
+
+       new_exts = (unsigned long)vec;
+#ifdef CONFIG_MEMCG
+       new_exts |= MEMCG_DATA_OBJEXTS;
+#endif
+       old_exts = slab->obj_exts;
+       handle_failed_objexts_alloc(old_exts, vec, objects);
+       if (new_slab) {
+               /*
+                * If the slab is brand new and nobody can yet access its
+                * obj_exts, no synchronization is required and obj_exts can
+                * be simply assigned.
+                */
+               slab->obj_exts = new_exts;
+       } else if (cmpxchg(&slab->obj_exts, old_exts, new_exts) != old_exts) {
+               /*
+                * If the slab is already in use, somebody can allocate and
+                * assign slabobj_exts in parallel. In this case the existing
+                * objcg vector should be reused.
+                */
+               mark_objexts_empty(vec);
+               kfree(vec);
+               return 0;
+       }
+
+       kmemleak_not_leak(vec);
+       return 0;
+}
+
+static inline void free_slab_obj_exts(struct slab *slab)
 {
+       struct slabobj_ext *obj_exts;
+
+       obj_exts = slab_obj_exts(slab);
+       if (!obj_exts)
+               return;
+
        /*
-        * The obtained objcg pointer is safe to use within the current scope,
-        * defined by current task or set_active_memcg() pair.
-        * obj_cgroup_get() is used to get a permanent reference.
+        * obj_exts was created with __GFP_NO_OBJ_EXT flag, therefore its
+        * corresponding extension will be NULL. alloc_tag_sub() will throw a
+        * warning if slab has extensions but the extension of an object is
+        * NULL, therefore replace NULL with CODETAG_EMPTY to indicate that
+        * the extension for obj_exts is expected to be NULL.
         */
-       struct obj_cgroup *objcg = current_obj_cgroup();
-       if (!objcg)
+       mark_objexts_empty(obj_exts);
+       kfree(obj_exts);
+       slab->obj_exts = 0;
+}
+
+static inline bool need_slab_obj_ext(void)
+{
+       if (mem_alloc_profiling_enabled())
                return true;
 
-       if (lru) {
-               int ret;
-               struct mem_cgroup *memcg;
+       /*
+        * CONFIG_MEMCG_KMEM creates vector of obj_cgroup objects conditionally
+        * inside memcg_slab_post_alloc_hook. No other users for now.
+        */
+       return false;
+}
 
-               memcg = get_mem_cgroup_from_objcg(objcg);
-               ret = memcg_list_lru_alloc(memcg, lru, flags);
-               css_put(&memcg->css);
+static inline struct slabobj_ext *
+prepare_slab_obj_exts_hook(struct kmem_cache *s, gfp_t flags, void *p)
+{
+       struct slab *slab;
 
-               if (ret)
-                       return false;
-       }
+       if (!p)
+               return NULL;
 
-       if (obj_cgroup_charge(objcg, flags, objects * obj_full_size(s)))
-               return false;
+       if (s->flags & (SLAB_NO_OBJ_EXT | SLAB_NOLEAKTRACE))
+               return NULL;
 
-       *objcgp = objcg;
-       return true;
+       if (flags & __GFP_NO_OBJ_EXT)
+               return NULL;
+
+       slab = virt_to_slab(p);
+       if (!slab_obj_exts(slab) &&
+           WARN(alloc_slab_obj_exts(slab, s, flags, false),
+                "%s, %s: Failed to create slab extension vector!\n",
+                __func__, s->name))
+               return NULL;
+
+       return slab_obj_exts(slab) + obj_to_index(s, slab, p);
 }
 
-/*
- * Returns false if the allocation should fail.
- */
-static __fastpath_inline
-bool memcg_slab_pre_alloc_hook(struct kmem_cache *s, struct list_lru *lru,
-                              struct obj_cgroup **objcgp, size_t objects,
-                              gfp_t flags)
+static inline void
+alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p,
+                            int objects)
 {
-       if (!memcg_kmem_online())
-               return true;
+#ifdef CONFIG_MEM_ALLOC_PROFILING
+       struct slabobj_ext *obj_exts;
+       int i;
 
-       if (likely(!(flags & __GFP_ACCOUNT) && !(s->flags & SLAB_ACCOUNT)))
-               return true;
+       if (!mem_alloc_profiling_enabled())
+               return;
 
-       return likely(__memcg_slab_pre_alloc_hook(s, lru, objcgp, objects,
-                                                 flags));
+       obj_exts = slab_obj_exts(slab);
+       if (!obj_exts)
+               return;
+
+       for (i = 0; i < objects; i++) {
+               unsigned int off = obj_to_index(s, slab, p[i]);
+
+               alloc_tag_sub(&obj_exts[off].ref, s->size);
+       }
+#endif
 }
 
-static void __memcg_slab_post_alloc_hook(struct kmem_cache *s,
-                                        struct obj_cgroup *objcg,
-                                        gfp_t flags, size_t size,
-                                        void **p)
+#else /* CONFIG_SLAB_OBJ_EXT */
+
+static int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
+                              gfp_t gfp, bool new_slab)
 {
-       struct slab *slab;
-       unsigned long off;
-       size_t i;
+       return 0;
+}
 
-       flags &= gfp_allowed_mask;
+static inline void free_slab_obj_exts(struct slab *slab)
+{
+}
 
-       for (i = 0; i < size; i++) {
-               if (likely(p[i])) {
-                       slab = virt_to_slab(p[i]);
+static inline bool need_slab_obj_ext(void)
+{
+       return false;
+}
 
-                       if (!slab_objcgs(slab) &&
-                           memcg_alloc_slab_cgroups(slab, s, flags, false)) {
-                               obj_cgroup_uncharge(objcg, obj_full_size(s));
-                               continue;
-                       }
+static inline struct slabobj_ext *
+prepare_slab_obj_exts_hook(struct kmem_cache *s, gfp_t flags, void *p)
+{
+       return NULL;
+}
 
-                       off = obj_to_index(s, slab, p[i]);
-                       obj_cgroup_get(objcg);
-                       slab_objcgs(slab)[off] = objcg;
-                       mod_objcg_state(objcg, slab_pgdat(slab),
-                                       cache_vmstat_idx(s), obj_full_size(s));
-               } else {
-                       obj_cgroup_uncharge(objcg, obj_full_size(s));
-               }
-       }
+static inline void
+alloc_tagging_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p,
+                            int objects)
+{
 }
 
+#endif /* CONFIG_SLAB_OBJ_EXT */
+
+#ifdef CONFIG_MEMCG_KMEM
+
+static void memcg_alloc_abort_single(struct kmem_cache *s, void *object);
+
 static __fastpath_inline
-void memcg_slab_post_alloc_hook(struct kmem_cache *s, struct obj_cgroup *objcg,
+bool memcg_slab_post_alloc_hook(struct kmem_cache *s, struct list_lru *lru,
                                gfp_t flags, size_t size, void **p)
 {
-       if (likely(!memcg_kmem_online() || !objcg))
-               return;
-
-       return __memcg_slab_post_alloc_hook(s, objcg, flags, size, p);
-}
+       if (likely(!memcg_kmem_online()))
+               return true;
 
-static void __memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,
-                                  void **p, int objects,
-                                  struct obj_cgroup **objcgs)
-{
-       for (int i = 0; i < objects; i++) {
-               struct obj_cgroup *objcg;
-               unsigned int off;
+       if (likely(!(flags & __GFP_ACCOUNT) && !(s->flags & SLAB_ACCOUNT)))
+               return true;
 
-               off = obj_to_index(s, slab, p[i]);
-               objcg = objcgs[off];
-               if (!objcg)
-                       continue;
+       if (likely(__memcg_slab_post_alloc_hook(s, lru, flags, size, p)))
+               return true;
 
-               objcgs[off] = NULL;
-               obj_cgroup_uncharge(objcg, obj_full_size(s));
-               mod_objcg_state(objcg, slab_pgdat(slab), cache_vmstat_idx(s),
-                               -obj_full_size(s));
-               obj_cgroup_put(objcg);
+       if (likely(size == 1)) {
+               memcg_alloc_abort_single(s, *p);
+               *p = NULL;
+       } else {
+               kmem_cache_free_bulk(s, size, p);
        }
+
+       return false;
 }
 
 static __fastpath_inline
 void memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p,
                          int objects)
 {
-       struct obj_cgroup **objcgs;
+       struct slabobj_ext *obj_exts;
 
        if (!memcg_kmem_online())
                return;
 
-       objcgs = slab_objcgs(slab);
-       if (likely(!objcgs))
+       obj_exts = slab_obj_exts(slab);
+       if (likely(!obj_exts))
                return;
 
-       __memcg_slab_free_hook(s, slab, p, objects, objcgs);
-}
-
-static inline
-void memcg_slab_alloc_error_hook(struct kmem_cache *s, int objects,
-                          struct obj_cgroup *objcg)
-{
-       if (objcg)
-               obj_cgroup_uncharge(objcg, objects * obj_full_size(s));
+       __memcg_slab_free_hook(s, slab, p, objects, obj_exts);
 }
 #else /* CONFIG_MEMCG_KMEM */
-static inline void memcg_free_slab_cgroups(struct slab *slab)
-{
-}
-
-static inline bool memcg_slab_pre_alloc_hook(struct kmem_cache *s,
-                                            struct list_lru *lru,
-                                            struct obj_cgroup **objcgp,
-                                            size_t objects, gfp_t flags)
-{
-       return true;
-}
-
-static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
-                                             struct obj_cgroup *objcg,
+static inline bool memcg_slab_post_alloc_hook(struct kmem_cache *s,
+                                             struct list_lru *lru,
                                              gfp_t flags, size_t size,
                                              void **p)
 {
+       return true;
 }
 
 static inline void memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,
                                        void **p, int objects)
 {
 }
-
-static inline
-void memcg_slab_alloc_error_hook(struct kmem_cache *s, int objects,
-                                struct obj_cgroup *objcg)
-{
-}
 #endif /* CONFIG_MEMCG_KMEM */
 
 /*
@@ -2121,9 +2195,9 @@ bool slab_free_hook(struct kmem_cache *s, void *x, bool init)
        return !kasan_slab_free(s, x, init);
 }
 
-static inline bool slab_free_freelist_hook(struct kmem_cache *s,
-                                          void **head, void **tail,
-                                          int *cnt)
+static __fastpath_inline
+bool slab_free_freelist_hook(struct kmem_cache *s, void **head, void **tail,
+                            int *cnt)
 {
 
        void *object;
@@ -2313,7 +2387,7 @@ static __always_inline void account_slab(struct slab *slab, int order,
                                         struct kmem_cache *s, gfp_t gfp)
 {
        if (memcg_kmem_online() && (s->flags & SLAB_ACCOUNT))
-               memcg_alloc_slab_cgroups(slab, s, gfp, true);
+               alloc_slab_obj_exts(slab, s, gfp, true);
 
        mod_node_page_state(slab_pgdat(slab), cache_vmstat_idx(s),
                            PAGE_SIZE << order);
@@ -2322,8 +2396,8 @@ static __always_inline void account_slab(struct slab *slab, int order,
 static __always_inline void unaccount_slab(struct slab *slab, int order,
                                           struct kmem_cache *s)
 {
-       if (memcg_kmem_online())
-               memcg_free_slab_cgroups(slab);
+       if (memcg_kmem_online() || need_slab_obj_ext())
+               free_slab_obj_exts(slab);
 
        mod_node_page_state(slab_pgdat(slab), cache_vmstat_idx(s),
                            -(PAGE_SIZE << order));
@@ -3809,10 +3883,7 @@ noinline int should_failslab(struct kmem_cache *s, gfp_t gfpflags)
 ALLOW_ERROR_INJECTION(should_failslab, ERRNO);
 
 static __fastpath_inline
-struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s,
-                                      struct list_lru *lru,
-                                      struct obj_cgroup **objcgp,
-                                      size_t size, gfp_t flags)
+struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
 {
        flags &= gfp_allowed_mask;
 
@@ -3821,18 +3892,16 @@ struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s,
        if (unlikely(should_failslab(s, flags)))
                return NULL;
 
-       if (unlikely(!memcg_slab_pre_alloc_hook(s, lru, objcgp, size, flags)))
-               return NULL;
-
        return s;
 }
 
 static __fastpath_inline
-void slab_post_alloc_hook(struct kmem_cache *s,        struct obj_cgroup *objcg,
+bool slab_post_alloc_hook(struct kmem_cache *s, struct list_lru *lru,
                          gfp_t flags, size_t size, void **p, bool init,
                          unsigned int orig_size)
 {
        unsigned int zero_size = s->object_size;
+       struct slabobj_ext *obj_exts;
        bool kasan_init = init;
        size_t i;
        gfp_t init_flags = flags & gfp_allowed_mask;
@@ -3875,9 +3944,21 @@ void slab_post_alloc_hook(struct kmem_cache *s,  struct obj_cgroup *objcg,
                kmemleak_alloc_recursive(p[i], s->object_size, 1,
                                         s->flags, init_flags);
                kmsan_slab_alloc(s, p[i], init_flags);
+               if (need_slab_obj_ext()) {
+                       obj_exts = prepare_slab_obj_exts_hook(s, flags, p[i]);
+#ifdef CONFIG_MEM_ALLOC_PROFILING
+                       /*
+                        * Currently obj_exts is used only for allocation profiling.
+                        * If other users appear then mem_alloc_profiling_enabled()
+                        * check should be added before alloc_tag_add().
+                        */
+                       if (likely(obj_exts))
+                               alloc_tag_add(&obj_exts->ref, current->alloc_tag, s->size);
+#endif
+               }
        }
 
-       memcg_slab_post_alloc_hook(s, objcg, flags, size, p);
+       return memcg_slab_post_alloc_hook(s, lru, flags, size, p);
 }
 
 /*
@@ -3894,10 +3975,9 @@ static __fastpath_inline void *slab_alloc_node(struct kmem_cache *s, struct list
                gfp_t gfpflags, int node, unsigned long addr, size_t orig_size)
 {
        void *object;
-       struct obj_cgroup *objcg = NULL;
        bool init = false;
 
-       s = slab_pre_alloc_hook(s, lru, &objcg, 1, gfpflags);
+       s = slab_pre_alloc_hook(s, gfpflags);
        if (unlikely(!s))
                return NULL;
 
@@ -3914,13 +3994,15 @@ out:
        /*
         * When init equals 'true', like for kzalloc() family, only
         * @orig_size bytes might be zeroed instead of s->object_size
+        * In case this fails due to memcg_slab_post_alloc_hook(),
+        * object is set to NULL
         */
-       slab_post_alloc_hook(s, objcg, gfpflags, 1, &object, init, orig_size);
+       slab_post_alloc_hook(s, lru, gfpflags, 1, &object, init, orig_size);
 
        return object;
 }
 
-void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
+void *kmem_cache_alloc_noprof(struct kmem_cache *s, gfp_t gfpflags)
 {
        void *ret = slab_alloc_node(s, NULL, gfpflags, NUMA_NO_NODE, _RET_IP_,
                                    s->object_size);
@@ -3929,9 +4011,9 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
 
        return ret;
 }
-EXPORT_SYMBOL(kmem_cache_alloc);
+EXPORT_SYMBOL(kmem_cache_alloc_noprof);
 
-void *kmem_cache_alloc_lru(struct kmem_cache *s, struct list_lru *lru,
+void *kmem_cache_alloc_lru_noprof(struct kmem_cache *s, struct list_lru *lru,
                           gfp_t gfpflags)
 {
        void *ret = slab_alloc_node(s, lru, gfpflags, NUMA_NO_NODE, _RET_IP_,
@@ -3941,7 +4023,7 @@ void *kmem_cache_alloc_lru(struct kmem_cache *s, struct list_lru *lru,
 
        return ret;
 }
-EXPORT_SYMBOL(kmem_cache_alloc_lru);
+EXPORT_SYMBOL(kmem_cache_alloc_lru_noprof);
 
 /**
  * kmem_cache_alloc_node - Allocate an object on the specified node
@@ -3956,7 +4038,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_lru);
  *
  * Return: pointer to the new object or %NULL in case of error
  */
-void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
+void *kmem_cache_alloc_node_noprof(struct kmem_cache *s, gfp_t gfpflags, int node)
 {
        void *ret = slab_alloc_node(s, NULL, gfpflags, node, _RET_IP_, s->object_size);
 
@@ -3964,7 +4046,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
 
        return ret;
 }
-EXPORT_SYMBOL(kmem_cache_alloc_node);
+EXPORT_SYMBOL(kmem_cache_alloc_node_noprof);
 
 /*
  * To avoid unnecessary overhead, we pass through large allocation requests
@@ -3981,7 +4063,7 @@ static void *__kmalloc_large_node(size_t size, gfp_t flags, int node)
                flags = kmalloc_fix_flags(flags);
 
        flags |= __GFP_COMP;
-       folio = (struct folio *)alloc_pages_node(node, flags, order);
+       folio = (struct folio *)alloc_pages_node_noprof(node, flags, order);
        if (folio) {
                ptr = folio_address(folio);
                lruvec_stat_mod_folio(folio, NR_SLAB_UNRECLAIMABLE_B,
@@ -3996,7 +4078,7 @@ static void *__kmalloc_large_node(size_t size, gfp_t flags, int node)
        return ptr;
 }
 
-void *kmalloc_large(size_t size, gfp_t flags)
+void *kmalloc_large_noprof(size_t size, gfp_t flags)
 {
        void *ret = __kmalloc_large_node(size, flags, NUMA_NO_NODE);
 
@@ -4004,9 +4086,9 @@ void *kmalloc_large(size_t size, gfp_t flags)
                      flags, NUMA_NO_NODE);
        return ret;
 }
-EXPORT_SYMBOL(kmalloc_large);
+EXPORT_SYMBOL(kmalloc_large_noprof);
 
-void *kmalloc_large_node(size_t size, gfp_t flags, int node)
+void *kmalloc_large_node_noprof(size_t size, gfp_t flags, int node)
 {
        void *ret = __kmalloc_large_node(size, flags, node);
 
@@ -4014,7 +4096,7 @@ void *kmalloc_large_node(size_t size, gfp_t flags, int node)
                      flags, node);
        return ret;
 }
-EXPORT_SYMBOL(kmalloc_large_node);
+EXPORT_SYMBOL(kmalloc_large_node_noprof);
 
 static __always_inline
 void *__do_kmalloc_node(size_t size, gfp_t flags, int node,
@@ -4041,26 +4123,26 @@ void *__do_kmalloc_node(size_t size, gfp_t flags, int node,
        return ret;
 }
 
-void *__kmalloc_node(size_t size, gfp_t flags, int node)
+void *__kmalloc_node_noprof(size_t size, gfp_t flags, int node)
 {
        return __do_kmalloc_node(size, flags, node, _RET_IP_);
 }
-EXPORT_SYMBOL(__kmalloc_node);
+EXPORT_SYMBOL(__kmalloc_node_noprof);
 
-void *__kmalloc(size_t size, gfp_t flags)
+void *__kmalloc_noprof(size_t size, gfp_t flags)
 {
        return __do_kmalloc_node(size, flags, NUMA_NO_NODE, _RET_IP_);
 }
-EXPORT_SYMBOL(__kmalloc);
+EXPORT_SYMBOL(__kmalloc_noprof);
 
-void *__kmalloc_node_track_caller(size_t size, gfp_t flags,
-                                 int node, unsigned long caller)
+void *kmalloc_node_track_caller_noprof(size_t size, gfp_t flags,
+                                      int node, unsigned long caller)
 {
        return __do_kmalloc_node(size, flags, node, caller);
 }
-EXPORT_SYMBOL(__kmalloc_node_track_caller);
+EXPORT_SYMBOL(kmalloc_node_track_caller_noprof);
 
-void *kmalloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
+void *kmalloc_trace_noprof(struct kmem_cache *s, gfp_t gfpflags, size_t size)
 {
        void *ret = slab_alloc_node(s, NULL, gfpflags, NUMA_NO_NODE,
                                            _RET_IP_, size);
@@ -4070,9 +4152,9 @@ void *kmalloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
        ret = kasan_kmalloc(s, ret, size, gfpflags);
        return ret;
 }
-EXPORT_SYMBOL(kmalloc_trace);
+EXPORT_SYMBOL(kmalloc_trace_noprof);
 
-void *kmalloc_node_trace(struct kmem_cache *s, gfp_t gfpflags,
+void *kmalloc_node_trace_noprof(struct kmem_cache *s, gfp_t gfpflags,
                         int node, size_t size)
 {
        void *ret = slab_alloc_node(s, NULL, gfpflags, node, _RET_IP_, size);
@@ -4082,7 +4164,7 @@ void *kmalloc_node_trace(struct kmem_cache *s, gfp_t gfpflags,
        ret = kasan_kmalloc(s, ret, size, gfpflags);
        return ret;
 }
-EXPORT_SYMBOL(kmalloc_node_trace);
+EXPORT_SYMBOL(kmalloc_node_trace_noprof);
 
 static noinline void free_to_partial_list(
        struct kmem_cache *s, struct slab *slab,
@@ -4349,16 +4431,28 @@ void slab_free(struct kmem_cache *s, struct slab *slab, void *object,
               unsigned long addr)
 {
        memcg_slab_free_hook(s, slab, &object, 1);
+       alloc_tagging_slab_free_hook(s, slab, &object, 1);
 
        if (likely(slab_free_hook(s, object, slab_want_init_on_free(s))))
                do_slab_free(s, slab, object, object, 1, addr);
 }
 
+#ifdef CONFIG_MEMCG_KMEM
+/* Do not inline the rare memcg charging failed path into the allocation path */
+static noinline
+void memcg_alloc_abort_single(struct kmem_cache *s, void *object)
+{
+       if (likely(slab_free_hook(s, object, slab_want_init_on_free(s))))
+               do_slab_free(s, virt_to_slab(object), object, object, 1, _RET_IP_);
+}
+#endif
+
 static __fastpath_inline
 void slab_free_bulk(struct kmem_cache *s, struct slab *slab, void *head,
                    void *tail, void **p, int cnt, unsigned long addr)
 {
        memcg_slab_free_hook(s, slab, p, cnt);
+       alloc_tagging_slab_free_hook(s, slab, p, cnt);
        /*
         * With KASAN enabled slab_free_freelist_hook modifies the freelist
         * to remove objects, whose reuse must be delayed.
@@ -4685,36 +4779,33 @@ error:
 #endif /* CONFIG_SLUB_TINY */
 
 /* Note that interrupts must be enabled when calling this function. */
-int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
-                         void **p)
+int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size,
+                                void **p)
 {
        int i;
-       struct obj_cgroup *objcg = NULL;
 
        if (!size)
                return 0;
 
-       /* memcg and kmem_cache debug support */
-       s = slab_pre_alloc_hook(s, NULL, &objcg, size, flags);
+       s = slab_pre_alloc_hook(s, flags);
        if (unlikely(!s))
                return 0;
 
        i = __kmem_cache_alloc_bulk(s, flags, size, p);
+       if (unlikely(i == 0))
+               return 0;
 
        /*
         * memcg and kmem_cache debug support and memory initialization.
         * Done outside of the IRQ disabled fastpath loop.
         */
-       if (likely(i != 0)) {
-               slab_post_alloc_hook(s, objcg, flags, size, p,
-                       slab_want_init_on_alloc(flags, s), s->object_size);
-       } else {
-               memcg_slab_alloc_error_hook(s, size, objcg);
+       if (unlikely(!slab_post_alloc_hook(s, NULL, flags, size, p,
+                   slab_want_init_on_alloc(flags, s), s->object_size))) {
+               return 0;
        }
-
        return i;
 }
-EXPORT_SYMBOL(kmem_cache_alloc_bulk);
+EXPORT_SYMBOL(kmem_cache_alloc_bulk_noprof);
 
 
 /*
@@ -5700,7 +5791,8 @@ void __init kmem_cache_init(void)
                node_set(node, slab_nodes);
 
        create_boot_cache(kmem_cache_node, "kmem_cache_node",
-               sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN, 0, 0);
+                       sizeof(struct kmem_cache_node),
+                       SLAB_HWCACHE_ALIGN | SLAB_NO_OBJ_EXT, 0, 0);
 
        hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
 
@@ -5710,7 +5802,7 @@ void __init kmem_cache_init(void)
        create_boot_cache(kmem_cache, "kmem_cache",
                        offsetof(struct kmem_cache, node) +
                                nr_node_ids * sizeof(struct kmem_cache_node *),
-                      SLAB_HWCACHE_ALIGN, 0, 0);
+                       SLAB_HWCACHE_ALIGN | SLAB_NO_OBJ_EXT, 0, 0);
 
        kmem_cache = bootstrap(&boot_kmem_cache);
        kmem_cache_node = bootstrap(&boot_kmem_cache_node);