Skip to content

Commit becfda6

Browse files
labbotttorvalds
authored andcommitted
slub: convert SLAB_DEBUG_FREE to SLAB_CONSISTENCY_CHECKS
SLAB_DEBUG_FREE allows expensive consistency checks at free to be turned on or off. Expand its use to be able to turn off all consistency checks. This gives a nice speed up if you only want features such as poisoning or tracing. Credit to Mathias Krause for the original work which inspired this series Signed-off-by: Laura Abbott <labbott@fedoraproject.org> Acked-by: Christoph Lameter <cl@linux.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Joonsoo Kim <js1304@gmail.com> Cc: Kees Cook <keescook@chromium.org> Cc: Mathias Krause <minipli@googlemail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 804aa13 commit becfda6

File tree

5 files changed

+66
-41
lines changed

5 files changed

+66
-41
lines changed

Documentation/vm/slub.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ slub_debug=<Debug-Options>,<slab name>
3535
Enable options only for select slabs
3636

3737
Possible debug options are
38-
F Sanity checks on (enables SLAB_DEBUG_FREE. Sorry
39-
SLAB legacy issues)
38+
F Sanity checks on (enables SLAB_DEBUG_CONSISTENCY_CHECKS
39+
Sorry SLAB legacy issues)
4040
Z Red zoning
4141
P Poisoning (object and padding)
4242
U User tracking (free and alloc)

include/linux/slab.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* Flags to pass to kmem_cache_create().
2121
* The ones marked DEBUG are only valid if CONFIG_DEBUG_SLAB is set.
2222
*/
23-
#define SLAB_DEBUG_FREE 0x00000100UL /* DEBUG: Perform (expensive) checks on free */
23+
#define SLAB_CONSISTENCY_CHECKS 0x00000100UL /* DEBUG: Perform (expensive) checks on alloc/free */
2424
#define SLAB_RED_ZONE 0x00000400UL /* DEBUG: Red zone objs in a cache */
2525
#define SLAB_POISON 0x00000800UL /* DEBUG: Poison objects */
2626
#define SLAB_HWCACHE_ALIGN 0x00002000UL /* Align objs on cache lines */

mm/slab.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ static inline unsigned long kmem_cache_flags(unsigned long object_size,
125125
#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER)
126126
#elif defined(CONFIG_SLUB_DEBUG)
127127
#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
128-
SLAB_TRACE | SLAB_DEBUG_FREE)
128+
SLAB_TRACE | SLAB_CONSISTENCY_CHECKS)
129129
#else
130130
#define SLAB_DEBUG_FLAGS (0)
131131
#endif
@@ -311,7 +311,8 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
311311
* to not do even the assignment. In that case, slab_equal_or_root
312312
* will also be a constant.
313313
*/
314-
if (!memcg_kmem_enabled() && !unlikely(s->flags & SLAB_DEBUG_FREE))
314+
if (!memcg_kmem_enabled() &&
315+
!unlikely(s->flags & SLAB_CONSISTENCY_CHECKS))
315316
return s;
316317

317318
page = virt_to_head_page(x);

mm/slub.c

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
160160
*/
161161
#define MAX_PARTIAL 10
162162

163-
#define DEBUG_DEFAULT_FLAGS (SLAB_DEBUG_FREE | SLAB_RED_ZONE | \
163+
#define DEBUG_DEFAULT_FLAGS (SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE | \
164164
SLAB_POISON | SLAB_STORE_USER)
165165

166166
/*
@@ -1007,20 +1007,32 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page,
10071007
init_tracking(s, object);
10081008
}
10091009

1010-
static noinline int alloc_debug_processing(struct kmem_cache *s,
1010+
static inline int alloc_consistency_checks(struct kmem_cache *s,
10111011
struct page *page,
10121012
void *object, unsigned long addr)
10131013
{
10141014
if (!check_slab(s, page))
1015-
goto bad;
1015+
return 0;
10161016

10171017
if (!check_valid_pointer(s, page, object)) {
10181018
object_err(s, page, object, "Freelist Pointer check fails");
1019-
goto bad;
1019+
return 0;
10201020
}
10211021

10221022
if (!check_object(s, page, object, SLUB_RED_INACTIVE))
1023-
goto bad;
1023+
return 0;
1024+
1025+
return 1;
1026+
}
1027+
1028+
static noinline int alloc_debug_processing(struct kmem_cache *s,
1029+
struct page *page,
1030+
void *object, unsigned long addr)
1031+
{
1032+
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
1033+
if (!alloc_consistency_checks(s, page, object, addr))
1034+
goto bad;
1035+
}
10241036

10251037
/* Success perform special debug activities for allocs */
10261038
if (s->flags & SLAB_STORE_USER)
@@ -1043,39 +1055,21 @@ static noinline int alloc_debug_processing(struct kmem_cache *s,
10431055
return 0;
10441056
}
10451057

1046-
/* Supports checking bulk free of a constructed freelist */
1047-
static noinline int free_debug_processing(
1048-
struct kmem_cache *s, struct page *page,
1049-
void *head, void *tail, int bulk_cnt,
1050-
unsigned long addr)
1058+
static inline int free_consistency_checks(struct kmem_cache *s,
1059+
struct page *page, void *object, unsigned long addr)
10511060
{
1052-
struct kmem_cache_node *n = get_node(s, page_to_nid(page));
1053-
void *object = head;
1054-
int cnt = 0;
1055-
unsigned long uninitialized_var(flags);
1056-
int ret = 0;
1057-
1058-
spin_lock_irqsave(&n->list_lock, flags);
1059-
slab_lock(page);
1060-
1061-
if (!check_slab(s, page))
1062-
goto out;
1063-
1064-
next_object:
1065-
cnt++;
1066-
10671061
if (!check_valid_pointer(s, page, object)) {
10681062
slab_err(s, page, "Invalid object pointer 0x%p", object);
1069-
goto out;
1063+
return 0;
10701064
}
10711065

10721066
if (on_freelist(s, page, object)) {
10731067
object_err(s, page, object, "Object already free");
1074-
goto out;
1068+
return 0;
10751069
}
10761070

10771071
if (!check_object(s, page, object, SLUB_RED_ACTIVE))
1078-
goto out;
1072+
return 0;
10791073

10801074
if (unlikely(s != page->slab_cache)) {
10811075
if (!PageSlab(page)) {
@@ -1088,7 +1082,37 @@ static noinline int free_debug_processing(
10881082
} else
10891083
object_err(s, page, object,
10901084
"page slab pointer corrupt.");
1091-
goto out;
1085+
return 0;
1086+
}
1087+
return 1;
1088+
}
1089+
1090+
/* Supports checking bulk free of a constructed freelist */
1091+
static noinline int free_debug_processing(
1092+
struct kmem_cache *s, struct page *page,
1093+
void *head, void *tail, int bulk_cnt,
1094+
unsigned long addr)
1095+
{
1096+
struct kmem_cache_node *n = get_node(s, page_to_nid(page));
1097+
void *object = head;
1098+
int cnt = 0;
1099+
unsigned long uninitialized_var(flags);
1100+
int ret = 0;
1101+
1102+
spin_lock_irqsave(&n->list_lock, flags);
1103+
slab_lock(page);
1104+
1105+
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
1106+
if (!check_slab(s, page))
1107+
goto out;
1108+
}
1109+
1110+
next_object:
1111+
cnt++;
1112+
1113+
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
1114+
if (!free_consistency_checks(s, page, object, addr))
1115+
goto out;
10921116
}
10931117

10941118
if (s->flags & SLAB_STORE_USER)
@@ -1145,7 +1169,7 @@ static int __init setup_slub_debug(char *str)
11451169
for (; *str && *str != ','; str++) {
11461170
switch (tolower(*str)) {
11471171
case 'f':
1148-
slub_debug |= SLAB_DEBUG_FREE;
1172+
slub_debug |= SLAB_CONSISTENCY_CHECKS;
11491173
break;
11501174
case 'z':
11511175
slub_debug |= SLAB_RED_ZONE;
@@ -1449,7 +1473,7 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
14491473
int order = compound_order(page);
14501474
int pages = 1 << order;
14511475

1452-
if (kmem_cache_debug(s)) {
1476+
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
14531477
void *p;
14541478

14551479
slab_pad_check(s, page);
@@ -4769,16 +4793,16 @@ SLAB_ATTR_RO(total_objects);
47694793

47704794
static ssize_t sanity_checks_show(struct kmem_cache *s, char *buf)
47714795
{
4772-
return sprintf(buf, "%d\n", !!(s->flags & SLAB_DEBUG_FREE));
4796+
return sprintf(buf, "%d\n", !!(s->flags & SLAB_CONSISTENCY_CHECKS));
47734797
}
47744798

47754799
static ssize_t sanity_checks_store(struct kmem_cache *s,
47764800
const char *buf, size_t length)
47774801
{
4778-
s->flags &= ~SLAB_DEBUG_FREE;
4802+
s->flags &= ~SLAB_CONSISTENCY_CHECKS;
47794803
if (buf[0] == '1') {
47804804
s->flags &= ~__CMPXCHG_DOUBLE;
4781-
s->flags |= SLAB_DEBUG_FREE;
4805+
s->flags |= SLAB_CONSISTENCY_CHECKS;
47824806
}
47834807
return length;
47844808
}
@@ -5313,7 +5337,7 @@ static char *create_unique_id(struct kmem_cache *s)
53135337
*p++ = 'd';
53145338
if (s->flags & SLAB_RECLAIM_ACCOUNT)
53155339
*p++ = 'a';
5316-
if (s->flags & SLAB_DEBUG_FREE)
5340+
if (s->flags & SLAB_CONSISTENCY_CHECKS)
53175341
*p++ = 'F';
53185342
if (!(s->flags & SLAB_NOTRACK))
53195343
*p++ = 't';

tools/vm/slabinfo.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ static void usage(void)
135135
"\nValid debug options (FZPUT may be combined)\n"
136136
"a / A Switch on all debug options (=FZUP)\n"
137137
"- Switch off all debug options\n"
138-
"f / F Sanity Checks (SLAB_DEBUG_FREE)\n"
138+
"f / F Sanity Checks (SLAB_CONSISTENCY_CHECKS)\n"
139139
"z / Z Redzoning\n"
140140
"p / P Poisoning\n"
141141
"u / U Tracking\n"

0 commit comments

Comments
 (0)