mm/slab: factor out debugging initialization in cache_init_objs()
[deliverable/linux.git] / mm / slab.c
index 907abe9964bf6f86a1d3e1a54fccf8015528f481..d3608d15fbe4c92968cc9a41977bf6d4d5f426d4 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -272,7 +272,6 @@ static void kmem_cache_node_init(struct kmem_cache_node *parent)
 
 #define CFLGS_OFF_SLAB         (0x80000000UL)
 #define        OFF_SLAB(x)     ((x)->flags & CFLGS_OFF_SLAB)
-#define OFF_SLAB_MIN_SIZE (max_t(size_t, PAGE_SIZE >> 5, KMALLOC_MIN_SIZE + 1))
 
 #define BATCHREFILL_LIMIT      16
 /*
@@ -380,22 +379,8 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
 
 #endif
 
-#define OBJECT_FREE (0)
-#define OBJECT_ACTIVE (1)
-
 #ifdef CONFIG_DEBUG_SLAB_LEAK
 
-static void set_obj_status(struct page *page, int idx, int val)
-{
-       int freelist_size;
-       char *status;
-       struct kmem_cache *cachep = page->slab_cache;
-
-       freelist_size = cachep->num * sizeof(freelist_idx_t);
-       status = (char *)page->freelist + freelist_size;
-       status[idx] = val;
-}
-
 static inline bool is_store_user_clean(struct kmem_cache *cachep)
 {
        return atomic_read(&cachep->store_user_clean) == 1;
@@ -413,7 +398,6 @@ static inline void set_store_user_dirty(struct kmem_cache *cachep)
 }
 
 #else
-static inline void set_obj_status(struct page *page, int idx, int val) {}
 static inline void set_store_user_dirty(struct kmem_cache *cachep) {}
 
 #endif
@@ -471,61 +455,12 @@ static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep)
        return this_cpu_ptr(cachep->cpu_cache);
 }
 
-static size_t calculate_freelist_size(int nr_objs, size_t align)
-{
-       size_t freelist_size;
-
-       freelist_size = nr_objs * sizeof(freelist_idx_t);
-       if (IS_ENABLED(CONFIG_DEBUG_SLAB_LEAK))
-               freelist_size += nr_objs * sizeof(char);
-
-       if (align)
-               freelist_size = ALIGN(freelist_size, align);
-
-       return freelist_size;
-}
-
-static int calculate_nr_objs(size_t slab_size, size_t buffer_size,
-                               size_t idx_size, size_t align)
-{
-       int nr_objs;
-       size_t remained_size;
-       size_t freelist_size;
-       int extra_space = 0;
-
-       if (IS_ENABLED(CONFIG_DEBUG_SLAB_LEAK))
-               extra_space = sizeof(char);
-       /*
-        * Ignore padding for the initial guess. The padding
-        * is at most @align-1 bytes, and @buffer_size is at
-        * least @align. In the worst case, this result will
-        * be one greater than the number of objects that fit
-        * into the memory allocation when taking the padding
-        * into account.
-        */
-       nr_objs = slab_size / (buffer_size + idx_size + extra_space);
-
-       /*
-        * This calculated number will be either the right
-        * amount, or one greater than what we want.
-        */
-       remained_size = slab_size - nr_objs * buffer_size;
-       freelist_size = calculate_freelist_size(nr_objs, align);
-       if (remained_size < freelist_size)
-               nr_objs--;
-
-       return nr_objs;
-}
-
 /*
  * Calculate the number of objects and left-over bytes for a given buffer size.
  */
 static void cache_estimate(unsigned long gfporder, size_t buffer_size,
-                          size_t align, int flags, size_t *left_over,
-                          unsigned int *num)
+               unsigned long flags, size_t *left_over, unsigned int *num)
 {
-       int nr_objs;
-       size_t mgmt_size;
        size_t slab_size = PAGE_SIZE << gfporder;
 
        /*
@@ -533,9 +468,12 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size,
         * on it. For the latter case, the memory allocated for a
         * slab is used for:
         *
-        * - One freelist_idx_t for each object
-        * - Padding to respect alignment of @align
         * - @buffer_size bytes for each object
+        * - One freelist_idx_t for each object
+        *
+        * We don't need to consider alignment of freelist because
+        * freelist will be at the end of slab page. The objects will be
+        * at the correct alignment.
         *
         * If the slab management structure is off the slab, then the
         * alignment will already be calculated into the size. Because
@@ -543,16 +481,13 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size,
         * correct alignment when allocated.
         */
        if (flags & CFLGS_OFF_SLAB) {
-               mgmt_size = 0;
-               nr_objs = slab_size / buffer_size;
-
+               *num = slab_size / buffer_size;
+               *left_over = slab_size % buffer_size;
        } else {
-               nr_objs = calculate_nr_objs(slab_size, buffer_size,
-                                       sizeof(freelist_idx_t), align);
-               mgmt_size = calculate_freelist_size(nr_objs, align);
+               *num = slab_size / (buffer_size + sizeof(freelist_idx_t));
+               *left_over = slab_size %
+                       (buffer_size + sizeof(freelist_idx_t));
        }
-       *num = nr_objs;
-       *left_over = slab_size - nr_objs*buffer_size - mgmt_size;
 }
 
 #if DEBUG
@@ -1932,7 +1867,6 @@ static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list)
  * calculate_slab_order - calculate size (page order) of slabs
  * @cachep: pointer to the cache that is being created
  * @size: size of objects to be created in this cache.
- * @align: required alignment for the objects.
  * @flags: slab allocation flags
  *
  * Also calculates the number of objects per slab.
@@ -1942,9 +1876,8 @@ static void slabs_destroy(struct kmem_cache *cachep, struct list_head *list)
  * towards high-order requests, this should be changed.
  */
 static size_t calculate_slab_order(struct kmem_cache *cachep,
-                       size_t size, size_t align, unsigned long flags)
+                               size_t size, unsigned long flags)
 {
-       unsigned long offslab_limit;
        size_t left_over = 0;
        int gfporder;
 
@@ -1952,7 +1885,7 @@ static size_t calculate_slab_order(struct kmem_cache *cachep,
                unsigned int num;
                size_t remainder;
 
-               cache_estimate(gfporder, size, align, flags, &remainder, &num);
+               cache_estimate(gfporder, size, flags, &remainder, &num);
                if (!num)
                        continue;
 
@@ -1961,19 +1894,24 @@ static size_t calculate_slab_order(struct kmem_cache *cachep,
                        break;
 
                if (flags & CFLGS_OFF_SLAB) {
-                       size_t freelist_size_per_obj = sizeof(freelist_idx_t);
+                       struct kmem_cache *freelist_cache;
+                       size_t freelist_size;
+
+                       freelist_size = num * sizeof(freelist_idx_t);
+                       freelist_cache = kmalloc_slab(freelist_size, 0u);
+                       if (!freelist_cache)
+                               continue;
+
                        /*
-                        * Max number of objs-per-slab for caches which
-                        * use off-slab slabs. Needed to avoid a possible
-                        * looping condition in cache_grow().
+                        * Needed to avoid possible looping condition
+                        * in cache_grow()
                         */
-                       if (IS_ENABLED(CONFIG_DEBUG_SLAB_LEAK))
-                               freelist_size_per_obj += sizeof(char);
-                       offslab_limit = size;
-                       offslab_limit /= freelist_size_per_obj;
+                       if (OFF_SLAB(freelist_cache))
+                               continue;
 
-                       if (num > offslab_limit)
-                               break;
+                       /* check if off slab has enough benefit */
+                       if (freelist_cache->size > cachep->size / 2)
+                               continue;
                }
 
                /* Found something acceptable - save it away */
@@ -2091,6 +2029,56 @@ __kmem_cache_alias(const char *name, size_t size, size_t align,
        return cachep;
 }
 
+static bool set_off_slab_cache(struct kmem_cache *cachep,
+                       size_t size, unsigned long flags)
+{
+       size_t left;
+
+       cachep->num = 0;
+
+       /*
+        * Always use on-slab management when SLAB_NOLEAKTRACE
+        * to avoid recursive calls into kmemleak.
+        */
+       if (flags & SLAB_NOLEAKTRACE)
+               return false;
+
+       /*
+        * Size is large, assume best to place the slab management obj
+        * off-slab (should allow better packing of objs).
+        */
+       left = calculate_slab_order(cachep, size, flags | CFLGS_OFF_SLAB);
+       if (!cachep->num)
+               return false;
+
+       /*
+        * If the slab has been placed off-slab, and we have enough space then
+        * move it on-slab. This is at the expense of any extra colouring.
+        */
+       if (left >= cachep->num * sizeof(freelist_idx_t))
+               return false;
+
+       cachep->colour = left / cachep->colour_off;
+
+       return true;
+}
+
+static bool set_on_slab_cache(struct kmem_cache *cachep,
+                       size_t size, unsigned long flags)
+{
+       size_t left;
+
+       cachep->num = 0;
+
+       left = calculate_slab_order(cachep, size, flags);
+       if (!cachep->num)
+               return false;
+
+       cachep->colour = left / cachep->colour_off;
+
+       return true;
+}
+
 /**
  * __kmem_cache_create - Create a cache.
  * @cachep: cache management descriptor
@@ -2115,7 +2103,6 @@ __kmem_cache_alias(const char *name, size_t size, size_t align,
 int
 __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
 {
-       size_t left_over, freelist_size;
        size_t ralign = BYTES_PER_WORD;
        gfp_t gfp;
        int err;
@@ -2166,6 +2153,10 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
         * 4) Store it.
         */
        cachep->align = ralign;
+       cachep->colour_off = cache_line_size();
+       /* Offset must be a multiple of the alignment. */
+       if (cachep->colour_off < cachep->align)
+               cachep->colour_off = cachep->align;
 
        if (slab_is_available())
                gfp = GFP_KERNEL;
@@ -2193,36 +2184,8 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
                else
                        size += BYTES_PER_WORD;
        }
-       /*
-        * To activate debug pagealloc, off-slab management is necessary
-        * requirement. In early phase of initialization, small sized slab
-        * doesn't get initialized so it would not be possible. So, we need
-        * to check size >= 256. It guarantees that all necessary small
-        * sized slab is initialized in current slab initialization sequence.
-        */
-       if (debug_pagealloc_enabled() && (flags & SLAB_POISON) &&
-               !slab_early_init && size >= kmalloc_size(INDEX_NODE) &&
-               size >= 256 && cachep->object_size > cache_line_size() &&
-               ALIGN(size, cachep->align) < PAGE_SIZE) {
-               cachep->obj_offset += PAGE_SIZE - ALIGN(size, cachep->align);
-               size = PAGE_SIZE;
-       }
 #endif
 
-       /*
-        * Determine if the slab management is 'on' or 'off' slab.
-        * (bootstrapping cannot cope with offslab caches so don't do
-        * it too early on. Always use on-slab management when
-        * SLAB_NOLEAKTRACE to avoid recursive calls into kmemleak)
-        */
-       if (size >= OFF_SLAB_MIN_SIZE && !slab_early_init &&
-           !(flags & SLAB_NOLEAKTRACE))
-               /*
-                * Size is large, assume best to place the slab management obj
-                * off-slab (should allow better packing of objs).
-                */
-               flags |= CFLGS_OFF_SLAB;
-
        size = ALIGN(size, cachep->align);
        /*
         * We should restrict the number of objects in a slab to implement
@@ -2231,33 +2194,41 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
        if (FREELIST_BYTE_INDEX && size < SLAB_OBJ_MIN_SIZE)
                size = ALIGN(SLAB_OBJ_MIN_SIZE, cachep->align);
 
-       left_over = calculate_slab_order(cachep, size, cachep->align, flags);
-
-       if (!cachep->num)
-               return -E2BIG;
-
-       freelist_size = calculate_freelist_size(cachep->num, cachep->align);
-
+#if DEBUG
        /*
-        * If the slab has been placed off-slab, and we have enough space then
-        * move it on-slab. This is at the expense of any extra colouring.
+        * To activate debug pagealloc, off-slab management is necessary
+        * requirement. In early phase of initialization, small sized slab
+        * doesn't get initialized so it would not be possible. So, we need
+        * to check size >= 256. It guarantees that all necessary small
+        * sized slab is initialized in current slab initialization sequence.
         */
-       if (flags & CFLGS_OFF_SLAB && left_over >= freelist_size) {
-               flags &= ~CFLGS_OFF_SLAB;
-               left_over -= freelist_size;
+       if (debug_pagealloc_enabled() && (flags & SLAB_POISON) &&
+               size >= 256 && cachep->object_size > cache_line_size()) {
+               if (size < PAGE_SIZE || size % PAGE_SIZE == 0) {
+                       size_t tmp_size = ALIGN(size, PAGE_SIZE);
+
+                       if (set_off_slab_cache(cachep, tmp_size, flags)) {
+                               flags |= CFLGS_OFF_SLAB;
+                               cachep->obj_offset += tmp_size - size;
+                               size = tmp_size;
+                               goto done;
+                       }
+               }
        }
+#endif
 
-       if (flags & CFLGS_OFF_SLAB) {
-               /* really off slab. No need for manual alignment */
-               freelist_size = calculate_freelist_size(cachep->num, 0);
+       if (set_off_slab_cache(cachep, size, flags)) {
+               flags |= CFLGS_OFF_SLAB;
+               goto done;
        }
 
-       cachep->colour_off = cache_line_size();
-       /* Offset must be a multiple of the alignment. */
-       if (cachep->colour_off < cachep->align)
-               cachep->colour_off = cachep->align;
-       cachep->colour = left_over / cachep->colour_off;
-       cachep->freelist_size = freelist_size;
+       if (set_on_slab_cache(cachep, size, flags))
+               goto done;
+
+       return -E2BIG;
+
+done:
+       cachep->freelist_size = cachep->num * sizeof(freelist_idx_t);
        cachep->flags = flags;
        cachep->allocflags = __GFP_COMP;
        if (CONFIG_ZONE_DMA_FLAG && (flags & SLAB_CACHE_DMA))
@@ -2278,15 +2249,8 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
 #endif
 
        if (OFF_SLAB(cachep)) {
-               cachep->freelist_cache = kmalloc_slab(freelist_size, 0u);
-               /*
-                * This is a possibility for one of the kmalloc_{dma,}_caches.
-                * But since we go off slab only for object size greater than
-                * OFF_SLAB_MIN_SIZE, and kmalloc_{dma,}_caches get created
-                * in ascending order,this should not happen at all.
-                * But leave a BUG_ON for some lucky dude.
-                */
-               BUG_ON(ZERO_OR_NULL_PTR(cachep->freelist_cache));
+               cachep->freelist_cache =
+                       kmalloc_slab(cachep->freelist_size, 0u);
        }
 
        err = setup_cpu_cache(cachep, gfp);
@@ -2467,6 +2431,9 @@ static void *alloc_slabmgmt(struct kmem_cache *cachep,
        void *freelist;
        void *addr = page_address(page);
 
+       page->s_mem = addr + colour_off;
+       page->active = 0;
+
        if (OFF_SLAB(cachep)) {
                /* Slab management obj is off-slab. */
                freelist = kmem_cache_alloc_node(cachep->freelist_cache,
@@ -2474,11 +2441,11 @@ static void *alloc_slabmgmt(struct kmem_cache *cachep,
                if (!freelist)
                        return NULL;
        } else {
-               freelist = addr + colour_off;
-               colour_off += cachep->freelist_size;
+               /* We will use last bytes at the slab for freelist */
+               freelist = addr + (PAGE_SIZE << cachep->gfporder) -
+                               cachep->freelist_size;
        }
-       page->active = 0;
-       page->s_mem = addr + colour_off;
+
        return freelist;
 }
 
@@ -2493,14 +2460,14 @@ static inline void set_free_obj(struct page *page,
        ((freelist_idx_t *)(page->freelist))[idx] = val;
 }
 
-static void cache_init_objs(struct kmem_cache *cachep,
-                           struct page *page)
+static void cache_init_objs_debug(struct kmem_cache *cachep, struct page *page)
 {
+#if DEBUG
        int i;
 
        for (i = 0; i < cachep->num; i++) {
                void *objp = index_to_obj(cachep, page, i);
-#if DEBUG
+
                if (cachep->flags & SLAB_STORE_USER)
                        *dbg_userword(cachep, objp) = NULL;
 
@@ -2529,11 +2496,22 @@ static void cache_init_objs(struct kmem_cache *cachep,
                        poison_obj(cachep, objp, POISON_FREE);
                        slab_kernel_map(cachep, objp, 0, 0);
                }
-#else
-               if (cachep->ctor)
-                       cachep->ctor(objp);
+       }
 #endif
-               set_obj_status(page, i, OBJECT_FREE);
+}
+
+static void cache_init_objs(struct kmem_cache *cachep,
+                           struct page *page)
+{
+       int i;
+
+       cache_init_objs_debug(cachep, page);
+
+       for (i = 0; i < cachep->num; i++) {
+               /* constructor could break poison info */
+               if (DEBUG == 0 && cachep->ctor)
+                       cachep->ctor(index_to_obj(cachep, page, i));
+
                set_free_obj(page, i, i);
        }
 }
@@ -2745,7 +2723,6 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
        BUG_ON(objnr >= cachep->num);
        BUG_ON(objp != index_to_obj(cachep, page, objnr));
 
-       set_obj_status(page, objnr, OBJECT_FREE);
        if (cachep->flags & SLAB_POISON) {
                poison_obj(cachep, objp, POISON_FREE);
                slab_kernel_map(cachep, objp, 0, caller);
@@ -2758,6 +2735,17 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
 #define cache_free_debugcheck(x,objp,z) (objp)
 #endif
 
+static inline void fixup_slab_list(struct kmem_cache *cachep,
+                               struct kmem_cache_node *n, struct page *page)
+{
+       /* move slabp to correct slabp list: */
+       list_del(&page->lru);
+       if (page->active == cachep->num)
+               list_add(&page->lru, &n->slabs_full);
+       else
+               list_add(&page->lru, &n->slabs_partial);
+}
+
 static struct page *get_first_slab(struct kmem_cache_node *n)
 {
        struct page *page;
@@ -2831,12 +2819,7 @@ retry:
                        ac_put_obj(cachep, ac, slab_get_obj(cachep, page));
                }
 
-               /* move slabp to correct slabp list: */
-               list_del(&page->lru);
-               if (page->active == cachep->num)
-                       list_add(&page->lru, &n->slabs_full);
-               else
-                       list_add(&page->lru, &n->slabs_partial);
+               fixup_slab_list(cachep, n, page);
        }
 
 must_grow:
@@ -2878,8 +2861,6 @@ static inline void cache_alloc_debugcheck_before(struct kmem_cache *cachep,
 static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
                                gfp_t flags, void *objp, unsigned long caller)
 {
-       struct page *page;
-
        if (!objp)
                return objp;
        if (cachep->flags & SLAB_POISON) {
@@ -2904,8 +2885,6 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
                *dbg_redzone2(cachep, objp) = RED_ACTIVE;
        }
 
-       page = virt_to_head_page(objp);
-       set_obj_status(page, obj_to_index(cachep, page, objp), OBJECT_ACTIVE);
        objp += obj_offset(cachep);
        if (cachep->ctor && cachep->flags & SLAB_POISON)
                cachep->ctor(objp);
@@ -3106,13 +3085,8 @@ retry:
 
        obj = slab_get_obj(cachep, page);
        n->free_objects--;
-       /* move slabp to correct slabp list: */
-       list_del(&page->lru);
 
-       if (page->active == cachep->num)
-               list_add(&page->lru, &n->slabs_full);
-       else
-               list_add(&page->lru, &n->slabs_partial);
+       fixup_slab_list(cachep, n, page);
 
        spin_unlock(&n->list_lock);
        goto done;
This page took 0.029242 seconds and 5 git commands to generate.