summaryrefslogtreecommitdiff
path: root/net/core/devlink.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2021-11-01 13:26:07 +0000
committerDavid S. Miller <davem@davemloft.net>2021-11-01 13:26:07 +0000
commit1adc58ea2330cd014fde8a254480441e10ee280d (patch)
treebd94424fa9d4bf6788edba77057a6822f3007d14 /net/core/devlink.c
parentc6e03dbe0c7cdbe7b259deeae0f193d15ec5002f (diff)
parent1af0a0948e28d83bcfa9d48cd0f992f616c5d62e (diff)
Merge branch 'devlink-locking'
Jakub Kicinski says: ==================== improve ethtool/rtnl vs devlink locking During ethtool netlink development we decided to move some of the commmands to devlink. Since we don't want drivers to implement both devlink and ethtool version of the commands ethtool ioctl falls back to calling devlink. Unfortunately devlink locks must be taken before rtnl_lock. This results in a questionable dev_hold() / rtnl_unlock() / devlink / rtnl_lock() / dev_put() pattern. This method "works" but it working depends on drivers in question not doing much in ethtool_ops->begin / complete, and on the netdev not having needs_free_netdev set. Since commit 437ebfd90a25 ("devlink: Count struct devlink consumers") we can hold a reference on a devlink instance and prevent it from going away (sort of like netdev with dev_hold()). We can use this to create a more natural reference nesting where we get a ref on the devlink instance and make the devlink call entirely outside of the rtnl_lock section. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/devlink.c')
-rw-r--r--net/core/devlink.c53
1 files changed, 12 insertions, 41 deletions
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 2d8abe88c6738..6b5ee862429eb 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -182,15 +182,17 @@ struct net *devlink_net(const struct devlink *devlink)
}
EXPORT_SYMBOL_GPL(devlink_net);
-static void devlink_put(struct devlink *devlink)
+void devlink_put(struct devlink *devlink)
{
if (refcount_dec_and_test(&devlink->refcount))
complete(&devlink->comp);
}
-static bool __must_check devlink_try_get(struct devlink *devlink)
+struct devlink *__must_check devlink_try_get(struct devlink *devlink)
{
- return refcount_inc_not_zero(&devlink->refcount);
+ if (refcount_inc_not_zero(&devlink->refcount))
+ return devlink;
+ return NULL;
}
static struct devlink *devlink_get_from_attrs(struct net *net,
@@ -11281,55 +11283,28 @@ static struct devlink_port *netdev_to_devlink_port(struct net_device *dev)
return dev->netdev_ops->ndo_get_devlink_port(dev);
}
-static struct devlink *netdev_to_devlink(struct net_device *dev)
-{
- struct devlink_port *devlink_port = netdev_to_devlink_port(dev);
-
- if (!devlink_port)
- return NULL;
-
- return devlink_port->devlink;
-}
-
-void devlink_compat_running_version(struct net_device *dev,
+void devlink_compat_running_version(struct devlink *devlink,
char *buf, size_t len)
{
- struct devlink *devlink;
-
- dev_hold(dev);
- rtnl_unlock();
-
- devlink = netdev_to_devlink(dev);
- if (!devlink || !devlink->ops->info_get)
- goto out;
+ if (!devlink->ops->info_get)
+ return;
mutex_lock(&devlink->lock);
__devlink_compat_running_version(devlink, buf, len);
mutex_unlock(&devlink->lock);
-
-out:
- rtnl_lock();
- dev_put(dev);
}
-int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
+int devlink_compat_flash_update(struct devlink *devlink, const char *file_name)
{
struct devlink_flash_update_params params = {};
- struct devlink *devlink;
int ret;
- dev_hold(dev);
- rtnl_unlock();
-
- devlink = netdev_to_devlink(dev);
- if (!devlink || !devlink->ops->flash_update) {
- ret = -EOPNOTSUPP;
- goto out;
- }
+ if (!devlink->ops->flash_update)
+ return -EOPNOTSUPP;
ret = request_firmware(&params.fw, file_name, devlink->dev);
if (ret)
- goto out;
+ return ret;
mutex_lock(&devlink->lock);
devlink_flash_update_begin_notify(devlink);
@@ -11339,10 +11314,6 @@ int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
release_firmware(params.fw);
-out:
- rtnl_lock();
- dev_put(dev);
-
return ret;
}