From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1166127AbdEZAR1 (ORCPT ); Thu, 25 May 2017 20:17:27 -0400 Received: from mail.kernel.org ([198.145.29.99]:34616 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S969506AbdEZAQk (ORCPT ); Thu, 25 May 2017 20:16:40 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2798323A03 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=kernel.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=mcgrof@kernel.org From: "Luis R. Rodriguez" To: akpm@linux-foundation.org, jeyu@redhat.com, shuah@kernel.org, rusty@rustcorp.com.au, ebiederm@xmission.com, dmitry.torokhov@gmail.com, acme@redhat.com, corbet@lwn.net Cc: martin.wilck@suse.com, mmarek@suse.com, pmladek@suse.com, hare@suse.com, rwright@hpe.com, jeffm@suse.com, DSterba@suse.com, fdmanana@suse.com, neilb@suse.com, linux@roeck-us.net, rgoldwyn@suse.com, subashab@codeaurora.org, xypron.glpk@gmx.de, keescook@chromium.org, atomlin@redhat.com, mbenes@suse.cz, paulmck@linux.vnet.ibm.com, dan.j.williams@intel.com, jpoimboe@redhat.com, davem@davemloft.net, mingo@redhat.com, alan@linux.intel.com, tytso@mit.edu, gregkh@linuxfoundation.org, torvalds@linux-foundation.org, linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, "Luis R. Rodriguez" , Tom Gundersen Subject: [PATCH v2 4/5] kmod: add helpers for getting kmod limit Date: Thu, 25 May 2017 17:16:29 -0700 Message-Id: <20170526001630.19203-5-mcgrof@kernel.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170526001630.19203-1-mcgrof@kernel.org> References: <20170519032444.18416-1-mcgrof@kernel.org> <20170526001630.19203-1-mcgrof@kernel.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This adds helpers for getting access to the kmod limit from userspace. This knob should help userspace more gracefully and deterministically handle module loading. Cc: Tom Gundersen Cc: Petr Mladek Signed-off-by: Luis R. Rodriguez --- Documentation/sysctl/kernel.txt | 20 ++++++++++++++++++++ include/linux/kmod.h | 5 +++++ kernel/kmod.c | 33 +++++++++++++++++++++++++++++++++ kernel/sysctl.c | 7 +++++++ 4 files changed, 65 insertions(+) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index bac23c198360..080ccdca1f10 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -370,6 +370,26 @@ with the "modules_disabled" sysctl. ============================================================== +kmod-limit: + +Get the max amount of concurrent requests (kmod_concurrent) the kernel can +make out to userspace to call 'modprobe'. This limit is known internally to the +kernel as max_modprobes. This interface is designed to enable userspace to +query the kernel for the max_modprobes limit so userspace can more +deterministically handle module loading by only enabling max_modprobes +'modprobe' calls at a time. + +Dependencies are resolved in userspace through depmod, so one modprobe +call only bumps the number of concurrent threads (kmod_concurrent) by one. +Dependencies for a module then are loaded directly in userspace using +init_module() / finit_module() skipping bumping kmod_concurrent or being +affected by max_modprobes. + +The max_modprobes value is set at build time with CONFIG_MAX_KMOD_CONCURRENT. +You can override at initialization with the module parameter max_modprobes. + +============================================================== + kptr_restrict: This toggle indicates whether restrictions are placed on diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 8e2f302b214a..bbc6d59190aa 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -39,13 +39,18 @@ int __request_module(bool wait, const char *name, ...); #define try_then_request_module(x, mod...) \ ((x) ?: (__request_module(true, mod), (x))) void init_kmod_umh(void); +unsigned int get_kmod_umh_limit(void); +int sysctl_kmod_limit(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); #else static inline int request_module(const char *name, ...) { return -ENOSYS; } static inline int request_module_nowait(const char *name, ...) { return -ENOSYS; } #define try_then_request_module(x, mod...) (x) static inline void init_kmod_umh(void) { } +static inline unsigned int get_kmod_umh_limit(void) { return 0; } #endif +#define get_kmod_umh_limit get_kmod_umh_limit struct cred; struct file; diff --git a/kernel/kmod.c b/kernel/kmod.c index cafd27b92d19..17de776cf368 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -111,6 +111,17 @@ static int call_modprobe(char *module_name, int wait) } /** + * get_kmod_umh_limit - get concurrent modprobe thread limit + * + * Returns the number of allowed concurrent modprobe calls. + */ +unsigned int get_kmod_umh_limit(void) +{ + return max_modprobes; +} +EXPORT_SYMBOL_GPL(get_kmod_umh_limit); + +/** * __request_module - try to load a kernel module * @wait: wait (or not) for the operation to complete * @fmt: printf style format string for the name of the module @@ -194,6 +205,28 @@ void __init init_kmod_umh(void) atomic_set(&kmod_concurrent_max, max_modprobes); } +int sysctl_kmod_limit(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table t; + int ret; + unsigned int local_max_modprobes = max_modprobes; + unsigned int min = 0; + unsigned int max = max_threads/2; + + t = *table; + t.data = &local_max_modprobes; + t.extra1 = &min; + t.extra2 = &max; + + if (write) + return -EPERM; + + ret = proc_douintvec_minmax(&t, write, buffer, lenp, ppos); + + return ret; +} + #endif /* CONFIG_MODULES */ static void call_usermodehelper_freeinfo(struct subprocess_info *info) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index df9f2a367882..d1c1d1999bb1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -682,6 +682,13 @@ static struct ctl_table kern_table[] = { .extra1 = &one, .extra2 = &one, }, + { + .procname = "kmod-limit", + .data = NULL, /* filled in by handler */ + .maxlen = sizeof(unsigned int), + .mode = 0444, + .proc_handler = sysctl_kmod_limit, + }, #endif #ifdef CONFIG_UEVENT_HELPER { -- 2.11.0