mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
driver core: Avoid careless re-use of existing device links
After commitead18c23c2
("driver core: Introduce device links reference counting"), if there is a link between the given supplier and the given consumer already, device_link_add() will refcount it and return it unconditionally. However, if the flags passed to it on the second (or any subsequent) attempt to create a device link between the same consumer-supplier pair are not compatible with the existing link's flags, that is incorrect. First off, if the existing link is stateless and the next caller of device_link_add() for the same consumer-supplier pair wants a stateful one, or the other way around, the existing link cannot be returned, because it will not match the expected behavior, so make device_link_add() dump the stack and return NULL in that case. Moreover, if the DL_FLAG_AUTOREMOVE_CONSUMER flag is passed to device_link_add(), its caller will expect its reference to the link to be dropped automatically on consumer driver removal, which will not happen if that flag is not set in the link's flags (and analogously for DL_FLAG_AUTOREMOVE_SUPPLIER). For this reason, make device_link_add() update the existing link's flags accordingly before returning it to the caller. Fixes:ead18c23c2
("driver core: Introduce device links reference counting") Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
c8d50986da
commit
f265df550a
1 changed files with 20 additions and 3 deletions
|
@ -221,12 +221,29 @@ struct device_link *device_link_add(struct device *consumer,
|
|||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(link, &supplier->links.consumers, s_node)
|
||||
if (link->consumer == consumer) {
|
||||
kref_get(&link->kref);
|
||||
list_for_each_entry(link, &supplier->links.consumers, s_node) {
|
||||
if (link->consumer != consumer)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't return a stateless link if the caller wants a stateful
|
||||
* one and vice versa.
|
||||
*/
|
||||
if (WARN_ON((flags & DL_FLAG_STATELESS) != (link->flags & DL_FLAG_STATELESS))) {
|
||||
link = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & DL_FLAG_AUTOREMOVE_CONSUMER)
|
||||
link->flags |= DL_FLAG_AUTOREMOVE_CONSUMER;
|
||||
|
||||
if (flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
|
||||
link->flags |= DL_FLAG_AUTOREMOVE_SUPPLIER;
|
||||
|
||||
kref_get(&link->kref);
|
||||
goto out;
|
||||
}
|
||||
|
||||
link = kzalloc(sizeof(*link), GFP_KERNEL);
|
||||
if (!link)
|
||||
goto out;
|
||||
|
|
Loading…
Reference in a new issue