From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D32A3C433E3 for ; Wed, 10 Jun 2020 16:32:01 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 9585420820 for ; Wed, 10 Jun 2020 16:32:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9585420820 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.cz Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 6B8EA6B006C; Wed, 10 Jun 2020 12:31:55 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 6166C6B006E; Wed, 10 Jun 2020 12:31:55 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 492926B0070; Wed, 10 Jun 2020 12:31:55 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0182.hostedemail.com [216.40.44.182]) by kanga.kvack.org (Postfix) with ESMTP id 110FC6B006E for ; Wed, 10 Jun 2020 12:31:55 -0400 (EDT) Received: from smtpin27.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay05.hostedemail.com (Postfix) with ESMTP id BDD86181ABEAA for ; Wed, 10 Jun 2020 16:31:54 +0000 (UTC) X-FDA: 76913843748.27.run59_570f9ce26dcc Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin27.hostedemail.com (Postfix) with ESMTP id 78EBD449EA for ; Wed, 10 Jun 2020 16:31:53 +0000 (UTC) X-HE-Tag: run59_570f9ce26dcc X-Filterd-Recvd-Size: 10702 Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by imf04.hostedemail.com (Postfix) with ESMTP for ; Wed, 10 Jun 2020 16:31:52 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id C278BAD74; Wed, 10 Jun 2020 16:31:53 +0000 (UTC) From: Vlastimil Babka To: Andrew Morton , Christoph Lameter , Pekka Enberg , David Rientjes , Joonsoo Kim Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, kernel-team@android.com, vinmenon@codeaurora.org, Kees Cook , Matthew Garrett , Roman Gushchin , Vlastimil Babka , Jann Horn , Vijayanand Jitta Subject: [PATCH 1/9] mm, slub: extend slub_debug syntax for multiple blocks Date: Wed, 10 Jun 2020 18:31:27 +0200 Message-Id: <20200610163135.17364-2-vbabka@suse.cz> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200610163135.17364-1-vbabka@suse.cz> References: <20200610163135.17364-1-vbabka@suse.cz> MIME-Version: 1.0 X-Rspamd-Queue-Id: 78EBD449EA X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam04 Content-Transfer-Encoding: quoted-printable X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: The slub_debug kernel boot parameter can either apply a single set of opt= ions 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 ei= ther global or slab-specific options can be specified, with blocks delimited b= y ';'. 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/1383cd32-1ddc-4dac-b5f8-9c42282fa81c@codeau= rora.org Signed-off-by: Vlastimil Babka Reviewed-by: Kees Cook --- .../admin-guide/kernel-parameters.txt | 2 +- Documentation/vm/slub.rst | 18 ++ mm/slub.c | 177 +++++++++++++----- 3 files changed, 145 insertions(+), 52 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentat= ion/admin-guide/kernel-parameters.txt index fb95fad81c79..a408876b64c9 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4604,7 +4604,7 @@ fragmentation. Defaults to 1 for systems with more than 32MB of RAM, 0 otherwise. =20 - slub_debug[=3Doptions[,slabs]] [MM, SLUB] + slub_debug[=3Doptions[,slabs][;[options[,slabs]]...] [MM, SLUB] Enabling slub_debug allows one to determine the culprit if slab objects become corrupted. Enabling slub_debug can create guard zones around objects and diff --git a/Documentation/vm/slub.rst b/Documentation/vm/slub.rst index 4eee598555c9..cfccb258cf42 100644 --- a/Documentation/vm/slub.rst +++ b/Documentation/vm/slub.rst @@ -41,6 +41,11 @@ slub_debug=3D,,= ,... Enable options only for select slabs (no spaces after a comma) =20 +Multiple blocks of options for all slabs or selected slabs can be given,= with +blocks of options delimited by ';'. The last of "all slabs" blocks is ap= plied +to all slabs except those that match one of the "select slabs" block. Op= tions +of the first "select slabs" blocks that matches the slab's name are appl= ied. + Possible debug options are:: =20 F Sanity checks on (enables SLAB_DEBUG_CONSISTENCY_CHECKS @@ -83,6 +88,19 @@ in low memory situations or if there's high fragmentat= ion of memory. To =20 slub_debug=3DO =20 +You can apply different options to different list of slab names, using b= locks +of options. This will enable red zoning for dentry and user tracking for +kmalloc. All other slabs will not get any debugging enabled:: + + slub_debug=3DZ,dentry;U,kmalloc-* + +You can also enable options (e.g. sanity checks and poisoning) for all c= aches +except some that are deemed too performance critical and don't need to b= e +debugged by specifying global debug options followed by a list of slab n= ames +with "-" as options:: + + slub_debug=3DFZ;-,zs_handle,zspage + In case you forgot to enable debugging on the kernel command line: It is possible to enable debugging manually when the kernel is up. Look at the contents of:: diff --git a/mm/slub.c b/mm/slub.c index b8f798b50d44..a53371426e06 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -499,7 +499,7 @@ static slab_flags_t slub_debug =3D DEBUG_DEFAULT_FLAG= S; static slab_flags_t slub_debug; #endif =20 -static char *slub_debug_slabs; +static char *slub_debug_string; static int disable_higher_order_debug; =20 /* @@ -1262,68 +1262,132 @@ static noinline int free_debug_processing( return ret; } =20 -static int __init setup_slub_debug(char *str) +/* + * Parse a block of slub_debug options. Blocks are delimited by ';' + * + * @str: start of block + * @flags: returns parsed flags, or DEBUG_DEFAULT_FLAGS if none specifi= ed + * @slabs: return start of list of slabs, or NULL when there's no list + * @init: assume this is initial parsing and not per-kmem-create parsi= ng + * + * returns the start of next block if there's any, or NULL + */ +char * +parse_slub_debug_flags(char *str, slab_flags_t *flags, char **slabs, boo= l init) { - slub_debug =3D DEBUG_DEFAULT_FLAGS; - if (*str++ !=3D '=3D' || !*str) - /* - * No options specified. Switch on full debugging. - */ - goto out; + bool higher_order_disable =3D false; =20 - if (*str =3D=3D ',') + /* Skip any completely empty blocks */ + while (*str && *str =3D=3D ';') + str++; + + if (*str =3D=3D ',') { /* * No options but restriction on slabs. This means full * debugging for slabs matching a pattern. */ + *flags =3D DEBUG_DEFAULT_FLAGS; goto check_slabs; + } + *flags =3D 0; =20 - slub_debug =3D 0; - if (*str =3D=3D '-') - /* - * Switch off all debugging measures. - */ - goto out; - - /* - * Determine which debug features should be switched on - */ - for (; *str && *str !=3D ','; str++) { + /* Determine which debug features should be switched on */ + for (; *str && *str !=3D ',' && *str !=3D ';'; str++) { switch (tolower(*str)) { + case '-': + *flags =3D 0; + break; case 'f': - slub_debug |=3D SLAB_CONSISTENCY_CHECKS; + *flags |=3D SLAB_CONSISTENCY_CHECKS; break; case 'z': - slub_debug |=3D SLAB_RED_ZONE; + *flags |=3D SLAB_RED_ZONE; break; case 'p': - slub_debug |=3D SLAB_POISON; + *flags |=3D SLAB_POISON; break; case 'u': - slub_debug |=3D SLAB_STORE_USER; + *flags |=3D SLAB_STORE_USER; break; case 't': - slub_debug |=3D SLAB_TRACE; + *flags |=3D SLAB_TRACE; break; case 'a': - slub_debug |=3D SLAB_FAILSLAB; + *flags |=3D SLAB_FAILSLAB; break; case 'o': /* * Avoid enabling debugging on caches if its minimum * order would increase as a result. */ - disable_higher_order_debug =3D 1; + higher_order_disable =3D true; break; default: - pr_err("slub_debug option '%c' unknown. skipped\n", - *str); + if (init) + pr_err("slub_debug option '%c' unknown. skipped\n", *str); } } - check_slabs: if (*str =3D=3D ',') - slub_debug_slabs =3D str + 1; + *slabs =3D ++str; + else + *slabs =3D NULL; + + /* Skip over the slab list */ + while (*str && *str !=3D ';') + str++; + + /* Skip any completely empty blocks */ + while (*str && *str =3D=3D ';') + str++; + + if (init && higher_order_disable) + disable_higher_order_debug =3D 1; + + if (*str) + return str; + else + return NULL; +} + +static int __init setup_slub_debug(char *str) +{ + slab_flags_t flags; + char *saved_str; + char *slab_list; + bool global_slub_debug_changed =3D false; + bool slab_list_specified =3D false; + + slub_debug =3D DEBUG_DEFAULT_FLAGS; + if (*str++ !=3D '=3D' || !*str) + /* + * No options specified. Switch on full debugging. + */ + goto out; + + saved_str =3D str; + while (str) { + str =3D parse_slub_debug_flags(str, &flags, &slab_list, true); + + if (!slab_list) { + slub_debug =3D flags; + global_slub_debug_changed =3D true; + } else { + slab_list_specified =3D true; + } + } + + /* + * For backwards compatibility, a single list of flags with list of + * slabs means debugging is only enabled for those slabs, so the global + * slub_debug should be 0. We can extended that to multiple lists as + * long as there is no option specifying flags without a slab list. + */ + if (slab_list_specified) { + if (!global_slub_debug_changed) + slub_debug =3D 0; + slub_debug_string =3D saved_str; + } out: if ((static_branch_unlikely(&init_on_alloc) || static_branch_unlikely(&init_on_free)) && @@ -1352,36 +1416,47 @@ slab_flags_t kmem_cache_flags(unsigned int object= _size, { char *iter; size_t len; + char *next_block; + slab_flags_t block_flags; =20 /* If slub_debug =3D 0, it folds into the if conditional. */ - if (!slub_debug_slabs) + if (!slub_debug_string) return flags | slub_debug; =20 len =3D strlen(name); - iter =3D slub_debug_slabs; - while (*iter) { - char *end, *glob; - size_t cmplen; - - end =3D strchrnul(iter, ','); + next_block =3D slub_debug_string; + /* Go through all blocks of debug options, see if any matches our slab'= s name */ + while (next_block) { + next_block =3D parse_slub_debug_flags(next_block, &block_flags, &iter,= false); + if (!iter) + continue; + /* Found a block that has a slab list, search it */ + while (*iter) { + char *end, *glob; + size_t cmplen; + + end =3D strchrnul(iter, ','); + if (next_block && next_block < end) + end =3D next_block - 1; + + glob =3D strnchr(iter, end - iter, '*'); + if (glob) + cmplen =3D glob - iter; + else + cmplen =3D max_t(size_t, len, (end - iter)); =20 - glob =3D strnchr(iter, end - iter, '*'); - if (glob) - cmplen =3D glob - iter; - else - cmplen =3D max_t(size_t, len, (end - iter)); + if (!strncmp(name, iter, cmplen)) { + flags |=3D block_flags; + return flags; + } =20 - if (!strncmp(name, iter, cmplen)) { - flags |=3D slub_debug; - break; + if (!*end || *end =3D=3D ';') + break; + iter =3D end + 1; } - - if (!*end) - break; - iter =3D end + 1; } =20 - return flags; + return slub_debug; } #else /* !CONFIG_SLUB_DEBUG */ static inline void setup_object_debug(struct kmem_cache *s, --=20 2.26.2