Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: syzbot+d94d214ea473e218fc89@syzkaller.appspotmail.com
Reported-by: syzbot+9f0dd863b87113935acf@syzkaller.appspotmail.com
Fixes: 9053637e0da7 ("devlink: remove the registration guarantee of references")
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://lore.kernel.org/r/20230111042908.988199-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+15 -4
+13 -3
net/devlink/core.c
··· 83 83 return NULL; 84 84 } 85 85 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 + 86 97 void devlink_put(struct devlink *devlink) 87 98 { 88 99 if (refcount_dec_and_test(&devlink->refcount)) 89 - kfree_rcu(devlink, rcu); 100 + queue_rcu_work(system_wq, &devlink->rwork); 90 101 } 91 102 92 103 struct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp) ··· 242 231 INIT_LIST_HEAD(&devlink->trap_list); 243 232 INIT_LIST_HEAD(&devlink->trap_group_list); 244 233 INIT_LIST_HEAD(&devlink->trap_policer_list); 234 + INIT_RCU_WORK(&devlink->rwork, devlink_release); 245 235 lockdep_register_key(&devlink->lock_key); 246 236 mutex_init(&devlink->lock); 247 237 lockdep_set_class(&devlink->lock, &devlink->lock_key); ··· 271 259 272 260 mutex_destroy(&devlink->linecards_lock); 273 261 mutex_destroy(&devlink->reporters_lock); 274 - mutex_destroy(&devlink->lock); 275 - lockdep_unregister_key(&devlink->lock_key); 276 262 WARN_ON(!list_empty(&devlink->trap_policer_list)); 277 263 WARN_ON(!list_empty(&devlink->trap_group_list)); 278 264 WARN_ON(!list_empty(&devlink->trap_list));
+2 -1
net/devlink/devl_internal.h
··· 7 7 #include <linux/netdevice.h> 8 8 #include <linux/notifier.h> 9 9 #include <linux/types.h> 10 + #include <linux/workqueue.h> 10 11 #include <linux/xarray.h> 11 12 #include <net/devlink.h> 12 13 #include <net/net_namespace.h> ··· 52 51 struct lock_class_key lock_key; 53 52 u8 reload_failed:1; 54 53 refcount_t refcount; 55 - struct rcu_head rcu; 54 + struct rcu_work rwork; 56 55 struct notifier_block netdevice_nb; 57 56 char priv[] __aligned(NETDEV_ALIGN); 58 57 };