[PATCH v2 5/5] nbd: set nr_hw_queues at device creation to skip queue freeze
- To: josef@toxicpanda.com, axboe@kernel.dk, hch@lst.de, yukuai@kernel.org
- Cc: yi.zhang@huawei.com, chengzhihao1@huawei.com, echo.chenlin@huawei.com, leo.lilong@huaweicloud.com, wangkefeng.wang@huawei.com, linux-block@vger.kernel.org, nbd@other.debian.org
- Subject: [PATCH v2 5/5] nbd: set nr_hw_queues at device creation to skip queue freeze
- From: Yang Erkun <yangerkun@huawei.com>
- Date: Thu, 25 Jun 2026 16:44:58 +0800
- Message-id: <[🔎] 20260625084458.4171890-6-yangerkun@huawei.com>
- In-reply-to: <[🔎] 20260625084458.4171890-1-yangerkun@huawei.com>
- References: <[🔎] 20260625084458.4171890-1-yangerkun@huawei.com>
The preceding patches in this series removed the blk_mq_freeze_queue()
call from nbd_add_socket(), eliminating the freeze/unfreeze overhead
during socket insertion. However, nbd_start_device() still calls
blk_mq_update_nr_hw_queues() when the hardware queue count differs
from the actual number of connections, which introduce freeze too.
There are two reasons nr_hw_queues may not match num_connections:
1. Reusing an existing nbd device (e.g. one pre-created at module
load which nr_hw_queues always set as 1) that was originally
configured with a different connection count. This case genuinely
requires blk_mq_update_nr_hw_queues() to adjust the hardware
queue count.
2. Creating a new nbd device via the netlink connect path
(nbd_genl_connect), where we know the exact number of connections
upfront from the NBD_ATTR_SOCKETS attribute. In this case, there
is no need to default to nr_hw_queues=1 and then update.
This patch optimizes case 2 by setting nr_hw_queues correctly at
device creation time, so that nbd_start_device() can skip
blk_mq_update_nr_hw_queues() entirely when the count already matches.
Two changes are made:
1. Add a nr_hw_queues parameter to nbd_dev_add() so callers can
specify the desired queue count instead of the hardcoded 1.
2. Add nbd_genl_count_sockets() to count socket FDs from the netlink
NBD_ATTR_SOCKETS attribute before the device is created, and pass
the count as nr_hw_queues when creating a new nbd device via
netlink.
The ioctl path (NBD_SET_SOCK + NBD_DO_IT) remains fully functional:
pre-created devices with nbds_max>0 default to nr_hw_queues=1, and
nbd_start_device() still calls blk_mq_update_nr_hw_queues() when
needed.
Signed-off-by: Yang Erkun <yangerkun@huawei.com>
---
drivers/block/nbd.c | 39 +++++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 953146c85f17..2b6f896037ad 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -1952,7 +1952,8 @@ static const struct blk_mq_ops nbd_mq_ops = {
.timeout = nbd_xmit_timeout,
};
-static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
+static struct nbd_device *nbd_dev_add(int index, unsigned int refs,
+ int nr_hw_queues)
{
struct queue_limits lim = {
.max_hw_sectors = 65536,
@@ -1969,7 +1970,7 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
goto out;
nbd->tag_set.ops = &nbd_mq_ops;
- nbd->tag_set.nr_hw_queues = 1;
+ nbd->tag_set.nr_hw_queues = nr_hw_queues;
nbd->tag_set.queue_depth = 128;
nbd->tag_set.numa_node = NUMA_NO_NODE;
nbd->tag_set.cmd_size = sizeof(struct nbd_cmd);
@@ -2092,6 +2093,35 @@ static const struct nla_policy nbd_sock_policy[NBD_SOCK_MAX + 1] = {
[NBD_SOCK_FD] = { .type = NLA_U32 },
};
+/*
+ * Count the number of socket FDs in the NBD_ATTR_SOCKETS netlink attribute.
+ * This is used to determine the correct nr_hw_queues before creating the
+ * nbd device, so that blk_mq_update_nr_hw_queues (and its RCU grace period
+ * overhead) can be avoided entirely.
+ */
+static int nbd_genl_count_sockets(struct genl_info *info)
+{
+ struct nlattr *attr;
+ int rem, count = 0;
+
+ if (!info->attrs[NBD_ATTR_SOCKETS])
+ return 0;
+
+ nla_for_each_nested(attr, info->attrs[NBD_ATTR_SOCKETS], rem) {
+ struct nlattr *socks[NBD_SOCK_MAX + 1];
+
+ if (nla_type(attr) != NBD_SOCK_ITEM)
+ continue;
+ if (nla_parse_nested_deprecated(socks, NBD_SOCK_MAX,
+ attr, nbd_sock_policy,
+ info->extack) != 0)
+ continue;
+ if (socks[NBD_SOCK_FD])
+ count++;
+ }
+ return count;
+}
+
/* We don't use this right now since we don't parse the incoming list, but we
* still want it here so userspace knows what to expect.
*/
@@ -2123,6 +2153,7 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
struct nbd_device *nbd;
struct nbd_config *config;
int index = -1;
+ int num_connections = nbd_genl_count_sockets(info);
int ret;
bool put_dev = false;
@@ -2170,7 +2201,7 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
mutex_unlock(&nbd_index_mutex);
if (!nbd) {
- nbd = nbd_dev_add(index, 2);
+ nbd = nbd_dev_add(index, 2, num_connections);
if (IS_ERR(nbd)) {
pr_err("failed to add new device\n");
return PTR_ERR(nbd);
@@ -2737,7 +2768,7 @@ static int __init nbd_init(void)
nbd_dbg_init();
for (i = 0; i < nbds_max; i++)
- nbd_dev_add(i, 1);
+ nbd_dev_add(i, 1, 1);
return 0;
}
--
2.52.0
Reply to: