driver core: add test of driver remove calls during probe

In recent discussions on ksummit-discuss[1], it was suggested to do a
sequence of probe, remove, probe for testing driver remove paths. This
adds a kconfig option for said test.

[1] https://lists.linuxfoundation.org/pipermail/ksummit-discuss/2016-August/003459.html

Suggested-by: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Rob Herring <robh@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Rob Herring 2016-08-11 10:20:58 -05:00 committed by Greg Kroah-Hartman
parent cebf8fd169
commit bea5b158ff
2 changed files with 31 additions and 0 deletions

View File

@ -212,6 +212,16 @@ config DEBUG_DEVRES
If you are unsure about this, Say N here. If you are unsure about this, Say N here.
config DEBUG_TEST_DRIVER_REMOVE
bool "Test driver remove calls during probe"
depends on DEBUG_KERNEL
help
Say Y here if you want the Driver core to test driver remove functions
by calling probe, remove, probe. This tests the remove path without
having to unbind the driver or unload the driver module.
If you are unsure about this, say N here.
config SYS_HYPERVISOR config SYS_HYPERVISOR
bool bool
default n default n

View File

@ -329,6 +329,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
{ {
int ret = -EPROBE_DEFER; int ret = -EPROBE_DEFER;
int local_trigger_count = atomic_read(&deferred_trigger_count); int local_trigger_count = atomic_read(&deferred_trigger_count);
bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE);
if (defer_all_probes) { if (defer_all_probes) {
/* /*
@ -346,6 +347,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
drv->bus->name, __func__, drv->name, dev_name(dev)); drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head)); WARN_ON(!list_empty(&dev->devres_head));
re_probe:
dev->driver = drv; dev->driver = drv;
/* If using pinctrl, bind pins now before probing */ /* If using pinctrl, bind pins now before probing */
@ -383,6 +385,25 @@ static int really_probe(struct device *dev, struct device_driver *drv)
goto probe_failed; goto probe_failed;
} }
if (test_remove) {
test_remove = false;
if (dev->bus && dev->bus->remove)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
if (dev->pm_domain && dev->pm_domain->dismiss)
dev->pm_domain->dismiss(dev);
pm_runtime_reinit(dev);
goto re_probe;
}
pinctrl_init_done(dev); pinctrl_init_done(dev);
if (dev->pm_domain && dev->pm_domain->sync) if (dev->pm_domain && dev->pm_domain->sync)