Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3535c7e authored by Rusty Russell's avatar Rusty Russell
Browse files

module: clean up load_module a little more.



1fb9341a made our locking in
load_module more complicated: we grab the mutex once to insert the
module in the list, then again to upgrade it once it's formed.

Since the locking is self-contained, it's neater to do this in
separate functions.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent f2e207f3
Loading
Loading
Loading
Loading
+68 −39
Original line number Diff line number Diff line
@@ -3145,12 +3145,72 @@ static int may_init_module(void)
	return 0;
}

/*
 * 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;
	struct module *old;

	mod->state = MODULE_STATE_UNFORMED;

again:
	mutex_lock(&module_mutex);
	if ((old = find_module_all(mod->name, true)) != NULL) {
		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,
					       finished_loading(mod->name));
			if (err)
				goto out_unlocked;
			goto again;
		}
		err = -EEXIST;
		goto out;
	}
	list_add_rcu(&mod->list, &modules);
	err = 0;

out:
	mutex_unlock(&module_mutex);
out_unlocked:
	return err;
}

static int complete_formation(struct module *mod, struct load_info *info)
{
	int err;

	mutex_lock(&module_mutex);

	/* Find duplicate symbols (must be called under lock). */
	err = verify_export_symbols(mod);
	if (err < 0)
		goto out;

	/* This relies on module_mutex for list integrity. */
	module_bug_finalize(info->hdr, info->sechdrs, mod);

	/* Mark state as coming so strong_try_module_get() ignores us,
	 * but kallsyms etc. can see us. */
	mod->state = MODULE_STATE_COMING;

out:
	mutex_unlock(&module_mutex);
	return err;
}

/* Allocate and load the module: note that size of section 0 is always
   zero, and we rely on this for optional sections. */
static int load_module(struct load_info *info, const char __user *uargs,
		       int flags)
{
	struct module *mod, *old;
	struct module *mod;
	long err;

	err = module_sig_check(info);
@@ -3168,31 +3228,10 @@ static int load_module(struct load_info *info, const char __user *uargs,
		goto free_copy;
	}

	/*
	 * 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.
	 */
	mod->state = MODULE_STATE_UNFORMED;
again:
	mutex_lock(&module_mutex);
	if ((old = find_module_all(mod->name, true)) != NULL) {
		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,
					       finished_loading(mod->name));
	/* Reserve our place in the list. */
	err = add_unformed_module(mod);
	if (err)
		goto free_module;
			goto again;
		}
		err = -EEXIST;
		mutex_unlock(&module_mutex);
		goto free_module;
	}
	list_add_rcu(&mod->list, &modules);
	mutex_unlock(&module_mutex);

#ifdef CONFIG_MODULE_SIG
	mod->sig_ok = info->sig_ok;
@@ -3245,21 +3284,11 @@ static int load_module(struct load_info *info, const char __user *uargs,

	dynamic_debug_setup(info->debug, info->num_debug);

	mutex_lock(&module_mutex);
	/* Find duplicate symbols (must be called under lock). */
	err = verify_export_symbols(mod);
	if (err < 0)
	/* Finally it's fully formed, ready to start executing. */
	err = complete_formation(mod, info);
	if (err)
		goto ddebug_cleanup;

	/* This relies on module_mutex for list integrity. */
	module_bug_finalize(info->hdr, info->sechdrs, mod);

	/* Mark state as coming so strong_try_module_get() ignores us,
	 * but kallsyms etc. can see us. */
	mod->state = MODULE_STATE_COMING;

	mutex_unlock(&module_mutex);

	/* Module is ready to execute: parsing args may do that. */
	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
			 -32768, 32767, &ddebug_dyndbg_module_param_cb);
@@ -3283,8 +3312,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
	/* module_bug_cleanup needs module_mutex protection */
	mutex_lock(&module_mutex);
	module_bug_cleanup(mod);
 ddebug_cleanup:
	mutex_unlock(&module_mutex);
 ddebug_cleanup:
	dynamic_debug_remove(info->debug);
	synchronize_sched();
	kfree(mod->args);