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

Generated by: LCOV version 1.13