In order to support NBD failover.

Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com>
---
 lib/backends/nbd.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/liberofs_nbd.h |  4 ++
 2 files changed, 99 insertions(+)

diff --git a/lib/backends/nbd.c b/lib/backends/nbd.c
index 8b1842c..bf1b43c 100644
--- a/lib/backends/nbd.c
+++ b/lib/backends/nbd.c
@@ -174,6 +174,26 @@ err_out:
        return err;
 }
 
+char *erofs_nbd_get_identifier(int nbdnum)
+{
+       char s[32], *line = NULL;
+       size_t n;
+       FILE *f;
+       int err;
+
+       (void)snprintf(s, sizeof(s), "/sys/block/nbd%d/backend", nbdnum);
+       f = fopen(s, "r");
+       if (!f)
+               return ERR_PTR(-errno);
+
+       if (getline(&line, &n, f) < 0)
+               err = -errno;
+       else
+               err = 0;
+       fclose(f);
+       return err ? ERR_PTR(err) : line;
+}
+
 #if defined(HAVE_NETLINK_GENL_GENL_H) && defined(HAVE_LIBNL_GENL_3)
 enum {
        NBD_ATTR_UNSPEC,
@@ -209,6 +229,7 @@ enum {
        NBD_CMD_UNSPEC,
        NBD_CMD_CONNECT,
        NBD_CMD_DISCONNECT,
+       NBD_CMD_RECONFIGURE,
        __NBD_CMD_MAX,
 };
 
@@ -312,6 +333,7 @@ int erofs_nbd_nl_connect(int *index, int blkbits, u64 
blocks,
        NLA_PUT_U64(msg, NBD_ATTR_SIZE_BYTES, blocks << blkbits);
        NLA_PUT_U64(msg, NBD_ATTR_SERVER_FLAGS, NBD_FLAG_READ_ONLY);
        NLA_PUT_U64(msg, NBD_ATTR_TIMEOUT, 0);
+       NLA_PUT_U64(msg, NBD_ATTR_DEAD_CONN_TIMEOUT, 
EROFS_NBD_DEAD_CONN_TIMEOUT);
        if (identifier)
                NLA_PUT_STRING(msg, NBD_ATTR_BACKEND_IDENTIFIER, identifier);
 
@@ -339,6 +361,74 @@ int erofs_nbd_nl_connect(int *index, int blkbits, u64 
blocks,
                return cbctx.errcode;
        return sv[0];
 
+nla_put_failure:
+       if (sock_opt)
+               nla_nest_cancel(msg, sock_opt);
+       if (sock_attr)
+               nla_nest_cancel(msg, sock_attr);
+err_nlm_free:
+       nlmsg_free(msg);
+err_nls_free:
+       nl_socket_free(socket);
+err_out:
+       close(sv[0]);
+       close(sv[1]);
+       return err;
+}
+
+int erofs_nbd_nl_reconnect(int index, const char *identifier)
+{
+       struct nlattr *sock_attr = NULL, *sock_opt = NULL;
+       struct nl_sock *socket;
+       struct nl_msg *msg;
+       int sv[2], err;
+       int driver_id;
+
+       err = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+       if (err < 0)
+               return -errno;
+
+       socket = erofs_nbd_get_nl_sock(&driver_id);
+       if (IS_ERR(socket)) {
+               err = PTR_ERR(socket);
+               goto err_out;
+       }
+
+       msg = nlmsg_alloc();
+       if (!msg) {
+               erofs_err("Couldn't allocate netlink message");
+               err = -ENOMEM;
+               goto err_nls_free;
+       }
+
+       genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, driver_id, 0, 0,
+                   NBD_CMD_RECONFIGURE, 0);
+       NLA_PUT_U32(msg, NBD_ATTR_INDEX, index);
+       if (identifier)
+               NLA_PUT_STRING(msg, NBD_ATTR_BACKEND_IDENTIFIER, identifier);
+
+       err = -EINVAL;
+       sock_attr = nla_nest_start(msg, NBD_ATTR_SOCKETS);
+       if (!sock_attr) {
+               erofs_err("Couldn't nest the sockets for our connection");
+               goto err_nlm_free;
+       }
+
+       sock_opt = nla_nest_start(msg, NBD_SOCK_ITEM);
+       if (!sock_opt) {
+               nla_nest_cancel(msg, sock_attr);
+               goto err_nlm_free;
+       }
+       NLA_PUT_U32(msg, NBD_SOCK_FD, sv[1]);
+       nla_nest_end(msg, sock_opt);
+       nla_nest_end(msg, sock_attr);
+
+       err = nl_send_sync(socket, msg);
+       if (err)
+               goto err_out;
+       nl_socket_free(socket);
+       return sv[0];
+
 nla_put_failure:
        if (sock_opt)
                nla_nest_cancel(msg, sock_opt);
@@ -359,6 +449,11 @@ int erofs_nbd_nl_connect(int *index, int blkbits, u64 
blocks,
 {
        return -EOPNOTSUPP;
 }
+
+int erofs_nbd_nl_reconnect(int index, const char *identifier)
+{
+       return -EOPNOTSUPP;
+}
 #endif
 
 int erofs_nbd_do_it(int nbdfd)
diff --git a/lib/liberofs_nbd.h b/lib/liberofs_nbd.h
index 89c4cf2..03886de 100644
--- a/lib/liberofs_nbd.h
+++ b/lib/liberofs_nbd.h
@@ -31,6 +31,9 @@ struct erofs_nbd_request {
         u32 len;
 } __packed;
 
+/* 30-day timeout for NBD recovery */
+#define EROFS_NBD_DEAD_CONN_TIMEOUT    (3600 * 24 * 30)
+
 long erofs_nbd_in_service(int nbdnum);
 int erofs_nbd_devscan(void);
 int erofs_nbd_connect(int nbdfd, int blkbits, u64 blocks);
@@ -41,4 +44,5 @@ int erofs_nbd_disconnect(int nbdfd);
 
 int erofs_nbd_nl_connect(int *index, int blkbits, u64 blocks,
                         const char *identifier);
+int erofs_nbd_nl_reconnect(int index, const char *identifier);
 #endif
-- 
2.43.0


Reply via email to