]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - mm/slub.c
Merge tag 'y2038-alsa-v8-signed' of git://git.kernel.org:/pub/scm/linux/kernel/git...
[linux.git] / mm / slub.c
index 3d63ae320d31bb07a667ead9ee90768d234c155d..d11389710b12d6f35479aa5d029ac6b5b9205228 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -93,9 +93,7 @@
  * minimal so we rely on the page allocators per cpu caches for
  * fast frees and allocs.
  *
- * Overloading of page flags that are otherwise used for LRU management.
- *
- * PageActive          The slab is frozen and exempt from list processing.
+ * page->frozen                The slab is frozen and exempt from list processing.
  *                     This means that the slab is dedicated to a purpose
  *                     such as satisfying allocations for a specific
  *                     processor. Objects may be freed in the slab while
  *                     free objects in addition to the regular freelist
  *                     that requires the slab lock.
  *
- * PageError           Slab requires special handling due to debug
+ * SLAB_DEBUG_FLAGS    Slab requires special handling due to debug
  *                     options set. This moves slab handling out of
  *                     the fast path and disables lockless freelists.
  */
@@ -736,6 +734,7 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
 {
        u8 *fault;
        u8 *end;
+       u8 *addr = page_address(page);
 
        metadata_access_enable();
        fault = memchr_inv(start, value, bytes);
@@ -748,8 +747,9 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
                end--;
 
        slab_bug(s, "%s overwritten", what);
-       pr_err("INFO: 0x%p-0x%p. First byte 0x%x instead of 0x%x\n",
-                                       fault, end - 1, fault[0], value);
+       pr_err("INFO: 0x%p-0x%p @offset=%tu. First byte 0x%x instead of 0x%x\n",
+                                       fault, end - 1, fault - addr,
+                                       fault[0], value);
        print_trailer(s, page, object);
 
        restore_bytes(s, what, value, fault, end);
@@ -844,7 +844,8 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
        while (end > fault && end[-1] == POISON_INUSE)
                end--;
 
-       slab_err(s, page, "Padding overwritten. 0x%p-0x%p", fault, end - 1);
+       slab_err(s, page, "Padding overwritten. 0x%p-0x%p @offset=%tu",
+                       fault, end - 1, fault - start);
        print_section(KERN_ERR, "Padding ", pad, remainder);
 
        restore_bytes(s, "slab padding", POISON_INUSE, fault, end);
@@ -1433,12 +1434,15 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
        void *old_tail = *tail ? *tail : *head;
        int rsize;
 
-       if (slab_want_init_on_free(s)) {
-               void *p = NULL;
+       /* Head and tail of the reconstructed freelist */
+       *head = NULL;
+       *tail = NULL;
 
-               do {
-                       object = next;
-                       next = get_freepointer(s, object);
+       do {
+               object = next;
+               next = get_freepointer(s, object);
+
+               if (slab_want_init_on_free(s)) {
                        /*
                         * Clear the object and the metadata, but don't touch
                         * the redzone.
@@ -1448,29 +1452,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
                                                           : 0;
                        memset((char *)object + s->inuse, 0,
                               s->size - s->inuse - rsize);
-                       set_freepointer(s, object, p);
-                       p = object;
-               } while (object != old_tail);
-       }
 
-/*
- * Compiler cannot detect this function can be removed if slab_free_hook()
- * evaluates to nothing.  Thus, catch all relevant config debug options here.
- */
-#if defined(CONFIG_LOCKDEP)    ||              \
-       defined(CONFIG_DEBUG_KMEMLEAK) ||       \
-       defined(CONFIG_DEBUG_OBJECTS_FREE) ||   \
-       defined(CONFIG_KASAN)
-
-       next = *head;
-
-       /* Head and tail of the reconstructed freelist */
-       *head = NULL;
-       *tail = NULL;
-
-       do {
-               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 */
@@ -1485,9 +1468,6 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
                *tail = NULL;
 
        return *head != NULL;
-#else
-       return true;
-#endif
 }
 
 static void *setup_object(struct kmem_cache *s, struct page *page,
@@ -2671,6 +2651,17 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
        return p;
 }
 
+/*
+ * If the object has been wiped upon free, make sure it's fully initialized by
+ * zeroing out freelist pointer.
+ */
+static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s,
+                                                  void *obj)
+{
+       if (unlikely(slab_want_init_on_free(s)) && obj)
+               memset((void *)((char *)obj + s->offset), 0, sizeof(void *));
+}
+
 /*
  * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc)
  * have the fastpath folded into their functions. So no function call
@@ -2759,12 +2750,8 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
                prefetch_freepointer(s, next_object);
                stat(s, ALLOC_FASTPATH);
        }
-       /*
-        * If the object has been wiped upon free, make sure it's fully
-        * initialized by zeroing out freelist pointer.
-        */
-       if (unlikely(slab_want_init_on_free(s)) && object)
-               memset(object + s->offset, 0, sizeof(void *));
+
+       maybe_wipe_obj_freeptr(s, object);
 
        if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object)
                memset(object, 0, s->object_size);
@@ -3178,10 +3165,13 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
                                goto error;
 
                        c = this_cpu_ptr(s->cpu_slab);
+                       maybe_wipe_obj_freeptr(s, p[i]);
+
                        continue; /* goto for-loop */
                }
                c->freelist = get_freepointer(s, object);
                p[i] = object;
+               maybe_wipe_obj_freeptr(s, p[i]);
        }
        c->tid = next_tid(c->tid);
        local_irq_enable();
@@ -4394,31 +4384,26 @@ static int count_total(struct page *page)
 #endif
 
 #ifdef CONFIG_SLUB_DEBUG
-static int validate_slab(struct kmem_cache *s, struct page *page,
+static void validate_slab(struct kmem_cache *s, struct page *page,
                                                unsigned long *map)
 {
        void *p;
        void *addr = page_address(page);
 
-       if (!check_slab(s, page) ||
-                       !on_freelist(s, page, NULL))
-               return 0;
+       if (!check_slab(s, page) || !on_freelist(s, page, NULL))
+               return;
 
        /* Now we know that a valid freelist exists */
        bitmap_zero(map, page->objects);
 
        get_map(s, page, map);
        for_each_object(p, s, addr, page->objects) {
-               if (test_bit(slab_index(p, s, addr), map))
-                       if (!check_object(s, page, p, SLUB_RED_INACTIVE))
-                               return 0;
-       }
+               u8 val = test_bit(slab_index(p, s, addr), map) ?
+                        SLUB_RED_INACTIVE : SLUB_RED_ACTIVE;
 
-       for_each_object(p, s, addr, page->objects)
-               if (!test_bit(slab_index(p, s, addr), map))
-                       if (!check_object(s, page, p, SLUB_RED_ACTIVE))
-                               return 0;
-       return 1;
+               if (!check_object(s, page, p, val))
+                       break;
+       }
 }
 
 static void validate_slab_slab(struct kmem_cache *s, struct page *page,
@@ -4846,7 +4831,17 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
                }
        }
 
-       get_online_mems();
+       /*
+        * It is impossible to take "mem_hotplug_lock" here with "kernfs_mutex"
+        * already held which will conflict with an existing lock order:
+        *
+        * mem_hotplug_lock->slab_mutex->kernfs_mutex
+        *
+        * We don't really need mem_hotplug_lock (to hold off
+        * slab_mem_going_offline_callback) here because slab's memory hot
+        * unplug code doesn't destroy the kmem_cache->node[] data.
+        */
+
 #ifdef CONFIG_SLUB_DEBUG
        if (flags & SO_ALL) {
                struct kmem_cache_node *n;
@@ -4887,7 +4882,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
                        x += sprintf(buf + x, " N%d=%lu",
                                        node, nodes[node]);
 #endif
-       put_online_mems();
        kfree(nodes);
        return x + sprintf(buf + x, "\n");
 }