]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - mm/slub.c
afs: Fix VNOVOL handling in address rotation
[mirror_ubuntu-bionic-kernel.git] / mm / slub.c
index cfd56e5a35fb9790ac6426dd62abb9964f1ce72b..fd45eeff1c60b3c9589e97e4e38081559061d090 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1360,10 +1360,8 @@ static inline void kfree_hook(const void *x)
        kasan_kfree_large(x);
 }
 
-static inline void *slab_free_hook(struct kmem_cache *s, void *x)
+static inline bool slab_free_hook(struct kmem_cache *s, void *x)
 {
-       void *freeptr;
-
        kmemleak_free_recursive(x, s->flags);
 
        /*
@@ -1383,17 +1381,12 @@ static inline void *slab_free_hook(struct kmem_cache *s, void *x)
        if (!(s->flags & SLAB_DEBUG_OBJECTS))
                debug_check_no_obj_freed(x, s->object_size);
 
-       freeptr = get_freepointer(s, x);
-       /*
-        * kasan_slab_free() may put x into memory quarantine, delaying its
-        * reuse. In this case the object's freelist pointer is changed.
-        */
-       kasan_slab_free(s, x);
-       return freeptr;
+       /* KASAN might put x into memory quarantine, delaying its reuse */
+       return kasan_slab_free(s, x);
 }
 
-static inline void slab_free_freelist_hook(struct kmem_cache *s,
-                                          void *head, void *tail)
+static inline bool slab_free_freelist_hook(struct kmem_cache *s,
+                                          void **head, void **tail)
 {
 /*
  * Compiler cannot detect this function can be removed if slab_free_hook()
@@ -1404,13 +1397,33 @@ static inline void slab_free_freelist_hook(struct kmem_cache *s,
        defined(CONFIG_DEBUG_OBJECTS_FREE) ||   \
        defined(CONFIG_KASAN)
 
-       void *object = head;
-       void *tail_obj = tail ? : head;
-       void *freeptr;
+       void *object;
+       void *next = *head;
+       void *old_tail = *tail ? *tail : *head;
+
+       /* Head and tail of the reconstructed freelist */
+       *head = NULL;
+       *tail = NULL;
 
        do {
-               freeptr = slab_free_hook(s, object);
-       } while ((object != tail_obj) && (object = freeptr));
+               object = next;
+               next = get_freepointer(s, object);
+               /* If object's reuse doesn't have to be delayed */
+               if (!slab_free_hook(s, object)) {
+                       /* Move object to the new freelist */
+                       set_freepointer(s, object, *head);
+                       *head = object;
+                       if (!*tail)
+                               *tail = object;
+               }
+       } while (object != old_tail);
+
+       if (*head == *tail)
+               *tail = NULL;
+
+       return *head != NULL;
+#else
+       return true;
 #endif
 }
 
@@ -2965,14 +2978,12 @@ static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
                                      void *head, void *tail, int cnt,
                                      unsigned long addr)
 {
-       slab_free_freelist_hook(s, head, tail);
        /*
-        * slab_free_freelist_hook() could have put the items into quarantine.
-        * If so, no need to free them.
+        * With KASAN enabled slab_free_freelist_hook modifies the freelist
+        * to remove objects, whose reuse must be delayed.
         */
-       if (s->flags & SLAB_KASAN && !(s->flags & SLAB_TYPESAFE_BY_RCU))
-               return;
-       do_slab_free(s, page, head, tail, cnt, addr);
+       if (slab_free_freelist_hook(s, &head, &tail))
+               do_slab_free(s, page, head, tail, cnt, addr);
 }
 
 #ifdef CONFIG_KASAN