Commit f2411da7 authored by Luis R. Rodriguez's avatar Luis R. Rodriguez Committed by Greg Kroah-Hartman

driver-core: add driver module asynchronous probe support

Some init systems may wish to express the desire to have device drivers
run their probe() code asynchronously. This implements support for this
and allows userspace to request async probe as a preference through a
generic shared device driver module parameter, async_probe.

Implementation for async probe is supported through a module parameter
given that since synchronous probe has been prevalent for years some
userspace might exist which relies on the fact that the device driver
will probe synchronously and the assumption that devices it provides
will be immediately available after this.
Signed-off-by: default avatarLuis R. Rodriguez <mcgrof@suse.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 765230b5
...@@ -943,6 +943,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -943,6 +943,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
auto selects the default scheme, which automatically auto selects the default scheme, which automatically
enables eagerfpu restore for xsaveopt. enables eagerfpu restore for xsaveopt.
module.async_probe [KNL]
Enable asynchronous probe on this module.
early_ioremap_debug [KNL] early_ioremap_debug [KNL]
Enable debug messages in early_ioremap support. This Enable debug messages in early_ioremap support. This
is useful for tracking down temporary early mappings is useful for tracking down temporary early mappings
......
...@@ -419,7 +419,13 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) ...@@ -419,7 +419,13 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
bool driver_allows_async_probing(struct device_driver *drv) bool driver_allows_async_probing(struct device_driver *drv)
{ {
return drv->probe_type == PROBE_PREFER_ASYNCHRONOUS; if (drv->probe_type == PROBE_PREFER_ASYNCHRONOUS)
return true;
if (drv->owner && drv->owner->async_probe_requested)
return true;
return false;
} }
struct device_attach_data { struct device_attach_data {
......
...@@ -201,10 +201,12 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus); ...@@ -201,10 +201,12 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus);
* respective probe routines. This tells the core what to * respective probe routines. This tells the core what to
* expect and prefer. * expect and prefer.
* *
* @PROBE_SYNCHRONOUS: Default. Drivers expect their probe routines * @PROBE_DEFAULT_STRATEGY: Drivers expect their probe routines
* to run synchronously with driver and device registration * to run synchronously with driver and device registration
* (with the exception of -EPROBE_DEFER handling - re-probing * (with the exception of -EPROBE_DEFER handling - re-probing
* always ends up being done asynchronously). * always ends up being done asynchronously) unless user
* explicitly requested asynchronous probing via module
* parameter.
* @PROBE_PREFER_ASYNCHRONOUS: Drivers for "slow" devices which * @PROBE_PREFER_ASYNCHRONOUS: Drivers for "slow" devices which
* probing order is not essential for booting the system may * probing order is not essential for booting the system may
* opt into executing their probes asynchronously. * opt into executing their probes asynchronously.
...@@ -216,7 +218,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus); ...@@ -216,7 +218,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus);
* drivers. * drivers.
*/ */
enum probe_type { enum probe_type {
PROBE_SYNCHRONOUS, PROBE_DEFAULT_STRATEGY,
PROBE_PREFER_ASYNCHRONOUS, PROBE_PREFER_ASYNCHRONOUS,
}; };
......
...@@ -257,6 +257,8 @@ struct module { ...@@ -257,6 +257,8 @@ struct module {
bool sig_ok; bool sig_ok;
#endif #endif
bool async_probe_requested;
/* symbols that will be GPL-only in the near future. */ /* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms; const struct kernel_symbol *gpl_future_syms;
const unsigned long *gpl_future_crcs; const unsigned long *gpl_future_crcs;
......
...@@ -3107,7 +3107,7 @@ static noinline int do_init_module(struct module *mod) ...@@ -3107,7 +3107,7 @@ static noinline int do_init_module(struct module *mod)
* *
* http://thread.gmane.org/gmane.linux.kernel/1420814 * http://thread.gmane.org/gmane.linux.kernel/1420814
*/ */
if (current->flags & PF_USED_ASYNC) if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
async_synchronize_full(); async_synchronize_full();
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
...@@ -3240,8 +3240,16 @@ static int complete_formation(struct module *mod, struct load_info *info) ...@@ -3240,8 +3240,16 @@ static int complete_formation(struct module *mod, struct load_info *info)
static int unknown_module_param_cb(char *param, char *val, const char *modname, static int unknown_module_param_cb(char *param, char *val, const char *modname,
void *arg) void *arg)
{ {
struct module *mod = arg;
int ret;
if (strcmp(param, "async_probe") == 0) {
mod->async_probe_requested = true;
return 0;
}
/* Check for magic 'dyndbg' arg */ /* Check for magic 'dyndbg' arg */
int ret = ddebug_dyndbg_module_param_cb(param, val, modname); ret = ddebug_dyndbg_module_param_cb(param, val, modname);
if (ret != 0) if (ret != 0)
pr_warn("%s: unknown parameter '%s' ignored\n", modname, param); pr_warn("%s: unknown parameter '%s' ignored\n", modname, param);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment