Skip to content

Commit 799f9a3

Browse files
josefbacikaxboe
authored andcommitted
nbd: multicast dead link notifications
Provide a mechanism to notify userspace that there's been a link problem on a NBD device. This will allow userspace to re-establish a connection and provide the new socket to the device without disrupting the device. Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent b7aa3d3 commit 799f9a3

File tree

2 files changed

+81
-14
lines changed

2 files changed

+81
-14
lines changed

drivers/block/nbd.c

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct nbd_sock {
5353
int sent;
5454
bool dead;
5555
int fallback_index;
56+
int cookie;
5657
};
5758

5859
struct recv_thread_args {
@@ -61,6 +62,11 @@ struct recv_thread_args {
6162
int index;
6263
};
6364

65+
struct link_dead_args {
66+
struct work_struct work;
67+
int index;
68+
};
69+
6470
#define NBD_TIMEDOUT 0
6571
#define NBD_DISCONNECT_REQUESTED 1
6672
#define NBD_DISCONNECTED 2
@@ -100,6 +106,7 @@ struct nbd_device {
100106
struct nbd_cmd {
101107
struct nbd_device *nbd;
102108
int index;
109+
int cookie;
103110
struct completion send_complete;
104111
};
105112

@@ -120,6 +127,7 @@ static int nbd_dev_dbg_init(struct nbd_device *nbd);
120127
static void nbd_dev_dbg_close(struct nbd_device *nbd);
121128
static void nbd_config_put(struct nbd_device *nbd);
122129
static void nbd_connect_reply(struct genl_info *info, int index);
130+
static void nbd_dead_link_work(struct work_struct *work);
123131

124132
static inline struct device *nbd_to_dev(struct nbd_device *nbd)
125133
{
@@ -152,8 +160,24 @@ static struct device_attribute pid_attr = {
152160
.show = pid_show,
153161
};
154162

155-
static void nbd_mark_nsock_dead(struct nbd_sock *nsock)
163+
static int nbd_disconnected(struct nbd_config *config)
164+
{
165+
return test_bit(NBD_DISCONNECTED, &config->runtime_flags) ||
166+
test_bit(NBD_DISCONNECT_REQUESTED, &config->runtime_flags);
167+
}
168+
169+
static void nbd_mark_nsock_dead(struct nbd_device *nbd, struct nbd_sock *nsock,
170+
int notify)
156171
{
172+
if (!nsock->dead && notify && !nbd_disconnected(nbd->config)) {
173+
struct link_dead_args *args;
174+
args = kmalloc(sizeof(struct link_dead_args), GFP_NOIO);
175+
if (args) {
176+
INIT_WORK(&args->work, nbd_dead_link_work);
177+
args->index = nbd->index;
178+
queue_work(system_wq, &args->work);
179+
}
180+
}
157181
if (!nsock->dead)
158182
kernel_sock_shutdown(nsock->sock, SHUT_RDWR);
159183
nsock->dead = true;
@@ -215,8 +239,7 @@ static void sock_shutdown(struct nbd_device *nbd)
215239
for (i = 0; i < config->num_connections; i++) {
216240
struct nbd_sock *nsock = config->socks[i];
217241
mutex_lock(&nsock->tx_lock);
218-
kernel_sock_shutdown(nsock->sock, SHUT_RDWR);
219-
nbd_mark_nsock_dead(nsock);
242+
nbd_mark_nsock_dead(nbd, nsock, 0);
220243
mutex_unlock(&nsock->tx_lock);
221244
}
222245
dev_warn(disk_to_dev(nbd->disk), "shutting down sockets\n");
@@ -248,7 +271,14 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req,
248271
struct nbd_sock *nsock =
249272
config->socks[cmd->index];
250273
mutex_lock(&nsock->tx_lock);
251-
nbd_mark_nsock_dead(nsock);
274+
/* We can have multiple outstanding requests, so
275+
* we don't want to mark the nsock dead if we've
276+
* already reconnected with a new socket, so
277+
* only mark it dead if its the same socket we
278+
* were sent out on.
279+
*/
280+
if (cmd->cookie == nsock->cookie)
281+
nbd_mark_nsock_dead(nbd, nsock, 1);
252282
mutex_unlock(&nsock->tx_lock);
253283
}
254284
blk_mq_requeue_request(req, true);
@@ -370,6 +400,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
370400
iov_iter_advance(&from, sent);
371401
}
372402
cmd->index = index;
403+
cmd->cookie = nsock->cookie;
373404
request.type = htonl(type);
374405
if (type != NBD_CMD_FLUSH) {
375406
request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
@@ -458,12 +489,6 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
458489
return 0;
459490
}
460491

461-
static int nbd_disconnected(struct nbd_config *config)
462-
{
463-
return test_bit(NBD_DISCONNECTED, &config->runtime_flags) ||
464-
test_bit(NBD_DISCONNECT_REQUESTED, &config->runtime_flags);
465-
}
466-
467492
/* NULL returned = something went wrong, inform userspace */
468493
static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
469494
{
@@ -564,7 +589,7 @@ static void recv_work(struct work_struct *work)
564589
struct nbd_sock *nsock = config->socks[args->index];
565590

566591
mutex_lock(&nsock->tx_lock);
567-
nbd_mark_nsock_dead(nsock);
592+
nbd_mark_nsock_dead(nbd, nsock, 1);
568593
mutex_unlock(&nsock->tx_lock);
569594
ret = PTR_ERR(cmd);
570595
break;
@@ -691,7 +716,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index)
691716
if (ret == -EAGAIN) {
692717
dev_err_ratelimited(disk_to_dev(nbd->disk),
693718
"Request send failed trying another connection\n");
694-
nbd_mark_nsock_dead(nsock);
719+
nbd_mark_nsock_dead(nbd, nsock, 1);
695720
mutex_unlock(&nsock->tx_lock);
696721
goto again;
697722
}
@@ -780,6 +805,7 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
780805
nsock->sock = sock;
781806
nsock->pending = NULL;
782807
nsock->sent = 0;
808+
nsock->cookie = 0;
783809
socks[config->num_connections++] = nsock;
784810

785811
return 0;
@@ -824,6 +850,7 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
824850
INIT_WORK(&args->work, recv_work);
825851
args->index = i;
826852
args->nbd = nbd;
853+
nsock->cookie++;
827854
mutex_unlock(&nsock->tx_lock);
828855
sockfd_put(old);
829856

@@ -1682,6 +1709,10 @@ static const struct genl_ops nbd_connect_genl_ops[] = {
16821709
},
16831710
};
16841711

1712+
static const struct genl_multicast_group nbd_mcast_grps[] = {
1713+
{ .name = NBD_GENL_MCAST_GROUP_NAME, },
1714+
};
1715+
16851716
static struct genl_family nbd_genl_family __ro_after_init = {
16861717
.hdrsize = 0,
16871718
.name = NBD_GENL_FAMILY_NAME,
@@ -1690,6 +1721,8 @@ static struct genl_family nbd_genl_family __ro_after_init = {
16901721
.ops = nbd_connect_genl_ops,
16911722
.n_ops = ARRAY_SIZE(nbd_connect_genl_ops),
16921723
.maxattr = NBD_ATTR_MAX,
1724+
.mcgrps = nbd_mcast_grps,
1725+
.n_mcgrps = ARRAY_SIZE(nbd_mcast_grps),
16931726
};
16941727

16951728
static void nbd_connect_reply(struct genl_info *info, int index)
@@ -1716,6 +1749,38 @@ static void nbd_connect_reply(struct genl_info *info, int index)
17161749
genlmsg_reply(skb, info);
17171750
}
17181751

1752+
static void nbd_mcast_index(int index)
1753+
{
1754+
struct sk_buff *skb;
1755+
void *msg_head;
1756+
int ret;
1757+
1758+
skb = genlmsg_new(nla_total_size(sizeof(u32)), GFP_KERNEL);
1759+
if (!skb)
1760+
return;
1761+
msg_head = genlmsg_put(skb, 0, 0, &nbd_genl_family, 0,
1762+
NBD_CMD_LINK_DEAD);
1763+
if (!msg_head) {
1764+
nlmsg_free(skb);
1765+
return;
1766+
}
1767+
ret = nla_put_u32(skb, NBD_ATTR_INDEX, index);
1768+
if (ret) {
1769+
nlmsg_free(skb);
1770+
return;
1771+
}
1772+
genlmsg_end(skb, msg_head);
1773+
genlmsg_multicast(&nbd_genl_family, skb, 0, 0, GFP_KERNEL);
1774+
}
1775+
1776+
static void nbd_dead_link_work(struct work_struct *work)
1777+
{
1778+
struct link_dead_args *args = container_of(work, struct link_dead_args,
1779+
work);
1780+
nbd_mcast_index(args->index);
1781+
kfree(args);
1782+
}
1783+
17191784
static int __init nbd_init(void)
17201785
{
17211786
int i;

include/uapi/linux/nbd-netlink.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
#ifndef _UAPILINUX_NBD_NETLINK_H
1919
#define _UAPILINUX_NBD_NETLINK_H
2020

21-
#define NBD_GENL_FAMILY_NAME "nbd"
22-
#define NBD_GENL_VERSION 0x1
21+
#define NBD_GENL_FAMILY_NAME "nbd"
22+
#define NBD_GENL_VERSION 0x1
23+
#define NBD_GENL_MCAST_GROUP_NAME "nbd_mc_group"
2324

2425
/* Configuration policy attributes, used for CONNECT */
2526
enum {
@@ -63,6 +64,7 @@ enum {
6364
NBD_CMD_CONNECT,
6465
NBD_CMD_DISCONNECT,
6566
NBD_CMD_RECONFIGURE,
67+
NBD_CMD_LINK_DEAD,
6668
__NBD_CMD_MAX,
6769
};
6870
#define NBD_CMD_MAX (__NBD_CMD_MAX - 1)

0 commit comments

Comments
 (0)