Skip to content

Commit 6aff7cb

Browse files
idoschkuba-moo
authored andcommitted
netdevsim: Block until all devices are released
Like other buses, devices on the netdevsim bus have a release callback that is invoked when the reference count of the device drops to zero. However, unlike other buses such as PCI, the release callback is not necessarily built into the kernel, as netdevsim can be built as a module. The above is problematic as nothing prevents the module from being unloaded before the release callback has been invoked, which can happen asynchronously. One such example can be found in commit a380687 ("devlink: take device reference for devlink object") where devlink calls put_device() from an RCU callback. The issue is not theoretical and the reproducer in [1] can reliably crash the kernel. The conclusion of this discussion was that the issue should be solved in netdevsim, which is what this patch is trying to do. Add a reference count that is increased when a device is added to the bus and decreased when a device is released. Signal a completion when the reference count drops to zero and wait for the completion when unloading the module so that the module will not be unloaded before all the devices were released. The reference count is initialized to one so that completion is only signaled when unloading the module. With this patch, the reproducer in [1] no longer crashes the kernel. [1] https://lore.kernel.org/netdev/[email protected]/ Fixes: a380687 ("devlink: take device reference for devlink object") Signed-off-by: Ido Schimmel <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 1a86a77 commit 6aff7cb

File tree

1 file changed

+12
-0
lines changed
  • drivers/net/netdevsim

1 file changed

+12
-0
lines changed

drivers/net/netdevsim/bus.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
* Copyright (C) 2019 Mellanox Technologies. All rights reserved
44
*/
55

6+
#include <linux/completion.h>
67
#include <linux/device.h>
78
#include <linux/idr.h>
89
#include <linux/kernel.h>
910
#include <linux/list.h>
1011
#include <linux/mutex.h>
12+
#include <linux/refcount.h>
1113
#include <linux/slab.h>
1214
#include <linux/sysfs.h>
1315

@@ -17,6 +19,8 @@ static DEFINE_IDA(nsim_bus_dev_ids);
1719
static LIST_HEAD(nsim_bus_dev_list);
1820
static DEFINE_MUTEX(nsim_bus_dev_list_lock);
1921
static bool nsim_bus_enable;
22+
static refcount_t nsim_bus_devs; /* Including the bus itself. */
23+
static DECLARE_COMPLETION(nsim_bus_devs_released);
2024

2125
static struct nsim_bus_dev *to_nsim_bus_dev(struct device *dev)
2226
{
@@ -121,6 +125,8 @@ static void nsim_bus_dev_release(struct device *dev)
121125

122126
nsim_bus_dev = container_of(dev, struct nsim_bus_dev, dev);
123127
kfree(nsim_bus_dev);
128+
if (refcount_dec_and_test(&nsim_bus_devs))
129+
complete(&nsim_bus_devs_released);
124130
}
125131

126132
static struct device_type nsim_bus_dev_type = {
@@ -170,6 +176,7 @@ new_device_store(const struct bus_type *bus, const char *buf, size_t count)
170176
goto err;
171177
}
172178

179+
refcount_inc(&nsim_bus_devs);
173180
/* Allow using nsim_bus_dev */
174181
smp_store_release(&nsim_bus_dev->init, true);
175182

@@ -326,6 +333,7 @@ int nsim_bus_init(void)
326333
err = driver_register(&nsim_driver);
327334
if (err)
328335
goto err_bus_unregister;
336+
refcount_set(&nsim_bus_devs, 1);
329337
/* Allow using resources */
330338
smp_store_release(&nsim_bus_enable, true);
331339
return 0;
@@ -341,6 +349,8 @@ void nsim_bus_exit(void)
341349

342350
/* Disallow using resources */
343351
smp_store_release(&nsim_bus_enable, false);
352+
if (refcount_dec_and_test(&nsim_bus_devs))
353+
complete(&nsim_bus_devs_released);
344354

345355
mutex_lock(&nsim_bus_dev_list_lock);
346356
list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) {
@@ -349,6 +359,8 @@ void nsim_bus_exit(void)
349359
}
350360
mutex_unlock(&nsim_bus_dev_list_lock);
351361

362+
wait_for_completion(&nsim_bus_devs_released);
363+
352364
driver_unregister(&nsim_driver);
353365
bus_unregister(&nsim_bus);
354366
}

0 commit comments

Comments
 (0)