aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesper Dangaard Brouer <brouer@redhat.com>2015-11-20 18:57:46 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-22 14:58:41 -0500
commit81084651d73737988355f167065fab8a73574db1 (patch)
treee4b011ccc83add5703f62dfe779b91f96ec9d02e
parentb4a64718797b84b64a6ddf3d4183c29c2e79ef1d (diff)
slub: support for bulk free with SLUB freelists
Make it possible to free a freelist with several objects by adjusting API of slab_free() and __slab_free() to have head, tail and an objects counter (cnt). Tail being NULL indicate single object free of head object. This allow compiler inline constant propagation in slab_free() and slab_free_freelist_hook() to avoid adding any overhead in case of single object free. This allows a freelist with several objects (all within the same slab-page) to be free'ed using a single locked cmpxchg_double in __slab_free() and with an unlocked cmpxchg_double in slab_free(). Object debugging on the free path is also extended to handle these freelists. When CONFIG_SLUB_DEBUG is enabled it will also detect if objects don't belong to the same slab-page. These changes are needed for the next patch to bulk free the detached freelists it introduces and constructs. Micro benchmarking showed no performance reduction due to this change, when debugging is turned off (compiled with CONFIG_SLUB_DEBUG). Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com> Acked-by: Christoph Lameter <cl@linux.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/slub.c85
1 files changed, 67 insertions, 18 deletions
diff --git a/mm/slub.c b/mm/slub.c
index a0c1365f6426..d52f0d0ab712 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1065,11 +1065,15 @@ bad:
1065 return 0; 1065 return 0;
1066} 1066}
1067 1067
1068/* Supports checking bulk free of a constructed freelist */
1068static noinline struct kmem_cache_node *free_debug_processing( 1069static noinline struct kmem_cache_node *free_debug_processing(
1069 struct kmem_cache *s, struct page *page, void *object, 1070 struct kmem_cache *s, struct page *page,
1071 void *head, void *tail, int bulk_cnt,
1070 unsigned long addr, unsigned long *flags) 1072 unsigned long addr, unsigned long *flags)
1071{ 1073{
1072 struct kmem_cache_node *n = get_node(s, page_to_nid(page)); 1074 struct kmem_cache_node *n = get_node(s, page_to_nid(page));
1075 void *object = head;
1076 int cnt = 0;
1073 1077
1074 spin_lock_irqsave(&n->list_lock, *flags); 1078 spin_lock_irqsave(&n->list_lock, *flags);
1075 slab_lock(page); 1079 slab_lock(page);
@@ -1077,6 +1081,9 @@ static noinline struct kmem_cache_node *free_debug_processing(
1077 if (!check_slab(s, page)) 1081 if (!check_slab(s, page))
1078 goto fail; 1082 goto fail;
1079 1083
1084next_object:
1085 cnt++;
1086
1080 if (!check_valid_pointer(s, page, object)) { 1087 if (!check_valid_pointer(s, page, object)) {
1081 slab_err(s, page, "Invalid object pointer 0x%p", object); 1088 slab_err(s, page, "Invalid object pointer 0x%p", object);
1082 goto fail; 1089 goto fail;
@@ -1107,8 +1114,19 @@ static noinline struct kmem_cache_node *free_debug_processing(
1107 if (s->flags & SLAB_STORE_USER) 1114 if (s->flags & SLAB_STORE_USER)
1108 set_track(s, object, TRACK_FREE, addr); 1115 set_track(s, object, TRACK_FREE, addr);
1109 trace(s, page, object, 0); 1116 trace(s, page, object, 0);
1117 /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */
1110 init_object(s, object, SLUB_RED_INACTIVE); 1118 init_object(s, object, SLUB_RED_INACTIVE);
1119
1120 /* Reached end of constructed freelist yet? */
1121 if (object != tail) {
1122 object = get_freepointer(s, object);
1123 goto next_object;
1124 }
1111out: 1125out:
1126 if (cnt != bulk_cnt)
1127 slab_err(s, page, "Bulk freelist count(%d) invalid(%d)\n",
1128 bulk_cnt, cnt);
1129
1112 slab_unlock(page); 1130 slab_unlock(page);
1113 /* 1131 /*
1114 * Keep node_lock to preserve integrity 1132 * Keep node_lock to preserve integrity
@@ -1212,7 +1230,8 @@ static inline int alloc_debug_processing(struct kmem_cache *s,
1212 struct page *page, void *object, unsigned long addr) { return 0; } 1230 struct page *page, void *object, unsigned long addr) { return 0; }
1213 1231
1214static inline struct kmem_cache_node *free_debug_processing( 1232static inline struct kmem_cache_node *free_debug_processing(
1215 struct kmem_cache *s, struct page *page, void *object, 1233 struct kmem_cache *s, struct page *page,
1234 void *head, void *tail, int bulk_cnt,
1216 unsigned long addr, unsigned long *flags) { return NULL; } 1235 unsigned long addr, unsigned long *flags) { return NULL; }
1217 1236
1218static inline int slab_pad_check(struct kmem_cache *s, struct page *page) 1237static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
@@ -1308,6 +1327,29 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
1308 kasan_slab_free(s, x); 1327 kasan_slab_free(s, x);
1309} 1328}
1310 1329
1330static inline void slab_free_freelist_hook(struct kmem_cache *s,
1331 void *head, void *tail)
1332{
1333/*
1334 * Compiler cannot detect this function can be removed if slab_free_hook()
1335 * evaluates to nothing. Thus, catch all relevant config debug options here.
1336 */
1337#if defined(CONFIG_KMEMCHECK) || \
1338 defined(CONFIG_LOCKDEP) || \
1339 defined(CONFIG_DEBUG_KMEMLEAK) || \
1340 defined(CONFIG_DEBUG_OBJECTS_FREE) || \
1341 defined(CONFIG_KASAN)
1342
1343 void *object = head;
1344 void *tail_obj = tail ? : head;
1345
1346 do {
1347 slab_free_hook(s, object);
1348 } while ((object != tail_obj) &&
1349 (object = get_freepointer(s, object)));
1350#endif
1351}
1352
1311static void setup_object(struct kmem_cache *s, struct page *page, 1353static void setup_object(struct kmem_cache *s, struct page *page,
1312 void *object) 1354 void *object)
1313{ 1355{
@@ -2583,10 +2625,11 @@ EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
2583 * handling required then we can return immediately. 2625 * handling required then we can return immediately.
2584 */ 2626 */
2585static void __slab_free(struct kmem_cache *s, struct page *page, 2627static void __slab_free(struct kmem_cache *s, struct page *page,
2586 void *x, unsigned long addr) 2628 void *head, void *tail, int cnt,
2629 unsigned long addr)
2630
2587{ 2631{
2588 void *prior; 2632 void *prior;
2589 void **object = (void *)x;
2590 int was_frozen; 2633 int was_frozen;
2591 struct page new; 2634 struct page new;
2592 unsigned long counters; 2635 unsigned long counters;
@@ -2596,7 +2639,8 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
2596 stat(s, FREE_SLOWPATH); 2639 stat(s, FREE_SLOWPATH);
2597 2640
2598 if (kmem_cache_debug(s) && 2641 if (kmem_cache_debug(s) &&
2599 !(n = free_debug_processing(s, page, x, addr, &flags))) 2642 !(n = free_debug_processing(s, page, head, tail, cnt,
2643 addr, &flags)))
2600 return; 2644 return;
2601 2645
2602 do { 2646 do {
@@ -2606,10 +2650,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
2606 } 2650 }
2607 prior = page->freelist; 2651 prior = page->freelist;
2608 counters = page->counters; 2652 counters = page->counters;
2609 set_freepointer(s, object, prior); 2653 set_freepointer(s, tail, prior);
2610 new.counters = counters; 2654 new.counters = counters;
2611 was_frozen = new.frozen; 2655 was_frozen = new.frozen;
2612 new.inuse--; 2656 new.inuse -= cnt;
2613 if ((!new.inuse || !prior) && !was_frozen) { 2657 if ((!new.inuse || !prior) && !was_frozen) {
2614 2658
2615 if (kmem_cache_has_cpu_partial(s) && !prior) { 2659 if (kmem_cache_has_cpu_partial(s) && !prior) {
@@ -2640,7 +2684,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
2640 2684
2641 } while (!cmpxchg_double_slab(s, page, 2685 } while (!cmpxchg_double_slab(s, page,
2642 prior, counters, 2686 prior, counters,
2643 object, new.counters, 2687 head, new.counters,
2644 "__slab_free")); 2688 "__slab_free"));
2645 2689
2646 if (likely(!n)) { 2690 if (likely(!n)) {
@@ -2705,15 +2749,20 @@ slab_empty:
2705 * 2749 *
2706 * If fastpath is not possible then fall back to __slab_free where we deal 2750 * If fastpath is not possible then fall back to __slab_free where we deal
2707 * with all sorts of special processing. 2751 * with all sorts of special processing.
2752 *
2753 * Bulk free of a freelist with several objects (all pointing to the
2754 * same page) possible by specifying head and tail ptr, plus objects
2755 * count (cnt). Bulk free indicated by tail pointer being set.
2708 */ 2756 */
2709static __always_inline void slab_free(struct kmem_cache *s, 2757static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
2710 struct page *page, void *x, unsigned long addr) 2758 void *head, void *tail, int cnt,
2759 unsigned long addr)
2711{ 2760{
2712 void **object = (void *)x; 2761 void *tail_obj = tail ? : head;
2713 struct kmem_cache_cpu *c; 2762 struct kmem_cache_cpu *c;
2714 unsigned long tid; 2763 unsigned long tid;
2715 2764
2716 slab_free_hook(s, x); 2765 slab_free_freelist_hook(s, head, tail);
2717 2766
2718redo: 2767redo:
2719 /* 2768 /*
@@ -2732,19 +2781,19 @@ redo:
2732 barrier(); 2781 barrier();
2733 2782
2734 if (likely(page == c->page)) { 2783 if (likely(page == c->page)) {
2735 set_freepointer(s, object, c->freelist); 2784 set_freepointer(s, tail_obj, c->freelist);
2736 2785
2737 if (unlikely(!this_cpu_cmpxchg_double( 2786 if (unlikely(!this_cpu_cmpxchg_double(
2738 s->cpu_slab->freelist, s->cpu_slab->tid, 2787 s->cpu_slab->freelist, s->cpu_slab->tid,
2739 c->freelist, tid, 2788 c->freelist, tid,
2740 object, next_tid(tid)))) { 2789 head, next_tid(tid)))) {
2741 2790
2742 note_cmpxchg_failure("slab_free", s, tid); 2791 note_cmpxchg_failure("slab_free", s, tid);
2743 goto redo; 2792 goto redo;
2744 } 2793 }
2745 stat(s, FREE_FASTPATH); 2794 stat(s, FREE_FASTPATH);
2746 } else 2795 } else
2747 __slab_free(s, page, x, addr); 2796 __slab_free(s, page, head, tail_obj, cnt, addr);
2748 2797
2749} 2798}
2750 2799
@@ -2753,7 +2802,7 @@ void kmem_cache_free(struct kmem_cache *s, void *x)
2753 s = cache_from_obj(s, x); 2802 s = cache_from_obj(s, x);
2754 if (!s) 2803 if (!s)
2755 return; 2804 return;
2756 slab_free(s, virt_to_head_page(x), x, _RET_IP_); 2805 slab_free(s, virt_to_head_page(x), x, NULL, 1, _RET_IP_);
2757 trace_kmem_cache_free(_RET_IP_, x); 2806 trace_kmem_cache_free(_RET_IP_, x);
2758} 2807}
2759EXPORT_SYMBOL(kmem_cache_free); 2808EXPORT_SYMBOL(kmem_cache_free);
@@ -2788,7 +2837,7 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
2788 c->tid = next_tid(c->tid); 2837 c->tid = next_tid(c->tid);
2789 local_irq_enable(); 2838 local_irq_enable();
2790 /* Slowpath: overhead locked cmpxchg_double_slab */ 2839 /* Slowpath: overhead locked cmpxchg_double_slab */
2791 __slab_free(s, page, object, _RET_IP_); 2840 __slab_free(s, page, object, object, 1, _RET_IP_);
2792 local_irq_disable(); 2841 local_irq_disable();
2793 c = this_cpu_ptr(s->cpu_slab); 2842 c = this_cpu_ptr(s->cpu_slab);
2794 } 2843 }
@@ -3523,7 +3572,7 @@ void kfree(const void *x)
3523 __free_kmem_pages(page, compound_order(page)); 3572 __free_kmem_pages(page, compound_order(page));
3524 return; 3573 return;
3525 } 3574 }
3526 slab_free(page->slab_cache, page, object, _RET_IP_); 3575 slab_free(page->slab_cache, page, object, NULL, 1, _RET_IP_);
3527} 3576}
3528EXPORT_SYMBOL(kfree); 3577EXPORT_SYMBOL(kfree);
3529 3578