LCOV - code coverage report
Current view: top level - drivers - block-nbd.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 428 0.0 %
Date: 2024-12-18 23:41:32 Functions: 0 27 0.0 %
Branches: 0 197 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2016, Citrix Systems, Inc.
       3                 :            :  *
       4                 :            :  * All rights reserved.
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions are met:
       8                 :            :  * 
       9                 :            :  *  1. Redistributions of source code must retain the above copyright
      10                 :            :  *     notice, this list of conditions and the following disclaimer.
      11                 :            :  *  2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *     notice, this list of conditions and the following disclaimer in the
      13                 :            :  *     documentation and/or other materials provided with the distribution.
      14                 :            :  *  3. Neither the name of the copyright holder nor the names of its 
      15                 :            :  *     contributors may be used to endorse or promote products derived from 
      16                 :            :  *     this software without specific prior written permission.
      17                 :            :  *
      18                 :            :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      19                 :            :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      20                 :            :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      21                 :            :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
      22                 :            :  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      23                 :            :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      24                 :            :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
      25                 :            :  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      26                 :            :  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      27                 :            :  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      28                 :            :  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29                 :            :  */
      30                 :            : 
      31                 :            : #include <errno.h>
      32                 :            : #include <stdio.h>
      33                 :            : #include <fcntl.h>
      34                 :            : #include <unistd.h>
      35                 :            : #include <stdlib.h>
      36                 :            : #include <sys/mman.h>
      37                 :            : #include <sys/socket.h>
      38                 :            : #include <sys/un.h>
      39                 :            : #include <sys/types.h>
      40                 :            : #include <sys/stat.h>
      41                 :            : #include <netdb.h>
      42                 :            : #include <arpa/inet.h>
      43                 :            : #include <netinet/tcp.h>
      44                 :            : #include <netinet/in.h>
      45                 :            : #include "tapdisk.h"
      46                 :            : #include "tapdisk-server.h"
      47                 :            : #include "tapdisk-driver.h"
      48                 :            : #include "tapdisk-interface.h"
      49                 :            : #include "tapdisk-utils.h"
      50                 :            : #include "tapdisk-fdreceiver.h"
      51                 :            : #include "timeout-math.h"
      52                 :            : #include "tapdisk-nbdserver.h"
      53                 :            : #include "tapdisk-protocol-new.h"
      54                 :            : #include "util.h"
      55                 :            : 
      56                 :            : #ifdef HAVE_CONFIG_H
      57                 :            : #include "config.h"
      58                 :            : #endif
      59                 :            : 
      60                 :            : #define INFO(_f, _a...)            tlog_syslog(TLOG_INFO, "nbd: " _f, ##_a)
      61                 :            : #define ERROR(_f, _a...)           tlog_syslog(TLOG_WARN, "nbd: " _f, ##_a)
      62                 :            : 
      63                 :            : #define N_PASSED_FDS 10
      64                 :            : #define TAPDISK_NBDCLIENT_MAX_PATH_LEN 256
      65                 :            : 
      66                 :            : #define MAX_NBD_REQS TAPDISK_DATA_REQUESTS
      67                 :            : #define NBD_TIMEOUT 30
      68                 :            : #define RECV_BUFFER_SIZE 256
      69                 :            : 
      70                 :            : static const int CLIENT_USE_OLD_HANDSHAKE = 1;
      71                 :            : 
      72                 :            : /*
      73                 :            :  * We'll only ever have one nbdclient fd receiver per tapdisk process, so let's 
      74                 :            :  * just store it here globally. We'll also keep track of the passed fds here
      75                 :            :  * too.
      76                 :            :  */
      77                 :            : 
      78                 :            : struct td_fdreceiver *fdreceiver = NULL;
      79                 :            : 
      80                 :            : struct tdnbd_passed_fd {
      81                 :            :         char                    id[40];
      82                 :            :         int                     fd;
      83                 :            : } passed_fds[N_PASSED_FDS];
      84                 :            : 
      85                 :            : struct nbd_queued_io {
      86                 :            :         char                   *buffer;
      87                 :            :         int                     len;
      88                 :            :         int                     so_far;
      89                 :            : };
      90                 :            : 
      91                 :            : struct td_nbd_request {
      92                 :            :         td_request_t            treq;
      93                 :            :         struct nbd_request      nreq;
      94                 :            :         int                     timeout_event;
      95                 :            :         int                     fake;
      96                 :            :         struct nbd_queued_io    header;
      97                 :            :         struct nbd_queued_io    body;     /* in or out, depending on whether
      98                 :            :                                              type is read or write. */
      99                 :            :         struct list_head        queue;
     100                 :            : };
     101                 :            : 
     102                 :            : struct tdnbd_data
     103                 :            : {
     104                 :            :         int                     writer_event_id;
     105                 :            :         struct list_head        sent_reqs;
     106                 :            :         struct list_head        pending_reqs;
     107                 :            :         struct list_head        free_reqs;
     108                 :            :         struct td_nbd_request   requests[MAX_NBD_REQS];
     109                 :            :         int                     nr_free_count;
     110                 :            : 
     111                 :            :         int                     reader_event_id;
     112                 :            :         struct nbd_reply        current_reply;
     113                 :            :         struct nbd_queued_io    cur_reply_qio;
     114                 :            :         struct td_nbd_request  *curr_reply_req;
     115                 :            : 
     116                 :            :         int                     socket;
     117                 :            :         /*
     118                 :            :          * TODO tapdisk can talk to an Internet socket or a UNIX domain socket.
     119                 :            :          * Try to group struct members accordingly e.g. in a union.
     120                 :            :          */
     121                 :            :         struct sockaddr_in     *remote;
     122                 :            :         struct sockaddr_un      remote_un;
     123                 :            :         char                   *peer_ip;
     124                 :            :         int                     port;
     125                 :            :         char                   *name;
     126                 :            : 
     127                 :            :         int                     flags;
     128                 :            :         int                     closed;
     129                 :            : };
     130                 :            : 
     131                 :            : int global_id = 0;
     132                 :            : 
     133                 :            : static void disable_write_queue(struct tdnbd_data *prv);
     134                 :            : 
     135                 :            : 
     136                 :            : /* -- fdreceiver bits and pieces -- */
     137                 :            : 
     138                 :            : static void
     139                 :          0 : tdnbd_stash_passed_fd(int fd, char *msg, void *data) 
     140                 :            : {
     141                 :          0 :         int free_index = -1;
     142                 :            :         int i;
     143         [ #  # ]:          0 :         for (i = 0; i < N_PASSED_FDS; i++)
     144                 :            :                 /* Check for unused slot before attempting to compare
     145                 :            :                  * names so that we never try to compare against the name
     146                 :            :                  * of an unused slot */
     147 [ #  # ][ #  # ]:          0 :                 if (passed_fds[i].fd == -1 || strncmp(msg, passed_fds[i].id,
     148                 :            :                                         sizeof(passed_fds[i].id) - 1) == 0) {
     149                 :            :                         free_index = i;
     150                 :            :                         break;
     151                 :            :                 }
     152                 :            : 
     153         [ #  # ]:          0 :         if (free_index == -1) {
     154                 :          0 :                 ERROR("Error - more than %d fds passed! cannot stash another",
     155                 :            :                                 N_PASSED_FDS);
     156                 :          0 :                 close(fd);
     157                 :          0 :                 return;
     158                 :            :         }
     159                 :            : 
     160                 :            :         /* There exists a possibility that the FD we are replacing is still
     161                 :            :          * open. Unconditionally close it here to avoid leaking FDs. Do not
     162                 :            :          * care about errors from close(). */
     163         [ #  # ]:          0 :         if (passed_fds[free_index].fd > -1)
     164                 :          0 :                 close(passed_fds[free_index].fd);
     165                 :            : 
     166                 :          0 :         passed_fds[free_index].fd = fd;
     167                 :          0 :         safe_strncpy(passed_fds[free_index].id, msg,
     168                 :            :                      sizeof(passed_fds[free_index].id));
     169                 :            : }
     170                 :            : 
     171                 :            : static int
     172                 :          0 : tdnbd_retrieve_passed_fd(const char *name)
     173                 :            : {
     174                 :            :         int fd, i;
     175                 :            : 
     176         [ #  # ]:          0 :         for (i = 0; i < N_PASSED_FDS; i++) {
     177         [ #  # ]:          0 :                 if (strncmp(name, passed_fds[i].id,
     178                 :            :                                         sizeof(passed_fds[i].id) - 1) == 0) {
     179                 :          0 :                         fd = passed_fds[i].fd;
     180                 :          0 :                         passed_fds[i].fd = -1;
     181                 :          0 :                         return fd;
     182                 :            :                 }
     183                 :            :         }
     184                 :            : 
     185                 :          0 :         ERROR("Couldn't find the fd named: %s", name);
     186                 :            : 
     187                 :          0 :         return -1;
     188                 :            : }
     189                 :            : 
     190                 :            : void
     191                 :          0 : tdnbd_fdreceiver_start()
     192                 :            : {
     193                 :            :         char fdreceiver_path[TAPDISK_NBDCLIENT_MAX_PATH_LEN];
     194                 :            :         int i;
     195                 :            : 
     196                 :            :         /* initialise the passed fds list */
     197         [ #  # ]:          0 :         for (i = 0; i < N_PASSED_FDS; i++)
     198                 :          0 :                 passed_fds[i].fd = -1;
     199                 :            : 
     200                 :          0 :         snprintf(fdreceiver_path, TAPDISK_NBDCLIENT_MAX_PATH_LEN,
     201                 :            :                         "%s%d", TAPDISK_NBDCLIENT_LISTEN_SOCK_PATH, getpid());
     202                 :            : 
     203                 :          0 :         fdreceiver = td_fdreceiver_start(fdreceiver_path,
     204                 :            :                         tdnbd_stash_passed_fd, NULL);
     205                 :            : 
     206                 :          0 : }
     207                 :            : 
     208                 :            : void
     209                 :          0 : tdnbd_fdreceiver_stop()
     210                 :            : {
     211         [ #  # ]:          0 :         if (fdreceiver)
     212                 :          0 :                 td_fdreceiver_stop(fdreceiver);
     213                 :          0 : }
     214                 :            : 
     215                 :            : static void
     216                 :          0 : __cancel_req(int i, struct td_nbd_request *pos, int e)
     217                 :            : {
     218                 :            :         char handle[9];
     219                 :          0 :         memcpy(handle, pos->nreq.handle, 8);
     220                 :          0 :         handle[8] = 0;
     221                 :          0 :         INFO("Entry %d: handle='%s' type=%d, len=%d: %s",
     222                 :            :              i, handle, ntohl(pos->nreq.type), ntohl(pos->nreq.len), strerror(e));
     223                 :            : 
     224         [ #  # ]:          0 :         if (pos->timeout_event >= 0) {
     225                 :          0 :                 tapdisk_server_unregister_event(pos->timeout_event);
     226                 :          0 :                 pos->timeout_event = -1;
     227                 :            :         }
     228                 :            : 
     229                 :          0 :         td_complete_request(pos->treq, e);
     230                 :          0 : }
     231                 :            : 
     232                 :            : static void
     233                 :          0 : tdnbd_disable(struct tdnbd_data *prv, int e)
     234                 :            : {
     235                 :            :         struct td_nbd_request *pos, *q;
     236                 :          0 :         int i = 0;
     237                 :            : 
     238                 :          0 :         INFO("NBD client full-disable");
     239                 :            : 
     240                 :          0 :         tapdisk_server_unregister_event(prv->writer_event_id);
     241                 :          0 :         tapdisk_server_unregister_event(prv->reader_event_id);
     242                 :            : 
     243                 :          0 :         INFO("NBD client cancelling sent reqs");
     244         [ #  # ]:          0 :         list_for_each_entry_safe(pos, q, &prv->sent_reqs, queue)
     245                 :          0 :                 __cancel_req(i++, pos, e);
     246                 :            : 
     247                 :          0 :         INFO("NBD client cancelling pending reqs");
     248         [ #  # ]:          0 :         list_for_each_entry_safe(pos, q, &prv->pending_reqs, queue)
     249                 :          0 :                 __cancel_req(i++, pos, e);
     250                 :            : 
     251                 :          0 :         INFO("Setting closed");
     252                 :          0 :         prv->closed = 3;
     253                 :          0 : }
     254                 :            : 
     255                 :            : /* NBD writer queue */
     256                 :            : 
     257                 :            : /* Return code: how much is left to write, or a negative error code */
     258                 :            : static int
     259                 :          0 : tdnbd_write_some(int fd, struct nbd_queued_io *data) 
     260                 :            : {
     261                 :          0 :         int left = data->len - data->so_far;
     262                 :            :         int rc;
     263                 :            :         char *code;
     264                 :            : 
     265         [ #  # ]:          0 :         while (left > 0) {
     266                 :          0 :                 rc = send(fd, data->buffer + data->so_far, left, 0);
     267                 :            : 
     268         [ #  # ]:          0 :                 if (rc == -1) {
     269         [ #  # ]:          0 :                         if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
     270                 :            :                                 return left;
     271                 :            : 
     272                 :          0 :                         code = strerror(errno);
     273         [ #  # ]:          0 :                         ERROR("Bad return code %d from send (%s)", rc, 
     274                 :            :                                         (code == 0 ? "unknown" : code));
     275                 :          0 :                         return rc;
     276                 :            :                 }
     277                 :            : 
     278         [ #  # ]:          0 :                 if (rc == 0) {
     279                 :          0 :                         ERROR("Server shutdown prematurely in write_some");
     280                 :          0 :                         return -1;
     281                 :            :                 }
     282                 :            : 
     283                 :          0 :                 left -= rc;
     284                 :          0 :                 data->so_far += rc;
     285                 :            :         }
     286                 :            : 
     287                 :            :         return left;
     288                 :            : }
     289                 :            : 
     290                 :            : static int
     291                 :          0 : tdnbd_read_some(int fd, struct nbd_queued_io *data)
     292                 :            : {
     293                 :          0 :         int left = data->len - data->so_far;
     294                 :            :         int rc;
     295                 :            :         char *code;
     296                 :            : 
     297         [ #  # ]:          0 :         while (left > 0) {
     298                 :          0 :                 rc = recv(fd, data->buffer + data->so_far, left, 0);
     299                 :            : 
     300         [ #  # ]:          0 :                 if (rc == -1) {
     301                 :            : 
     302         [ #  # ]:          0 :                         if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
     303                 :            :                                 return left;
     304                 :            : 
     305                 :          0 :                         code = strerror(errno);
     306         [ #  # ]:          0 :                         ERROR("Bad return code %d from send (%s)", rc,
     307                 :            :                                         (code == 0 ? "unknown" : code));
     308                 :          0 :                         return rc;
     309                 :            :                 }
     310                 :            : 
     311         [ #  # ]:          0 :                 if (rc == 0) {
     312                 :          0 :                         ERROR("Server shutdown prematurely in read_some");
     313                 :          0 :                         return -1;
     314                 :            :                 }
     315                 :            : 
     316                 :          0 :                 data->so_far += rc;
     317                 :          0 :                 left -= rc;
     318                 :            :         }
     319                 :            : 
     320                 :            :         return left;
     321                 :            : }
     322                 :            : 
     323                 :            : static void
     324                 :          0 : tdnbd_writer_cb(event_id_t eb, char mode, void *data)
     325                 :            : {
     326                 :            :         struct td_nbd_request *pos, *q;
     327                 :          0 :         struct tdnbd_data *prv = data;
     328                 :            : 
     329         [ #  # ]:          0 :         list_for_each_entry_safe(pos, q, &prv->pending_reqs, queue) {
     330         [ #  # ]:          0 :                 if (tdnbd_write_some(prv->socket, &pos->header) > 0)
     331                 :            :                         return;
     332                 :            : 
     333         [ #  # ]:          0 :                 if (ntohl(pos->nreq.type) == TAPDISK_NBD_CMD_WRITE) {
     334         [ #  # ]:          0 :                         if (tdnbd_write_some(prv->socket, &pos->body) > 0)
     335                 :            :                                 return;
     336                 :            :                 }
     337                 :            : 
     338         [ #  # ]:          0 :                 if (ntohl(pos->nreq.type) == TAPDISK_NBD_CMD_DISC) {
     339                 :          0 :                         INFO("sent close request");
     340                 :            :                         /*
     341                 :            :                          * We don't expect a response from a DISC, so move the
     342                 :            :                          * request back onto the free list
     343                 :            :                          */
     344                 :          0 :                         list_move(&pos->queue, &prv->free_reqs);
     345                 :          0 :                         prv->nr_free_count++;
     346                 :          0 :                         prv->closed = 2;
     347                 :            :                 } else {
     348                 :          0 :                         list_move(&pos->queue, &prv->sent_reqs);
     349                 :            :                 }
     350                 :            :         }
     351                 :            : 
     352                 :            :         /* If we're here, we've written everything */
     353                 :            : 
     354                 :          0 :         disable_write_queue(prv);
     355                 :            : 
     356         [ #  # ]:          0 :         if (prv->closed == 2)
     357                 :          0 :                 tdnbd_disable(prv, EIO);
     358                 :            : 
     359                 :            :         return;
     360                 :            : }
     361                 :            : 
     362                 :            : static int
     363                 :          0 : enable_write_queue(struct tdnbd_data *prv)
     364                 :            : {
     365         [ #  # ]:          0 :         if (prv->writer_event_id >= 0) 
     366                 :            :                 return 0;
     367                 :            : 
     368                 :          0 :         prv->writer_event_id = 
     369                 :          0 :                 tapdisk_server_register_event(SCHEDULER_POLL_WRITE_FD,
     370                 :            :                                 prv->socket,
     371                 :          0 :                                 TV_ZERO,
     372                 :            :                                 tdnbd_writer_cb,
     373                 :            :                                 prv);
     374                 :            : 
     375                 :          0 :         return prv->writer_event_id;
     376                 :            : }
     377                 :            : 
     378                 :            : static void
     379                 :          0 : disable_write_queue(struct tdnbd_data *prv)
     380                 :            : {
     381         [ #  # ]:          0 :         if (prv->writer_event_id < 0)
     382                 :          0 :                 return;
     383                 :            : 
     384                 :          0 :         tapdisk_server_unregister_event(prv->writer_event_id);
     385                 :            : 
     386                 :          0 :         prv->writer_event_id = -1;
     387                 :            : }
     388                 :            : 
     389                 :            : static int
     390                 :          0 : tdnbd_queue_request(struct tdnbd_data *prv, int type, uint64_t offset,
     391                 :            :                 char *buffer, uint32_t length, td_request_t treq, int fake)
     392                 :            : {
     393         [ #  # ]:          0 :         if (prv->nr_free_count == 0) 
     394                 :            :                 return -EBUSY;
     395                 :            : 
     396         [ #  # ]:          0 :         if (prv->closed == 3) {
     397                 :          0 :                 td_complete_request(treq, -ETIMEDOUT);
     398                 :          0 :                 return -ETIMEDOUT;
     399                 :            :         }
     400                 :            : 
     401                 :          0 :         struct td_nbd_request *req = list_entry(prv->free_reqs.next,
     402                 :            :                         struct td_nbd_request, queue);
     403                 :            : 
     404                 :            :         /* fill in the request */
     405                 :            : 
     406                 :          0 :         req->treq = treq;
     407                 :          0 :         int id = global_id++;
     408                 :          0 :         snprintf(req->nreq.handle, 8, "td%05x", id % 0xffff);
     409                 :            : 
     410                 :            :         /* Don't time the NBD requests out */
     411                 :          0 :         req->timeout_event = -1;
     412                 :            : 
     413                 :          0 :         req->nreq.magic = htonl(NBD_REQUEST_MAGIC);
     414                 :          0 :         req->nreq.type = htonl(type);
     415                 :          0 :         req->nreq.from = htonll(offset);
     416                 :          0 :         req->nreq.len = htonl(length);
     417                 :          0 :         req->header.buffer = (char *)&req->nreq;
     418                 :          0 :         req->header.len = sizeof(req->nreq);
     419                 :          0 :         req->header.so_far = 0;
     420                 :          0 :         req->body.buffer = buffer;
     421                 :          0 :         req->body.len = length;
     422                 :          0 :         req->body.so_far = 0;
     423                 :          0 :         req->fake = fake;
     424                 :            : 
     425                 :          0 :         list_move_tail(&req->queue, &prv->pending_reqs);
     426                 :          0 :         prv->nr_free_count--;
     427                 :            : 
     428         [ #  # ]:          0 :         if (prv->writer_event_id < 0)
     429                 :          0 :                 enable_write_queue(prv);
     430                 :            : 
     431                 :            :         return 0;
     432                 :            : }
     433                 :            : 
     434                 :            : /* NBD Reader callback */
     435                 :            : 
     436                 :            : static void
     437                 :          0 : tdnbd_reader_cb(event_id_t eb, char mode, void *data)
     438                 :            : {
     439                 :            :         char handle[9];
     440                 :          0 :         int do_disable = 0;
     441                 :            : 
     442                 :            :         /* Check to see if we're in the middle of reading a response already */
     443                 :          0 :         struct tdnbd_data *prv = data;
     444                 :          0 :         int rc = tdnbd_read_some(prv->socket, &prv->cur_reply_qio);
     445                 :            : 
     446         [ #  # ]:          0 :         if (rc < 0) {
     447                 :          0 :                 ERROR("Error reading reply header: %d", rc);
     448                 :          0 :                 tdnbd_disable(prv, EIO);
     449                 :          0 :                 return;
     450                 :            :         }
     451                 :            : 
     452         [ #  # ]:          0 :         if (rc > 0)
     453                 :            :                 return; /* need more data */
     454                 :            : 
     455                 :            :         /* Got a header. */
     456         [ #  # ]:          0 :         if (prv->current_reply.error != 0) {
     457                 :          0 :                 ERROR("Error in reply: %d", prv->current_reply.error);
     458                 :          0 :                 tdnbd_disable(prv, EIO);
     459                 :            :                 return;
     460                 :            :         }
     461                 :            : 
     462                 :            :         /* Have we found the request yet? */
     463         [ #  # ]:          0 :         if (prv->curr_reply_req == NULL) {
     464                 :            :                 struct td_nbd_request *pos, *q;
     465         [ #  # ]:          0 :                 list_for_each_entry_safe(pos, q, &prv->sent_reqs, queue) {
     466         [ #  # ]:          0 :                         if (memcmp(pos->nreq.handle, prv->current_reply.handle,
     467                 :            :                                                 8) == 0) {
     468                 :          0 :                                 prv->curr_reply_req = pos;
     469                 :          0 :                                 break;
     470                 :            :                         }
     471                 :            :                 }
     472                 :            : 
     473         [ #  # ]:          0 :                 if (prv->curr_reply_req == NULL) {
     474                 :          0 :                         memcpy(handle, prv->current_reply.handle, 8);
     475                 :          0 :                         handle[8] = 0;
     476                 :            : 
     477                 :          0 :                         ERROR("Couldn't find request corresponding to reply "
     478                 :            :                                         "(reply handle='%s')", handle);
     479                 :          0 :                         tdnbd_disable(prv, EIO);
     480                 :            :                         return;
     481                 :            :                 }
     482                 :            :         }
     483                 :            : 
     484      [ #  #  # ]:          0 :         switch(ntohl(prv->curr_reply_req->nreq.type)) {
     485                 :            :         case TAPDISK_NBD_CMD_READ:
     486                 :          0 :                 rc = tdnbd_read_some(prv->socket,
     487                 :            :                                 &prv->curr_reply_req->body);
     488                 :            : 
     489         [ #  # ]:          0 :                 if (rc < 0) {
     490                 :          0 :                         ERROR("Error reading body of request: %d", rc);
     491                 :          0 :                         tdnbd_disable(prv, EIO);
     492                 :            :                         return;
     493                 :            :                 }
     494                 :            : 
     495         [ #  # ]:          0 :                 if (rc > 0)
     496                 :            :                         return; /* need more data */
     497                 :            : 
     498                 :          0 :                 td_complete_request(prv->curr_reply_req->treq, 0);
     499                 :            : 
     500                 :            :                 break;
     501                 :            :         case TAPDISK_NBD_CMD_WRITE:
     502                 :          0 :                 td_complete_request(prv->curr_reply_req->treq, 0);
     503                 :            : 
     504                 :            :                 break;
     505                 :            :         default:
     506                 :          0 :                 ERROR("Unhandled request response: %d",
     507                 :            :                                 ntohl(prv->curr_reply_req->nreq.type));
     508                 :            :                 do_disable = 1;
     509                 :            :                 return;
     510                 :            :         } 
     511                 :            : 
     512                 :            :         /* remove the state */
     513                 :          0 :         list_move(&prv->curr_reply_req->queue, &prv->free_reqs);
     514                 :          0 :         prv->nr_free_count++;
     515                 :            : 
     516                 :          0 :         prv->cur_reply_qio.so_far = 0;
     517         [ #  # ]:          0 :         if (prv->curr_reply_req->timeout_event >= 0) {
     518                 :          0 :                 tapdisk_server_unregister_event(
     519                 :            :                                 prv->curr_reply_req->timeout_event);
     520                 :            :         }
     521                 :            : 
     522                 :          0 :         prv->curr_reply_req = NULL;
     523                 :            : 
     524                 :            :         /*
     525                 :            :          * NB: do this here otherwise we cancel the request that has just been 
     526                 :            :          * moved
     527                 :            :          */
     528                 :            :         if (do_disable)
     529                 :            :                 tdnbd_disable(prv, EIO);
     530                 :            : }
     531                 :            : 
     532                 :            : static int
     533                 :          0 : tdnbd_wait_read(int fd)
     534                 :            : {
     535                 :            :         struct timeval select_tv;
     536                 :            :         fd_set socks;
     537                 :            :         int rc;
     538                 :            : 
     539                 :          0 :         FD_ZERO(&socks);
     540 [ #  # ][ #  # ]:          0 :         FD_SET(fd, &socks);
     541                 :          0 :         select_tv.tv_sec = 10;
     542                 :          0 :         select_tv.tv_usec = 0;
     543                 :          0 :         rc = select(fd + 1, &socks, NULL, NULL, &select_tv);
     544                 :          0 :         return rc;
     545                 :            : }
     546                 :            : 
     547                 :            : int 
     548                 :          0 : negotiate_client_newstyle_options(int sock, td_driver_t *driver)
     549                 :            : {
     550                 :            :         int rc;
     551                 :            :         struct nbd_new_option new_option;
     552                 :          0 :         char exportname[] = "tapdisk_client"; /* Hard code could make this unique */
     553                 :          0 :         new_option.version = htobe64(NBD_OPT_MAGIC);
     554                 :          0 :         new_option.optlen = htobe32(sizeof(exportname));
     555                 :          0 :         new_option.option = htobe32( NBD_OPT_EXPORT_NAME);
     556                 :            : 
     557                 :            :         /* Send EXPORTNAME_NAME option request */
     558                 :          0 :         rc = send_fully_or_fail(sock, &new_option, sizeof(new_option));
     559         [ #  # ]:          0 :         if (rc < 0)
     560                 :            :         {
     561                 :          0 :                 ERROR("Failed to send options to sock");
     562                 :          0 :                 close(sock);
     563                 :          0 :                 return -1;
     564                 :            :         }
     565                 :            :         /* Send exportname name */
     566                 :          0 :         rc = send_fully_or_fail(sock, exportname, sizeof(exportname));
     567         [ #  # ]:          0 :         if (rc < 0)
     568                 :            :         {
     569                 :          0 :                 ERROR("Failed to send export name to sock");
     570                 :          0 :                 close(sock);
     571                 :            :                 return -1;
     572                 :            :         }
     573                 :            : 
     574                 :            :         /* Collect the results in the handshake finished */
     575                 :            :         struct nbd_export_name_option_reply handshake_finish;
     576                 :            :         static const size_t NO_ZERO_HANDSHAKE_FINISH_SIZE = 10;
     577                 :          0 :         rc = recv_fully_or_fail(sock, &handshake_finish, NO_ZERO_HANDSHAKE_FINISH_SIZE);
     578         [ #  # ]:          0 :         if (rc < 0)
     579                 :            :         {
     580                 :          0 :                 ERROR("Failed to read handshake from sock");
     581                 :          0 :                 close(sock);
     582                 :            :                 return -1;
     583                 :            :         }
     584                 :            : 
     585                 :          0 :         driver->info.size = be64toh(handshake_finish.exportsize) >> SECTOR_SHIFT;
     586                 :          0 :         driver->info.sector_size = DEFAULT_SECTOR_SIZE;
     587                 :          0 :         driver->info.info = 0;
     588                 :            : 
     589                 :          0 :         rc = fcntl(sock, F_SETFL, O_NONBLOCK);
     590                 :            : 
     591         [ #  # ]:          0 :         if (rc != 0) {
     592                 :          0 :                 ERROR("Could not set O_NONBLOCK flag");
     593                 :          0 :                 close(sock);
     594                 :            :                 return -1;
     595                 :            :         }
     596                 :            : 
     597                 :          0 :         INFO("Successfully connected to NBD server");
     598                 :            : 
     599                 :            :         return 0;
     600                 :            : }
     601                 :            : 
     602                 :            : static int
     603                 :          0 : tdnbd_nbd_negotiate_old(struct tdnbd_data *prv, td_driver_t *driver)
     604                 :            : {
     605                 :            :         int rc;
     606                 :            :         char buffer[RECV_BUFFER_SIZE];
     607                 :            :         uint64_t magic;
     608                 :            :         uint64_t size;
     609                 :            :         uint32_t flags;
     610                 :          0 :         int padbytes = 124;
     611                 :          0 :         int sock = prv->socket;
     612                 :            : 
     613                 :            :         /*
     614                 :            :          * NBD negotiation protocol: 
     615                 :            :          *
     616                 :            :          * Server sends 'NBDMAGIC'
     617                 :            :          * then it sends 0x00420281861253L
     618                 :            :          * then it sends a 64 bit bigendian size
     619                 :            :          * then it sends a 32 bit bigendian flags
     620                 :            :          * then it sends 124 bytes of nothing
     621                 :            :          */
     622                 :            : 
     623                 :            :         /*
     624                 :            :          * We need to limit the time we spend in this function as we're still
     625                 :            :          * using blocking IO at this point
     626                 :            :          */
     627         [ #  # ]:          0 :         if (tdnbd_wait_read(sock) <= 0) {
     628                 :          0 :                 ERROR("Timeout in nbd_negotiate");
     629                 :          0 :                 close(sock);
     630                 :          0 :                 return -1;
     631                 :            :         }
     632                 :            : 
     633                 :          0 :         rc = recv(sock, buffer, 8, 0);
     634         [ #  # ]:          0 :         if (rc < 8) {
     635                 :          0 :                 ERROR("Short read in negotiation(1) (%d)\n", rc);
     636                 :          0 :                 close(sock);
     637                 :            :                 return -1;
     638                 :            :         }
     639                 :            : 
     640         [ #  # ]:          0 :         if (memcmp(buffer, "NBDMAGIC", 8) != 0) {
     641                 :          0 :                 buffer[8] = 0;
     642                 :          0 :                 ERROR("Error in NBD negotiation: got '%s'", buffer);
     643                 :          0 :                 close(sock);
     644                 :            :                 return -1;
     645                 :            :         }
     646                 :            : 
     647         [ #  # ]:          0 :         if (tdnbd_wait_read(sock) <= 0) {
     648                 :          0 :                 ERROR("Timeout in nbd_negotiate");
     649                 :          0 :                 close(sock);
     650                 :            :                 return -1;
     651                 :            :         }
     652                 :            : 
     653                 :          0 :         rc = recv(sock, &magic, sizeof(magic), 0);
     654         [ #  # ]:          0 :         if (rc < 8) {
     655                 :          0 :                 ERROR("Short read in negotiation(2) (%d)\n", rc);
     656                 :            : 
     657                 :            :                 return -1;
     658                 :            :         }
     659                 :            : 
     660         [ #  # ]:          0 :         if (ntohll(magic) != NBD_NEGOTIATION_MAGIC) {
     661                 :          0 :                 ERROR("Not enough magic in negotiation(2) (%"PRIu64")\n",
     662                 :            :                                 ntohll(magic));
     663                 :          0 :                 close(sock);
     664                 :            :                 return -1;
     665                 :            :         }
     666                 :            : 
     667         [ #  # ]:          0 :         if (tdnbd_wait_read(sock) <= 0) {
     668                 :          0 :                 ERROR("Timeout in nbd_negotiate");
     669                 :          0 :                 close(sock);
     670                 :            :                 return -1;
     671                 :            :         }
     672                 :            : 
     673                 :          0 :         rc = recv(sock, &size, sizeof(size), 0);
     674         [ #  # ]:          0 :         if (rc < sizeof(size)) {
     675                 :          0 :                 ERROR("Short read in negotiation(3) (%d)\n", rc);
     676                 :          0 :                 close(sock);
     677                 :            :                 return -1;
     678                 :            :         }
     679                 :            : 
     680                 :          0 :         INFO("Got size: %"PRIu64"", ntohll(size));
     681                 :            : 
     682                 :          0 :         driver->info.size = ntohll(size) >> SECTOR_SHIFT;
     683                 :          0 :         driver->info.sector_size = DEFAULT_SECTOR_SIZE;
     684                 :          0 :         driver->info.info = 0;
     685                 :            : 
     686         [ #  # ]:          0 :         if (tdnbd_wait_read(sock) <= 0) {
     687                 :          0 :                 ERROR("Timeout in nbd_negotiate");
     688                 :          0 :                 close(sock);
     689                 :            :                 return -1;
     690                 :            :         }
     691                 :            : 
     692                 :          0 :         rc = recv(sock, &flags, sizeof(flags), 0);
     693         [ #  # ]:          0 :         if (rc < sizeof(flags)) {
     694                 :          0 :                 ERROR("Short read in negotiation(4) (%d)\n", rc);
     695                 :          0 :                 close(sock);
     696                 :            :                 return -1;
     697                 :            :         }
     698                 :            : 
     699                 :          0 :         INFO("Got flags: %"PRIu32"", ntohl(flags));
     700                 :            : 
     701         [ #  # ]:          0 :         while (padbytes > 0) {
     702         [ #  # ]:          0 :                 if (tdnbd_wait_read(sock) <= 0) {
     703                 :          0 :                         ERROR("Timeout in nbd_negotiate");
     704                 :          0 :                         close(sock);
     705                 :            :                         return -1;
     706                 :            :                 }
     707                 :            : 
     708                 :          0 :                 rc = recv(sock, buffer, padbytes, 0);
     709         [ #  # ]:          0 :                 if (rc < 0) {
     710                 :          0 :                         ERROR("Bad read in negotiation(5) (%d)\n", rc);
     711                 :          0 :                         close(sock);
     712                 :            :                         return -1;
     713                 :            :                 }
     714                 :          0 :                 padbytes -= rc;
     715                 :            :         }
     716                 :            : 
     717                 :          0 :         rc = fcntl(sock, F_SETFL, O_NONBLOCK);
     718                 :            : 
     719         [ #  # ]:          0 :         if (rc != 0) {
     720                 :          0 :                 ERROR("Could not set O_NONBLOCK flag");
     721                 :          0 :                 close(sock);
     722                 :            :                 return -1;
     723                 :            :         }
     724                 :          0 :         INFO("Successfully connected to NBD server");
     725                 :            : 
     726                 :            :         return 0;
     727                 :            : }
     728                 :            : 
     729                 :            : static int
     730                 :          0 : tdnbd_nbd_negotiate_new(struct tdnbd_data *prv, td_driver_t *driver)
     731                 :            : {
     732                 :            :         int rc;
     733                 :            :         uint64_t magic_version;
     734                 :            :         uint16_t gflags;
     735                 :          0 :         uint32_t cflags = htobe32(NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES);
     736                 :          0 :         int sock = prv->socket;
     737                 :            :         char buffer[RECV_BUFFER_SIZE];
     738                 :            : 
     739         [ #  # ]:          0 :         if (tdnbd_wait_read(sock) <= 0) {
     740                 :          0 :                 ERROR("Timeout in nbd_negotiate");
     741                 :          0 :                 close(sock);
     742                 :          0 :                 return -1;
     743                 :            :         }
     744                 :            : 
     745                 :          0 :         rc = recv(sock, buffer, 8, 0);
     746         [ #  # ]:          0 :         if (rc < 8) {
     747                 :          0 :                 ERROR("Short read in negotiation(1) (%d)\n", rc);
     748                 :          0 :                 close(sock);
     749                 :            :                 return -1;
     750                 :            :         }
     751                 :            : 
     752         [ #  # ]:          0 :         if (memcmp(buffer, "NBDMAGIC", 8) != 0) {
     753                 :          0 :           buffer[8] = 0;
     754                 :          0 :           ERROR("Error in NBD negotiation: got '%s'", buffer);
     755                 :          0 :           close(sock);
     756                 :            :           return -1;
     757                 :            :         }
     758                 :            : 
     759         [ #  # ]:          0 :         if (tdnbd_wait_read(sock) <= 0) {
     760                 :          0 :           ERROR("Timeout in nbd_negotiate");
     761                 :          0 :           close(sock);
     762                 :            :           return -1;
     763                 :            :         }
     764                 :            : 
     765                 :            :         /* Receive NBD magic_version */
     766                 :          0 :         rc = recv_fully_or_fail(sock, &magic_version, sizeof(magic_version));
     767         [ #  # ]:          0 :         if (rc < 0)
     768                 :            :         {
     769                 :          0 :                 ERROR("Failed to read magic from sock");
     770                 :          0 :                 close(sock);
     771                 :            :                 return -1;
     772                 :            :         }
     773                 :            : 
     774         [ #  # ]:          0 :         if (ntohll(magic_version) != NBD_NEW_VERSION) {
     775                 :          0 :                 ERROR("Not enough magic in negotiation(2) (%"PRIu64")\n",
     776                 :            :                                 ntohll(magic_version));
     777                 :          0 :                 close(sock);
     778                 :            :                 return -1;
     779                 :            :         }
     780                 :            : 
     781                 :            :         /* Receive NBD flags */
     782                 :          0 :         rc = recv(sock, &gflags, sizeof(gflags), 0);
     783         [ #  # ]:          0 :         if (rc < sizeof(gflags)) {
     784                 :          0 :                 ERROR("Short read in negotiation(2) (%d)\n", rc);
     785                 :            : 
     786                 :            :                 return -1;
     787                 :            :         }
     788                 :            : 
     789                 :            :         /* Send back flags*/
     790                 :          0 :         rc = send(sock, &cflags, sizeof(cflags), 0);
     791         [ #  # ]:          0 :         if (rc < sizeof(cflags)) {
     792                 :          0 :                 ERROR("Failed to send client flags");
     793                 :            :                 return -1;
     794                 :            :         }
     795                 :            : 
     796                 :          0 :         return negotiate_client_newstyle_options(sock, driver);
     797                 :            : }
     798                 :            : 
     799                 :            : static int
     800                 :          0 : tdnbd_nbd_negotiate(struct tdnbd_data *prv, td_driver_t *driver)
     801                 :            : {
     802         [ #  # ]:          0 :         if(CLIENT_USE_OLD_HANDSHAKE && !td_flag_test(driver->state, TD_DRIVER_NEW_NBD)) {
     803                 :          0 :                 return tdnbd_nbd_negotiate_old(prv, driver);
     804                 :            :         } else {
     805                 :          0 :                 return tdnbd_nbd_negotiate_new(prv, driver);
     806                 :            :         }
     807                 :            : }
     808                 :            : 
     809                 :            : static int
     810                 :          0 : tdnbd_connect_import_session(struct tdnbd_data *prv, td_driver_t* driver)
     811                 :            : {
     812                 :            :         int sock;
     813                 :          0 :         int opt = 1;
     814                 :            :         int rc;
     815                 :            : 
     816                 :          0 :         sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     817         [ #  # ]:          0 :         if (sock < 0) {
     818                 :          0 :                 ERROR("Could not create socket: %s\n", strerror(errno));
     819                 :          0 :                 return -1;
     820                 :            :         }
     821                 :            : 
     822                 :          0 :         rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&opt,
     823                 :            :                         sizeof(opt));
     824         [ #  # ]:          0 :         if (rc < 0) {
     825                 :          0 :                 ERROR("Could not set TCP_NODELAY: %s\n", strerror(errno));
     826                 :          0 :                 close(sock);
     827                 :            :                 return -1;
     828                 :            :         }
     829                 :            : 
     830                 :          0 :         prv->remote = (struct sockaddr_in *)malloc(
     831                 :            :                         sizeof(struct sockaddr_in));
     832         [ #  # ]:          0 :         if (!prv->remote) {
     833                 :          0 :                 ERROR("struct sockaddr_in malloc failure\n");
     834                 :          0 :                 close(sock);
     835                 :            :                 return -1;
     836                 :            :         }
     837                 :          0 :         prv->remote->sin_family = AF_INET;
     838                 :          0 :         rc = inet_pton(AF_INET, prv->peer_ip, &(prv->remote->sin_addr.s_addr));
     839         [ #  # ]:          0 :         if (rc < 0) {
     840                 :          0 :                 ERROR("Could not create inaddr: %s\n", strerror(errno));
     841                 :          0 :                 free(prv->remote);
     842                 :          0 :                 prv->remote = NULL;
     843                 :          0 :                 close(sock);
     844                 :            :                 return -1;
     845                 :            :         }
     846         [ #  # ]:          0 :         else if (rc == 0) {
     847                 :          0 :                 ERROR("inet_pton parse error\n");
     848                 :          0 :                 free(prv->remote);
     849                 :          0 :                 prv->remote = NULL;
     850                 :          0 :                 close(sock);
     851                 :            :                 return -1;
     852                 :            :         }
     853         [ #  # ]:          0 :         prv->remote->sin_port = htons(prv->port);
     854                 :            : 
     855         [ #  # ]:          0 :         if (connect(sock, (struct sockaddr *)prv->remote,
     856                 :            :                                 sizeof(struct sockaddr)) < 0) {
     857                 :          0 :                 ERROR("Could not connect to peer: %s\n", strerror(errno));
     858                 :          0 :                 free(prv->remote);
     859                 :          0 :                 close(sock);
     860                 :            :                 return -1;
     861                 :            :         }
     862                 :            : 
     863                 :          0 :         prv->socket = sock;
     864                 :            : 
     865                 :          0 :         return tdnbd_nbd_negotiate(prv, driver);
     866                 :            : }
     867                 :            : 
     868                 :            : /* -- interface -- */
     869                 :            : 
     870                 :            : static int tdnbd_close(td_driver_t*);
     871                 :            : 
     872                 :            : static int
     873                 :          0 : tdnbd_open(td_driver_t* driver, const char* name,
     874                 :            :            struct td_vbd_encryption *encryption, td_flag_t flags)
     875                 :            : {
     876                 :            :         struct tdnbd_data *prv;
     877                 :            :         char peer_ip[256];
     878                 :            :         int port;
     879                 :            :         int rc;
     880                 :            :         int i;
     881                 :            :         struct stat buf;
     882                 :            : 
     883                 :          0 :         driver->info.sector_size = 512;
     884                 :          0 :         driver->info.info = 0;
     885                 :            : 
     886                 :          0 :         prv = (struct tdnbd_data *)driver->data;
     887                 :            :         memset(prv, 0, sizeof(struct tdnbd_data));
     888                 :            : 
     889                 :          0 :         INFO("Opening nbd export to %s (flags=%x)\n", name, flags);
     890                 :            : 
     891                 :          0 :         prv->writer_event_id = -1;
     892                 :          0 :         INIT_LIST_HEAD(&prv->sent_reqs);
     893                 :          0 :         INIT_LIST_HEAD(&prv->pending_reqs);
     894                 :          0 :         INIT_LIST_HEAD(&prv->free_reqs);
     895         [ #  # ]:          0 :         for (i = 0; i < MAX_NBD_REQS; i++) {
     896                 :          0 :                 INIT_LIST_HEAD(&prv->requests[i].queue);
     897                 :          0 :                 prv->requests[i].timeout_event = -1;
     898                 :          0 :                 list_add(&prv->requests[i].queue, &prv->free_reqs);
     899                 :            :         }
     900                 :          0 :         prv->nr_free_count = MAX_NBD_REQS;
     901                 :          0 :         prv->cur_reply_qio.buffer = (char *)&prv->current_reply;
     902                 :          0 :         prv->cur_reply_qio.len = sizeof(struct nbd_reply);
     903                 :            : 
     904                 :            :         bzero(&buf, sizeof(buf));
     905                 :          0 :         rc = stat(name, &buf);
     906 [ #  # ][ #  # ]:          0 :         if (!rc && S_ISSOCK(buf.st_mode)) {
     907                 :          0 :                 int len = 0;
     908         [ #  # ]:          0 :                 if ((prv->socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
     909                 :          0 :                         ERROR("failed to create UNIX domain socket: %s\n",
     910                 :            :                                         strerror(errno));
     911                 :          0 :                         return -1;
     912                 :            :                 }
     913                 :          0 :                 prv->remote_un.sun_family = AF_UNIX;
     914                 :          0 :                 safe_strncpy(prv->remote_un.sun_path, name, sizeof(prv->remote_un.sun_path));
     915                 :          0 :                 len = strlen(prv->remote_un.sun_path)
     916                 :            :                         + sizeof(prv->remote_un.sun_family);
     917         [ #  # ]:          0 :                 if ((rc = connect(prv->socket, (struct sockaddr*)&prv->remote_un, len)
     918                 :          0 :                                         == -1)) {
     919                 :          0 :                         ERROR("failed to connect to %s: %s\n", name, strerror(errno));
     920                 :            :                         return -1;
     921                 :            :                 }
     922                 :          0 :                 rc = tdnbd_nbd_negotiate(prv, driver);
     923         [ #  # ]:          0 :                 if (rc) {
     924                 :          0 :                         ERROR("failed to negotiate with the NBD server\n");
     925                 :            :                         return -1;
     926                 :            :                 }
     927                 :            :         } else {
     928                 :          0 :                 rc = sscanf(name, "%255[^:]:%d", peer_ip, &port);
     929         [ #  # ]:          0 :                 if (rc == 2) {
     930                 :          0 :                         prv->peer_ip = strdup(peer_ip);
     931         [ #  # ]:          0 :                         if (!prv->peer_ip) {
     932                 :          0 :                                 ERROR("Failure to malloc for NBD destination");
     933                 :            :                                 return -1;
     934                 :            :                         }
     935                 :          0 :                         prv->port = port;
     936                 :          0 :                         prv->name = NULL;
     937                 :          0 :                         INFO("Export peer=%s port=%d\n", prv->peer_ip, prv->port);
     938         [ #  # ]:          0 :                         if (tdnbd_connect_import_session(prv, driver) < 0)
     939                 :            :                                 return -1;
     940                 :            : 
     941                 :            :                 } else {
     942                 :          0 :                         prv->socket = tdnbd_retrieve_passed_fd(name);
     943         [ #  # ]:          0 :                         if (prv->socket < 0) {
     944                 :          0 :                                 ERROR("Couldn't find fd named: %s", name);
     945                 :            :                                 return -1;
     946                 :            :                         }
     947                 :          0 :                         INFO("Found passed fd. Connecting...");
     948                 :          0 :                         prv->remote = NULL;
     949                 :          0 :                         prv->peer_ip = NULL;
     950                 :          0 :                         prv->name = strdup(name);
     951                 :          0 :                         prv->port = -1;
     952         [ #  # ]:          0 :                         if (tdnbd_nbd_negotiate(prv, driver) < 0) {
     953                 :          0 :                                 ERROR("Failed to negotiate");
     954                 :            :                                 return -1;
     955                 :            :                         }
     956                 :            :                 }
     957                 :            :         }
     958                 :            : 
     959                 :          0 :         prv->reader_event_id =
     960                 :          0 :                 tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
     961                 :          0 :                                 prv->socket, TV_ZERO,
     962                 :            :                                 tdnbd_reader_cb,
     963                 :            :                                 (void *)prv);
     964                 :            : 
     965                 :          0 :         prv->flags = flags;
     966                 :          0 :         prv->closed = 0;
     967                 :            : 
     968         [ #  # ]:          0 :         if (flags & TD_OPEN_SECONDARY)
     969                 :          0 :                 INFO("Opening in secondary mode: Read requests will be "
     970                 :            :                                 "forwarded");
     971                 :            : 
     972                 :            :         return 0;
     973                 :            : 
     974                 :            : }
     975                 :            : 
     976                 :            : static int
     977                 :          0 : tdnbd_close(td_driver_t* driver)
     978                 :            : {
     979                 :          0 :         struct tdnbd_data *prv = (struct tdnbd_data *)driver->data;
     980                 :            :         td_request_t treq;
     981                 :            : 
     982                 :            :         bzero(&treq, sizeof(treq));
     983                 :            : 
     984         [ #  # ]:          0 :         if (prv->closed == 3) {
     985                 :          0 :                 INFO("NBD close: already decided that the connection is dead.");
     986         [ #  # ]:          0 :                 if (prv->socket >= 0)
     987                 :          0 :                         close(prv->socket);
     988                 :          0 :                 prv->socket = -1;
     989                 :          0 :                 return 0;
     990                 :            :         }
     991                 :            : 
     992                 :            :         /* Send a close packet */
     993                 :            : 
     994                 :          0 :         INFO("Sending disconnect request");
     995                 :          0 :         tdnbd_queue_request(prv, TAPDISK_NBD_CMD_DISC, 0, 0, 0, treq, 0);
     996                 :            : 
     997                 :          0 :         INFO("Switching socket to blocking IO mode");
     998                 :          0 :         fcntl(prv->socket, F_SETFL, fcntl(prv->socket, F_GETFL) & ~O_NONBLOCK);
     999                 :            : 
    1000                 :          0 :         INFO("Writing disconnection request");
    1001                 :          0 :         tdnbd_writer_cb(0, 0, prv);
    1002                 :            : 
    1003                 :          0 :         INFO("Written");
    1004                 :            : 
    1005         [ #  # ]:          0 :         if (prv->peer_ip) {
    1006                 :          0 :                 free(prv->peer_ip);
    1007                 :          0 :                 prv->peer_ip = NULL;
    1008                 :            :         }
    1009                 :            : 
    1010         [ #  # ]:          0 :         if (prv->name) {
    1011                 :          0 :                 tdnbd_stash_passed_fd(prv->socket, prv->name, 0);
    1012                 :          0 :                 free(prv->name);
    1013                 :            :         } else {
    1014         [ #  # ]:          0 :                 if (prv->socket >= 0)
    1015                 :          0 :                         close(prv->socket);
    1016                 :          0 :                 prv->socket = -1;
    1017                 :            :         }
    1018                 :            : 
    1019                 :            :         return 0;
    1020                 :            : }
    1021                 :            : 
    1022                 :            : static void
    1023                 :          0 : tdnbd_queue_read(td_driver_t* driver, td_request_t treq)
    1024                 :            : {
    1025                 :          0 :         struct tdnbd_data *prv = (struct tdnbd_data *)driver->data;
    1026                 :          0 :         int      size    = treq.secs * driver->info.sector_size;
    1027                 :          0 :         uint64_t offset  = treq.sec * (uint64_t)driver->info.sector_size;
    1028                 :            : 
    1029         [ #  # ]:          0 :         if (prv->flags & TD_OPEN_SECONDARY)
    1030                 :          0 :                 td_forward_request(treq);
    1031                 :            :         else
    1032                 :          0 :                 tdnbd_queue_request(prv, TAPDISK_NBD_CMD_READ, offset, treq.buf, size,
    1033                 :            :                                 treq, 0);
    1034                 :          0 : }
    1035                 :            : 
    1036                 :            : static void
    1037                 :          0 : tdnbd_queue_write(td_driver_t* driver, td_request_t treq)
    1038                 :            : {
    1039                 :          0 :         struct tdnbd_data *prv = (struct tdnbd_data *)driver->data;
    1040                 :          0 :         int      size    = treq.secs * driver->info.sector_size;
    1041                 :          0 :         uint64_t offset  = treq.sec * (uint64_t)driver->info.sector_size;
    1042                 :            : 
    1043                 :          0 :         tdnbd_queue_request(prv, TAPDISK_NBD_CMD_WRITE,
    1044                 :          0 :                         offset, treq.buf, size, treq, 0);
    1045                 :          0 : }
    1046                 :            : 
    1047                 :            : static int
    1048                 :          0 : tdnbd_get_parent_id(td_driver_t* driver, td_disk_id_t* id)
    1049                 :            : {
    1050                 :          0 :         return TD_NO_PARENT;
    1051                 :            : }
    1052                 :            : 
    1053                 :            : static int
    1054                 :          0 : tdnbd_validate_parent(td_driver_t *driver,
    1055                 :            :                 td_driver_t *parent, td_flag_t flags)
    1056                 :            : {
    1057                 :          0 :         return -EINVAL;
    1058                 :            : }
    1059                 :            : 
    1060                 :            : struct tap_disk tapdisk_nbd = {
    1061                 :            :         .disk_type          = "tapdisk_nbd",
    1062                 :            :         .private_data_size  = sizeof(struct tdnbd_data),
    1063                 :            :         .flags              = 0,
    1064                 :            :         .td_open            = tdnbd_open,
    1065                 :            :         .td_close           = tdnbd_close,
    1066                 :            :         .td_queue_read      = tdnbd_queue_read,
    1067                 :            :         .td_queue_write     = tdnbd_queue_write,
    1068                 :            :         .td_get_parent_id   = tdnbd_get_parent_id,
    1069                 :            :         .td_validate_parent = tdnbd_validate_parent,
    1070                 :            : };

Generated by: LCOV version 1.13