From: Matthew Wilcox Date: Fri, 15 Feb 2019 15:32:20 +0000 (-0500) Subject: nbd: Convert nbd_index_idr to XArray X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=468a02f3392b4570deabdb0a85d4818cbd0a7719;p=users%2Fwilly%2Fxarray.git nbd: Convert nbd_index_idr to XArray Signed-off-by: Matthew Wilcox --- diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index e21d2ded732b7..7e50c1dfade8d 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -46,8 +46,8 @@ #define CREATE_TRACE_POINTS #include -static DEFINE_IDR(nbd_index_idr); -static DEFINE_MUTEX(nbd_index_mutex); +static DEFINE_XARRAY_ALLOC(nbd_devs); +static DEFINE_MUTEX(nbd_global_mutex); static int nbd_total_devices = 0; struct nbd_sock { @@ -227,10 +227,9 @@ static void nbd_dev_remove(struct nbd_device *nbd) static void nbd_put(struct nbd_device *nbd) { - if (refcount_dec_and_mutex_lock(&nbd->refs, - &nbd_index_mutex)) { - idr_remove(&nbd_index_idr, nbd->index); - mutex_unlock(&nbd_index_mutex); + if (refcount_dec_and_mutex_lock(&nbd->refs, &nbd_global_mutex)) { + xa_erase(&nbd_devs, nbd->index); + mutex_unlock(&nbd_global_mutex); nbd_dev_remove(nbd); } } @@ -1354,7 +1353,7 @@ static int nbd_open(struct block_device *bdev, fmode_t mode) struct nbd_device *nbd; int ret = 0; - mutex_lock(&nbd_index_mutex); + mutex_lock(&nbd_global_mutex); nbd = bdev->bd_disk->private_data; if (!nbd) { ret = -ENXIO; @@ -1386,7 +1385,7 @@ static int nbd_open(struct block_device *bdev, fmode_t mode) bdev->bd_invalidated = 1; } out: - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); return ret; } @@ -1574,15 +1573,13 @@ static int nbd_dev_add(int index) goto out_free_nbd; if (index >= 0) { - err = idr_alloc(&nbd_index_idr, nbd, index, index + 1, - GFP_KERNEL); - if (err == -ENOSPC) - err = -EEXIST; + err = xa_insert(&nbd_devs, index, nbd, GFP_KERNEL); } else { - err = idr_alloc(&nbd_index_idr, nbd, 0, 0, GFP_KERNEL); - if (err >= 0) - index = err; + err = xa_alloc(&nbd_devs, &index, nbd, xa_limit_32b, + GFP_KERNEL); } + if (err == -EBUSY) + err = -EEXIST; if (err < 0) goto out_free_disk; @@ -1599,7 +1596,7 @@ static int nbd_dev_add(int index) err = blk_mq_alloc_tag_set(&nbd->tag_set); if (err) - goto out_free_idr; + goto out_free_dev; q = blk_mq_init_queue(&nbd->tag_set); if (IS_ERR(q)) { @@ -1636,8 +1633,8 @@ static int nbd_dev_add(int index) out_free_tags: blk_mq_free_tag_set(&nbd->tag_set); -out_free_idr: - idr_remove(&nbd_index_idr, index); +out_free_dev: + xa_erase(&nbd_devs, index); out_free_disk: put_disk(disk); out_free_nbd: @@ -1646,18 +1643,6 @@ out: return err; } -static int find_free_cb(int id, void *ptr, void *data) -{ - struct nbd_device *nbd = ptr; - struct nbd_device **found = data; - - if (!refcount_read(&nbd->config_refs)) { - *found = nbd; - return 1; - } - return 0; -} - /* Netlink interface. */ static const struct nla_policy nbd_attr_policy[NBD_ATTR_MAX + 1] = { [NBD_ATTR_INDEX] = { .type = NLA_U32 }, @@ -1730,46 +1715,51 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } again: - mutex_lock(&nbd_index_mutex); + mutex_lock(&nbd_global_mutex); if (index == -1) { - ret = idr_for_each(&nbd_index_idr, &find_free_cb, &nbd); - if (ret == 0) { + unsigned long i; + xa_for_each(&nbd_devs, i, nbd) { + if (!refcount_read(&nbd->config_refs)) + break; + } + + if (!nbd) { int new_index; new_index = nbd_dev_add(-1); if (new_index < 0) { - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); printk(KERN_ERR "nbd: failed to add new device\n"); return new_index; } - nbd = idr_find(&nbd_index_idr, new_index); + nbd = xa_load(&nbd_devs, new_index); } } else { - nbd = idr_find(&nbd_index_idr, index); + nbd = xa_load(&nbd_devs, index); if (!nbd) { ret = nbd_dev_add(index); if (ret < 0) { - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); printk(KERN_ERR "nbd: failed to add new device\n"); return ret; } - nbd = idr_find(&nbd_index_idr, index); + nbd = xa_load(&nbd_devs, index); } } if (!nbd) { + mutex_unlock(&nbd_global_mutex); printk(KERN_ERR "nbd: couldn't find device at index %d\n", index); - mutex_unlock(&nbd_index_mutex); return -EINVAL; } if (!refcount_inc_not_zero(&nbd->refs)) { - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); if (index == -1) goto again; printk(KERN_ERR "nbd: device at index %d is going down\n", index); return -EINVAL; } - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); mutex_lock(&nbd->config_lock); if (refcount_read(&nbd->config_refs)) { @@ -1893,21 +1883,21 @@ static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]); - mutex_lock(&nbd_index_mutex); - nbd = idr_find(&nbd_index_idr, index); + mutex_lock(&nbd_global_mutex); + nbd = xa_load(&nbd_devs, index); if (!nbd) { - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); printk(KERN_ERR "nbd: couldn't find device at index %d\n", index); return -EINVAL; } if (!refcount_inc_not_zero(&nbd->refs)) { - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); printk(KERN_ERR "nbd: device at index %d is going down\n", index); return -EINVAL; } - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); if (!refcount_inc_not_zero(&nbd->config_refs)) { nbd_put(nbd); return 0; @@ -1934,21 +1924,21 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]); - mutex_lock(&nbd_index_mutex); - nbd = idr_find(&nbd_index_idr, index); + mutex_lock(&nbd_global_mutex); + nbd = xa_load(&nbd_devs, index); if (!nbd) { - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); printk(KERN_ERR "nbd: couldn't find a device at index %d\n", index); return -EINVAL; } if (!refcount_inc_not_zero(&nbd->refs)) { - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); printk(KERN_ERR "nbd: device at index %d is going down\n", index); return -EINVAL; } - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); if (!refcount_inc_not_zero(&nbd->config_refs)) { dev_err(nbd_to_dev(nbd), @@ -2094,7 +2084,7 @@ static int populate_nbd_status(struct nbd_device *nbd, struct sk_buff *reply) /* This is a little racey, but for status it's ok. The * reason we don't take a ref here is because we can't * take a ref in the index == -1 case as we would need - * to put under the nbd_index_mutex, which could + * to put under the nbd_global_mutex, which could * deadlock if we are configured to remove ourselves * once we're disconnected. */ @@ -2114,16 +2104,11 @@ static int populate_nbd_status(struct nbd_device *nbd, struct sk_buff *reply) return 0; } -static int status_cb(int id, void *ptr, void *data) -{ - struct nbd_device *nbd = ptr; - return populate_nbd_status(nbd, (struct sk_buff *)data); -} - static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info) { struct nlattr *dev_list; struct sk_buff *reply; + struct nbd_device *nbd; void *reply_head; size_t msg_size; int index = -1; @@ -2132,7 +2117,7 @@ static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NBD_ATTR_INDEX]) index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]); - mutex_lock(&nbd_index_mutex); + mutex_lock(&nbd_global_mutex); msg_size = nla_total_size(nla_attr_size(sizeof(u32)) + nla_attr_size(sizeof(u8))); @@ -2150,14 +2135,17 @@ static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info) dev_list = nla_nest_start_noflag(reply, NBD_ATTR_DEVICE_LIST); if (index == -1) { - ret = idr_for_each(&nbd_index_idr, &status_cb, reply); - if (ret) { - nlmsg_free(reply); - goto out; + unsigned long i; + + xa_for_each(&nbd_devs, i, nbd) { + ret = populate_nbd_status(nbd, reply); + if (ret) { + nlmsg_free(reply); + goto out; + } } } else { - struct nbd_device *nbd; - nbd = idr_find(&nbd_index_idr, index); + nbd = xa_load(&nbd_devs, index); if (nbd) { ret = populate_nbd_status(nbd, reply); if (ret) { @@ -2170,7 +2158,7 @@ static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info) genlmsg_end(reply, reply_head); ret = genlmsg_reply(reply, info); out: - mutex_unlock(&nbd_index_mutex); + mutex_unlock(&nbd_global_mutex); return ret; } @@ -2279,42 +2267,27 @@ static int __init nbd_init(void) } nbd_dbg_init(); - mutex_lock(&nbd_index_mutex); + mutex_lock(&nbd_global_mutex); for (i = 0; i < nbds_max; i++) nbd_dev_add(i); - mutex_unlock(&nbd_index_mutex); - return 0; -} - -static int nbd_exit_cb(int id, void *ptr, void *data) -{ - struct list_head *list = (struct list_head *)data; - struct nbd_device *nbd = ptr; - - list_add_tail(&nbd->list, list); + mutex_unlock(&nbd_global_mutex); return 0; } static void __exit nbd_cleanup(void) { struct nbd_device *nbd; - LIST_HEAD(del_list); + unsigned long index; nbd_dbg_close(); - mutex_lock(&nbd_index_mutex); - idr_for_each(&nbd_index_idr, &nbd_exit_cb, &del_list); - mutex_unlock(&nbd_index_mutex); - - while (!list_empty(&del_list)) { - nbd = list_first_entry(&del_list, struct nbd_device, list); - list_del_init(&nbd->list); + xa_for_each(&nbd_devs, index, nbd) { if (refcount_read(&nbd->refs) != 1) printk(KERN_ERR "nbd: possibly leaking a device\n"); nbd_put(nbd); } - idr_destroy(&nbd_index_idr); + xa_destroy(&nbd_devs); genl_unregister_family(&nbd_genl_family); destroy_workqueue(recv_workqueue); unregister_blkdev(NBD_MAJOR, "nbd");