summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorPetr Pavlu <petr.pavlu@suse.com>2026-08-06 11:10:17 +0200
committerPetr Pavlu <petr.pavlu@suse.com>2026-08-06 13:29:03 +0200
commit96e6f752fc25af366de2b3f8aa09c93963d00d2a (patch)
treed4540acd4dbeccdaab9598c4284f47b4d9620576 /kernel
parent5eecb11b543f9f417bcf0dea239ff99c6af65dbd (diff)
module/dups: Avoid unnecessary kmod_dup_req allocations
The kmod dups code preallocates kmod_dup_req before taking kmod_dup_mutex to avoid allocating memory while holding the lock. This provides little benefit, since the allocation is fast and can safely be done under the lock. On the other hand, it leads to unnecessary allocations when the request turns out to be a duplicate and slightly complicates the code. Allocate kmod_dup_req only when needed and introduce a helper function alloc_kmod_req() to initialize the structure. Reviewed-by: Aaron Tomlin <atomlin@atomlin.com> Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/module/dups.c38
1 files changed, 22 insertions, 16 deletions
diff --git a/kernel/module/dups.c b/kernel/module/dups.c
index db7377229703..276016051ad2 100644
--- a/kernel/module/dups.c
+++ b/kernel/module/dups.c
@@ -104,28 +104,31 @@ static void kmod_dup_request_delete(struct work_struct *work)
put_kmod_req(kmod_req);
}
-bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)
+static struct kmod_dup_req *alloc_kmod_req(const char *module_name)
{
- struct kmod_dup_req *kmod_req, *new_kmod_req;
- int ret;
+ struct kmod_dup_req *kmod_req = kzalloc_obj(*kmod_req);
- /*
- * Pre-allocate the entry in case we have to use it later
- * to avoid contention with the mutex.
- */
- new_kmod_req = kzalloc_obj(*new_kmod_req);
- if (!new_kmod_req)
- return false;
+ if (!kmod_req)
+ return NULL;
- refcount_set(&new_kmod_req->refcount, 1);
- strscpy(new_kmod_req->name, module_name);
- INIT_DELAYED_WORK(&new_kmod_req->delete_work, kmod_dup_request_delete);
- init_completion(&new_kmod_req->first_req_done);
+ refcount_set(&kmod_req->refcount, 1);
+ strscpy(kmod_req->name, module_name);
+ INIT_DELAYED_WORK(&kmod_req->delete_work, kmod_dup_request_delete);
+ init_completion(&kmod_req->first_req_done);
+ return kmod_req;
+}
+
+bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)
+{
+ struct kmod_dup_req *kmod_req;
+ int ret;
mutex_lock(&kmod_dup_mutex);
kmod_req = kmod_dup_request_lookup(module_name);
if (!kmod_req) {
+ struct kmod_dup_req *new_kmod_req;
+
/*
* If the first request that came through for a module
* was with request_module_nowait() we cannot wait for it
@@ -138,7 +141,6 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)
* would benefit from duplicate detection.
*/
if (!wait) {
- kfree(new_kmod_req);
pr_debug("New request_module_nowait() for %s -- cannot track duplicates for this request\n", module_name);
mutex_unlock(&kmod_dup_mutex);
return false;
@@ -149,6 +151,11 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)
* keep tab on duplicates later.
*/
pr_debug("New request_module() for %s\n", module_name);
+ new_kmod_req = alloc_kmod_req(module_name);
+ if (!new_kmod_req) {
+ mutex_unlock(&kmod_dup_mutex);
+ return false;
+ }
list_add(&new_kmod_req->list, &dup_kmod_reqs);
mutex_unlock(&kmod_dup_mutex);
return false;
@@ -158,7 +165,6 @@ bool kmod_dup_request_exists_wait(char *module_name, bool wait, int *dup_ret)
mutex_unlock(&kmod_dup_mutex);
/* We are dealing with a duplicate request now */
- kfree(new_kmod_req);
/*
* To fix these try to use try_then_request_module() instead as that