| From foo@baz Fri Feb 5 09:58:31 AM CET 2021 |
| From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> |
| Date: Fri, 15 Jan 2021 19:30:51 +0100 |
| Subject: driver core: Extend device_is_dependent() |
| |
| From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> |
| |
| commit 3d1cf435e201d1fd63e4346b141881aed086effd upstream |
| |
| If the device passed as the target (second argument) to |
| device_is_dependent() is not completely registered (that is, it has |
| been initialized, but not added yet), but the parent pointer of it |
| is set, it may be missing from the list of the parent's children |
| and device_for_each_child() called by device_is_dependent() cannot |
| be relied on to catch that dependency. |
| |
| For this reason, modify device_is_dependent() to check the ancestors |
| of the target device by following its parent pointer in addition to |
| the device_for_each_child() walk. |
| |
| Fixes: 9ed9895370ae ("driver core: Functional dependencies tracking support") |
| Reported-by: Stephan Gerhold <stephan@gerhold.net> |
| Tested-by: Stephan Gerhold <stephan@gerhold.net> |
| Reviewed-by: Saravana Kannan <saravanak@google.com> |
| Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
| Link: https://lore.kernel.org/r/17705994.d592GUb2YH@kreacher |
| Cc: stable <stable@vger.kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/base/core.c | 17 ++++++++++++++++- |
| 1 file changed, 16 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/base/core.c |
| +++ b/drivers/base/core.c |
| @@ -96,6 +96,16 @@ void device_links_read_unlock(int not_us |
| } |
| #endif /* !CONFIG_SRCU */ |
| |
| +static bool device_is_ancestor(struct device *dev, struct device *target) |
| +{ |
| + while (target->parent) { |
| + target = target->parent; |
| + if (dev == target) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| /** |
| * device_is_dependent - Check if one device depends on another one |
| * @dev: Device to check dependencies for. |
| @@ -109,7 +119,12 @@ static int device_is_dependent(struct de |
| struct device_link *link; |
| int ret; |
| |
| - if (dev == target) |
| + /* |
| + * The "ancestors" check is needed to catch the case when the target |
| + * device has not been completely initialized yet and it is still |
| + * missing from the list of children of its parent device. |
| + */ |
| + if (dev == target || device_is_ancestor(dev, target)) |
| return 1; |
| |
| ret = device_for_each_child(dev, target, device_is_dependent); |