lkml.org 
[lkml]   [2022]   [Nov]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH] module: Don't wait for GOING modules
    Date
    During a system boot, it can happen that the kernel receives a burst of
    requests to insert the same module but loading it eventually fails
    during its init call. For instance, udev can make a request to insert
    a frequency module for each individual CPU when another frequency module
    is already loaded which causes the init function of the new module to
    return an error.

    Since commit 6e6de3dee51a ("kernel/module.c: Only return -EEXIST for
    modules that have finished loading"), the kernel waits for modules in
    MODULE_STATE_GOING state to finish unloading before making another
    attempt to load the same module.

    This creates unnecessary work in the described scenario and delays the
    boot. In the worst case, it can prevent udev from loading drivers for
    other devices and might cause timeouts of services waiting on them and
    subsequently a failed boot.

    This patch attempts a different solution for the problem 6e6de3dee51a
    was trying to solve. Rather than waiting for the unloading to complete,
    it returns a different error code (-EBUSY) for modules in the GOING
    state. This should avoid the error situation that was described in
    6e6de3dee51a (user space attempting to load a dependent module because
    the -EEXIST error code would suggest to user space that the first module
    had been loaded successfully), while avoiding the delay situation too.

    Fixes: 6e6de3dee51a ("kernel/module.c: Only return -EEXIST for modules that have finished loading")
    Co-developed-by: Martin Wilck <mwilck@suse.com>
    Signed-off-by: Martin Wilck <mwilck@suse.com>
    Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
    Cc: stable@vger.kernel.org
    ---

    Notes:
    Sending this alternative patch per the discussion in
    https://lore.kernel.org/linux-modules/20220919123233.8538-1-petr.pavlu@suse.com/.
    The initial version comes internally from Martin, hence the co-developed tag.

    kernel/module/main.c | 8 +++++---
    1 file changed, 5 insertions(+), 3 deletions(-)

    diff --git a/kernel/module/main.c b/kernel/module/main.c
    index d02d39c7174e..b7e08d1edc27 100644
    --- a/kernel/module/main.c
    +++ b/kernel/module/main.c
    @@ -2386,7 +2386,8 @@ static bool finished_loading(const char *name)
    sched_annotate_sleep();
    mutex_lock(&module_mutex);
    mod = find_module_all(name, strlen(name), true);
    - ret = !mod || mod->state == MODULE_STATE_LIVE;
    + ret = !mod || mod->state == MODULE_STATE_LIVE
    + || mod->state == MODULE_STATE_GOING;
    mutex_unlock(&module_mutex);

    return ret;
    @@ -2566,7 +2567,8 @@ static int add_unformed_module(struct module *mod)
    mutex_lock(&module_mutex);
    old = find_module_all(mod->name, strlen(mod->name), true);
    if (old != NULL) {
    - if (old->state != MODULE_STATE_LIVE) {
    + if (old->state == MODULE_STATE_COMING
    + || old->state == MODULE_STATE_UNFORMED) {
    /* Wait in case it fails to load. */
    mutex_unlock(&module_mutex);
    err = wait_event_interruptible(module_wq,
    @@ -2575,7 +2577,7 @@ static int add_unformed_module(struct module *mod)
    goto out_unlocked;
    goto again;
    }
    - err = -EEXIST;
    + err = old->state != MODULE_STATE_LIVE ? -EBUSY : -EEXIST;
    goto out;
    }
    mod_update_bounds(mod);
    --
    2.35.3
    \
     
     \ /
      Last update: 2022-11-23 14:34    [W:2.713 / U:0.128 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site