Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[linux-2.6-block.git] / mm / slab.c
index 8133ebea77a48e11366f11304119158d82815688..cc8bbc1e6bc9b6fe5d980ffe3837d7b4c8843d84 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -522,22 +522,15 @@ static DEFINE_PER_CPU(unsigned long, slab_reap_node);
 
 static void init_reap_node(int cpu)
 {
-       int node;
-
-       node = next_node(cpu_to_mem(cpu), node_online_map);
-       if (node == MAX_NUMNODES)
-               node = first_node(node_online_map);
-
-       per_cpu(slab_reap_node, cpu) = node;
+       per_cpu(slab_reap_node, cpu) = next_node_in(cpu_to_mem(cpu),
+                                                   node_online_map);
 }
 
 static void next_reap_node(void)
 {
        int node = __this_cpu_read(slab_reap_node);
 
-       node = next_node(node, node_online_map);
-       if (unlikely(node >= MAX_NUMNODES))
-               node = first_node(node_online_map);
+       node = next_node_in(node, node_online_map);
        __this_cpu_write(slab_reap_node, node);
 }
 
@@ -1243,6 +1236,61 @@ static void __init set_up_node(struct kmem_cache *cachep, int index)
        }
 }
 
+#ifdef CONFIG_SLAB_FREELIST_RANDOM
+static void freelist_randomize(struct rnd_state *state, freelist_idx_t *list,
+                       size_t count)
+{
+       size_t i;
+       unsigned int rand;
+
+       for (i = 0; i < count; i++)
+               list[i] = i;
+
+       /* Fisher-Yates shuffle */
+       for (i = count - 1; i > 0; i--) {
+               rand = prandom_u32_state(state);
+               rand %= (i + 1);
+               swap(list[i], list[rand]);
+       }
+}
+
+/* Create a random sequence per cache */
+static int cache_random_seq_create(struct kmem_cache *cachep, gfp_t gfp)
+{
+       unsigned int seed, count = cachep->num;
+       struct rnd_state state;
+
+       if (count < 2)
+               return 0;
+
+       /* If it fails, we will just use the global lists */
+       cachep->random_seq = kcalloc(count, sizeof(freelist_idx_t), gfp);
+       if (!cachep->random_seq)
+               return -ENOMEM;
+
+       /* Get best entropy at this stage */
+       get_random_bytes_arch(&seed, sizeof(seed));
+       prandom_seed_state(&state, seed);
+
+       freelist_randomize(&state, cachep->random_seq, count);
+       return 0;
+}
+
+/* Destroy the per-cache random freelist sequence */
+static void cache_random_seq_destroy(struct kmem_cache *cachep)
+{
+       kfree(cachep->random_seq);
+       cachep->random_seq = NULL;
+}
+#else
+static inline int cache_random_seq_create(struct kmem_cache *cachep, gfp_t gfp)
+{
+       return 0;
+}
+static inline void cache_random_seq_destroy(struct kmem_cache *cachep) { }
+#endif /* CONFIG_SLAB_FREELIST_RANDOM */
+
+
 /*
  * Initialisation.  Called after the page allocator have been initialised and
  * before smp_init().
@@ -2181,7 +2229,7 @@ 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))
+       if (flags & SLAB_CACHE_DMA)
                cachep->allocflags |= GFP_DMA;
        cachep->size = size;
        cachep->reciprocal_buffer_size = reciprocal_value(size);
@@ -2374,6 +2422,8 @@ void __kmem_cache_release(struct kmem_cache *cachep)
        int i;
        struct kmem_cache_node *n;
 
+       cache_random_seq_destroy(cachep);
+
        free_percpu(cachep->cpu_cache);
 
        /* NUMA: free the node structures */
@@ -2480,15 +2530,115 @@ static void cache_init_objs_debug(struct kmem_cache *cachep, struct page *page)
 #endif
 }
 
+#ifdef CONFIG_SLAB_FREELIST_RANDOM
+/* Hold information during a freelist initialization */
+union freelist_init_state {
+       struct {
+               unsigned int pos;
+               freelist_idx_t *list;
+               unsigned int count;
+               unsigned int rand;
+       };
+       struct rnd_state rnd_state;
+};
+
+/*
+ * Initialize the state based on the randomization methode available.
+ * return true if the pre-computed list is available, false otherwize.
+ */
+static bool freelist_state_initialize(union freelist_init_state *state,
+                               struct kmem_cache *cachep,
+                               unsigned int count)
+{
+       bool ret;
+       unsigned int rand;
+
+       /* Use best entropy available to define a random shift */
+       get_random_bytes_arch(&rand, sizeof(rand));
+
+       /* Use a random state if the pre-computed list is not available */
+       if (!cachep->random_seq) {
+               prandom_seed_state(&state->rnd_state, rand);
+               ret = false;
+       } else {
+               state->list = cachep->random_seq;
+               state->count = count;
+               state->pos = 0;
+               state->rand = rand;
+               ret = true;
+       }
+       return ret;
+}
+
+/* Get the next entry on the list and randomize it using a random shift */
+static freelist_idx_t next_random_slot(union freelist_init_state *state)
+{
+       return (state->list[state->pos++] + state->rand) % state->count;
+}
+
+/*
+ * Shuffle the freelist initialization state based on pre-computed lists.
+ * return true if the list was successfully shuffled, false otherwise.
+ */
+static bool shuffle_freelist(struct kmem_cache *cachep, struct page *page)
+{
+       unsigned int objfreelist = 0, i, count = cachep->num;
+       union freelist_init_state state;
+       bool precomputed;
+
+       if (count < 2)
+               return false;
+
+       precomputed = freelist_state_initialize(&state, cachep, count);
+
+       /* Take a random entry as the objfreelist */
+       if (OBJFREELIST_SLAB(cachep)) {
+               if (!precomputed)
+                       objfreelist = count - 1;
+               else
+                       objfreelist = next_random_slot(&state);
+               page->freelist = index_to_obj(cachep, page, objfreelist) +
+                                               obj_offset(cachep);
+               count--;
+       }
+
+       /*
+        * On early boot, generate the list dynamically.
+        * Later use a pre-computed list for speed.
+        */
+       if (!precomputed) {
+               freelist_randomize(&state.rnd_state, page->freelist, count);
+       } else {
+               for (i = 0; i < count; i++)
+                       set_free_obj(page, i, next_random_slot(&state));
+       }
+
+       if (OBJFREELIST_SLAB(cachep))
+               set_free_obj(page, cachep->num - 1, objfreelist);
+
+       return true;
+}
+#else
+static inline bool shuffle_freelist(struct kmem_cache *cachep,
+                               struct page *page)
+{
+       return false;
+}
+#endif /* CONFIG_SLAB_FREELIST_RANDOM */
+
 static void cache_init_objs(struct kmem_cache *cachep,
                            struct page *page)
 {
        int i;
        void *objp;
+       bool shuffled;
 
        cache_init_objs_debug(cachep, page);
 
-       if (OBJFREELIST_SLAB(cachep)) {
+       /* Try to randomize the freelist if enabled */
+       shuffled = shuffle_freelist(cachep, page);
+
+       if (!shuffled && OBJFREELIST_SLAB(cachep)) {
                page->freelist = index_to_obj(cachep, page, cachep->num - 1) +
                                                obj_offset(cachep);
        }
@@ -2502,17 +2652,8 @@ static void cache_init_objs(struct kmem_cache *cachep,
                        kasan_poison_object_data(cachep, objp);
                }
 
-               set_free_obj(page, i, i);
-       }
-}
-
-static void kmem_flagcheck(struct kmem_cache *cachep, gfp_t flags)
-{
-       if (CONFIG_ZONE_DMA_FLAG) {
-               if (flags & GFP_DMA)
-                       BUG_ON(!(cachep->allocflags & GFP_DMA));
-               else
-                       BUG_ON(cachep->allocflags & GFP_DMA);
+               if (!shuffled)
+                       set_free_obj(page, i, i);
        }
 }
 
@@ -2594,14 +2735,6 @@ static struct page *cache_grow_begin(struct kmem_cache *cachep,
        if (gfpflags_allow_blocking(local_flags))
                local_irq_enable();
 
-       /*
-        * The test for missing atomic flag is performed here, rather than
-        * the more obvious place, simply to reduce the critical path length
-        * in kmem_cache_alloc(). If a caller is seriously mis-behaving they
-        * will eventually be caught here (where it matters).
-        */
-       kmem_flagcheck(cachep, flags);
-
        /*
         * Get mem for the objs.  Attempt to allocate a physical page from
         * 'nodeid'.
@@ -2987,9 +3120,6 @@ static inline void cache_alloc_debugcheck_before(struct kmem_cache *cachep,
                                                gfp_t flags)
 {
        might_sleep_if(gfpflags_allow_blocking(flags));
-#if DEBUG
-       kmem_flagcheck(cachep, flags);
-#endif
 }
 
 #if DEBUG
@@ -3417,9 +3547,17 @@ free_done:
 static inline void __cache_free(struct kmem_cache *cachep, void *objp,
                                unsigned long caller)
 {
-       struct array_cache *ac = cpu_cache_get(cachep);
+       /* Put the object into the quarantine, don't touch it for now. */
+       if (kasan_slab_free(cachep, objp))
+               return;
 
-       kasan_slab_free(cachep, objp);
+       ___cache_free(cachep, objp, caller);
+}
+
+void ___cache_free(struct kmem_cache *cachep, void *objp,
+               unsigned long caller)
+{
+       struct array_cache *ac = cpu_cache_get(cachep);
 
        check_irq_off();
        kmemleak_free_recursive(objp, cachep->flags);
@@ -3841,6 +3979,10 @@ static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
        int shared = 0;
        int batchcount = 0;
 
+       err = cache_random_seq_create(cachep, gfp);
+       if (err)
+               goto end;
+
        if (!is_root_cache(cachep)) {
                struct kmem_cache *root = memcg_root_cache(cachep);
                limit = root->limit;
@@ -3894,6 +4036,7 @@ static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
        batchcount = (limit + 1) / 2;
 skip_setup:
        err = do_tune_cpucache(cachep, limit, batchcount, shared, gfp);
+end:
        if (err)
                pr_err("enable_cpucache failed for %s, error %d\n",
                       cachep->name, -err);
@@ -4358,7 +4501,7 @@ size_t ksize(const void *objp)
        /* We assume that ksize callers could use the whole allocated area,
         * so we need to unpoison this area.
         */
-       kasan_krealloc(objp, size, GFP_NOWAIT);
+       kasan_unpoison_shadow(objp, size);
 
        return size;
 }