LCOV - code coverage report
Current view: top level - spdk/lib/virtio - virtio_vhost_user.c (source / functions) Hit Total Coverage
Test: Combined Lines: 372 526 70.7 %
Date: 2024-07-13 13:09:57 Functions: 31 32 96.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 134 254 52.8 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2010-2016 Intel Corporation. All rights reserved.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include <sys/eventfd.h>
       9                 :            : 
      10                 :            : #include "spdk/string.h"
      11                 :            : #include "spdk/config.h"
      12                 :            : #include "spdk/util.h"
      13                 :            : 
      14                 :            : #include "spdk_internal/virtio.h"
      15                 :            : #include "spdk_internal/vhost_user.h"
      16                 :            : 
      17                 :            : /* The version of the protocol we support */
      18                 :            : #define VHOST_USER_VERSION    0x1
      19                 :            : 
      20                 :            : #define VIRTIO_USER_SUPPORTED_PROTOCOL_FEATURES \
      21                 :            :         ((1ULL << VHOST_USER_PROTOCOL_F_MQ) | \
      22                 :            :         (1ULL << VHOST_USER_PROTOCOL_F_CONFIG))
      23                 :            : 
      24                 :            : struct virtio_user_dev {
      25                 :            :         int             vhostfd;
      26                 :            : 
      27                 :            :         int             callfds[SPDK_VIRTIO_MAX_VIRTQUEUES];
      28                 :            :         int             kickfds[SPDK_VIRTIO_MAX_VIRTQUEUES];
      29                 :            :         uint32_t        queue_size;
      30                 :            : 
      31                 :            :         uint8_t         status;
      32                 :            :         bool            is_stopping;
      33                 :            :         char            path[PATH_MAX];
      34                 :            :         uint64_t        protocol_features;
      35                 :            :         struct vring    vrings[SPDK_VIRTIO_MAX_VIRTQUEUES];
      36                 :            :         struct spdk_mem_map *mem_map;
      37                 :            : };
      38                 :            : 
      39                 :            : static int
      40                 :       1549 : vhost_user_write(int fd, void *buf, int len, int *fds, int fd_num)
      41                 :       1549 : {
      42                 :            :         int r;
      43                 :          0 :         struct msghdr msgh;
      44                 :          0 :         struct iovec iov;
      45                 :       1549 :         size_t fd_size = fd_num * sizeof(int);
      46         [ -  + ]:       1549 :         char control[CMSG_SPACE(fd_size)];
      47                 :            :         struct cmsghdr *cmsg;
      48                 :            : 
      49                 :       1549 :         memset(&msgh, 0, sizeof(msgh));
      50         [ -  + ]:       1549 :         memset(control, 0, sizeof(control));
      51                 :            : 
      52                 :       1549 :         iov.iov_base = (uint8_t *)buf;
      53                 :       1549 :         iov.iov_len = len;
      54                 :            : 
      55                 :       1549 :         msgh.msg_iov = &iov;
      56                 :       1549 :         msgh.msg_iovlen = 1;
      57                 :            : 
      58   [ +  -  +  + ]:       1549 :         if (fds && fd_num > 0) {
      59                 :        402 :                 msgh.msg_control = control;
      60                 :        402 :                 msgh.msg_controllen = sizeof(control);
      61         [ +  - ]:        402 :                 cmsg = CMSG_FIRSTHDR(&msgh);
      62         [ -  + ]:        402 :                 if (!cmsg) {
      63                 :          0 :                         SPDK_WARNLOG("First HDR is NULL\n");
      64                 :          0 :                         return -EIO;
      65                 :            :                 }
      66                 :        402 :                 cmsg->cmsg_len = CMSG_LEN(fd_size);
      67                 :        402 :                 cmsg->cmsg_level = SOL_SOCKET;
      68                 :        402 :                 cmsg->cmsg_type = SCM_RIGHTS;
      69   [ -  +  -  + ]:        402 :                 memcpy(CMSG_DATA(cmsg), fds, fd_size);
      70                 :            :         } else {
      71                 :       1147 :                 msgh.msg_control = NULL;
      72                 :       1147 :                 msgh.msg_controllen = 0;
      73                 :            :         }
      74                 :            : 
      75                 :            :         do {
      76                 :       1549 :                 r = sendmsg(fd, &msgh, 0);
      77   [ -  +  -  - ]:       1549 :         } while (r < 0 && errno == EINTR);
      78                 :            : 
      79         [ -  + ]:       1549 :         if (r == -1) {
      80                 :          0 :                 return -errno;
      81                 :            :         }
      82                 :            : 
      83                 :       1549 :         return 0;
      84                 :            : }
      85                 :            : 
      86                 :            : static int
      87                 :        372 : vhost_user_read(int fd, struct vhost_user_msg *msg)
      88                 :            : {
      89                 :        372 :         uint32_t valid_flags = VHOST_USER_REPLY_MASK | VHOST_USER_VERSION;
      90                 :            :         ssize_t ret;
      91                 :        372 :         size_t sz_hdr = VHOST_USER_HDR_SIZE, sz_payload;
      92                 :            : 
      93                 :        372 :         ret = recv(fd, (void *)msg, sz_hdr, 0);
      94         [ -  + ]:        372 :         if ((size_t)ret != sz_hdr) {
      95                 :          0 :                 SPDK_WARNLOG("Failed to recv msg hdr: %zd instead of %zu.\n",
      96                 :            :                              ret, sz_hdr);
      97         [ #  # ]:          0 :                 if (ret == -1) {
      98                 :          0 :                         return -errno;
      99                 :            :                 } else {
     100                 :          0 :                         return -EBUSY;
     101                 :            :                 }
     102                 :            :         }
     103                 :            : 
     104                 :            :         /* validate msg flags */
     105         [ -  + ]:        372 :         if (msg->flags != (valid_flags)) {
     106                 :          0 :                 SPDK_WARNLOG("Failed to recv msg: flags %"PRIx32" instead of %"PRIx32".\n",
     107                 :            :                              msg->flags, valid_flags);
     108                 :          0 :                 return -EIO;
     109                 :            :         }
     110                 :            : 
     111                 :        372 :         sz_payload = msg->size;
     112                 :            : 
     113         [ -  + ]:        372 :         if (sz_payload > VHOST_USER_PAYLOAD_SIZE) {
     114                 :          0 :                 SPDK_WARNLOG("Received oversized msg: payload size %zu > available space %zu\n",
     115                 :            :                              sz_payload, VHOST_USER_PAYLOAD_SIZE);
     116                 :          0 :                 return -EIO;
     117                 :            :         }
     118                 :            : 
     119         [ +  - ]:        372 :         if (sz_payload) {
     120                 :        372 :                 ret = recv(fd, (void *)((char *)msg + sz_hdr), sz_payload, 0);
     121         [ -  + ]:        372 :                 if ((size_t)ret != sz_payload) {
     122                 :          0 :                         SPDK_WARNLOG("Failed to recv msg payload: %zd instead of %"PRIu32".\n",
     123                 :            :                                      ret, msg->size);
     124         [ #  # ]:          0 :                         if (ret == -1) {
     125                 :          0 :                                 return -errno;
     126                 :            :                         } else {
     127                 :          0 :                                 return -EBUSY;
     128                 :            :                         }
     129                 :            :                 }
     130                 :            :         }
     131                 :            : 
     132                 :        372 :         return 0;
     133                 :            : }
     134                 :            : 
     135                 :            : struct hugepage_file_info {
     136                 :            :         uint64_t addr;            /**< virtual addr */
     137                 :            :         size_t   size;            /**< the file size */
     138                 :            :         char     path[PATH_MAX];  /**< path to backing file */
     139                 :            : };
     140                 :            : 
     141                 :            : /* Two possible options:
     142                 :            :  * 1. Match HUGEPAGE_INFO_FMT to find the file storing struct hugepage_file
     143                 :            :  * array. This is simple but cannot be used in secondary process because
     144                 :            :  * secondary process will close and munmap that file.
     145                 :            :  * 2. Match HUGEFILE_FMT to find hugepage files directly.
     146                 :            :  *
     147                 :            :  * We choose option 2.
     148                 :            :  */
     149                 :            : static int
     150                 :         58 : get_hugepage_file_info(struct hugepage_file_info hugepages[], int max)
     151                 :            : {
     152                 :            :         int idx, rc;
     153                 :            :         FILE *f;
     154                 :          0 :         char buf[BUFSIZ], *tmp, *tail;
     155                 :            :         char *str_underline, *str_start;
     156                 :          0 :         int huge_index;
     157                 :          0 :         uint64_t v_start, v_end;
     158                 :            : 
     159                 :         58 :         f = fopen("/proc/self/maps", "r");
     160         [ -  + ]:         58 :         if (!f) {
     161                 :          0 :                 SPDK_ERRLOG("cannot open /proc/self/maps\n");
     162                 :          0 :                 rc = -errno;
     163         [ #  # ]:          0 :                 assert(rc < 0); /* scan-build hack */
     164                 :          0 :                 return rc;
     165                 :            :         }
     166                 :            : 
     167                 :         58 :         idx = 0;
     168         [ +  + ]:      68379 :         while (fgets(buf, sizeof(buf), f) != NULL) {
     169         [ -  + ]:      68321 :                 if (sscanf(buf, "%" PRIx64 "-%" PRIx64, &v_start, &v_end) < 2) {
     170                 :          0 :                         SPDK_ERRLOG("Failed to parse address\n");
     171                 :          0 :                         rc = -EIO;
     172                 :          0 :                         goto out;
     173                 :            :                 }
     174                 :            : 
     175                 :      68321 :                 tmp = strchr(buf, ' ') + 1; /** skip address */
     176         [ -  + ]:      68321 :                 tmp = strchr(tmp, ' ') + 1; /** skip perm */
     177         [ -  + ]:      68321 :                 tmp = strchr(tmp, ' ') + 1; /** skip offset */
     178         [ -  + ]:      68321 :                 tmp = strchr(tmp, ' ') + 1; /** skip dev */
     179         [ -  + ]:      68321 :                 tmp = strchr(tmp, ' ') + 1; /** skip inode */
     180         [ +  + ]:    1357681 :                 while (*tmp == ' ') {       /** skip spaces */
     181                 :    1289360 :                         tmp++;
     182                 :            :                 }
     183         [ -  + ]:      68321 :                 tail = strrchr(tmp, '\n');  /** remove newline if exists */
     184         [ +  - ]:      68321 :                 if (tail) {
     185                 :      68321 :                         *tail = '\0';
     186                 :            :                 }
     187                 :            : 
     188                 :            :                 /* Match HUGEFILE_FMT, aka "%s/%smap_%d",
     189                 :            :                  * which is defined in eal_filesystem.h
     190                 :            :                  */
     191         [ -  + ]:      68321 :                 str_underline = strrchr(tmp, '_');
     192         [ +  + ]:      68321 :                 if (!str_underline) {
     193                 :      14163 :                         continue;
     194                 :            :                 }
     195                 :            : 
     196                 :      54158 :                 str_start = str_underline - strlen("map");
     197         [ -  + ]:      54158 :                 if (str_start < tmp) {
     198                 :          0 :                         continue;
     199                 :            :                 }
     200                 :            : 
     201         [ +  + ]:      54158 :                 if (sscanf(str_start, "map_%d", &huge_index) != 1) {
     202                 :      23950 :                         continue;
     203                 :            :                 }
     204                 :            : 
     205         [ -  + ]:      30208 :                 if (idx >= max) {
     206                 :          0 :                         SPDK_ERRLOG("Exceed maximum of %d\n", max);
     207                 :          0 :                         rc = -ENOSPC;
     208                 :          0 :                         goto out;
     209                 :            :                 }
     210                 :            : 
     211         [ +  + ]:      30208 :                 if (idx > 0 &&
     212   [ -  +  -  +  :      30150 :                     strncmp(tmp, hugepages[idx - 1].path, PATH_MAX) == 0 &&
                   +  - ]
     213         [ +  - ]:      30150 :                     v_start == hugepages[idx - 1].addr + hugepages[idx - 1].size) {
     214                 :      30150 :                         hugepages[idx - 1].size += (v_end - v_start);
     215                 :      30150 :                         continue;
     216                 :            :                 }
     217                 :            : 
     218                 :         58 :                 hugepages[idx].addr = v_start;
     219                 :         58 :                 hugepages[idx].size = v_end - v_start;
     220                 :         58 :                 snprintf(hugepages[idx].path, PATH_MAX, "%s", tmp);
     221                 :         58 :                 idx++;
     222                 :            :         }
     223                 :            : 
     224                 :         58 :         rc = idx;
     225                 :         58 : out:
     226                 :         58 :         fclose(f);
     227                 :         58 :         return rc;
     228                 :            : }
     229                 :            : 
     230                 :            : static int
     231                 :         58 : prepare_vhost_memory_user(struct vhost_user_msg *msg, int fds[])
     232                 :            : {
     233                 :            :         int i, num;
     234                 :          0 :         struct hugepage_file_info hugepages[VHOST_USER_MEMORY_MAX_NREGIONS];
     235                 :            : 
     236                 :         58 :         num = get_hugepage_file_info(hugepages, VHOST_USER_MEMORY_MAX_NREGIONS);
     237         [ -  + ]:         58 :         if (num < 0) {
     238                 :          0 :                 SPDK_ERRLOG("Failed to prepare memory for vhost-user\n");
     239                 :          0 :                 return num;
     240                 :            :         }
     241                 :            : 
     242         [ +  + ]:        116 :         for (i = 0; i < num; ++i) {
     243                 :            :                 /* the memory regions are unaligned */
     244                 :         58 :                 msg->payload.memory.regions[i].guest_phys_addr = hugepages[i].addr; /* use vaddr! */
     245                 :         58 :                 msg->payload.memory.regions[i].userspace_addr = hugepages[i].addr;
     246                 :         58 :                 msg->payload.memory.regions[i].memory_size = hugepages[i].size;
     247                 :         58 :                 msg->payload.memory.regions[i].flags_padding = 0;
     248         [ -  + ]:         58 :                 fds[i] = open(hugepages[i].path, O_RDWR);
     249                 :            :         }
     250                 :            : 
     251                 :         58 :         msg->payload.memory.nregions = num;
     252                 :         58 :         msg->payload.memory.padding = 0;
     253                 :            : 
     254                 :         58 :         return 0;
     255                 :            : }
     256                 :            : 
     257                 :            : static const char *const vhost_msg_strings[VHOST_USER_MAX] = {
     258                 :            :         [VHOST_USER_SET_OWNER] = "VHOST_SET_OWNER",
     259                 :            :         [VHOST_USER_RESET_OWNER] = "VHOST_RESET_OWNER",
     260                 :            :         [VHOST_USER_SET_FEATURES] = "VHOST_SET_FEATURES",
     261                 :            :         [VHOST_USER_GET_FEATURES] = "VHOST_GET_FEATURES",
     262                 :            :         [VHOST_USER_SET_VRING_CALL] = "VHOST_SET_VRING_CALL",
     263                 :            :         [VHOST_USER_GET_PROTOCOL_FEATURES] = "VHOST_USER_GET_PROTOCOL_FEATURES",
     264                 :            :         [VHOST_USER_SET_PROTOCOL_FEATURES] = "VHOST_USER_SET_PROTOCOL_FEATURES",
     265                 :            :         [VHOST_USER_SET_VRING_NUM] = "VHOST_SET_VRING_NUM",
     266                 :            :         [VHOST_USER_SET_VRING_BASE] = "VHOST_SET_VRING_BASE",
     267                 :            :         [VHOST_USER_GET_VRING_BASE] = "VHOST_GET_VRING_BASE",
     268                 :            :         [VHOST_USER_SET_VRING_ADDR] = "VHOST_SET_VRING_ADDR",
     269                 :            :         [VHOST_USER_SET_VRING_KICK] = "VHOST_SET_VRING_KICK",
     270                 :            :         [VHOST_USER_SET_MEM_TABLE] = "VHOST_SET_MEM_TABLE",
     271                 :            :         [VHOST_USER_SET_VRING_ENABLE] = "VHOST_SET_VRING_ENABLE",
     272                 :            :         [VHOST_USER_GET_QUEUE_NUM] = "VHOST_USER_GET_QUEUE_NUM",
     273                 :            :         [VHOST_USER_GET_CONFIG] = "VHOST_USER_GET_CONFIG",
     274                 :            :         [VHOST_USER_SET_CONFIG] = "VHOST_USER_SET_CONFIG",
     275                 :            : };
     276                 :            : 
     277                 :            : static int
     278                 :       1549 : vhost_user_sock(struct virtio_user_dev *dev,
     279                 :            :                 enum vhost_user_request req,
     280                 :            :                 void *arg)
     281                 :            : {
     282                 :          0 :         struct vhost_user_msg msg;
     283                 :       1549 :         struct vhost_vring_file *file = 0;
     284                 :       1549 :         int need_reply = 0;
     285                 :          0 :         int fds[VHOST_USER_MEMORY_MAX_NREGIONS];
     286                 :       1549 :         int fd_num = 0;
     287                 :            :         int i, len, rc;
     288                 :       1549 :         int vhostfd = dev->vhostfd;
     289                 :            : 
     290   [ -  +  -  + ]:       1549 :         SPDK_DEBUGLOG(virtio_user, "sent message %d = %s\n", req, vhost_msg_strings[req]);
     291                 :            : 
     292                 :       1549 :         msg.request = req;
     293                 :       1549 :         msg.flags = VHOST_USER_VERSION;
     294                 :       1549 :         msg.size = 0;
     295                 :            : 
     296   [ +  +  +  +  :       1549 :         switch (req) {
          -  +  +  +  +  
                +  -  - ]
     297                 :        145 :         case VHOST_USER_GET_FEATURES:
     298                 :            :         case VHOST_USER_GET_PROTOCOL_FEATURES:
     299                 :            :         case VHOST_USER_GET_QUEUE_NUM:
     300                 :        145 :                 need_reply = 1;
     301                 :        145 :                 break;
     302                 :            : 
     303                 :         58 :         case VHOST_USER_SET_FEATURES:
     304                 :            :         case VHOST_USER_SET_LOG_BASE:
     305                 :            :         case VHOST_USER_SET_PROTOCOL_FEATURES:
     306                 :         58 :                 msg.payload.u64 = *((__u64 *)arg);
     307                 :         58 :                 msg.size = sizeof(msg.payload.u64);
     308                 :         58 :                 break;
     309                 :            : 
     310                 :         29 :         case VHOST_USER_SET_OWNER:
     311                 :            :         case VHOST_USER_RESET_OWNER:
     312                 :         29 :                 break;
     313                 :            : 
     314                 :         58 :         case VHOST_USER_SET_MEM_TABLE:
     315                 :         58 :                 rc = prepare_vhost_memory_user(&msg, fds);
     316         [ -  + ]:         58 :                 if (rc < 0) {
     317                 :          0 :                         return rc;
     318                 :            :                 }
     319                 :         58 :                 fd_num = msg.payload.memory.nregions;
     320                 :         58 :                 msg.size = sizeof(msg.payload.memory.nregions);
     321                 :         58 :                 msg.size += sizeof(msg.payload.memory.padding);
     322                 :         58 :                 msg.size += fd_num * sizeof(struct vhost_memory_region);
     323                 :         58 :                 break;
     324                 :            : 
     325                 :          0 :         case VHOST_USER_SET_LOG_FD:
     326                 :          0 :                 fds[fd_num++] = *((int *)arg);
     327                 :          0 :                 break;
     328                 :            : 
     329                 :        516 :         case VHOST_USER_SET_VRING_NUM:
     330                 :            :         case VHOST_USER_SET_VRING_BASE:
     331                 :            :         case VHOST_USER_SET_VRING_ENABLE:
     332                 :        516 :                 memcpy(&msg.payload.state, arg, sizeof(msg.payload.state));
     333                 :        516 :                 msg.size = sizeof(msg.payload.state);
     334                 :        516 :                 break;
     335                 :            : 
     336                 :        172 :         case VHOST_USER_GET_VRING_BASE:
     337                 :        172 :                 memcpy(&msg.payload.state, arg, sizeof(msg.payload.state));
     338                 :        172 :                 msg.size = sizeof(msg.payload.state);
     339                 :        172 :                 need_reply = 1;
     340                 :        172 :                 break;
     341                 :            : 
     342                 :        172 :         case VHOST_USER_SET_VRING_ADDR:
     343   [ -  +  -  + ]:        172 :                 memcpy(&msg.payload.addr, arg, sizeof(msg.payload.addr));
     344                 :        172 :                 msg.size = sizeof(msg.payload.addr);
     345                 :        172 :                 break;
     346                 :            : 
     347                 :        344 :         case VHOST_USER_SET_VRING_KICK:
     348                 :            :         case VHOST_USER_SET_VRING_CALL:
     349                 :            :         case VHOST_USER_SET_VRING_ERR:
     350                 :        344 :                 file = arg;
     351                 :        344 :                 msg.payload.u64 = file->index & VHOST_USER_VRING_IDX_MASK;
     352                 :        344 :                 msg.size = sizeof(msg.payload.u64);
     353         [ +  - ]:        344 :                 if (file->fd > 0) {
     354                 :        344 :                         fds[fd_num++] = file->fd;
     355                 :            :                 } else {
     356                 :          0 :                         msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
     357                 :            :                 }
     358                 :        344 :                 break;
     359                 :            : 
     360                 :         55 :         case VHOST_USER_GET_CONFIG:
     361   [ -  +  -  + ]:         55 :                 memcpy(&msg.payload.cfg, arg, sizeof(msg.payload.cfg));
     362                 :         55 :                 msg.size = sizeof(msg.payload.cfg);
     363                 :         55 :                 need_reply = 1;
     364                 :         55 :                 break;
     365                 :            : 
     366                 :          0 :         case VHOST_USER_SET_CONFIG:
     367   [ #  #  #  # ]:          0 :                 memcpy(&msg.payload.cfg, arg, sizeof(msg.payload.cfg));
     368                 :          0 :                 msg.size = sizeof(msg.payload.cfg);
     369                 :          0 :                 break;
     370                 :            : 
     371                 :          0 :         default:
     372                 :          0 :                 SPDK_ERRLOG("trying to send unknown msg\n");
     373                 :          0 :                 return -EINVAL;
     374                 :            :         }
     375                 :            : 
     376                 :       1549 :         len = VHOST_USER_HDR_SIZE + msg.size;
     377                 :       1549 :         rc = vhost_user_write(vhostfd, &msg, len, fds, fd_num);
     378         [ -  + ]:       1549 :         if (rc < 0) {
     379                 :          0 :                 SPDK_ERRLOG("%s failed: %s\n",
     380                 :            :                             vhost_msg_strings[req], spdk_strerror(-rc));
     381                 :          0 :                 return rc;
     382                 :            :         }
     383                 :            : 
     384         [ +  + ]:       1549 :         if (req == VHOST_USER_SET_MEM_TABLE)
     385         [ +  + ]:        116 :                 for (i = 0; i < fd_num; ++i) {
     386                 :         58 :                         close(fds[i]);
     387                 :            :                 }
     388                 :            : 
     389         [ +  + ]:       1549 :         if (need_reply) {
     390                 :        372 :                 rc = vhost_user_read(vhostfd, &msg);
     391         [ -  + ]:        372 :                 if (rc < 0) {
     392                 :          0 :                         SPDK_WARNLOG("Received msg failed: %s\n", spdk_strerror(-rc));
     393                 :          0 :                         return rc;
     394                 :            :                 }
     395                 :            : 
     396         [ -  + ]:        372 :                 if (req != msg.request) {
     397                 :          0 :                         SPDK_WARNLOG("Received unexpected msg type\n");
     398                 :          0 :                         return -EIO;
     399                 :            :                 }
     400                 :            : 
     401   [ +  +  +  - ]:        372 :                 switch (req) {
     402                 :        145 :                 case VHOST_USER_GET_FEATURES:
     403                 :            :                 case VHOST_USER_GET_PROTOCOL_FEATURES:
     404                 :            :                 case VHOST_USER_GET_QUEUE_NUM:
     405         [ -  + ]:        145 :                         if (msg.size != sizeof(msg.payload.u64)) {
     406                 :          0 :                                 SPDK_WARNLOG("Received bad msg size\n");
     407                 :          0 :                                 return -EIO;
     408                 :            :                         }
     409                 :        145 :                         *((__u64 *)arg) = msg.payload.u64;
     410                 :        145 :                         break;
     411                 :        172 :                 case VHOST_USER_GET_VRING_BASE:
     412         [ -  + ]:        172 :                         if (msg.size != sizeof(msg.payload.state)) {
     413                 :          0 :                                 SPDK_WARNLOG("Received bad msg size\n");
     414                 :          0 :                                 return -EIO;
     415                 :            :                         }
     416                 :        172 :                         memcpy(arg, &msg.payload.state,
     417                 :            :                                sizeof(struct vhost_vring_state));
     418                 :        172 :                         break;
     419                 :         55 :                 case VHOST_USER_GET_CONFIG:
     420         [ -  + ]:         55 :                         if (msg.size != sizeof(msg.payload.cfg)) {
     421                 :          0 :                                 SPDK_WARNLOG("Received bad msg size\n");
     422                 :          0 :                                 return -EIO;
     423                 :            :                         }
     424   [ -  +  -  + ]:         55 :                         memcpy(arg, &msg.payload.cfg, sizeof(msg.payload.cfg));
     425                 :         55 :                         break;
     426                 :          0 :                 default:
     427                 :          0 :                         SPDK_WARNLOG("Received unexpected msg type\n");
     428                 :          0 :                         return -EBADMSG;
     429                 :            :                 }
     430                 :          0 :         }
     431                 :            : 
     432                 :       1549 :         return 0;
     433                 :            : }
     434                 :            : 
     435                 :            : /**
     436                 :            :  * Set up environment to talk with a vhost user backend.
     437                 :            :  *
     438                 :            :  * @return
     439                 :            :  *   - (-1) if fail;
     440                 :            :  *   - (0) if succeed.
     441                 :            :  */
     442                 :            : static int
     443                 :         29 : vhost_user_setup(struct virtio_user_dev *dev)
     444                 :            : {
     445                 :            :         int fd;
     446                 :            :         int flag;
     447                 :          0 :         struct sockaddr_un un;
     448                 :            :         ssize_t rc;
     449                 :            : 
     450                 :         29 :         fd = socket(AF_UNIX, SOCK_STREAM, 0);
     451         [ -  + ]:         29 :         if (fd < 0) {
     452                 :          0 :                 SPDK_ERRLOG("socket() error, %s\n", spdk_strerror(errno));
     453                 :          0 :                 return -errno;
     454                 :            :         }
     455                 :            : 
     456                 :         29 :         flag = fcntl(fd, F_GETFD);
     457         [ -  + ]:         29 :         if (fcntl(fd, F_SETFD, flag | FD_CLOEXEC) < 0) {
     458                 :          0 :                 SPDK_ERRLOG("fcntl failed, %s\n", spdk_strerror(errno));
     459                 :            :         }
     460                 :            : 
     461                 :         29 :         memset(&un, 0, sizeof(un));
     462                 :         29 :         un.sun_family = AF_UNIX;
     463                 :         29 :         rc = snprintf(un.sun_path, sizeof(un.sun_path), "%s", dev->path);
     464   [ +  -  -  + ]:         29 :         if (rc < 0 || (size_t)rc >= sizeof(un.sun_path)) {
     465                 :          0 :                 SPDK_ERRLOG("socket path too long\n");
     466                 :          0 :                 close(fd);
     467         [ #  # ]:          0 :                 if (rc < 0) {
     468                 :          0 :                         return -errno;
     469                 :            :                 } else {
     470                 :          0 :                         return -EINVAL;
     471                 :            :                 }
     472                 :            :         }
     473         [ -  + ]:         29 :         if (connect(fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
     474                 :          0 :                 SPDK_ERRLOG("connect error, %s\n", spdk_strerror(errno));
     475                 :          0 :                 close(fd);
     476                 :          0 :                 return -errno;
     477                 :            :         }
     478                 :            : 
     479                 :         29 :         dev->vhostfd = fd;
     480                 :         29 :         return 0;
     481                 :            : }
     482                 :            : 
     483                 :            : static int
     484                 :        172 : virtio_user_create_queue(struct virtio_dev *vdev, uint32_t queue_sel)
     485                 :            : {
     486                 :        172 :         struct virtio_user_dev *dev = vdev->ctx;
     487                 :            : 
     488                 :            :         /* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come
     489                 :            :          * firstly because vhost depends on this msg to allocate virtqueue
     490                 :            :          * pair.
     491                 :            :          */
     492                 :          0 :         struct vhost_vring_file file;
     493                 :            : 
     494                 :        172 :         file.index = queue_sel;
     495                 :        172 :         file.fd = dev->callfds[queue_sel];
     496                 :        172 :         return vhost_user_sock(dev, VHOST_USER_SET_VRING_CALL, &file);
     497                 :            : }
     498                 :            : 
     499                 :            : static int
     500                 :        172 : virtio_user_set_vring_addr(struct virtio_dev *vdev, uint32_t queue_sel)
     501                 :            : {
     502                 :        172 :         struct virtio_user_dev *dev = vdev->ctx;
     503                 :        172 :         struct vring *vring = &dev->vrings[queue_sel];
     504                 :        688 :         struct vhost_vring_addr addr = {
     505                 :            :                 .index = queue_sel,
     506                 :        172 :                 .desc_user_addr = (uint64_t)(uintptr_t)vring->desc,
     507                 :        172 :                 .avail_user_addr = (uint64_t)(uintptr_t)vring->avail,
     508                 :        172 :                 .used_user_addr = (uint64_t)(uintptr_t)vring->used,
     509                 :            :                 .log_guest_addr = 0,
     510                 :            :                 .flags = 0, /* disable log */
     511                 :            :         };
     512                 :            : 
     513                 :        172 :         return vhost_user_sock(dev, VHOST_USER_SET_VRING_ADDR, &addr);
     514                 :            : }
     515                 :            : 
     516                 :            : static int
     517                 :        172 : virtio_user_kick_queue(struct virtio_dev *vdev, uint32_t queue_sel)
     518                 :            : {
     519                 :        172 :         struct virtio_user_dev *dev = vdev->ctx;
     520                 :          0 :         struct vhost_vring_file file;
     521                 :          0 :         struct vhost_vring_state state;
     522                 :        172 :         struct vring *vring = &dev->vrings[queue_sel];
     523                 :            :         int rc;
     524                 :            : 
     525                 :        172 :         state.index = queue_sel;
     526                 :        172 :         state.num = vring->num;
     527                 :        172 :         rc = vhost_user_sock(dev, VHOST_USER_SET_VRING_NUM, &state);
     528         [ -  + ]:        172 :         if (rc < 0) {
     529                 :          0 :                 return rc;
     530                 :            :         }
     531                 :            : 
     532                 :        172 :         state.index = queue_sel;
     533                 :        172 :         state.num = 0; /* no reservation */
     534                 :        172 :         rc = vhost_user_sock(dev, VHOST_USER_SET_VRING_BASE, &state);
     535         [ -  + ]:        172 :         if (rc < 0) {
     536                 :          0 :                 return rc;
     537                 :            :         }
     538                 :            : 
     539                 :        172 :         virtio_user_set_vring_addr(vdev, queue_sel);
     540                 :            : 
     541                 :            :         /* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes
     542                 :            :          * lastly because vhost depends on this msg to judge if
     543                 :            :          * virtio is ready.
     544                 :            :          */
     545                 :        172 :         file.index = queue_sel;
     546                 :        172 :         file.fd = dev->kickfds[queue_sel];
     547                 :        172 :         return vhost_user_sock(dev, VHOST_USER_SET_VRING_KICK, &file);
     548                 :            : }
     549                 :            : 
     550                 :            : static int
     551                 :        172 : virtio_user_stop_queue(struct virtio_dev *vdev, uint32_t queue_sel)
     552                 :            : {
     553                 :        172 :         struct virtio_user_dev *dev = vdev->ctx;
     554                 :          0 :         struct vhost_vring_state state;
     555                 :            : 
     556                 :        172 :         state.index = queue_sel;
     557                 :        172 :         state.num = 0;
     558                 :            : 
     559                 :        172 :         return vhost_user_sock(dev, VHOST_USER_GET_VRING_BASE, &state);
     560                 :            : }
     561                 :            : 
     562                 :            : static int
     563                 :         87 : virtio_user_queue_setup(struct virtio_dev *vdev,
     564                 :            :                         int (*fn)(struct virtio_dev *, uint32_t))
     565                 :            : {
     566                 :            :         uint32_t i;
     567                 :            :         int rc;
     568                 :            : 
     569         [ +  + ]:        603 :         for (i = 0; i < vdev->max_queues; ++i) {
     570                 :        516 :                 rc = fn(vdev, i);
     571         [ -  + ]:        516 :                 if (rc < 0) {
     572                 :          0 :                         SPDK_ERRLOG("setup tx vq fails: %"PRIu32".\n", i);
     573                 :          0 :                         return rc;
     574                 :            :                 }
     575                 :            :         }
     576                 :            : 
     577                 :         87 :         return 0;
     578                 :            : }
     579                 :            : 
     580                 :            : static int
     581                 :         58 : virtio_user_map_notify(void *cb_ctx, struct spdk_mem_map *map,
     582                 :            :                        enum spdk_mem_map_notify_action action,
     583                 :            :                        void *vaddr, size_t size)
     584                 :            : {
     585                 :         58 :         struct virtio_dev *vdev = cb_ctx;
     586                 :         58 :         struct virtio_user_dev *dev = vdev->ctx;
     587                 :          0 :         uint64_t features;
     588                 :            :         int ret;
     589                 :            : 
     590                 :            :         /* We do not support dynamic memory allocation with virtio-user.  If this is the
     591                 :            :          * initial notification when the device is started, dev->mem_map will be NULL.  If
     592                 :            :          * this is the final notification when the device is stopped, dev->is_stopping will
     593                 :            :          * be true.  All other cases are unsupported.
     594                 :            :          */
     595   [ +  +  -  +  :         58 :         if (dev->mem_map != NULL && !dev->is_stopping) {
                   -  + ]
     596                 :          0 :                 assert(false);
     597                 :            :                 SPDK_ERRLOG("Memory map change with active virtio_user_devs not allowed.\n");
     598                 :            :                 SPDK_ERRLOG("Pre-allocate memory for application using -s (mem_size) option.\n");
     599                 :            :                 return -1;
     600                 :            :         }
     601                 :            : 
     602                 :            :         /* We have to resend all mappings anyway, so don't bother with any
     603                 :            :          * page tracking.
     604                 :            :          */
     605                 :         58 :         ret = vhost_user_sock(dev, VHOST_USER_SET_MEM_TABLE, NULL);
     606         [ -  + ]:         58 :         if (ret < 0) {
     607                 :          0 :                 return ret;
     608                 :            :         }
     609                 :            : 
     610                 :            :         /* Since we might want to use that mapping straight away, we have to
     611                 :            :          * make sure the guest has already processed our SET_MEM_TABLE message.
     612                 :            :          * F_REPLY_ACK is just a feature and the host is not obliged to
     613                 :            :          * support it, so we send a simple message that always has a response
     614                 :            :          * and we wait for that response. Messages are always processed in order.
     615                 :            :          */
     616                 :         58 :         return vhost_user_sock(dev, VHOST_USER_GET_FEATURES, &features);
     617                 :            : }
     618                 :            : 
     619                 :            : static int
     620                 :         29 : virtio_user_register_mem(struct virtio_dev *vdev)
     621                 :            : {
     622                 :         29 :         struct virtio_user_dev *dev = vdev->ctx;
     623                 :         29 :         const struct spdk_mem_map_ops virtio_user_map_ops = {
     624                 :            :                 .notify_cb = virtio_user_map_notify,
     625                 :            :                 .are_contiguous = NULL
     626                 :            :         };
     627                 :            : 
     628                 :         29 :         dev->mem_map = spdk_mem_map_alloc(0, &virtio_user_map_ops, vdev);
     629         [ -  + ]:         29 :         if (dev->mem_map == NULL) {
     630                 :          0 :                 SPDK_ERRLOG("spdk_mem_map_alloc() failed\n");
     631                 :          0 :                 return -1;
     632                 :            :         }
     633                 :            : 
     634                 :         29 :         return 0;
     635                 :            : }
     636                 :            : 
     637                 :            : static void
     638                 :         29 : virtio_user_unregister_mem(struct virtio_dev *vdev)
     639                 :            : {
     640                 :         29 :         struct virtio_user_dev *dev = vdev->ctx;
     641                 :            : 
     642                 :         29 :         dev->is_stopping = true;
     643                 :         29 :         spdk_mem_map_free(&dev->mem_map);
     644                 :         29 : }
     645                 :            : 
     646                 :            : static int
     647                 :         29 : virtio_user_start_device(struct virtio_dev *vdev)
     648                 :            : {
     649                 :         29 :         struct virtio_user_dev *dev = vdev->ctx;
     650                 :          0 :         uint64_t host_max_queues;
     651                 :            :         int ret;
     652                 :            : 
     653         [ -  + ]:         29 :         if ((dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) == 0 &&
     654         [ #  # ]:          0 :             vdev->max_queues > 1 + vdev->fixed_queues_num) {
     655                 :          0 :                 SPDK_WARNLOG("%s: requested %"PRIu16" request queues, but the "
     656                 :            :                              "host doesn't support VHOST_USER_PROTOCOL_F_MQ. "
     657                 :            :                              "Only one request queue will be used.\n",
     658                 :            :                              vdev->name, vdev->max_queues - vdev->fixed_queues_num);
     659                 :          0 :                 vdev->max_queues = 1 + vdev->fixed_queues_num;
     660                 :            :         }
     661                 :            : 
     662                 :            :         /* negotiate the number of I/O queues. */
     663                 :         29 :         ret = vhost_user_sock(dev, VHOST_USER_GET_QUEUE_NUM, &host_max_queues);
     664         [ -  + ]:         29 :         if (ret < 0) {
     665                 :          0 :                 return ret;
     666                 :            :         }
     667                 :            : 
     668         [ -  + ]:         29 :         if (vdev->max_queues > host_max_queues + vdev->fixed_queues_num) {
     669                 :          0 :                 SPDK_WARNLOG("%s: requested %"PRIu16" request queues"
     670                 :            :                              "but only %"PRIu64" available\n",
     671                 :            :                              vdev->name, vdev->max_queues - vdev->fixed_queues_num,
     672                 :            :                              host_max_queues);
     673                 :          0 :                 vdev->max_queues = host_max_queues;
     674                 :            :         }
     675                 :            : 
     676                 :            :         /* tell vhost to create queues */
     677                 :         29 :         ret = virtio_user_queue_setup(vdev, virtio_user_create_queue);
     678         [ -  + ]:         29 :         if (ret < 0) {
     679                 :          0 :                 return ret;
     680                 :            :         }
     681                 :            : 
     682                 :         29 :         ret = virtio_user_register_mem(vdev);
     683         [ -  + ]:         29 :         if (ret < 0) {
     684                 :          0 :                 return ret;
     685                 :            :         }
     686                 :            : 
     687                 :         29 :         return virtio_user_queue_setup(vdev, virtio_user_kick_queue);
     688                 :            : }
     689                 :            : 
     690                 :            : static int
     691                 :         29 : virtio_user_stop_device(struct virtio_dev *vdev)
     692                 :            : {
     693                 :            :         int ret;
     694                 :            : 
     695                 :         29 :         ret = virtio_user_queue_setup(vdev, virtio_user_stop_queue);
     696                 :            :         /* a queue might fail to stop for various reasons, e.g. socket
     697                 :            :          * connection going down, but this mustn't prevent us from freeing
     698                 :            :          * the mem map.
     699                 :            :          */
     700                 :         29 :         virtio_user_unregister_mem(vdev);
     701                 :         29 :         return ret;
     702                 :            : }
     703                 :            : 
     704                 :            : static int
     705                 :         29 : virtio_user_dev_setup(struct virtio_dev *vdev)
     706                 :            : {
     707                 :         29 :         struct virtio_user_dev *dev = vdev->ctx;
     708                 :            :         uint16_t i;
     709                 :            : 
     710                 :         29 :         dev->vhostfd = -1;
     711                 :            : 
     712         [ +  + ]:       7453 :         for (i = 0; i < SPDK_VIRTIO_MAX_VIRTQUEUES; ++i) {
     713                 :       7424 :                 dev->callfds[i] = -1;
     714                 :       7424 :                 dev->kickfds[i] = -1;
     715                 :            :         }
     716                 :            : 
     717                 :         29 :         return vhost_user_setup(dev);
     718                 :            : }
     719                 :            : 
     720                 :            : static int
     721                 :         55 : virtio_user_read_dev_config(struct virtio_dev *vdev, size_t offset,
     722                 :            :                             void *dst, int length)
     723                 :            : {
     724                 :         55 :         struct virtio_user_dev *dev = vdev->ctx;
     725                 :         55 :         struct vhost_user_config cfg = {0};
     726                 :            :         int rc;
     727                 :            : 
     728         [ -  + ]:         55 :         if ((dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_CONFIG)) == 0) {
     729                 :          0 :                 return -ENOTSUP;
     730                 :            :         }
     731                 :            : 
     732                 :         55 :         cfg.offset = 0;
     733                 :         55 :         cfg.size = VHOST_USER_MAX_CONFIG_SIZE;
     734                 :            : 
     735                 :         55 :         rc = vhost_user_sock(dev, VHOST_USER_GET_CONFIG, &cfg);
     736         [ -  + ]:         55 :         if (rc < 0) {
     737                 :          0 :                 SPDK_ERRLOG("get_config failed: %s\n", spdk_strerror(-rc));
     738                 :          0 :                 return rc;
     739                 :            :         }
     740                 :            : 
     741   [ -  +  -  + ]:         55 :         memcpy(dst, cfg.region + offset, length);
     742                 :         55 :         return 0;
     743                 :            : }
     744                 :            : 
     745                 :            : static int
     746                 :          0 : virtio_user_write_dev_config(struct virtio_dev *vdev, size_t offset,
     747                 :            :                              const void *src, int length)
     748                 :            : {
     749                 :          0 :         struct virtio_user_dev *dev = vdev->ctx;
     750                 :          0 :         struct vhost_user_config cfg = {0};
     751                 :            :         int rc;
     752                 :            : 
     753         [ #  # ]:          0 :         if ((dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_CONFIG)) == 0) {
     754                 :          0 :                 return -ENOTSUP;
     755                 :            :         }
     756                 :            : 
     757                 :          0 :         cfg.offset = offset;
     758                 :          0 :         cfg.size = length;
     759   [ #  #  #  # ]:          0 :         memcpy(cfg.region, src, length);
     760                 :            : 
     761                 :          0 :         rc = vhost_user_sock(dev, VHOST_USER_SET_CONFIG, &cfg);
     762         [ #  # ]:          0 :         if (rc < 0) {
     763                 :          0 :                 SPDK_ERRLOG("set_config failed: %s\n", spdk_strerror(-rc));
     764                 :          0 :                 return rc;
     765                 :            :         }
     766                 :            : 
     767                 :          0 :         return 0;
     768                 :            : }
     769                 :            : 
     770                 :            : static void
     771                 :        174 : virtio_user_set_status(struct virtio_dev *vdev, uint8_t status)
     772                 :            : {
     773                 :        174 :         struct virtio_user_dev *dev = vdev->ctx;
     774                 :        174 :         int rc = 0;
     775                 :            : 
     776   [ -  +  -  - ]:        174 :         if ((dev->status & VIRTIO_CONFIG_S_NEEDS_RESET) &&
     777                 :            :             status != VIRTIO_CONFIG_S_RESET) {
     778                 :          0 :                 rc = -1;
     779         [ +  + ]:        174 :         } else if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
     780                 :         29 :                 rc = virtio_user_start_device(vdev);
     781         [ +  + ]:        145 :         } else if (status == VIRTIO_CONFIG_S_RESET &&
     782         [ +  + ]:         58 :                    (dev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
     783                 :         29 :                 rc = virtio_user_stop_device(vdev);
     784                 :            :         }
     785                 :            : 
     786         [ -  + ]:        174 :         if (rc != 0) {
     787                 :          0 :                 dev->status |= VIRTIO_CONFIG_S_NEEDS_RESET;
     788                 :            :         } else {
     789                 :        174 :                 dev->status = status;
     790                 :            :         }
     791                 :        174 : }
     792                 :            : 
     793                 :            : static uint8_t
     794                 :        290 : virtio_user_get_status(struct virtio_dev *vdev)
     795                 :            : {
     796                 :        290 :         struct virtio_user_dev *dev = vdev->ctx;
     797                 :            : 
     798                 :        290 :         return dev->status;
     799                 :            : }
     800                 :            : 
     801                 :            : static uint64_t
     802                 :         29 : virtio_user_get_features(struct virtio_dev *vdev)
     803                 :            : {
     804                 :         29 :         struct virtio_user_dev *dev = vdev->ctx;
     805                 :          0 :         uint64_t features;
     806                 :            :         int rc;
     807                 :            : 
     808                 :         29 :         rc = vhost_user_sock(dev, VHOST_USER_GET_FEATURES, &features);
     809         [ -  + ]:         29 :         if (rc < 0) {
     810                 :          0 :                 SPDK_ERRLOG("get_features failed: %s\n", spdk_strerror(-rc));
     811                 :          0 :                 return 0;
     812                 :            :         }
     813                 :            : 
     814                 :         29 :         return features;
     815                 :            : }
     816                 :            : 
     817                 :            : static int
     818                 :         29 : virtio_user_set_features(struct virtio_dev *vdev, uint64_t features)
     819                 :            : {
     820                 :         29 :         struct virtio_user_dev *dev = vdev->ctx;
     821                 :          0 :         uint64_t protocol_features;
     822                 :            :         int ret;
     823                 :            : 
     824                 :         29 :         ret = vhost_user_sock(dev, VHOST_USER_SET_FEATURES, &features);
     825         [ -  + ]:         29 :         if (ret < 0) {
     826                 :          0 :                 return ret;
     827                 :            :         }
     828                 :            : 
     829                 :         29 :         vdev->negotiated_features = features;
     830                 :         29 :         vdev->modern = virtio_dev_has_feature(vdev, VIRTIO_F_VERSION_1);
     831                 :            : 
     832         [ -  + ]:         29 :         if (!virtio_dev_has_feature(vdev, VHOST_USER_F_PROTOCOL_FEATURES)) {
     833                 :            :                 /* nothing else to do */
     834                 :          0 :                 return 0;
     835                 :            :         }
     836                 :            : 
     837                 :         29 :         ret = vhost_user_sock(dev, VHOST_USER_GET_PROTOCOL_FEATURES, &protocol_features);
     838         [ -  + ]:         29 :         if (ret < 0) {
     839                 :          0 :                 return ret;
     840                 :            :         }
     841                 :            : 
     842                 :         29 :         protocol_features &= VIRTIO_USER_SUPPORTED_PROTOCOL_FEATURES;
     843                 :         29 :         ret = vhost_user_sock(dev, VHOST_USER_SET_PROTOCOL_FEATURES, &protocol_features);
     844         [ -  + ]:         29 :         if (ret < 0) {
     845                 :          0 :                 return ret;
     846                 :            :         }
     847                 :            : 
     848                 :         29 :         dev->protocol_features = protocol_features;
     849                 :         29 :         return 0;
     850                 :            : }
     851                 :            : 
     852                 :            : static uint16_t
     853                 :        268 : virtio_user_get_queue_size(struct virtio_dev *vdev, uint16_t queue_id)
     854                 :            : {
     855                 :        268 :         struct virtio_user_dev *dev = vdev->ctx;
     856                 :            : 
     857                 :            :         /* Currently each queue has same queue size */
     858                 :        268 :         return dev->queue_size;
     859                 :            : }
     860                 :            : 
     861                 :            : static int
     862                 :        172 : virtio_user_setup_queue(struct virtio_dev *vdev, struct virtqueue *vq)
     863                 :            : {
     864                 :        172 :         struct virtio_user_dev *dev = vdev->ctx;
     865                 :          0 :         struct vhost_vring_state state;
     866                 :        172 :         uint16_t queue_idx = vq->vq_queue_index;
     867                 :            :         void *queue_mem;
     868                 :            :         uint64_t desc_addr, avail_addr, used_addr;
     869                 :            :         int callfd, kickfd, rc;
     870                 :            : 
     871   [ +  -  -  + ]:        172 :         if (dev->callfds[queue_idx] != -1 || dev->kickfds[queue_idx] != -1) {
     872                 :          0 :                 SPDK_ERRLOG("queue %"PRIu16" already exists\n", queue_idx);
     873                 :          0 :                 return -EEXIST;
     874                 :            :         }
     875                 :            : 
     876                 :            :         /* May use invalid flag, but some backend uses kickfd and
     877                 :            :          * callfd as criteria to judge if dev is alive. so finally we
     878                 :            :          * use real event_fd.
     879                 :            :          */
     880                 :        172 :         callfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
     881         [ -  + ]:        172 :         if (callfd < 0) {
     882                 :          0 :                 SPDK_ERRLOG("callfd error, %s\n", spdk_strerror(errno));
     883                 :          0 :                 return -errno;
     884                 :            :         }
     885                 :            : 
     886                 :        172 :         kickfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
     887         [ -  + ]:        172 :         if (kickfd < 0) {
     888                 :          0 :                 SPDK_ERRLOG("kickfd error, %s\n", spdk_strerror(errno));
     889                 :          0 :                 close(callfd);
     890                 :          0 :                 return -errno;
     891                 :            :         }
     892                 :            : 
     893                 :        172 :         queue_mem = spdk_zmalloc(vq->vq_ring_size, VIRTIO_PCI_VRING_ALIGN, NULL,
     894                 :            :                                  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
     895         [ -  + ]:        172 :         if (queue_mem == NULL) {
     896                 :          0 :                 close(kickfd);
     897                 :          0 :                 close(callfd);
     898                 :          0 :                 return -ENOMEM;
     899                 :            :         }
     900                 :            : 
     901                 :        172 :         vq->vq_ring_mem = SPDK_VTOPHYS_ERROR;
     902                 :        172 :         vq->vq_ring_virt_mem = queue_mem;
     903                 :            : 
     904                 :        172 :         state.index = vq->vq_queue_index;
     905                 :        172 :         state.num = 1;
     906                 :            : 
     907         [ +  - ]:        172 :         if (virtio_dev_has_feature(vdev, VHOST_USER_F_PROTOCOL_FEATURES)) {
     908                 :        172 :                 rc = vhost_user_sock(dev, VHOST_USER_SET_VRING_ENABLE, &state);
     909         [ -  + ]:        172 :                 if (rc < 0) {
     910                 :          0 :                         SPDK_ERRLOG("failed to send VHOST_USER_SET_VRING_ENABLE: %s\n",
     911                 :            :                                     spdk_strerror(-rc));
     912                 :          0 :                         close(kickfd);
     913                 :          0 :                         close(callfd);
     914                 :          0 :                         spdk_free(queue_mem);
     915                 :          0 :                         return -rc;
     916                 :            :                 }
     917                 :            :         }
     918                 :            : 
     919                 :        172 :         dev->callfds[queue_idx] = callfd;
     920                 :        172 :         dev->kickfds[queue_idx] = kickfd;
     921                 :            : 
     922                 :        172 :         desc_addr = (uintptr_t)vq->vq_ring_virt_mem;
     923                 :        172 :         avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
     924                 :        172 :         used_addr = SPDK_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
     925                 :            :                                     ring[vq->vq_nentries]),
     926                 :            :                                     VIRTIO_PCI_VRING_ALIGN);
     927                 :            : 
     928                 :        172 :         dev->vrings[queue_idx].num = vq->vq_nentries;
     929                 :        172 :         dev->vrings[queue_idx].desc = (void *)(uintptr_t)desc_addr;
     930                 :        172 :         dev->vrings[queue_idx].avail = (void *)(uintptr_t)avail_addr;
     931                 :        172 :         dev->vrings[queue_idx].used = (void *)(uintptr_t)used_addr;
     932                 :            : 
     933                 :        172 :         return 0;
     934                 :            : }
     935                 :            : 
     936                 :            : static void
     937                 :        172 : virtio_user_del_queue(struct virtio_dev *vdev, struct virtqueue *vq)
     938                 :            : {
     939                 :            :         /* For legacy devices, write 0 to VIRTIO_PCI_QUEUE_PFN port, QEMU
     940                 :            :          * correspondingly stops the ioeventfds, and reset the status of
     941                 :            :          * the device.
     942                 :            :          * For modern devices, set queue desc, avail, used in PCI bar to 0,
     943                 :            :          * not see any more behavior in QEMU.
     944                 :            :          *
     945                 :            :          * Here we just care about what information to deliver to vhost-user.
     946                 :            :          * So we just close ioeventfd for now.
     947                 :            :          */
     948                 :        172 :         struct virtio_user_dev *dev = vdev->ctx;
     949                 :            : 
     950                 :        172 :         close(dev->callfds[vq->vq_queue_index]);
     951                 :        172 :         close(dev->kickfds[vq->vq_queue_index]);
     952                 :        172 :         dev->callfds[vq->vq_queue_index] = -1;
     953                 :        172 :         dev->kickfds[vq->vq_queue_index] = -1;
     954                 :            : 
     955                 :        172 :         spdk_free(vq->vq_ring_virt_mem);
     956                 :        172 : }
     957                 :            : 
     958                 :            : static void
     959                 :        217 : virtio_user_notify_queue(struct virtio_dev *vdev, struct virtqueue *vq)
     960                 :            : {
     961                 :        217 :         uint64_t buf = 1;
     962                 :        217 :         struct virtio_user_dev *dev = vdev->ctx;
     963                 :            : 
     964         [ -  + ]:        217 :         if (write(dev->kickfds[vq->vq_queue_index], &buf, sizeof(buf)) < 0) {
     965                 :          0 :                 SPDK_ERRLOG("failed to kick backend: %s.\n", spdk_strerror(errno));
     966                 :            :         }
     967                 :        217 : }
     968                 :            : 
     969                 :            : static void
     970                 :         29 : virtio_user_destroy(struct virtio_dev *vdev)
     971                 :            : {
     972                 :         29 :         struct virtio_user_dev *dev = vdev->ctx;
     973                 :            : 
     974         [ +  - ]:         29 :         if (dev) {
     975                 :         29 :                 close(dev->vhostfd);
     976                 :         29 :                 free(dev);
     977                 :            :         }
     978                 :         29 : }
     979                 :            : 
     980                 :            : static void
     981                 :         85 : virtio_user_dump_json_info(struct virtio_dev *vdev, struct spdk_json_write_ctx *w)
     982                 :            : {
     983                 :         85 :         struct virtio_user_dev *dev = vdev->ctx;
     984                 :            : 
     985                 :         85 :         spdk_json_write_named_string(w, "type", "user");
     986                 :         85 :         spdk_json_write_named_string(w, "socket", dev->path);
     987                 :         85 : }
     988                 :            : 
     989                 :            : static void
     990                 :         11 : virtio_user_write_json_config(struct virtio_dev *vdev, struct spdk_json_write_ctx *w)
     991                 :            : {
     992                 :         11 :         struct virtio_user_dev *dev = vdev->ctx;
     993                 :            : 
     994                 :         11 :         spdk_json_write_named_string(w, "trtype", "user");
     995                 :         11 :         spdk_json_write_named_string(w, "traddr", dev->path);
     996                 :         11 :         spdk_json_write_named_uint32(w, "vq_count", vdev->max_queues - vdev->fixed_queues_num);
     997                 :         11 :         spdk_json_write_named_uint32(w, "vq_size", virtio_dev_backend_ops(vdev)->get_queue_size(vdev, 0));
     998                 :         11 : }
     999                 :            : 
    1000                 :            : static const struct virtio_dev_ops virtio_user_ops = {
    1001                 :            :         .read_dev_cfg   = virtio_user_read_dev_config,
    1002                 :            :         .write_dev_cfg  = virtio_user_write_dev_config,
    1003                 :            :         .get_status     = virtio_user_get_status,
    1004                 :            :         .set_status     = virtio_user_set_status,
    1005                 :            :         .get_features   = virtio_user_get_features,
    1006                 :            :         .set_features   = virtio_user_set_features,
    1007                 :            :         .destruct_dev   = virtio_user_destroy,
    1008                 :            :         .get_queue_size = virtio_user_get_queue_size,
    1009                 :            :         .setup_queue    = virtio_user_setup_queue,
    1010                 :            :         .del_queue      = virtio_user_del_queue,
    1011                 :            :         .notify_queue   = virtio_user_notify_queue,
    1012                 :            :         .dump_json_info = virtio_user_dump_json_info,
    1013                 :            :         .write_json_config = virtio_user_write_json_config,
    1014                 :            : };
    1015                 :            : 
    1016                 :            : int
    1017                 :         29 : virtio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *path,
    1018                 :            :                      uint32_t queue_size)
    1019                 :            : {
    1020                 :            :         struct virtio_user_dev *dev;
    1021                 :            :         int rc;
    1022                 :            : 
    1023         [ -  + ]:         29 :         if (name == NULL) {
    1024                 :          0 :                 SPDK_ERRLOG("No name gived for controller: %s\n", path);
    1025                 :          0 :                 return -EINVAL;
    1026                 :            :         }
    1027                 :            : 
    1028                 :         29 :         dev = calloc(1, sizeof(*dev));
    1029         [ -  + ]:         29 :         if (dev == NULL) {
    1030                 :          0 :                 return -ENOMEM;
    1031                 :            :         }
    1032                 :            : 
    1033                 :         29 :         rc = virtio_dev_construct(vdev, name, &virtio_user_ops, dev);
    1034         [ -  + ]:         29 :         if (rc != 0) {
    1035                 :          0 :                 SPDK_ERRLOG("Failed to init device: %s\n", path);
    1036                 :          0 :                 free(dev);
    1037                 :          0 :                 return rc;
    1038                 :            :         }
    1039                 :            : 
    1040                 :         29 :         vdev->is_hw = 0;
    1041                 :            : 
    1042         [ -  + ]:         29 :         snprintf(dev->path, PATH_MAX, "%s", path);
    1043                 :         29 :         dev->queue_size = queue_size;
    1044                 :            : 
    1045                 :         29 :         rc = virtio_user_dev_setup(vdev);
    1046         [ -  + ]:         29 :         if (rc < 0) {
    1047                 :          0 :                 SPDK_ERRLOG("backend set up fails\n");
    1048                 :          0 :                 goto err;
    1049                 :            :         }
    1050                 :            : 
    1051                 :         29 :         rc = vhost_user_sock(dev, VHOST_USER_SET_OWNER, NULL);
    1052         [ -  + ]:         29 :         if (rc < 0) {
    1053                 :          0 :                 SPDK_ERRLOG("set_owner fails: %s\n", spdk_strerror(-rc));
    1054                 :          0 :                 goto err;
    1055                 :            :         }
    1056                 :            : 
    1057                 :         29 :         return 0;
    1058                 :            : 
    1059                 :          0 : err:
    1060                 :          0 :         virtio_dev_destruct(vdev);
    1061                 :          0 :         return rc;
    1062                 :            : }
    1063                 :       2375 : SPDK_LOG_REGISTER_COMPONENT(virtio_user)

Generated by: LCOV version 1.14