From: "Matthew Wilcox (Oracle)" <wi...@infradead.org> The minor_lock can be removed as the XArray contains its own spinlock. I suspect the GFP_ATOMIC allocation could be GFP_KERNEL, but I couldn't prove it.
Signed-off-by: Matthew Wilcox (Oracle) <wi...@infradead.org> --- drivers/net/tap.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/net/tap.c b/drivers/net/tap.c index dd614c2cd994..81b06a21d96c 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -14,9 +14,9 @@ #include <linux/slab.h> #include <linux/wait.h> #include <linux/cdev.h> -#include <linux/idr.h> #include <linux/fs.h> #include <linux/uio.h> +#include <linux/xarray.h> #include <net/net_namespace.h> #include <net/rtnetlink.h> @@ -106,8 +106,7 @@ static LIST_HEAD(major_list); struct major_info { struct rcu_head rcu; dev_t major; - struct idr minor_idr; - spinlock_t minor_lock; + struct xarray tap_devs; const char *device_name; struct list_head next; }; @@ -414,19 +413,16 @@ int tap_get_minor(dev_t major, struct tap_dev *tap) goto unlock; } - spin_lock(&tap_major->minor_lock); - retval = idr_alloc(&tap_major->minor_idr, tap, 1, TAP_NUM_DEVS, GFP_ATOMIC); - if (retval >= 0) { - tap->minor = retval; - } else if (retval == -ENOSPC) { + retval = xa_alloc(&tap_major->tap_devs, &tap->minor, tap, + XA_LIMIT(0, TAP_NUM_DEVS), GFP_ATOMIC); + if (retval == -EBUSY) { netdev_err(tap->dev, "Too many tap devices\n"); retval = -EINVAL; } - spin_unlock(&tap_major->minor_lock); unlock: rcu_read_unlock(); - return retval < 0 ? retval : 0; + return retval; } EXPORT_SYMBOL_GPL(tap_get_minor); @@ -440,12 +436,12 @@ void tap_free_minor(dev_t major, struct tap_dev *tap) goto unlock; } - spin_lock(&tap_major->minor_lock); + xa_lock(&tap_major->tap_devs); if (tap->minor) { - idr_remove(&tap_major->minor_idr, tap->minor); + __xa_erase(&tap_major->tap_devs, tap->minor); tap->minor = 0; } - spin_unlock(&tap_major->minor_lock); + xa_unlock(&tap_major->tap_devs); unlock: rcu_read_unlock(); @@ -465,13 +461,13 @@ static struct tap_dev *dev_get_by_tap_file(int major, int minor) goto unlock; } - spin_lock(&tap_major->minor_lock); - tap = idr_find(&tap_major->minor_idr, minor); + xa_lock(&tap_major->tap_devs); + tap = xa_load(&tap_major->tap_devs, minor); if (tap) { dev = tap->dev; dev_hold(dev); } - spin_unlock(&tap_major->minor_lock); + xa_unlock(&tap_major->tap_devs); unlock: rcu_read_unlock(); @@ -1322,8 +1318,7 @@ static int tap_list_add(dev_t major, const char *device_name) tap_major->major = MAJOR(major); - idr_init(&tap_major->minor_idr); - spin_lock_init(&tap_major->minor_lock); + xa_init_flags(&tap_major->tap_devs, XA_FLAGS_ALLOC1); tap_major->device_name = device_name; @@ -1369,7 +1364,6 @@ void tap_destroy_cdev(dev_t major, struct cdev *tap_cdev) unregister_chrdev_region(major, TAP_NUM_DEVS); list_for_each_entry_safe(tap_major, tmp, &major_list, next) { if (tap_major->major == MAJOR(major)) { - idr_destroy(&tap_major->minor_idr); list_del_rcu(&tap_major->next); kfree_rcu(tap_major, rcu); } -- 2.23.0.rc1