summaryrefslogtreecommitdiff
path: root/kernel/kmod.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-12 17:22:01 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-12 17:22:01 -0700
commit3a75ad1457d9cd84bc17d5b9cffb4d73b52be20b (patch)
tree8ca06468b1f9feffeefe04f700264ed7345d7803 /kernel/kmod.c
parent235b84fc862ae2637dc0dabada18d97f1bfc18e1 (diff)
parent96b5b19459b3c2aed2872bac42cbe19edfae710f (diff)
Merge tag 'modules-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux
Pull modules updates from Jessica Yu: "Summary of modules changes for the 4.13 merge window: - Minor code cleanups - Avoid accessing mod struct prior to checking module struct version, from Kees - Fix racy atomic inc/dec logic of kmod_concurrent_max in kmod, from Luis" * tag 'modules-for-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux: module: make the modinfo name const kmod: reduce atomic operations on kmod_concurrent and simplify module: use list_for_each_entry_rcu() on find_module_all() kernel/module.c: suppress warning about unused nowarn variable module: Add module name to modinfo module: Pass struct load_info into symbol checks
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r--kernel/kmod.c40
1 files changed, 18 insertions, 22 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 563f97e2be36..ff68198fe83b 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -45,8 +45,6 @@
#include <trace/events/module.h>
-extern int max_threads;
-
#define CAP_BSET (void *)1
#define CAP_PI (void *)2
@@ -56,6 +54,20 @@ static DEFINE_SPINLOCK(umh_sysctl_lock);
static DECLARE_RWSEM(umhelper_sem);
#ifdef CONFIG_MODULES
+/*
+ * Assuming:
+ *
+ * threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE,
+ * (u64) THREAD_SIZE * 8UL);
+ *
+ * If you need less than 50 threads would mean we're dealing with systems
+ * smaller than 3200 pages. This assuems you are capable of having ~13M memory,
+ * and this would only be an be an upper limit, after which the OOM killer
+ * would take effect. Systems like these are very unlikely if modules are
+ * enabled.
+ */
+#define MAX_KMOD_CONCURRENT 50
+static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT);
/*
modprobe_path is set via /proc/sys.
@@ -127,10 +139,7 @@ int __request_module(bool wait, const char *fmt, ...)
{
va_list args;
char module_name[MODULE_NAME_LEN];
- unsigned int max_modprobes;
int ret;
- static atomic_t kmod_concurrent = ATOMIC_INIT(0);
-#define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
static int kmod_loop_msg;
/*
@@ -154,21 +163,7 @@ int __request_module(bool wait, const char *fmt, ...)
if (ret)
return ret;
- /* If modprobe needs a service that is in a module, we get a recursive
- * loop. Limit the number of running kmod threads to max_threads/2 or
- * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method
- * would be to run the parents of this process, counting how many times
- * kmod was invoked. That would mean accessing the internals of the
- * process tables to get the command line, proc_pid_cmdline is static
- * and it is not worth changing the proc code just to handle this case.
- * KAO.
- *
- * "trace the ppid" is simple, but will fail if someone's
- * parent exits. I think this is as good as it gets. --RR
- */
- max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT);
- atomic_inc(&kmod_concurrent);
- if (atomic_read(&kmod_concurrent) > max_modprobes) {
+ if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) {
/* We may be blaming an innocent here, but unlikely */
if (kmod_loop_msg < 5) {
printk(KERN_ERR
@@ -176,7 +171,6 @@ int __request_module(bool wait, const char *fmt, ...)
module_name);
kmod_loop_msg++;
}
- atomic_dec(&kmod_concurrent);
return -ENOMEM;
}
@@ -184,10 +178,12 @@ int __request_module(bool wait, const char *fmt, ...)
ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
- atomic_dec(&kmod_concurrent);
+ atomic_inc(&kmod_concurrent_max);
+
return ret;
}
EXPORT_SYMBOL(__request_module);
+
#endif /* CONFIG_MODULES */
static void call_usermodehelper_freeinfo(struct subprocess_info *info)