module: extract patient module check into helper

The patient module check inside add_unformed_module() is large
enough as we need it. It is a bit hard to read too, so just
move it to a helper and do the inverse checks first to help
shift the code and make it easier to read. The new helper then
is module_patient_check_exists().

To make this work we need to mvoe the finished_loading() up,
we do that without making any functional changes to that routine.

Reviewed-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
This commit is contained in:
Luis Chamberlain 2023-03-10 20:05:52 -08:00
parent 25a1b5b518
commit f71afa6a42

View File

@ -2447,27 +2447,6 @@ static int post_relocation(struct module *mod, const struct load_info *info)
return module_finalize(info->hdr, info->sechdrs, mod); return module_finalize(info->hdr, info->sechdrs, mod);
} }
/* Is this module of this name done loading? No locks held. */
static bool finished_loading(const char *name)
{
struct module *mod;
bool ret;
/*
* The module_mutex should not be a heavily contended lock;
* if we get the occasional sleep here, we'll go an extra iteration
* in the wait_event_interruptible(), which is harmless.
*/
sched_annotate_sleep();
mutex_lock(&module_mutex);
mod = find_module_all(name, strlen(name), true);
ret = !mod || mod->state == MODULE_STATE_LIVE
|| mod->state == MODULE_STATE_GOING;
mutex_unlock(&module_mutex);
return ret;
}
/* Call module constructors. */ /* Call module constructors. */
static void do_mod_ctors(struct module *mod) static void do_mod_ctors(struct module *mod)
{ {
@ -2631,34 +2610,49 @@ static int may_init_module(void)
return 0; return 0;
} }
/* /* Is this module of this name done loading? No locks held. */
* We try to place it in the list now to make sure it's unique before static bool finished_loading(const char *name)
* we dedicate too many resources. In particular, temporary percpu
* memory exhaustion.
*/
static int add_unformed_module(struct module *mod)
{ {
int err; struct module *mod;
struct module *old; bool ret;
mod->state = MODULE_STATE_UNFORMED;
/*
* The module_mutex should not be a heavily contended lock;
* if we get the occasional sleep here, we'll go an extra iteration
* in the wait_event_interruptible(), which is harmless.
*/
sched_annotate_sleep();
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
old = find_module_all(mod->name, strlen(mod->name), true); mod = find_module_all(name, strlen(name), true);
if (old != NULL) { ret = !mod || mod->state == MODULE_STATE_LIVE
if (old->state == MODULE_STATE_COMING || mod->state == MODULE_STATE_GOING;
|| old->state == MODULE_STATE_UNFORMED) { mutex_unlock(&module_mutex);
return ret;
}
/* Must be called with module_mutex held */
static int module_patient_check_exists(const char *name)
{
struct module *old;
int err = 0;
old = find_module_all(name, strlen(name), true);
if (old == NULL)
return 0;
if (old->state == MODULE_STATE_COMING ||
old->state == MODULE_STATE_UNFORMED) {
/* Wait in case it fails to load. */ /* Wait in case it fails to load. */
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
err = wait_event_interruptible(module_wq, err = wait_event_interruptible(module_wq,
finished_loading(mod->name)); finished_loading(name));
mutex_lock(&module_mutex);
if (err) if (err)
goto out_unlocked; return err;
/* The module might have gone in the meantime. */ /* The module might have gone in the meantime. */
mutex_lock(&module_mutex); old = find_module_all(name, strlen(name), true);
old = find_module_all(mod->name, strlen(mod->name),
true);
} }
/* /*
@ -2669,11 +2663,26 @@ static int add_unformed_module(struct module *mod)
* a particular module. * a particular module.
*/ */
if (old && old->state == MODULE_STATE_LIVE) if (old && old->state == MODULE_STATE_LIVE)
err = -EEXIST; return -EEXIST;
else return -EBUSY;
err = -EBUSY;
goto out;
} }
/*
* We try to place it in the list now to make sure it's unique before
* we dedicate too many resources. In particular, temporary percpu
* memory exhaustion.
*/
static int add_unformed_module(struct module *mod)
{
int err;
mod->state = MODULE_STATE_UNFORMED;
mutex_lock(&module_mutex);
err = module_patient_check_exists(mod->name);
if (err)
goto out;
mod_update_bounds(mod); mod_update_bounds(mod);
list_add_rcu(&mod->list, &modules); list_add_rcu(&mod->list, &modules);
mod_tree_insert(mod); mod_tree_insert(mod);
@ -2681,7 +2690,6 @@ static int add_unformed_module(struct module *mod)
out: out:
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
out_unlocked:
return err; return err;
} }