From patchwork Wed Jun 12 16:31:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Stratiienko X-Patchwork-Id: 10990337 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C5DC413AF for ; Wed, 12 Jun 2019 16:31:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B5F7928721 for ; Wed, 12 Jun 2019 16:31:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AA36528742; Wed, 12 Jun 2019 16:31:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8CF17286DD for ; Wed, 12 Jun 2019 16:31:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2407917AbfFLQb4 (ORCPT ); Wed, 12 Jun 2019 12:31:56 -0400 Received: from mail-lf1-f68.google.com ([209.85.167.68]:43569 "EHLO mail-lf1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404956AbfFLQbz (ORCPT ); Wed, 12 Jun 2019 12:31:55 -0400 Received: by mail-lf1-f68.google.com with SMTP id j29so12652415lfk.10 for ; Wed, 12 Jun 2019 09:31:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=globallogic.com; s=google; h=from:to:cc:subject:date:message-id; bh=uyGy4WWNd2ICdtMeMw4Zv+i9/3GDsNbkiJ11wIkXVHk=; b=cM2YdyHPEuHJeH6B4zlWv7cFDZ58r/VLbHAjpEq7LRr4gfQuJgyJVY8V7eqma8hgte 4zGM0EC3wvKYWvhAAB+wiA89/DLZ7cZ+w+jCKeHn3apaCzmlnKJxVqZTHJiHufE0+9Mz QpJ6bZNRmZzIzi5TUNQGP6Cec/IxleJOQAiWNRceu0qYiIiSSpt8Yi03c/qcS3/S/QE2 HYAXO9oAqV46cS9rpAQUr6ZlNHHpKeA2cQrpJUCCod2ERVIppHZSaIAS6XlgwlBpIZno 4lZ46FPrXVeSpOx3J1ujNz1AunbzDoe3C9O52LCg25K+JRdropo2buWQjcQl/FesB8Jo aONw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=uyGy4WWNd2ICdtMeMw4Zv+i9/3GDsNbkiJ11wIkXVHk=; b=A887ToVa9GE5KKPkqHRP0vi6jajG5s/L3gXOC9jByPxVl7ukUj/P8PxKMuJWXQRPfj gLB3O9Q5Oqe8ncCgZ57YBKt+XmII6+hFfUFkTr/YxF4qoZlf5iKIJaLQl+06YfpNRWTr lvUj+6Xh7N2RzKMV+rP6B8ORKsVWC5lcVPdBuu1s5AAcWKN0IjzM3BCsC//XscZ6TEwe gy0u79fhNZ0eDsItDxhaouaL/sX+ask9MCvG8eL4RZehk2JIFxLGW5XwuVKRZ2EHfFw7 hyYl1P1ylGU29goz0vxJYODiJGTbJI6D2cEiblyHRuUxkuYGfay04HvbJ8RJaXJVjVzN 5OLA== X-Gm-Message-State: APjAAAV11Q7efSk/x0hMEGBb/fdTcEGej4v2Di3V0/rPukvoO5l7PMtx uR8pk5tNwh+i/SeTuas9RdqFQQ== X-Google-Smtp-Source: APXvYqxXheLkvoces0WjHrstT2gH4vDKkOotaV8dXkmVihwqMr/COQ6Whd22gTXlZGmoX2kwSjz5tQ== X-Received: by 2002:a19:ae01:: with SMTP id f1mr40901890lfc.29.1560357113198; Wed, 12 Jun 2019 09:31:53 -0700 (PDT) Received: from virtualhost-PowerEdge-R810.synapse.com ([195.238.92.107]) by smtp.gmail.com with ESMTPSA id e26sm54358ljl.33.2019.06.12.09.31.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 12 Jun 2019 09:31:52 -0700 (PDT) From: roman.stratiienko@globallogic.com To: linux-kernel@vger.kernel.org, josef@toxicpanda.com, nbd@other.debian.org, A.Bulyshchenko@globallogic.com, linux-block@vger.kernel.org, axboe@kernel.dkn.org Cc: Roman Stratiienko Subject: [PATCH 1/2] nbd: make sock_xmit() and nbd_add_socket() more generic Date: Wed, 12 Jun 2019 19:31:43 +0300 Message-Id: <20190612163144.18486-1-roman.stratiienko@globallogic.com> X-Mailer: git-send-email 2.17.1 Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Roman Stratiienko Prepare base for the nbd-root patch: - allow to reuse sock_xmit without struct nbd_device as an argument. - allow to reuse nbd_add_socket with struct socket as an argument. Signed-off-by: Roman Stratiienko Reviewed-by: Aleksandr Bulyshchenko --- drivers/block/nbd.c | 62 +++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 3a9bca3aa093..63fcfb38e640 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -404,22 +404,13 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, /* * Send or receive packet. */ -static int sock_xmit(struct nbd_device *nbd, int index, int send, +static int sock_xmit(struct socket *sock, int send, struct iov_iter *iter, int msg_flags, int *sent) { - struct nbd_config *config = nbd->config; - struct socket *sock = config->socks[index]->sock; int result; struct msghdr msg; unsigned int noreclaim_flag; - if (unlikely(!sock)) { - dev_err_ratelimited(disk_to_dev(nbd->disk), - "Attempted %s on closed socket in sock_xmit\n", - (send ? "send" : "recv")); - return -EINVAL; - } - msg.msg_iter = *iter; noreclaim_flag = memalloc_noreclaim_save(); @@ -450,6 +441,22 @@ static int sock_xmit(struct nbd_device *nbd, int index, int send, return result; } +static int nbd_xmit(struct nbd_device *nbd, int index, int send, + struct iov_iter *iter, int msg_flags, int *sent) +{ + struct nbd_config *config = nbd->config; + struct socket *sock = config->socks[index]->sock; + + if (unlikely(!sock)) { + dev_err_ratelimited(disk_to_dev(nbd->disk), + "Attempted %s on closed socket in %s\n", + (send ? "send" : "recv"), __func__); + return -EINVAL; + } + + return sock_xmit(sock, send, iter, msg_flags, sent); +} + /* * Different settings for sk->sk_sndtimeo can result in different return values * if there is a signal pending when we enter sendmsg, because reasons? @@ -537,7 +544,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) dev_dbg(nbd_to_dev(nbd), "request %p: sending control (%s@%llu,%uB)\n", req, nbdcmd_to_ascii(type), (unsigned long long)blk_rq_pos(req) << 9, blk_rq_bytes(req)); - result = sock_xmit(nbd, index, 1, &from, + result = nbd_xmit(nbd, index, 1, &from, (type == NBD_CMD_WRITE) ? MSG_MORE : 0, &sent); trace_nbd_header_sent(req, handle); if (result <= 0) { @@ -583,7 +590,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) iov_iter_advance(&from, skip); skip = 0; } - result = sock_xmit(nbd, index, 1, &from, flags, &sent); + result = nbd_xmit(nbd, index, 1, &from, flags, &sent); if (result <= 0) { if (was_interrupted(result)) { /* We've already sent the header, we @@ -635,7 +642,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) reply.magic = 0; iov_iter_kvec(&to, READ, &iov, 1, sizeof(reply)); - result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); + result = nbd_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); if (result <= 0) { if (!nbd_disconnected(config)) dev_err(disk_to_dev(nbd->disk), @@ -690,7 +697,7 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) rq_for_each_segment(bvec, req, iter) { iov_iter_bvec(&to, READ, &bvec, 1, bvec.bv_len); - result = sock_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); + result = nbd_xmit(nbd, index, 0, &to, MSG_WAITALL, NULL); if (result <= 0) { dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n", result); @@ -931,18 +938,12 @@ static blk_status_t nbd_queue_rq(struct blk_mq_hw_ctx *hctx, return ret; } -static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg, +static int nbd_add_socket(struct nbd_device *nbd, struct socket *sock, bool netlink) { struct nbd_config *config = nbd->config; - struct socket *sock; struct nbd_sock **socks; struct nbd_sock *nsock; - int err; - - sock = sockfd_lookup(arg, &err); - if (!sock) - return err; if (!netlink && !nbd->task_setup && !test_bit(NBD_BOUND, &config->runtime_flags)) @@ -984,6 +985,19 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg, return 0; } +static int nbd_add_socket_fd(struct nbd_device *nbd, unsigned long arg, + bool netlink) +{ + struct socket *sock; + int err; + + sock = sockfd_lookup(arg, &err); + if (!sock) + return err; + + return nbd_add_socket(nbd, sock, netlink); +} + static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg) { struct nbd_config *config = nbd->config; @@ -1087,7 +1101,7 @@ static void send_disconnects(struct nbd_device *nbd) iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request)); mutex_lock(&nsock->tx_lock); - ret = sock_xmit(nbd, i, 1, &from, 0, NULL); + ret = nbd_xmit(nbd, i, 1, &from, 0, NULL); if (ret <= 0) dev_err(disk_to_dev(nbd->disk), "Send disconnect failed %d\n", ret); @@ -1249,7 +1263,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, nbd_clear_sock_ioctl(nbd, bdev); return 0; case NBD_SET_SOCK: - return nbd_add_socket(nbd, arg, false); + return nbd_add_socket_fd(nbd, arg, false); case NBD_SET_BLKSIZE: if (!arg || !is_power_of_2(arg) || arg < 512 || arg > PAGE_SIZE) @@ -1821,7 +1835,7 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) if (!socks[NBD_SOCK_FD]) continue; fd = (int)nla_get_u32(socks[NBD_SOCK_FD]); - ret = nbd_add_socket(nbd, fd, true); + ret = nbd_add_socket_fd(nbd, fd, true); if (ret) goto out; } From patchwork Wed Jun 12 16:31:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Stratiienko X-Patchwork-Id: 10990339 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BD09F13AD for ; Wed, 12 Jun 2019 16:32:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AE3BC286FD for ; Wed, 12 Jun 2019 16:32:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A2F3328721; Wed, 12 Jun 2019 16:32:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9E200286FD for ; Wed, 12 Jun 2019 16:32:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2440276AbfFLQb6 (ORCPT ); Wed, 12 Jun 2019 12:31:58 -0400 Received: from mail-lj1-f196.google.com ([209.85.208.196]:35434 "EHLO mail-lj1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2406775AbfFLQb5 (ORCPT ); Wed, 12 Jun 2019 12:31:57 -0400 Received: by mail-lj1-f196.google.com with SMTP id x25so11072501ljh.2 for ; Wed, 12 Jun 2019 09:31:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=globallogic.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HGZCcHNEAujaoQpz7hTvgflL6M87QkjZmmLX2/Xue6Q=; b=RUC+EYhpraNYK/Rlf/N0BEPsjELRPixbnog9GgyvTc++6Ug0xNyEsE2eHaMcUEVDgM +acMFdIzEEgOiWP773/EGircb6ihqaea5gRG8vNyaejkh7Lu2boHJEbSjFNJS8rd2Pmm qzV08oC0SnNpSLHcHYuzNE5FcrLKThcMbut26fiDnH0r+f0XjFlozDHl3y5dCJ13LIGo QWuQJLkIfbGRxuQc48ae2Huyxk+kGChEvj74I/YadPtiUbYDVudqP+MdBm75n6UEQkpv wVTEg7CzA0tIa661hPzkvJA6K/K3QbGDe2P3VBx6XeL4j/2zQF9tKUYbui3NL8kIbA4u KqQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=HGZCcHNEAujaoQpz7hTvgflL6M87QkjZmmLX2/Xue6Q=; b=ZGS6nxkAO2PiOOqtkF3Hlfgc8EFAy5EPmvw/8PBaMi6jTlNhyYhp4nJzP68bxUGjBo 1frmnVCI3YlT1QRRuis1djc8Sm1Ax0d62XlT4kiIKOf3ceLLEes6TQ/L6Qb0xk/75UhN nkjS4WslYexmnwE0MiwvCmOnO6pyOMuy9Yx3/zeq0GzMrNKuQiXE+ncLvkLQCQo2tUyk +kE9+2x1bf2DJQpGtlDe+HsyGP7ZsjYo9wt+6l1r3ZBQ65NWWPsIw6hHPkcm26cbyyoW ZMNCaYUXEWaCWuDzngnazYQGXnNtX1FIC0cPX3QOkVbPk2kkFEUkCxgsI9svkpN+8N1o URIQ== X-Gm-Message-State: APjAAAWN8Fc6xgK233y7ef4C4zQb6ei2v9B8iaVvJBdvhUJEDi0LQTmE dw1mkLnOHRLH5U71Pimt2mlLMQ== X-Google-Smtp-Source: APXvYqylIJwYaB2IbLbaiDOpf7UoxWY9LigMZytt9CrNcVDG0hk9EVsNyJIyC59DZWUEwIBD1AmV/A== X-Received: by 2002:a2e:12c8:: with SMTP id 69mr33409068ljs.189.1560357114332; Wed, 12 Jun 2019 09:31:54 -0700 (PDT) Received: from virtualhost-PowerEdge-R810.synapse.com ([195.238.92.107]) by smtp.gmail.com with ESMTPSA id e26sm54358ljl.33.2019.06.12.09.31.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 12 Jun 2019 09:31:53 -0700 (PDT) From: roman.stratiienko@globallogic.com To: linux-kernel@vger.kernel.org, josef@toxicpanda.com, nbd@other.debian.org, A.Bulyshchenko@globallogic.com, linux-block@vger.kernel.org, axboe@kernel.dkn.org Cc: Roman Stratiienko Subject: [PATCH 2/2] nbd: add support for nbd as root device Date: Wed, 12 Jun 2019 19:31:44 +0300 Message-Id: <20190612163144.18486-2-roman.stratiienko@globallogic.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190612163144.18486-1-roman.stratiienko@globallogic.com> References: <20190612163144.18486-1-roman.stratiienko@globallogic.com> Sender: linux-block-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-block@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Roman Stratiienko Adding support to nbd to use it as a root device. This code essentially provides a minimal nbd-client implementation within the kernel. It opens a socket and makes the negotiation with the server. Afterwards it passes the socket to the normal nbd-code to handle the connection. The arguments for the server are passed via kernel command line. The kernel command line has the format 'nbdroot=[:]/'. SERVER_IP is optional. If it is not available it will use the root_server_addr transmitted through DHCP. Based on those arguments, the connection to the server is established and is connected to the nbd0 device. The rootdevice therefore is root=/dev/nbd0. Patch was initialy posted by Markus Pargmann and can be found at https://lore.kernel.org/patchwork/patch/532556/ Change-Id: I78f7313918bf31b9dc01a74a42f0f068bede312c Signed-off-by: Roman Stratiienko Reviewed-by: Aleksandr Bulyshchenko --- drivers/block/Kconfig | 19 +++ drivers/block/nbd.c | 294 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 313 insertions(+) diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 20bb4bfa4be6..e17f2376de60 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -273,6 +273,25 @@ config BLK_DEV_NBD If unsure, say N. +config BLK_DEV_NBDROOT + bool "Early network block device client support" + depends on BLK_DEV_NBD=y + ---help--- + Saying yes will enable kernel NBD client support. This allows to + connect entire disk with multiple partitions before mounting rootfs. + + The arguments for the server are passed via kernel command line. + The kernel command line has the format + 'nbdroot=[:]/'. + SERVER_IP is optional. If it is not available it will use the + root_server_addr transmitted through DHCP. + + Based on those arguments, the connection to the server is established + and is connected to the nbd0 device. The rootdevice therefore is + root=/dev/nbd0. + + If unsure, say N. + config BLK_DEV_SKD tristate "STEC S1120 Block Driver" depends on PCI diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 63fcfb38e640..cb5e60419e07 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -46,6 +46,35 @@ #define CREATE_TRACE_POINTS #include +#include +#include +#include +#include +#include + +#define ADDR_NONE cpu_to_be32(INADDR_NONE) + +static const char nbd_magic[] = "NBDMAGIC"; +static const u64 nbd_opts_magic = 0x49484156454F5054LL; + +/* Options used for the kernel driver */ +#define NBD_OPT_EXPORT_NAME 1 + +#define NBD_DEFAULT_BLOCKSIZE 512 /* bytes */ + +#define NBD_DEFAULT_TIMEOUT 2 /* seconds */ + +#define NBD_MAXPATHLEN NFS_MAXPATHLEN + +struct nbdroot { + const char *bdev; + __be32 server_addr; + __be32 server_port; + loff_t block_size; + int timeout; + char server_export[NBD_MAXPATHLEN + 1]; +}; + static DEFINE_IDR(nbd_index_idr); static DEFINE_MUTEX(nbd_index_mutex); static int nbd_total_devices = 0; @@ -441,6 +470,16 @@ static int sock_xmit(struct socket *sock, int send, return result; } +static int sock_xmit_buf(struct socket *sock, int send, + void *buf, size_t size) +{ + struct iov_iter iter; + struct kvec iov = {.iov_base = buf, .iov_len = size}; + + iov_iter_kvec(&iter, WRITE | ITER_KVEC, &iov, 1, size); + return sock_xmit(sock, send, &iter, 0, 0); +} + static int nbd_xmit(struct nbd_device *nbd, int index, int send, struct iov_iter *iter, int msg_flags, int *sent) { @@ -2301,6 +2340,261 @@ static void __exit nbd_cleanup(void) unregister_blkdev(NBD_MAJOR, "nbd"); } +#ifdef CONFIG_BLK_DEV_NBDROOT + +struct nbdroot nbdroot_0 = {.bdev = "nbd0", + .server_export = "", + .server_addr = ADDR_NONE, + .timeout = NBD_DEFAULT_TIMEOUT, + .block_size = NBD_DEFAULT_BLOCKSIZE}; + +static int nbd_connect(struct nbdroot *nbdroot, struct socket **socket) +{ + struct socket *sock; + struct sockaddr_in sockaddr; + int err; + char val; + + err = sock_create_kern(&init_net, AF_INET, SOCK_STREAM, + IPPROTO_TCP, &sock); + if (err < 0) + return err; + + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr.s_addr = nbdroot->server_addr; + sockaddr.sin_port = nbdroot->server_port; + + val = 1; + sock->ops->setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, + sizeof(val)); + + err = sock->ops->connect(sock, (struct sockaddr *)&sockaddr, + sizeof(sockaddr), 0); + if (err < 0) + return err; + + *socket = sock; + + return 0; +} + +static int nbd_connection_negotiate(struct socket *sock, char *export_name, + size_t *rsize, u16 *nflags) +{ + char buf[256]; + int ret; + u64 magic; + u16 flags; + u32 client_flags; + u32 opt; + u32 name_len; + u64 nbd_size; + + ret = sock_xmit_buf(sock, 0, buf, 8); + if (ret < 0) + return ret; + + if (strncmp(buf, nbd_magic, 8)) + return -EINVAL; + + ret = sock_xmit_buf(sock, 0, &magic, sizeof(magic)); + if (ret < 0) + return ret; + magic = be64_to_cpu(magic); + + if (magic != nbd_opts_magic) + return -EINVAL; + + ret = sock_xmit_buf(sock, 0, &flags, sizeof(flags)); + if (ret < 0) + return ret; + + *nflags = ntohs(flags); + + client_flags = 0; + + ret = sock_xmit_buf(sock, 1, &client_flags, sizeof(client_flags)); + if (ret < 0) + return ret; + + magic = cpu_to_be64(nbd_opts_magic); + ret = sock_xmit_buf(sock, 1, &magic, sizeof(magic)); + if (ret < 0) + return ret; + + opt = htonl(NBD_OPT_EXPORT_NAME); + ret = sock_xmit_buf(sock, 1, &opt, sizeof(opt)); + if (ret < 0) + return ret; + + name_len = strlen(export_name) + 1; + name_len = htonl(name_len); + ret = sock_xmit_buf(sock, 1, &name_len, sizeof(name_len)); + if (ret < 0) + return ret; + + ret = sock_xmit_buf(sock, 1, export_name, strlen(export_name) + 1); + if (ret < 0) + return ret; + + ret = sock_xmit_buf(sock, 0, &nbd_size, sizeof(nbd_size)); + if (ret < 0) + return ret; + nbd_size = be64_to_cpu(nbd_size); + + ret = sock_xmit_buf(sock, 0, &flags, sizeof(flags)); + if (ret < 0) + return ret; + *nflags = ntohs(flags); + + ret = sock_xmit_buf(sock, 0, buf, 124); + if (ret < 0) + return ret; + + *rsize = nbd_size; + + return 0; +} + +static int nbd_bind_connection(struct nbdroot *nbdroot, struct nbd_device *nbd, + struct socket *sock, size_t rsize, u32 flags) +{ + int conn, ret; + struct block_device *bdev = blkdev_get_by_dev(disk_devt(nbd->disk), + FMODE_READ | FMODE_WRITE, 0); + + if (IS_ERR(bdev)) { + pr_err("nbdroot: blkdev_get_by_dev failed %ld\n", + PTR_ERR(bdev)); + return PTR_ERR(bdev); + } + + conn = nbd->config->num_connections; + ret = nbd_add_socket(nbd, sock, false); + if (ret) { + pr_err("nbdroot: add socket failed %d\n", ret); + return ret; + } + + mutex_lock(&nbd->config->socks[conn]->tx_lock); + + nbd->config->flags = flags; + + nbd_size_set(nbd, nbdroot->block_size, + div_s64(rsize, nbdroot->block_size)); + + nbd->tag_set.timeout = nbdroot->timeout * HZ; + blk_queue_rq_timeout(nbd->disk->queue, nbdroot->timeout * HZ); + + mutex_unlock(&nbd->config->socks[conn]->tx_lock); + + ret = nbd_start_device_ioctl(nbd, bdev); + if (ret) { + pr_err("nbdroot: start device ioctl failed %d\n", ret); + return ret; + } + + return 0; +} + +static int nbdroot_thread(void *arg) +{ + struct nbdroot *nbdroot = (struct nbdroot *)arg; + struct socket *sock = 0; + size_t rsize; + u16 nflags; + int ret; + dev_t devt = blk_lookup_devt(nbdroot->bdev, 0); + struct gendisk *disk = get_gendisk(devt, &ret); + struct nbd_device *nbd = (struct nbd_device *)disk->private_data; + + ret = nbd_connect(nbdroot, &sock); + if (ret) { + pr_err("nbdroot: connect failed %d\n", ret); + goto err; + } + + ret = nbd_connection_negotiate(sock, nbdroot->server_export, + &rsize, &nflags); + if (ret) { + pr_err("nbdroot: negotiation failed %d\n", ret); + goto err; + } + + ret = nbd_bind_connection(nbdroot, nbd, sock, rsize, nflags); + if (ret) { + pr_err("nbdroot: nbd_bind_connection failed %d\n", ret); + goto err; + } + return 0; + +err: + pr_err("nbdroot: %s init failed, IP: %pI4, port: %i, export: %s\n", + nbdroot->bdev, &nbdroot->server_addr, + ntohs(nbdroot->server_port), nbdroot->server_export); + + if (sock) + sock_release(sock); + + return ret; +} + +static int __init nbdroot_init(void) +{ + if (nbdroot_0.server_port != 0) + kthread_run(nbdroot_thread, &nbdroot_0, "nbdroot_0"); + + return 0; +} + +/* We need this in late_initcall_sync to be sure that the network is setup */ +late_initcall_sync(nbdroot_init); + +/* + * Parse format "[:]/" + */ +static int __init nbdroot_setup(char *line) +{ + struct nbdroot *nbdroot = &nbdroot_0; + char *export; + u16 port; + int ret; + char buf[NBD_MAXPATHLEN + 1]; + + strlcpy(buf, line, sizeof(buf) - 1); + + nbdroot->server_addr = root_nfs_parse_addr(buf); + + if (*buf == '\0') + return -EINVAL; + + if (nbdroot->server_addr == ADDR_NONE) { + if (root_server_addr == ADDR_NONE) { + pr_err("nbdroot: Failed to find server address\n"); + return -EINVAL; + } + nbdroot->server_addr = root_server_addr; + } + + export = strchr(buf, '/'); + *export = '\0'; + ++export; + + ret = kstrtou16(buf, 10, &port); + if (ret) + return ret; + + nbdroot->server_port = htons(port); + strlcpy(nbdroot->server_export, export, + sizeof(nbdroot->server_export) - 1); + + return 0; +} + +__setup("nbdroot=", nbdroot_setup); + +#endif /* CONFIG_BLK_DEV_NBDROOT */ + module_init(nbd_init); module_exit(nbd_cleanup);