Skip to content

Commit e17f1df

Browse files
tehcastertorvalds
authored andcommitted
mm, slub: extend slub_debug syntax for multiple blocks
Patch series "slub_debug fixes and improvements". The slub_debug kernel boot parameter can either apply a single set of options to all caches or a list of caches. There is a use case where debugging is applied for all caches and then disabled at runtime for specific caches, for performance and memory consumption reasons [1]. As runtime changes are dangerous, extend the boot parameter syntax so that multiple blocks of either global or slab-specific options can be specified, with blocks delimited by ';'. This will also support the use case of [1] without runtime changes. For details see the updated Documentation/vm/slub.rst [1] https://lore.kernel.org/r/[email protected] [[email protected]: make parse_slub_debug_flags() static] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Vlastimil Babka <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Reviewed-by: Kees Cook <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Jann Horn <[email protected]> Cc: Roman Gushchin <[email protected]> Cc: Vijayanand Jitta <[email protected]> Cc: Pekka Enberg <[email protected]> Cc: David Rientjes <[email protected]> Cc: Joonsoo Kim <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
1 parent 221503e commit e17f1df

File tree

3 files changed

+145
-52
lines changed

3 files changed

+145
-52
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4689,7 +4689,7 @@
46894689
fragmentation. Defaults to 1 for systems with
46904690
more than 32MB of RAM, 0 otherwise.
46914691

4692-
slub_debug[=options[,slabs]] [MM, SLUB]
4692+
slub_debug[=options[,slabs][;[options[,slabs]]...] [MM, SLUB]
46934693
Enabling slub_debug allows one to determine the
46944694
culprit if slab objects become corrupted. Enabling
46954695
slub_debug can create guard zones around objects and

Documentation/vm/slub.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ slub_debug=<Debug-Options>,<slab name1>,<slab name2>,...
4141
Enable options only for select slabs (no spaces
4242
after a comma)
4343

44+
Multiple blocks of options for all slabs or selected slabs can be given, with
45+
blocks of options delimited by ';'. The last of "all slabs" blocks is applied
46+
to all slabs except those that match one of the "select slabs" block. Options
47+
of the first "select slabs" blocks that matches the slab's name are applied.
48+
4449
Possible debug options are::
4550

4651
F Sanity checks on (enables SLAB_DEBUG_CONSISTENCY_CHECKS
@@ -83,6 +88,19 @@ switch off debugging for such caches by default, use::
8388

8489
slub_debug=O
8590

91+
You can apply different options to different list of slab names, using blocks
92+
of options. This will enable red zoning for dentry and user tracking for
93+
kmalloc. All other slabs will not get any debugging enabled::
94+
95+
slub_debug=Z,dentry;U,kmalloc-*
96+
97+
You can also enable options (e.g. sanity checks and poisoning) for all caches
98+
except some that are deemed too performance critical and don't need to be
99+
debugged by specifying global debug options followed by a list of slab names
100+
with "-" as options::
101+
102+
slub_debug=FZ;-,zs_handle,zspage
103+
86104
In case you forgot to enable debugging on the kernel command line: It is
87105
possible to enable debugging manually when the kernel is up. Look at the
88106
contents of::

mm/slub.c

Lines changed: 126 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ static slab_flags_t slub_debug = DEBUG_DEFAULT_FLAGS;
499499
static slab_flags_t slub_debug;
500500
#endif
501501

502-
static char *slub_debug_slabs;
502+
static char *slub_debug_string;
503503
static int disable_higher_order_debug;
504504

505505
/*
@@ -1262,68 +1262,132 @@ static noinline int free_debug_processing(
12621262
return ret;
12631263
}
12641264

1265-
static int __init setup_slub_debug(char *str)
1265+
/*
1266+
* Parse a block of slub_debug options. Blocks are delimited by ';'
1267+
*
1268+
* @str: start of block
1269+
* @flags: returns parsed flags, or DEBUG_DEFAULT_FLAGS if none specified
1270+
* @slabs: return start of list of slabs, or NULL when there's no list
1271+
* @init: assume this is initial parsing and not per-kmem-create parsing
1272+
*
1273+
* returns the start of next block if there's any, or NULL
1274+
*/
1275+
static char *
1276+
parse_slub_debug_flags(char *str, slab_flags_t *flags, char **slabs, bool init)
12661277
{
1267-
slub_debug = DEBUG_DEFAULT_FLAGS;
1268-
if (*str++ != '=' || !*str)
1269-
/*
1270-
* No options specified. Switch on full debugging.
1271-
*/
1272-
goto out;
1278+
bool higher_order_disable = false;
12731279

1274-
if (*str == ',')
1280+
/* Skip any completely empty blocks */
1281+
while (*str && *str == ';')
1282+
str++;
1283+
1284+
if (*str == ',') {
12751285
/*
12761286
* No options but restriction on slabs. This means full
12771287
* debugging for slabs matching a pattern.
12781288
*/
1289+
*flags = DEBUG_DEFAULT_FLAGS;
12791290
goto check_slabs;
1291+
}
1292+
*flags = 0;
12801293

1281-
slub_debug = 0;
1282-
if (*str == '-')
1283-
/*
1284-
* Switch off all debugging measures.
1285-
*/
1286-
goto out;
1287-
1288-
/*
1289-
* Determine which debug features should be switched on
1290-
*/
1291-
for (; *str && *str != ','; str++) {
1294+
/* Determine which debug features should be switched on */
1295+
for (; *str && *str != ',' && *str != ';'; str++) {
12921296
switch (tolower(*str)) {
1297+
case '-':
1298+
*flags = 0;
1299+
break;
12931300
case 'f':
1294-
slub_debug |= SLAB_CONSISTENCY_CHECKS;
1301+
*flags |= SLAB_CONSISTENCY_CHECKS;
12951302
break;
12961303
case 'z':
1297-
slub_debug |= SLAB_RED_ZONE;
1304+
*flags |= SLAB_RED_ZONE;
12981305
break;
12991306
case 'p':
1300-
slub_debug |= SLAB_POISON;
1307+
*flags |= SLAB_POISON;
13011308
break;
13021309
case 'u':
1303-
slub_debug |= SLAB_STORE_USER;
1310+
*flags |= SLAB_STORE_USER;
13041311
break;
13051312
case 't':
1306-
slub_debug |= SLAB_TRACE;
1313+
*flags |= SLAB_TRACE;
13071314
break;
13081315
case 'a':
1309-
slub_debug |= SLAB_FAILSLAB;
1316+
*flags |= SLAB_FAILSLAB;
13101317
break;
13111318
case 'o':
13121319
/*
13131320
* Avoid enabling debugging on caches if its minimum
13141321
* order would increase as a result.
13151322
*/
1316-
disable_higher_order_debug = 1;
1323+
higher_order_disable = true;
13171324
break;
13181325
default:
1319-
pr_err("slub_debug option '%c' unknown. skipped\n",
1320-
*str);
1326+
if (init)
1327+
pr_err("slub_debug option '%c' unknown. skipped\n", *str);
13211328
}
13221329
}
1323-
13241330
check_slabs:
13251331
if (*str == ',')
1326-
slub_debug_slabs = str + 1;
1332+
*slabs = ++str;
1333+
else
1334+
*slabs = NULL;
1335+
1336+
/* Skip over the slab list */
1337+
while (*str && *str != ';')
1338+
str++;
1339+
1340+
/* Skip any completely empty blocks */
1341+
while (*str && *str == ';')
1342+
str++;
1343+
1344+
if (init && higher_order_disable)
1345+
disable_higher_order_debug = 1;
1346+
1347+
if (*str)
1348+
return str;
1349+
else
1350+
return NULL;
1351+
}
1352+
1353+
static int __init setup_slub_debug(char *str)
1354+
{
1355+
slab_flags_t flags;
1356+
char *saved_str;
1357+
char *slab_list;
1358+
bool global_slub_debug_changed = false;
1359+
bool slab_list_specified = false;
1360+
1361+
slub_debug = DEBUG_DEFAULT_FLAGS;
1362+
if (*str++ != '=' || !*str)
1363+
/*
1364+
* No options specified. Switch on full debugging.
1365+
*/
1366+
goto out;
1367+
1368+
saved_str = str;
1369+
while (str) {
1370+
str = parse_slub_debug_flags(str, &flags, &slab_list, true);
1371+
1372+
if (!slab_list) {
1373+
slub_debug = flags;
1374+
global_slub_debug_changed = true;
1375+
} else {
1376+
slab_list_specified = true;
1377+
}
1378+
}
1379+
1380+
/*
1381+
* For backwards compatibility, a single list of flags with list of
1382+
* slabs means debugging is only enabled for those slabs, so the global
1383+
* slub_debug should be 0. We can extended that to multiple lists as
1384+
* long as there is no option specifying flags without a slab list.
1385+
*/
1386+
if (slab_list_specified) {
1387+
if (!global_slub_debug_changed)
1388+
slub_debug = 0;
1389+
slub_debug_string = saved_str;
1390+
}
13271391
out:
13281392
if ((static_branch_unlikely(&init_on_alloc) ||
13291393
static_branch_unlikely(&init_on_free)) &&
@@ -1352,36 +1416,47 @@ slab_flags_t kmem_cache_flags(unsigned int object_size,
13521416
{
13531417
char *iter;
13541418
size_t len;
1419+
char *next_block;
1420+
slab_flags_t block_flags;
13551421

13561422
/* If slub_debug = 0, it folds into the if conditional. */
1357-
if (!slub_debug_slabs)
1423+
if (!slub_debug_string)
13581424
return flags | slub_debug;
13591425

13601426
len = strlen(name);
1361-
iter = slub_debug_slabs;
1362-
while (*iter) {
1363-
char *end, *glob;
1364-
size_t cmplen;
1365-
1366-
end = strchrnul(iter, ',');
1427+
next_block = slub_debug_string;
1428+
/* Go through all blocks of debug options, see if any matches our slab's name */
1429+
while (next_block) {
1430+
next_block = parse_slub_debug_flags(next_block, &block_flags, &iter, false);
1431+
if (!iter)
1432+
continue;
1433+
/* Found a block that has a slab list, search it */
1434+
while (*iter) {
1435+
char *end, *glob;
1436+
size_t cmplen;
1437+
1438+
end = strchrnul(iter, ',');
1439+
if (next_block && next_block < end)
1440+
end = next_block - 1;
1441+
1442+
glob = strnchr(iter, end - iter, '*');
1443+
if (glob)
1444+
cmplen = glob - iter;
1445+
else
1446+
cmplen = max_t(size_t, len, (end - iter));
13671447

1368-
glob = strnchr(iter, end - iter, '*');
1369-
if (glob)
1370-
cmplen = glob - iter;
1371-
else
1372-
cmplen = max_t(size_t, len, (end - iter));
1448+
if (!strncmp(name, iter, cmplen)) {
1449+
flags |= block_flags;
1450+
return flags;
1451+
}
13731452

1374-
if (!strncmp(name, iter, cmplen)) {
1375-
flags |= slub_debug;
1376-
break;
1453+
if (!*end || *end == ';')
1454+
break;
1455+
iter = end + 1;
13771456
}
1378-
1379-
if (!*end)
1380-
break;
1381-
iter = end + 1;
13821457
}
13831458

1384-
return flags;
1459+
return slub_debug;
13851460
}
13861461
#else /* !CONFIG_SLUB_DEBUG */
13871462
static inline void setup_object_debug(struct kmem_cache *s,

0 commit comments

Comments
 (0)