Skip to content

Commit 93e71ed

Browse files
committed
devlink: keep the instance mutex alive until references are gone
The reference needs to keep the instance memory around, but also the instance lock must remain valid. Users will take the lock, check registration status and release the lock. mutex_destroy() etc. belong in the same place as the freeing of the memory. Unfortunately lockdep_unregister_key() sleeps so we need to switch the an rcu_work. Note that the problem is a bit hard to repro, because devlink_pernet_pre_exit() iterates over registered instances. AFAIU the instances must get devlink_free()d concurrently with the namespace getting deleted for the problem to occur. Reported-by: [email protected] Reported-by: [email protected] Fixes: 9053637 ("devlink: remove the registration guarantee of references") Reviewed-by: Jiri Pirko <[email protected]> Reviewed-by: Jacob Keller <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 80c0576 commit 93e71ed

File tree

2 files changed

+15
-4
lines changed

2 files changed

+15
-4
lines changed

net/devlink/core.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,21 @@ struct devlink *__must_check devlink_try_get(struct devlink *devlink)
8383
return NULL;
8484
}
8585

86+
static void devlink_release(struct work_struct *work)
87+
{
88+
struct devlink *devlink;
89+
90+
devlink = container_of(to_rcu_work(work), struct devlink, rwork);
91+
92+
mutex_destroy(&devlink->lock);
93+
lockdep_unregister_key(&devlink->lock_key);
94+
kfree(devlink);
95+
}
96+
8697
void devlink_put(struct devlink *devlink)
8798
{
8899
if (refcount_dec_and_test(&devlink->refcount))
89-
kfree_rcu(devlink, rcu);
100+
queue_rcu_work(system_wq, &devlink->rwork);
90101
}
91102

92103
struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp)
@@ -231,6 +242,7 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
231242
INIT_LIST_HEAD(&devlink->trap_list);
232243
INIT_LIST_HEAD(&devlink->trap_group_list);
233244
INIT_LIST_HEAD(&devlink->trap_policer_list);
245+
INIT_RCU_WORK(&devlink->rwork, devlink_release);
234246
lockdep_register_key(&devlink->lock_key);
235247
mutex_init(&devlink->lock);
236248
lockdep_set_class(&devlink->lock, &devlink->lock_key);
@@ -259,8 +271,6 @@ void devlink_free(struct devlink *devlink)
259271

260272
mutex_destroy(&devlink->linecards_lock);
261273
mutex_destroy(&devlink->reporters_lock);
262-
mutex_destroy(&devlink->lock);
263-
lockdep_unregister_key(&devlink->lock_key);
264274
WARN_ON(!list_empty(&devlink->trap_policer_list));
265275
WARN_ON(!list_empty(&devlink->trap_group_list));
266276
WARN_ON(!list_empty(&devlink->trap_list));

net/devlink/devl_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/netdevice.h>
88
#include <linux/notifier.h>
99
#include <linux/types.h>
10+
#include <linux/workqueue.h>
1011
#include <linux/xarray.h>
1112
#include <net/devlink.h>
1213
#include <net/net_namespace.h>
@@ -51,7 +52,7 @@ struct devlink {
5152
struct lock_class_key lock_key;
5253
u8 reload_failed:1;
5354
refcount_t refcount;
54-
struct rcu_head rcu;
55+
struct rcu_work rwork;
5556
struct notifier_block netdevice_nb;
5657
char priv[] __aligned(NETDEV_ALIGN);
5758
};

0 commit comments

Comments
 (0)