Skip to content

Commit 25a1b5b

Browse files
committed
modules/kmod: replace implementation with a semaphore
Simplify the concurrency delimiter we use for kmod with the semaphore. I had used the kmod strategy to try to implement a similar concurrency delimiter for the kernel_read*() calls from the finit_module() path so to reduce vmalloc() memory pressure. That effort didn't provide yet conclusive results, but one thing that became clear is we can use the suggested alternative solution with semaphores which Linus hinted at instead of using the atomic / wait strategy. I've stress tested this with kmod test 0008: time /data/linux-next/tools/testing/selftests/kmod/kmod.sh -t 0008 And I get only a *slight* delay. That delay however is small, a few seconds for a full test loop run that runs 150 times, for about ~30-40 seconds. The small delay is worth the simplfication IMHO. Reviewed-by: Davidlohr Bueso <dave@stgolabs.net> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Reviewed-by: David Hildenbrand <david@redhat.com> Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
1 parent 4838036 commit 25a1b5b

File tree

1 file changed

+7
-19
lines changed

1 file changed

+7
-19
lines changed

kernel/module/kmod.c

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@
4040
* effect. Systems like these are very unlikely if modules are enabled.
4141
*/
4242
#define MAX_KMOD_CONCURRENT 50
43-
static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT);
44-
static DECLARE_WAIT_QUEUE_HEAD(kmod_wq);
43+
static DEFINE_SEMAPHORE(kmod_concurrent_max, MAX_KMOD_CONCURRENT);
4544

4645
/*
4746
* This is a restriction on having *all* MAX_KMOD_CONCURRENT threads
@@ -148,29 +147,18 @@ int __request_module(bool wait, const char *fmt, ...)
148147
if (ret)
149148
return ret;
150149

151-
if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) {
152-
pr_warn_ratelimited("request_module: kmod_concurrent_max (%u) close to 0 (max_modprobes: %u), for module %s, throttling...",
153-
atomic_read(&kmod_concurrent_max),
154-
MAX_KMOD_CONCURRENT, module_name);
155-
ret = wait_event_killable_timeout(kmod_wq,
156-
atomic_dec_if_positive(&kmod_concurrent_max) >= 0,
157-
MAX_KMOD_ALL_BUSY_TIMEOUT * HZ);
158-
if (!ret) {
159-
pr_warn_ratelimited("request_module: modprobe %s cannot be processed, kmod busy with %d threads for more than %d seconds now",
160-
module_name, MAX_KMOD_CONCURRENT, MAX_KMOD_ALL_BUSY_TIMEOUT);
161-
return -ETIME;
162-
} else if (ret == -ERESTARTSYS) {
163-
pr_warn_ratelimited("request_module: sigkill sent for modprobe %s, giving up", module_name);
164-
return ret;
165-
}
150+
ret = down_timeout(&kmod_concurrent_max, MAX_KMOD_ALL_BUSY_TIMEOUT * HZ);
151+
if (ret) {
152+
pr_warn_ratelimited("request_module: modprobe %s cannot be processed, kmod busy with %d threads for more than %d seconds now",
153+
module_name, MAX_KMOD_CONCURRENT, MAX_KMOD_ALL_BUSY_TIMEOUT);
154+
return ret;
166155
}
167156

168157
trace_module_request(module_name, wait, _RET_IP_);
169158

170159
ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
171160

172-
atomic_inc(&kmod_concurrent_max);
173-
wake_up(&kmod_wq);
161+
up(&kmod_concurrent_max);
174162

175163
return ret;
176164
}

0 commit comments

Comments
 (0)