Skip to content

Commit e21c52d

Browse files
idoschdavem330
authored andcommitted
devlink: Acquire device lock during netns dismantle
Device drivers register with devlink from their probe routines (under the device lock) by acquiring the devlink instance lock and calling devl_register(). Drivers that support a devlink reload usually implement the reload_{down, up}() operations in a similar fashion to their remove and probe routines, respectively. However, while the remove and probe routines are invoked with the device lock held, the reload operations are only invoked with the devlink instance lock held. It is therefore impossible for drivers to acquire the device lock from their reload operations, as this would result in lock inversion. The motivating use case for invoking the reload operations with the device lock held is in mlxsw which needs to trigger a PCI reset as part of the reload. The driver cannot call pci_reset_function() as this function acquires the device lock. Instead, it needs to call __pci_reset_function_locked which expects the device lock to be held. To that end, adjust devlink to always acquire the device lock before the devlink instance lock when performing a reload. For now, only do that when reload is triggered as part of netns dismantle. Subsequent patches will handle the case where reload is explicitly triggered by user space. Signed-off-by: Ido Schimmel <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: Petr Machata <[email protected]> Reviewed-by: Simon Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 526dd6d commit e21c52d

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

net/devlink/core.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -503,14 +503,14 @@ static void __net_exit devlink_pernet_pre_exit(struct net *net)
503503
* all devlink instances from this namespace into init_net.
504504
*/
505505
devlinks_xa_for_each_registered_get(net, index, devlink) {
506-
devl_lock(devlink);
506+
devl_dev_lock(devlink, true);
507507
err = 0;
508508
if (devl_is_registered(devlink))
509509
err = devlink_reload(devlink, &init_net,
510510
DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
511511
DEVLINK_RELOAD_LIMIT_UNSPEC,
512512
&actions_performed, NULL);
513-
devl_unlock(devlink);
513+
devl_dev_unlock(devlink, true);
514514
devlink_put(devlink);
515515
if (err && err != -EOPNOTSUPP)
516516
pr_warn("Failed to reload devlink instance into init_net\n");

net/devlink/devl_internal.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (c) 2016 Jiri Pirko <[email protected]>
44
*/
55

6+
#include <linux/device.h>
67
#include <linux/etherdevice.h>
78
#include <linux/mutex.h>
89
#include <linux/netdevice.h>
@@ -96,6 +97,20 @@ static inline bool devl_is_registered(struct devlink *devlink)
9697
return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
9798
}
9899

100+
static inline void devl_dev_lock(struct devlink *devlink, bool dev_lock)
101+
{
102+
if (dev_lock)
103+
device_lock(devlink->dev);
104+
devl_lock(devlink);
105+
}
106+
107+
static inline void devl_dev_unlock(struct devlink *devlink, bool dev_lock)
108+
{
109+
devl_unlock(devlink);
110+
if (dev_lock)
111+
device_unlock(devlink->dev);
112+
}
113+
99114
typedef void devlink_rel_notify_cb_t(struct devlink *devlink, u32 obj_index);
100115
typedef void devlink_rel_cleanup_cb_t(struct devlink *devlink, u32 obj_index,
101116
u32 rel_index);

0 commit comments

Comments
 (0)