nbd: factor out a nbd_genl_foreach_sock

The NBD_ATTR_SOCKETS walk is duplicated in nbd_genl_connect (add sockets)
and nbd_genl_reconfigure (reconnect).  Factor out a single helper that
walks the list and calls a callback per fd; with a NULL callback it is a
pure counter, used by a later patch to learn nr_hw_queues before the
device exists.  Returns the number of fds walked (>= 0) or a negative
errno; a callback >0 will stops early.

Reviewed-by: Yu Kuai <yukuai@fygo.io>
Signed-off-by: Yang Erkun <yangerkun@huawei.com>
Link: https://patch.msgid.link/20260805122930.57647-7-yangerkun@huawei.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Yang Erkun 2026-08-05 20:29:28 +08:00 committed by Jens Axboe
parent db285268df
commit f8d21c590e

View File

@ -1344,7 +1344,7 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
return err;
}
static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
static int nbd_genl_reconnect_sock_cb(struct nbd_device *nbd, unsigned long arg)
{
struct nbd_config *config = nbd->config;
struct socket *sock, *old;
@ -1399,11 +1399,12 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
atomic_inc(&config->live_connections);
wake_up(&config->conn_wait);
dev_info(nbd_to_dev(nbd), "reconnected socket\n");
return 0;
}
sockfd_put(sock);
kfree(args);
return -ENOSPC;
return 1;
}
static void nbd_bdev_reset(struct nbd_device *nbd)
@ -2109,6 +2110,58 @@ static int nbd_genl_size_set(struct genl_info *info, struct nbd_device *nbd)
return 0;
}
/*
* Walk the NBD_ATTR_SOCKETS nested list can call @cb for each socket fd.
*
* Return the number of fds walked, or a negative errno.
*/
static int nbd_genl_foreach_sock(struct genl_info *info,
int (*cb)(struct nbd_device *nbd, unsigned long fd),
struct nbd_device *nbd)
{
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];
int ret;
if (nla_type(attr) != NBD_SOCK_ITEM) {
pr_err("socks must be embedded in a SOCK_ITEM attr\n");
return -EINVAL;
}
if (nla_parse_nested_deprecated(socks, NBD_SOCK_MAX,
attr,
nbd_sock_policy,
info->extack)) {
pr_err("error processing sock list\n");
return -EINVAL;
}
if (!socks[NBD_SOCK_FD])
continue;
count++;
if (cb) {
ret = cb(nbd, (int)nla_get_u32(socks[NBD_SOCK_FD]));
if (ret > 0)
return count;
if (ret < 0)
return ret;
}
}
return count;
}
static int nbd_genl_connect_sock_cb(struct nbd_device *nbd, unsigned long fd)
{
return nbd_add_socket(nbd, fd, true);
}
static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
{
struct nbd_device *nbd;
@ -2228,36 +2281,9 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
}
}
if (info->attrs[NBD_ATTR_SOCKETS]) {
struct nlattr *attr;
int rem, fd;
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) {
pr_err("socks must be embedded in a SOCK_ITEM attr\n");
ret = -EINVAL;
goto out;
}
ret = nla_parse_nested_deprecated(socks, NBD_SOCK_MAX,
attr,
nbd_sock_policy,
info->extack);
if (ret != 0) {
pr_err("error processing sock list\n");
ret = -EINVAL;
goto out;
}
if (!socks[NBD_SOCK_FD])
continue;
fd = (int)nla_get_u32(socks[NBD_SOCK_FD]);
ret = nbd_add_socket(nbd, fd, true);
if (ret)
goto out;
}
}
ret = nbd_genl_foreach_sock(info, nbd_genl_connect_sock_cb, nbd);
if (ret < 0)
goto out;
if (info->attrs[NBD_ATTR_BACKEND_IDENTIFIER]) {
nbd->backend = nla_strdup(info->attrs[NBD_ATTR_BACKEND_IDENTIFIER],
@ -2442,40 +2468,10 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
}
}
if (info->attrs[NBD_ATTR_SOCKETS]) {
struct nlattr *attr;
int rem, fd;
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) {
pr_err("socks must be embedded in a SOCK_ITEM attr\n");
ret = -EINVAL;
goto out;
}
ret = nla_parse_nested_deprecated(socks, NBD_SOCK_MAX,
attr,
nbd_sock_policy,
info->extack);
if (ret != 0) {
pr_err("error processing sock list\n");
ret = -EINVAL;
goto out;
}
if (!socks[NBD_SOCK_FD])
continue;
fd = (int)nla_get_u32(socks[NBD_SOCK_FD]);
ret = nbd_reconnect_socket(nbd, fd);
if (ret) {
if (ret == -ENOSPC)
ret = 0;
goto out;
}
dev_info(nbd_to_dev(nbd), "reconnected socket\n");
}
}
ret = nbd_genl_foreach_sock(info, nbd_genl_reconnect_sock_cb, nbd);
/* foreach_sock returns a positive count on success; doit must return 0 */
if (ret >= 0)
ret = 0;
out:
mutex_unlock(&nbd->config_lock);
nbd_config_put(nbd);