From 409e0ff10ead30a620ee48acb6d4545d9cb95359 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 25 Aug 2021 18:31:04 +0200 Subject: [PATCH] nbd: reset NBD to NULL when restarting in nbd_genl_connect When nbd_genl_connect restarts to wait for a disconnecting device, nbd needs to be reset to NULL. Do that by facoring out a helper to find an unused device. Fixes: 6177b56c96ff ("nbd: refactor device search and allocation in nbd_genl_connect") Reported-by: Tetsuo Handa Reported-by: Hillf Danton Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20210825163108.50713-3-hch@lst.de Reviewed-by: Josef Bacik Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 0c1389da3066..938ca7f5a11f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1781,6 +1781,20 @@ out: return ERR_PTR(err); } +static struct nbd_device *nbd_find_unused(void) +{ + struct nbd_device *nbd; + int id; + + lockdep_assert_held(&nbd_index_mutex); + + idr_for_each_entry(&nbd_index_idr, nbd, id) + if (!refcount_read(&nbd->config_refs)) + return nbd; + + return NULL; +} + /* Netlink interface. */ static const struct nla_policy nbd_attr_policy[NBD_ATTR_MAX + 1] = { [NBD_ATTR_INDEX] = { .type = NLA_U32 }, @@ -1828,7 +1842,7 @@ static int nbd_genl_size_set(struct genl_info *info, struct nbd_device *nbd) static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) { DECLARE_COMPLETION_ONSTACK(destroy_complete); - struct nbd_device *nbd = NULL; + struct nbd_device *nbd; struct nbd_config *config; int index = -1; int ret; @@ -1849,20 +1863,10 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) } again: mutex_lock(&nbd_index_mutex); - if (index == -1) { - struct nbd_device *tmp; - int id; - - idr_for_each_entry(&nbd_index_idr, tmp, id) { - if (!refcount_read(&tmp->config_refs)) { - nbd = tmp; - break; - } - } - } else { + if (index == -1) + nbd = nbd_find_unused(); + else nbd = idr_find(&nbd_index_idr, index); - } - if (nbd) { if (test_bit(NBD_DESTROY_ON_DISCONNECT, &nbd->flags) && test_bit(NBD_DISCONNECT_REQUESTED, &nbd->flags)) {