| From 8145849a45a47b8fb34e7eec43c44b1f48789f62 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 12 Mar 2024 12:52:38 +0200 |
| Subject: devlink: Fix devlink parallel commands processing |
| |
| From: Shay Drory <shayd@nvidia.com> |
| |
| [ Upstream commit d7d75124965aee23e5e4421d78376545cf070b0a ] |
| |
| Commit 870c7ad4a52b ("devlink: protect devlink->dev by the instance |
| lock") added devlink instance locking inside a loop that iterates over |
| all the registered devlink instances on the machine in the pre-doit |
| phase. This can lead to serialization of devlink commands over |
| different devlink instances. |
| |
| For example: While the first devlink instance is executing firmware |
| flash, all commands to other devlink instances on the machine are |
| forced to wait until the first devlink finishes. |
| |
| Therefore, in the pre-doit phase, take the devlink instance lock only |
| for the devlink instance the command is targeting. Devlink layer is |
| taking a reference on the devlink instance, ensuring the devlink->dev |
| pointer is valid. This reference taking was introduced by commit |
| a380687200e0 ("devlink: take device reference for devlink object"). |
| Without this commit, it would not be safe to access devlink->dev |
| lockless. |
| |
| Fixes: 870c7ad4a52b ("devlink: protect devlink->dev by the instance lock") |
| Signed-off-by: Shay Drory <shayd@nvidia.com> |
| Reviewed-by: Jiri Pirko <jiri@nvidia.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/devlink/netlink.c | 13 +++++++------ |
| 1 file changed, 7 insertions(+), 6 deletions(-) |
| |
| diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c |
| index 86f12531bf998..0f41fded6a6d7 100644 |
| --- a/net/devlink/netlink.c |
| +++ b/net/devlink/netlink.c |
| @@ -80,12 +80,13 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs, |
| devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]); |
| |
| devlinks_xa_for_each_registered_get(net, index, devlink) { |
| - devl_dev_lock(devlink, dev_lock); |
| - if (devl_is_registered(devlink) && |
| - strcmp(devlink->dev->bus->name, busname) == 0 && |
| - strcmp(dev_name(devlink->dev), devname) == 0) |
| - return devlink; |
| - devl_dev_unlock(devlink, dev_lock); |
| + if (strcmp(devlink->dev->bus->name, busname) == 0 && |
| + strcmp(dev_name(devlink->dev), devname) == 0) { |
| + devl_dev_lock(devlink, dev_lock); |
| + if (devl_is_registered(devlink)) |
| + return devlink; |
| + devl_dev_unlock(devlink, dev_lock); |
| + } |
| devlink_put(devlink); |
| } |
| |
| -- |
| 2.43.0 |
| |