LCOV - code coverage report
Current view: top level - spdk/lib/vhost - vhost_blk.c (source / functions) Hit Total Coverage
Test: Combined Lines: 553 987 56.0 %
Date: 2024-07-15 00:06:18 Functions: 55 78 70.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 218 585 37.3 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <linux/virtio_blk.h>
       7                 :            : 
       8                 :            : #include "spdk/env.h"
       9                 :            : #include "spdk/bdev.h"
      10                 :            : #include "spdk/bdev_module.h"
      11                 :            : #include "spdk/thread.h"
      12                 :            : #include "spdk/likely.h"
      13                 :            : #include "spdk/string.h"
      14                 :            : #include "spdk/util.h"
      15                 :            : #include "spdk/vhost.h"
      16                 :            : #include "spdk/json.h"
      17                 :            : 
      18                 :            : #include "vhost_internal.h"
      19                 :            : #include <rte_version.h>
      20                 :            : 
      21                 :            : /* Minimal set of features supported by every SPDK VHOST-BLK device */
      22                 :            : #define SPDK_VHOST_BLK_FEATURES_BASE (SPDK_VHOST_FEATURES | \
      23                 :            :                 (1ULL << VIRTIO_BLK_F_SIZE_MAX) | (1ULL << VIRTIO_BLK_F_SEG_MAX) | \
      24                 :            :                 (1ULL << VIRTIO_BLK_F_GEOMETRY) | (1ULL << VIRTIO_BLK_F_BLK_SIZE) | \
      25                 :            :                 (1ULL << VIRTIO_BLK_F_TOPOLOGY) | (1ULL << VIRTIO_BLK_F_BARRIER)  | \
      26                 :            :                 (1ULL << VIRTIO_BLK_F_SCSI)     | (1ULL << VIRTIO_BLK_F_CONFIG_WCE) | \
      27                 :            :                 (1ULL << VIRTIO_BLK_F_MQ))
      28                 :            : 
      29                 :            : /* Not supported features */
      30                 :            : #define SPDK_VHOST_BLK_DISABLED_FEATURES (SPDK_VHOST_DISABLED_FEATURES | \
      31                 :            :                 (1ULL << VIRTIO_BLK_F_GEOMETRY) | (1ULL << VIRTIO_BLK_F_CONFIG_WCE) | \
      32                 :            :                 (1ULL << VIRTIO_BLK_F_BARRIER)  | (1ULL << VIRTIO_BLK_F_SCSI))
      33                 :            : 
      34                 :            : /* Vhost-blk support protocol features */
      35                 :            : #define SPDK_VHOST_BLK_PROTOCOL_FEATURES ((1ULL << VHOST_USER_PROTOCOL_F_CONFIG) | \
      36                 :            :                 (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))
      37                 :            : 
      38                 :            : #define VIRTIO_BLK_DEFAULT_TRANSPORT "vhost_user_blk"
      39                 :            : 
      40                 :            : struct spdk_vhost_user_blk_task {
      41                 :            :         struct spdk_vhost_blk_task blk_task;
      42                 :            :         struct spdk_vhost_blk_session *bvsession;
      43                 :            :         struct spdk_vhost_virtqueue *vq;
      44                 :            : 
      45                 :            :         uint16_t req_idx;
      46                 :            :         uint16_t num_descs;
      47                 :            :         uint16_t buffer_id;
      48                 :            :         uint16_t inflight_head;
      49                 :            : 
      50                 :            :         /* If set, the task is currently used for I/O processing. */
      51                 :            :         bool used;
      52                 :            : };
      53                 :            : 
      54                 :            : struct spdk_vhost_blk_dev {
      55                 :            :         struct spdk_vhost_dev vdev;
      56                 :            :         struct spdk_bdev *bdev;
      57                 :            :         struct spdk_bdev_desc *bdev_desc;
      58                 :            :         const struct spdk_virtio_blk_transport_ops *ops;
      59                 :            : 
      60                 :            :         bool readonly;
      61                 :            :         /* Next poll group index to be assigned */
      62                 :            :         uint32_t next_pg_index;
      63                 :            : };
      64                 :            : 
      65                 :            : struct vhost_user_pg_vq_info {
      66                 :            :         struct vhost_user_poll_group *pg;
      67                 :            :         struct spdk_vhost_virtqueue *vq;
      68                 :            :         struct spdk_vhost_session *vsession;
      69                 :            : 
      70                 :            :         TAILQ_ENTRY(vhost_user_pg_vq_info) link;
      71                 :            : };
      72                 :            : 
      73                 :            : struct vhost_user_poll_group {
      74                 :            :         struct spdk_vhost_dev *vdev;
      75                 :            :         struct spdk_vhost_session *vsession;
      76                 :            : 
      77                 :            :         struct spdk_thread *thread;
      78                 :            :         struct spdk_poller *requestq_poller;
      79                 :            :         struct spdk_io_channel *io_channel;
      80                 :            : 
      81                 :            :         int task_cnt;
      82                 :            : 
      83                 :            :         TAILQ_HEAD(, vhost_user_pg_vq_info) vqs;
      84                 :            : 
      85                 :            :         struct spdk_poller *stop_poller;
      86                 :            :         uint32_t stop_retry_count;
      87                 :            : };
      88                 :            : 
      89                 :            : struct spdk_vhost_blk_session {
      90                 :            :         /* The parent session must be the very first field in this struct */
      91                 :            :         struct spdk_vhost_session vsession;
      92                 :            :         struct spdk_vhost_blk_dev *bvdev;
      93                 :            :         struct spdk_poller *stop_poller;
      94                 :            : 
      95                 :            :         struct spdk_thread *thread;
      96                 :            :         struct vhost_user_poll_group *poll_groups;
      97                 :            :         uint32_t num_poll_groups;
      98                 :            : 
      99                 :            :         uint32_t num_stopped_poll_groups;
     100                 :            : };
     101                 :            : 
     102                 :            : /* forward declaration */
     103                 :            : static const struct spdk_vhost_dev_backend vhost_blk_device_backend;
     104                 :            : 
     105                 :            : static void vhost_user_blk_request_finish(uint8_t status, struct spdk_vhost_blk_task *task,
     106                 :            :                 void *cb_arg);
     107                 :            : 
     108                 :            : static void session_stop_poll_groups(struct spdk_vhost_blk_session *bvsession);
     109                 :            : 
     110                 :            : static int
     111                 :    2448366 : vhost_user_process_blk_request(struct spdk_vhost_user_blk_task *user_task)
     112                 :            : {
     113                 :    2448366 :         struct spdk_vhost_blk_session *bvsession = user_task->bvsession;
     114                 :    2448366 :         struct spdk_vhost_dev *vdev = &bvsession->bvdev->vdev;
     115                 :    2448366 :         struct vhost_user_poll_group *pg = (struct vhost_user_poll_group *)user_task->vq->poll_group;
     116                 :            : 
     117                 :    2448366 :         return virtio_blk_process_request(vdev, pg->io_channel, &user_task->blk_task,
     118                 :            :                                           vhost_user_blk_request_finish, NULL);
     119                 :            : }
     120                 :            : 
     121                 :            : static struct spdk_vhost_blk_dev *
     122                 :    2449692 : to_blk_dev(struct spdk_vhost_dev *vdev)
     123                 :            : {
     124         [ -  + ]:    2449692 :         if (vdev == NULL) {
     125                 :          0 :                 return NULL;
     126                 :            :         }
     127                 :            : 
     128         [ -  + ]:    2449692 :         if (vdev->backend->type != VHOST_BACKEND_BLK) {
     129                 :          0 :                 SPDK_ERRLOG("%s: not a vhost-blk device\n", vdev->name);
     130                 :          0 :                 return NULL;
     131                 :            :         }
     132                 :            : 
     133                 :    2449692 :         return SPDK_CONTAINEROF(vdev, struct spdk_vhost_blk_dev, vdev);
     134                 :            : }
     135                 :            : 
     136                 :            : struct spdk_bdev *
     137                 :         73 : vhost_blk_get_bdev(struct spdk_vhost_dev *vdev)
     138                 :            : {
     139                 :         73 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
     140                 :            : 
     141         [ -  + ]:         73 :         assert(bvdev != NULL);
     142                 :            : 
     143                 :         73 :         return bvdev->bdev;
     144                 :            : }
     145                 :            : 
     146                 :            : static struct spdk_vhost_blk_session *
     147                 :  123699265 : to_blk_session(struct spdk_vhost_session *vsession)
     148                 :            : {
     149         [ -  + ]:  123699265 :         assert(vsession->vdev->backend->type == VHOST_BACKEND_BLK);
     150                 :  123699265 :         return (struct spdk_vhost_blk_session *)vsession;
     151                 :            : }
     152                 :            : 
     153                 :            : static inline void
     154                 :    2448367 : blk_task_inc_task_cnt(struct spdk_vhost_user_blk_task *task)
     155                 :            : {
     156                 :    2448367 :         struct spdk_vhost_virtqueue *vq = task->vq;
     157                 :    2448367 :         struct vhost_user_poll_group *pg = (struct vhost_user_poll_group *)vq->poll_group;
     158                 :            : 
     159                 :    2448367 :         pg->task_cnt++;
     160                 :    2448367 : }
     161                 :            : 
     162                 :            : static inline void
     163                 :    2448367 : blk_task_dec_task_cnt(struct spdk_vhost_user_blk_task *task)
     164                 :            : {
     165                 :    2448367 :         struct spdk_vhost_virtqueue *vq = task->vq;
     166                 :    2448367 :         struct vhost_user_poll_group *pg = (struct vhost_user_poll_group *)vq->poll_group;
     167                 :            : 
     168         [ -  + ]:    2448367 :         assert(pg->task_cnt > 0);
     169                 :    2448367 :         pg->task_cnt--;
     170                 :    2448367 : }
     171                 :            : 
     172                 :            : static void
     173                 :    2448367 : blk_task_finish(struct spdk_vhost_user_blk_task *task)
     174                 :            : {
     175                 :    2448367 :         blk_task_dec_task_cnt(task);
     176                 :    2448367 :         task->used = false;
     177                 :    2448367 : }
     178                 :            : 
     179                 :            : static void
     180                 :    2448367 : blk_task_init(struct spdk_vhost_user_blk_task *task)
     181                 :            : {
     182                 :    2448367 :         struct spdk_vhost_blk_task *blk_task = &task->blk_task;
     183                 :            : 
     184                 :    2448367 :         task->used = true;
     185                 :    2448367 :         blk_task->iovcnt = SPDK_COUNTOF(blk_task->iovs);
     186                 :    2448367 :         blk_task->status = NULL;
     187                 :    2448367 :         blk_task->used_len = 0;
     188                 :    2448367 :         blk_task->payload_size = 0;
     189                 :    2448367 : }
     190                 :            : 
     191                 :            : static void
     192                 :    2448367 : blk_task_enqueue(struct spdk_vhost_user_blk_task *task)
     193                 :            : {
     194         [ -  + ]:    2448367 :         if (task->vq->packed.packed_ring) {
     195                 :          0 :                 vhost_vq_packed_ring_enqueue(&task->bvsession->vsession, task->vq,
     196                 :          0 :                                              task->num_descs,
     197                 :          0 :                                              task->buffer_id, task->blk_task.used_len,
     198                 :          0 :                                              task->inflight_head);
     199                 :            :         } else {
     200                 :    4896734 :                 vhost_vq_used_ring_enqueue(&task->bvsession->vsession, task->vq,
     201                 :    2448367 :                                            task->req_idx, task->blk_task.used_len);
     202                 :            :         }
     203                 :    2448367 : }
     204                 :            : 
     205                 :            : static void
     206                 :    2448367 : vhost_user_blk_request_finish(uint8_t status, struct spdk_vhost_blk_task *task, void *cb_arg)
     207                 :            : {
     208                 :            :         struct spdk_vhost_user_blk_task *user_task;
     209                 :            : 
     210                 :    2448367 :         user_task = SPDK_CONTAINEROF(task, struct spdk_vhost_user_blk_task, blk_task);
     211                 :            : 
     212                 :    2448367 :         blk_task_enqueue(user_task);
     213                 :            : 
     214   [ -  +  -  + ]:    2448367 :         SPDK_DEBUGLOG(vhost_blk, "Finished task (%p) req_idx=%d\n status: %" PRIu8"\n",
     215                 :            :                       user_task, user_task->req_idx, status);
     216                 :    2448367 :         blk_task_finish(user_task);
     217                 :    2448367 : }
     218                 :            : 
     219                 :            : static void
     220                 :    2448366 : blk_request_finish(uint8_t status, struct spdk_vhost_blk_task *task)
     221                 :            : {
     222                 :            : 
     223         [ +  - ]:    2448366 :         if (task->status) {
     224                 :    2448366 :                 *task->status = status;
     225                 :            :         }
     226                 :            : 
     227                 :    2448366 :         task->cb(status, task, task->cb_arg);
     228                 :    2448366 : }
     229                 :            : 
     230                 :            : /*
     231                 :            :  * Process task's descriptor chain and setup data related fields.
     232                 :            :  * Return
     233                 :            :  *   total size of supplied buffers
     234                 :            :  *
     235                 :            :  *   FIXME: Make this function return to rd_cnt and wr_cnt
     236                 :            :  */
     237                 :            : static int
     238                 :    2448367 : blk_iovs_split_queue_setup(struct spdk_vhost_blk_session *bvsession,
     239                 :            :                            struct spdk_vhost_virtqueue *vq,
     240                 :            :                            uint16_t req_idx, struct iovec *iovs, uint16_t *iovs_cnt, uint32_t *length)
     241                 :            : {
     242                 :    2448367 :         struct spdk_vhost_session *vsession = &bvsession->vsession;
     243                 :    2448367 :         struct spdk_vhost_dev *vdev = vsession->vdev;
     244                 :    2448367 :         struct vring_desc *desc, *desc_table;
     245                 :    2448367 :         uint16_t out_cnt = 0, cnt = 0;
     246                 :    2448367 :         uint32_t desc_table_size, len = 0;
     247                 :            :         uint32_t desc_handled_cnt;
     248                 :            :         int rc;
     249                 :            : 
     250                 :    2448367 :         rc = vhost_vq_get_desc(vsession, vq, req_idx, &desc, &desc_table, &desc_table_size);
     251         [ -  + ]:    2448367 :         if (rc != 0) {
     252                 :          0 :                 SPDK_ERRLOG("%s: invalid descriptor at index %"PRIu16".\n", vdev->name, req_idx);
     253                 :          0 :                 return -1;
     254                 :            :         }
     255                 :            : 
     256                 :    2448367 :         desc_handled_cnt = 0;
     257                 :            :         while (1) {
     258                 :            :                 /*
     259                 :            :                  * Maximum cnt reached?
     260                 :            :                  * Should not happen if request is well formatted, otherwise this is a BUG.
     261                 :            :                  */
     262         [ -  + ]:   11230504 :                 if (spdk_unlikely(cnt == *iovs_cnt)) {
     263   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vhost_blk, "%s: max IOVs in request reached (req_idx = %"PRIu16").\n",
     264                 :            :                                       vsession->name, req_idx);
     265                 :          0 :                         return -1;
     266                 :            :                 }
     267                 :            : 
     268         [ -  + ]:   11230504 :                 if (spdk_unlikely(vhost_vring_desc_to_iov(vsession, iovs, &cnt, desc))) {
     269   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vhost_blk, "%s: invalid descriptor %" PRIu16" (req_idx = %"PRIu16").\n",
     270                 :            :                                       vsession->name, req_idx, cnt);
     271                 :          0 :                         return -1;
     272                 :            :                 }
     273                 :            : 
     274                 :   11230504 :                 len += desc->len;
     275                 :            : 
     276                 :   11230504 :                 out_cnt += vhost_vring_desc_is_wr(desc);
     277                 :            : 
     278                 :   11230504 :                 rc = vhost_vring_desc_get_next(&desc, desc_table, desc_table_size);
     279         [ -  + ]:   11230504 :                 if (rc != 0) {
     280                 :          0 :                         SPDK_ERRLOG("%s: descriptor chain at index %"PRIu16" terminated unexpectedly.\n",
     281                 :            :                                     vsession->name, req_idx);
     282                 :          0 :                         return -1;
     283         [ +  + ]:   11230504 :                 } else if (desc == NULL) {
     284                 :    2448367 :                         break;
     285                 :            :                 }
     286                 :            : 
     287                 :    8782137 :                 desc_handled_cnt++;
     288         [ -  + ]:    8782137 :                 if (spdk_unlikely(desc_handled_cnt > desc_table_size)) {
     289                 :            :                         /* Break a cycle and report an error, if any. */
     290                 :          0 :                         SPDK_ERRLOG("%s: found a cycle in the descriptor chain: desc_table_size = %d, desc_handled_cnt = %d.\n",
     291                 :            :                                     vsession->name, desc_table_size, desc_handled_cnt);
     292                 :          0 :                         return -1;
     293                 :            :                 }
     294                 :            :         }
     295                 :            : 
     296                 :            :         /*
     297                 :            :          * There must be least two descriptors.
     298                 :            :          * First contain request so it must be readable.
     299                 :            :          * Last descriptor contain buffer for response so it must be writable.
     300                 :            :          */
     301   [ +  -  +  + ]:    2448367 :         if (spdk_unlikely(out_cnt == 0 || cnt < 2)) {
     302                 :          1 :                 return -1;
     303                 :            :         }
     304                 :            : 
     305                 :    2448366 :         *length = len;
     306                 :    2448366 :         *iovs_cnt = cnt;
     307                 :    2448366 :         return 0;
     308                 :            : }
     309                 :            : 
     310                 :            : static int
     311                 :          0 : blk_iovs_packed_desc_setup(struct spdk_vhost_session *vsession,
     312                 :            :                            struct spdk_vhost_virtqueue *vq, uint16_t req_idx,
     313                 :            :                            struct vring_packed_desc *desc_table, uint16_t desc_table_size,
     314                 :            :                            struct iovec *iovs, uint16_t *iovs_cnt, uint32_t *length)
     315                 :            : {
     316                 :          0 :         struct vring_packed_desc *desc;
     317                 :          0 :         uint16_t cnt = 0, out_cnt = 0;
     318                 :          0 :         uint32_t len = 0;
     319                 :            : 
     320         [ #  # ]:          0 :         if (desc_table == NULL) {
     321                 :          0 :                 desc = &vq->vring.desc_packed[req_idx];
     322                 :            :         } else {
     323                 :          0 :                 req_idx = 0;
     324                 :          0 :                 desc = desc_table;
     325                 :            :         }
     326                 :            : 
     327                 :            :         while (1) {
     328                 :            :                 /*
     329                 :            :                  * Maximum cnt reached?
     330                 :            :                  * Should not happen if request is well formatted, otherwise this is a BUG.
     331                 :            :                  */
     332         [ #  # ]:          0 :                 if (spdk_unlikely(cnt == *iovs_cnt)) {
     333                 :          0 :                         SPDK_ERRLOG("%s: max IOVs in request reached (req_idx = %"PRIu16").\n",
     334                 :            :                                     vsession->name, req_idx);
     335                 :          0 :                         return -EINVAL;
     336                 :            :                 }
     337                 :            : 
     338         [ #  # ]:          0 :                 if (spdk_unlikely(vhost_vring_packed_desc_to_iov(vsession, iovs, &cnt, desc))) {
     339                 :          0 :                         SPDK_ERRLOG("%s: invalid descriptor %" PRIu16" (req_idx = %"PRIu16").\n",
     340                 :            :                                     vsession->name, req_idx, cnt);
     341                 :          0 :                         return -EINVAL;
     342                 :            :                 }
     343                 :            : 
     344                 :          0 :                 len += desc->len;
     345                 :          0 :                 out_cnt += vhost_vring_packed_desc_is_wr(desc);
     346                 :            : 
     347                 :            :                 /* desc is NULL means we reach the last desc of this request */
     348                 :          0 :                 vhost_vring_packed_desc_get_next(&desc, &req_idx, vq, desc_table, desc_table_size);
     349         [ #  # ]:          0 :                 if (desc == NULL) {
     350                 :          0 :                         break;
     351                 :            :                 }
     352                 :            :         }
     353                 :            : 
     354                 :            :         /*
     355                 :            :          * There must be least two descriptors.
     356                 :            :          * First contain request so it must be readable.
     357                 :            :          * Last descriptor contain buffer for response so it must be writable.
     358                 :            :          */
     359   [ #  #  #  # ]:          0 :         if (spdk_unlikely(out_cnt == 0 || cnt < 2)) {
     360                 :          0 :                 return -EINVAL;
     361                 :            :         }
     362                 :            : 
     363                 :          0 :         *length = len;
     364                 :          0 :         *iovs_cnt = cnt;
     365                 :            : 
     366                 :          0 :         return 0;
     367                 :            : }
     368                 :            : 
     369                 :            : static int
     370                 :          0 : blk_iovs_packed_queue_setup(struct spdk_vhost_blk_session *bvsession,
     371                 :            :                             struct spdk_vhost_virtqueue *vq, uint16_t req_idx,
     372                 :            :                             struct iovec *iovs, uint16_t *iovs_cnt, uint32_t *length)
     373                 :            : {
     374                 :          0 :         struct spdk_vhost_session *vsession = &bvsession->vsession;
     375                 :          0 :         struct spdk_vhost_dev *vdev = vsession->vdev;
     376                 :          0 :         struct vring_packed_desc *desc = NULL, *desc_table;
     377                 :          0 :         uint32_t desc_table_size;
     378                 :            :         int rc;
     379                 :            : 
     380                 :          0 :         rc = vhost_vq_get_desc_packed(vsession, vq, req_idx, &desc,
     381                 :            :                                       &desc_table, &desc_table_size);
     382         [ #  # ]:          0 :         if (spdk_unlikely(rc != 0)) {
     383                 :          0 :                 SPDK_ERRLOG("%s: Invalid descriptor at index %"PRIu16".\n", vdev->name, req_idx);
     384                 :          0 :                 return rc;
     385                 :            :         }
     386                 :            : 
     387                 :          0 :         return blk_iovs_packed_desc_setup(vsession, vq, req_idx, desc_table, desc_table_size,
     388                 :            :                                           iovs, iovs_cnt, length);
     389                 :            : }
     390                 :            : 
     391                 :            : static int
     392                 :          0 : blk_iovs_inflight_queue_setup(struct spdk_vhost_blk_session *bvsession,
     393                 :            :                               struct spdk_vhost_virtqueue *vq, uint16_t req_idx,
     394                 :            :                               struct iovec *iovs, uint16_t *iovs_cnt, uint32_t *length)
     395                 :            : {
     396                 :          0 :         struct spdk_vhost_session *vsession = &bvsession->vsession;
     397                 :          0 :         struct spdk_vhost_dev *vdev = vsession->vdev;
     398                 :          0 :         spdk_vhost_inflight_desc *inflight_desc;
     399                 :          0 :         struct vring_packed_desc *desc_table;
     400                 :          0 :         uint16_t out_cnt = 0, cnt = 0;
     401                 :          0 :         uint32_t desc_table_size, len = 0;
     402                 :          0 :         int rc = 0;
     403                 :            : 
     404                 :          0 :         rc = vhost_inflight_queue_get_desc(vsession, vq->vring_inflight.inflight_packed->desc,
     405                 :            :                                            req_idx, &inflight_desc, &desc_table, &desc_table_size);
     406         [ #  # ]:          0 :         if (spdk_unlikely(rc != 0)) {
     407                 :          0 :                 SPDK_ERRLOG("%s: Invalid descriptor at index %"PRIu16".\n", vdev->name, req_idx);
     408                 :          0 :                 return rc;
     409                 :            :         }
     410                 :            : 
     411         [ #  # ]:          0 :         if (desc_table != NULL) {
     412                 :          0 :                 return blk_iovs_packed_desc_setup(vsession, vq, req_idx, desc_table, desc_table_size,
     413                 :            :                                                   iovs, iovs_cnt, length);
     414                 :            :         }
     415                 :            : 
     416                 :            :         while (1) {
     417                 :            :                 /*
     418                 :            :                  * Maximum cnt reached?
     419                 :            :                  * Should not happen if request is well formatted, otherwise this is a BUG.
     420                 :            :                  */
     421         [ #  # ]:          0 :                 if (spdk_unlikely(cnt == *iovs_cnt)) {
     422                 :          0 :                         SPDK_ERRLOG("%s: max IOVs in request reached (req_idx = %"PRIu16").\n",
     423                 :            :                                     vsession->name, req_idx);
     424                 :          0 :                         return -EINVAL;
     425                 :            :                 }
     426                 :            : 
     427         [ #  # ]:          0 :                 if (spdk_unlikely(vhost_vring_inflight_desc_to_iov(vsession, iovs, &cnt, inflight_desc))) {
     428                 :          0 :                         SPDK_ERRLOG("%s: invalid descriptor %" PRIu16" (req_idx = %"PRIu16").\n",
     429                 :            :                                     vsession->name, req_idx, cnt);
     430                 :          0 :                         return -EINVAL;
     431                 :            :                 }
     432                 :            : 
     433                 :          0 :                 len += inflight_desc->len;
     434                 :          0 :                 out_cnt += vhost_vring_inflight_desc_is_wr(inflight_desc);
     435                 :            : 
     436                 :            :                 /* Without F_NEXT means it's the last desc */
     437         [ #  # ]:          0 :                 if ((inflight_desc->flags & VRING_DESC_F_NEXT) == 0) {
     438                 :          0 :                         break;
     439                 :            :                 }
     440                 :            : 
     441                 :          0 :                 inflight_desc = &vq->vring_inflight.inflight_packed->desc[inflight_desc->next];
     442                 :            :         }
     443                 :            : 
     444                 :            :         /*
     445                 :            :          * There must be least two descriptors.
     446                 :            :          * First contain request so it must be readable.
     447                 :            :          * Last descriptor contain buffer for response so it must be writable.
     448                 :            :          */
     449   [ #  #  #  # ]:          0 :         if (spdk_unlikely(out_cnt == 0 || cnt < 2)) {
     450                 :          0 :                 return -EINVAL;
     451                 :            :         }
     452                 :            : 
     453                 :          0 :         *length = len;
     454                 :          0 :         *iovs_cnt = cnt;
     455                 :            : 
     456                 :          0 :         return 0;
     457                 :            : }
     458                 :            : 
     459                 :            : static void
     460                 :    2319522 : blk_request_complete_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     461                 :            : {
     462                 :    2319522 :         struct spdk_vhost_blk_task *task = cb_arg;
     463                 :            : 
     464                 :    2319522 :         spdk_bdev_free_io(bdev_io);
     465                 :    2319522 :         blk_request_finish(success ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR, task);
     466                 :    2319522 : }
     467                 :            : 
     468                 :            : static void
     469                 :          0 : blk_request_resubmit(void *arg)
     470                 :            : {
     471                 :          0 :         struct spdk_vhost_blk_task *task = arg;
     472                 :          0 :         int rc = 0;
     473                 :            : 
     474                 :          0 :         rc = virtio_blk_process_request(task->bdev_io_wait_vdev, task->bdev_io_wait_ch, task,
     475                 :            :                                         task->cb, task->cb_arg);
     476         [ #  # ]:          0 :         if (rc == 0) {
     477   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "====== Task %p resubmitted ======\n", task);
     478                 :            :         } else {
     479   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "====== Task %p failed ======\n", task);
     480                 :            :         }
     481                 :          0 : }
     482                 :            : 
     483                 :            : static inline void
     484                 :          0 : blk_request_queue_io(struct spdk_vhost_dev *vdev, struct spdk_io_channel *ch,
     485                 :            :                      struct spdk_vhost_blk_task *task)
     486                 :            : {
     487                 :            :         int rc;
     488                 :          0 :         struct spdk_bdev *bdev = vhost_blk_get_bdev(vdev);
     489                 :            : 
     490                 :          0 :         task->bdev_io_wait.bdev = bdev;
     491                 :          0 :         task->bdev_io_wait.cb_fn = blk_request_resubmit;
     492                 :          0 :         task->bdev_io_wait.cb_arg = task;
     493                 :          0 :         task->bdev_io_wait_ch = ch;
     494                 :          0 :         task->bdev_io_wait_vdev = vdev;
     495                 :            : 
     496                 :          0 :         rc = spdk_bdev_queue_io_wait(bdev, ch, &task->bdev_io_wait);
     497         [ #  # ]:          0 :         if (rc != 0) {
     498                 :          0 :                 blk_request_finish(VIRTIO_BLK_S_IOERR, task);
     499                 :            :         }
     500                 :          0 : }
     501                 :            : 
     502                 :            : int
     503                 :    2448366 : virtio_blk_process_request(struct spdk_vhost_dev *vdev, struct spdk_io_channel *ch,
     504                 :            :                            struct spdk_vhost_blk_task *task, virtio_blk_request_cb cb, void *cb_arg)
     505                 :            : {
     506                 :    2448366 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
     507                 :    2448366 :         struct virtio_blk_outhdr req;
     508                 :            :         struct virtio_blk_discard_write_zeroes *desc;
     509                 :            :         struct iovec *iov;
     510                 :            :         uint32_t type;
     511                 :            :         uint64_t flush_bytes;
     512                 :            :         uint32_t payload_len;
     513                 :            :         uint16_t iovcnt;
     514                 :            :         int rc;
     515                 :            : 
     516         [ -  + ]:    2448366 :         assert(bvdev != NULL);
     517                 :            : 
     518                 :    2448366 :         task->cb = cb;
     519                 :    2448366 :         task->cb_arg = cb_arg;
     520                 :            : 
     521                 :    2448366 :         iov = &task->iovs[0];
     522         [ -  + ]:    2448366 :         if (spdk_unlikely(iov->iov_len != sizeof(req))) {
     523   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk,
     524                 :            :                               "First descriptor size is %zu but expected %zu (task = %p).\n",
     525                 :            :                               iov->iov_len, sizeof(req), task);
     526                 :          0 :                 blk_request_finish(VIRTIO_BLK_S_UNSUPP, task);
     527                 :          0 :                 return -1;
     528                 :            :         }
     529                 :            : 
     530                 :            :         /* Some SeaBIOS versions don't align the virtio_blk_outhdr on an 8-byte boundary, which
     531                 :            :          * triggers ubsan errors.  So copy this small 16-byte structure to the stack to workaround
     532                 :            :          * this problem.
     533                 :            :          */
     534                 :    2448366 :         memcpy(&req, iov->iov_base, sizeof(req));
     535                 :            : 
     536                 :    2448366 :         iov = &task->iovs[task->iovcnt - 1];
     537         [ -  + ]:    2448366 :         if (spdk_unlikely(iov->iov_len != 1)) {
     538   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk,
     539                 :            :                               "Last descriptor size is %zu but expected %d (task = %p).\n",
     540                 :            :                               iov->iov_len, 1, task);
     541                 :          0 :                 blk_request_finish(VIRTIO_BLK_S_UNSUPP, task);
     542                 :          0 :                 return -1;
     543                 :            :         }
     544                 :            : 
     545                 :    2448366 :         payload_len = task->payload_size;
     546                 :    2448366 :         task->status = iov->iov_base;
     547                 :    2448366 :         payload_len -= sizeof(req) + sizeof(*task->status);
     548                 :    2448366 :         iovcnt = task->iovcnt - 2;
     549                 :            : 
     550                 :    2448366 :         type = req.type;
     551                 :            : #ifdef VIRTIO_BLK_T_BARRIER
     552                 :            :         /* Don't care about barrier for now (as QEMU's virtio-blk do). */
     553                 :    2448366 :         type &= ~VIRTIO_BLK_T_BARRIER;
     554                 :            : #endif
     555                 :            : 
     556   [ +  +  +  +  :    2448366 :         switch (type) {
                   +  + ]
     557                 :    2202932 :         case VIRTIO_BLK_T_IN:
     558                 :            :         case VIRTIO_BLK_T_OUT:
     559   [ +  -  -  + ]:    2202932 :                 if (spdk_unlikely(payload_len == 0 || (payload_len & (512 - 1)) != 0)) {
     560         [ #  # ]:          0 :                         SPDK_ERRLOG("%s - passed IO buffer is not multiple of 512b (task = %p).\n",
     561                 :            :                                     type ? "WRITE" : "READ", task);
     562                 :          0 :                         blk_request_finish(VIRTIO_BLK_S_UNSUPP, task);
     563                 :          0 :                         return -1;
     564                 :            :                 }
     565                 :            : 
     566         [ +  + ]:    2202932 :                 if (type == VIRTIO_BLK_T_IN) {
     567                 :     885229 :                         task->used_len = payload_len + sizeof(*task->status);
     568                 :     885229 :                         rc = spdk_bdev_readv(bvdev->bdev_desc, ch,
     569                 :     885229 :                                              &task->iovs[1], iovcnt, req.sector * 512,
     570                 :            :                                              payload_len, blk_request_complete_cb, task);
     571   [ -  +  +  - ]:    1317703 :                 } else if (!bvdev->readonly) {
     572                 :    1317703 :                         task->used_len = sizeof(*task->status);
     573                 :    1317703 :                         rc = spdk_bdev_writev(bvdev->bdev_desc, ch,
     574                 :    1317703 :                                               &task->iovs[1], iovcnt, req.sector * 512,
     575                 :            :                                               payload_len, blk_request_complete_cb, task);
     576                 :            :                 } else {
     577   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vhost_blk, "Device is in read-only mode!\n");
     578                 :          0 :                         rc = -1;
     579                 :            :                 }
     580                 :            : 
     581         [ -  + ]:    2202932 :                 if (rc) {
     582         [ #  # ]:          0 :                         if (rc == -ENOMEM) {
     583   [ #  #  #  # ]:          0 :                                 SPDK_DEBUGLOG(vhost_blk, "No memory, start to queue io.\n");
     584                 :          0 :                                 blk_request_queue_io(vdev, ch, task);
     585                 :            :                         } else {
     586                 :          0 :                                 blk_request_finish(VIRTIO_BLK_S_IOERR, task);
     587                 :          0 :                                 return -1;
     588                 :            :                         }
     589                 :            :                 }
     590                 :    2202932 :                 break;
     591                 :     116341 :         case VIRTIO_BLK_T_DISCARD:
     592                 :     116341 :                 desc = task->iovs[1].iov_base;
     593         [ -  + ]:     116341 :                 if (payload_len != sizeof(*desc)) {
     594                 :          0 :                         SPDK_NOTICELOG("Invalid discard payload size: %u\n", payload_len);
     595                 :          0 :                         blk_request_finish(VIRTIO_BLK_S_IOERR, task);
     596                 :          0 :                         return -1;
     597                 :            :                 }
     598                 :            : 
     599         [ -  + ]:     116341 :                 if (desc->flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
     600                 :          0 :                         SPDK_ERRLOG("UNMAP flag is only used for WRITE ZEROES command\n");
     601                 :          0 :                         blk_request_finish(VIRTIO_BLK_S_UNSUPP, task);
     602                 :          0 :                         return -1;
     603                 :            :                 }
     604                 :            : 
     605                 :     116341 :                 rc = spdk_bdev_unmap(bvdev->bdev_desc, ch,
     606                 :     116341 :                                      desc->sector * 512, desc->num_sectors * 512,
     607                 :            :                                      blk_request_complete_cb, task);
     608         [ -  + ]:     116341 :                 if (rc) {
     609         [ #  # ]:          0 :                         if (rc == -ENOMEM) {
     610   [ #  #  #  # ]:          0 :                                 SPDK_DEBUGLOG(vhost_blk, "No memory, start to queue io.\n");
     611                 :          0 :                                 blk_request_queue_io(vdev, ch, task);
     612                 :            :                         } else {
     613                 :          0 :                                 blk_request_finish(VIRTIO_BLK_S_IOERR, task);
     614                 :          0 :                                 return -1;
     615                 :            :                         }
     616                 :            :                 }
     617                 :     116341 :                 break;
     618                 :        157 :         case VIRTIO_BLK_T_WRITE_ZEROES:
     619                 :        157 :                 desc = task->iovs[1].iov_base;
     620         [ -  + ]:        157 :                 if (payload_len != sizeof(*desc)) {
     621                 :          0 :                         SPDK_NOTICELOG("Invalid write zeroes payload size: %u\n", payload_len);
     622                 :          0 :                         blk_request_finish(VIRTIO_BLK_S_IOERR, task);
     623                 :          0 :                         return -1;
     624                 :            :                 }
     625                 :            : 
     626                 :            :                 /* Unmap this range, SPDK doesn't support it, kernel will enable this flag by default
     627                 :            :                  * without checking unmap feature is negotiated or not, the flag isn't mandatory, so
     628                 :            :                  * just print a warning.
     629                 :            :                  */
     630         [ +  + ]:        157 :                 if (desc->flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
     631                 :         79 :                         SPDK_WARNLOG("Ignore the unmap flag for WRITE ZEROES from %"PRIx64", len %"PRIx64"\n",
     632                 :            :                                      (uint64_t)desc->sector * 512, (uint64_t)desc->num_sectors * 512);
     633                 :            :                 }
     634                 :            : 
     635                 :        157 :                 rc = spdk_bdev_write_zeroes(bvdev->bdev_desc, ch,
     636                 :        157 :                                             desc->sector * 512, desc->num_sectors * 512,
     637                 :            :                                             blk_request_complete_cb, task);
     638         [ -  + ]:        157 :                 if (rc) {
     639         [ #  # ]:          0 :                         if (rc == -ENOMEM) {
     640   [ #  #  #  # ]:          0 :                                 SPDK_DEBUGLOG(vhost_blk, "No memory, start to queue io.\n");
     641                 :          0 :                                 blk_request_queue_io(vdev, ch, task);
     642                 :            :                         } else {
     643                 :          0 :                                 blk_request_finish(VIRTIO_BLK_S_IOERR, task);
     644                 :          0 :                                 return -1;
     645                 :            :                         }
     646                 :            :                 }
     647                 :        157 :                 break;
     648                 :         92 :         case VIRTIO_BLK_T_FLUSH:
     649                 :         92 :                 flush_bytes = spdk_bdev_get_num_blocks(bvdev->bdev) * spdk_bdev_get_block_size(bvdev->bdev);
     650         [ -  + ]:         92 :                 if (req.sector != 0) {
     651                 :          0 :                         SPDK_NOTICELOG("sector must be zero for flush command\n");
     652                 :          0 :                         blk_request_finish(VIRTIO_BLK_S_IOERR, task);
     653                 :          0 :                         return -1;
     654                 :            :                 }
     655                 :         92 :                 rc = spdk_bdev_flush(bvdev->bdev_desc, ch,
     656                 :            :                                      0, flush_bytes,
     657                 :            :                                      blk_request_complete_cb, task);
     658         [ -  + ]:         92 :                 if (rc) {
     659         [ #  # ]:          0 :                         if (rc == -ENOMEM) {
     660   [ #  #  #  # ]:          0 :                                 SPDK_DEBUGLOG(vhost_blk, "No memory, start to queue io.\n");
     661                 :          0 :                                 blk_request_queue_io(vdev, ch, task);
     662                 :            :                         } else {
     663                 :          0 :                                 blk_request_finish(VIRTIO_BLK_S_IOERR, task);
     664                 :          0 :                                 return -1;
     665                 :            :                         }
     666                 :            :                 }
     667                 :         92 :                 break;
     668                 :        139 :         case VIRTIO_BLK_T_GET_ID:
     669   [ +  -  -  + ]:        139 :                 if (!iovcnt || !payload_len) {
     670                 :          0 :                         blk_request_finish(VIRTIO_BLK_S_UNSUPP, task);
     671                 :          0 :                         return -1;
     672                 :            :                 }
     673                 :        139 :                 task->used_len = spdk_min((size_t)VIRTIO_BLK_ID_BYTES, task->iovs[1].iov_len);
     674                 :        139 :                 spdk_strcpy_pad(task->iovs[1].iov_base, spdk_bdev_get_name(bvdev->bdev),
     675                 :        139 :                                 task->used_len, ' ');
     676                 :        139 :                 blk_request_finish(VIRTIO_BLK_S_OK, task);
     677                 :        139 :                 break;
     678                 :     128705 :         default:
     679   [ -  +  -  + ]:     128705 :                 SPDK_DEBUGLOG(vhost_blk, "Not supported request type '%"PRIu32"'.\n", type);
     680                 :     128705 :                 blk_request_finish(VIRTIO_BLK_S_UNSUPP, task);
     681                 :     128705 :                 return -1;
     682                 :            :         }
     683                 :            : 
     684                 :    2319661 :         return 0;
     685                 :            : }
     686                 :            : 
     687                 :            : static void
     688                 :    2448367 : process_blk_task(struct spdk_vhost_virtqueue *vq, uint16_t req_idx)
     689                 :            : {
     690                 :            :         struct spdk_vhost_user_blk_task *task;
     691                 :            :         struct spdk_vhost_blk_task *blk_task;
     692                 :            :         int rc;
     693                 :            : 
     694         [ -  + ]:    2448367 :         assert(vq->packed.packed_ring == false);
     695                 :            : 
     696                 :    2448367 :         task = &((struct spdk_vhost_user_blk_task *)vq->tasks)[req_idx];
     697                 :    2448367 :         blk_task = &task->blk_task;
     698   [ -  +  -  + ]:    2448367 :         if (spdk_unlikely(task->used)) {
     699                 :          0 :                 SPDK_ERRLOG("%s: request with idx '%"PRIu16"' is already pending.\n",
     700                 :            :                             task->bvsession->vsession.name, req_idx);
     701                 :          0 :                 blk_task->used_len = 0;
     702                 :          0 :                 blk_task_enqueue(task);
     703                 :          0 :                 return;
     704                 :            :         }
     705                 :            : 
     706                 :    2448367 :         blk_task_inc_task_cnt(task);
     707                 :            : 
     708                 :    2448367 :         blk_task_init(task);
     709                 :            : 
     710                 :    4896734 :         rc = blk_iovs_split_queue_setup(task->bvsession, vq, task->req_idx,
     711                 :    2448367 :                                         blk_task->iovs, &blk_task->iovcnt, &blk_task->payload_size);
     712                 :            : 
     713         [ +  + ]:    2448367 :         if (rc) {
     714   [ -  +  -  + ]:          1 :                 SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
     715                 :            :                 /* Only READ and WRITE are supported for now. */
     716                 :          1 :                 vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task, NULL);
     717                 :          1 :                 return;
     718                 :            :         }
     719                 :            : 
     720         [ +  + ]:    2448366 :         if (vhost_user_process_blk_request(task) == 0) {
     721   [ -  +  -  + ]:    2319661 :                 SPDK_DEBUGLOG(vhost_blk, "====== Task %p req_idx %d submitted ======\n", task,
     722                 :            :                               req_idx);
     723                 :            :         } else {
     724                 :     128705 :                 SPDK_ERRLOG("====== Task %p req_idx %d failed ======\n", task, req_idx);
     725                 :            :         }
     726                 :            : }
     727                 :            : 
     728                 :            : static void
     729                 :          0 : process_packed_blk_task(struct spdk_vhost_virtqueue *vq, uint16_t req_idx)
     730                 :            : {
     731                 :            :         struct spdk_vhost_user_blk_task *task;
     732                 :            :         struct spdk_vhost_blk_task *blk_task;
     733                 :          0 :         uint16_t task_idx = req_idx, num_descs;
     734                 :            :         int rc;
     735                 :            : 
     736         [ #  # ]:          0 :         assert(vq->packed.packed_ring);
     737                 :            : 
     738                 :            :         /* Packed ring used the buffer_id as the task_idx to get task struct.
     739                 :            :          * In kernel driver, it uses the vq->free_head to set the buffer_id so the value
     740                 :            :          * must be in the range of 0 ~ vring.size. The free_head value must be unique
     741                 :            :          * in the outstanding requests.
     742                 :            :          * We can't use the req_idx as the task_idx because the desc can be reused in
     743                 :            :          * the next phase even when it's not completed in the previous phase. For example,
     744                 :            :          * At phase 0, last_used_idx was 2 and desc0 was not completed.Then after moving
     745                 :            :          * phase 1, last_avail_idx is updated to 1. In this case, req_idx can not be used
     746                 :            :          * as task_idx because we will know task[0]->used is true at phase 1.
     747                 :            :          * The split queue is quite different, the desc would insert into the free list when
     748                 :            :          * device completes the request, the driver gets the desc from the free list which
     749                 :            :          * ensures the req_idx is unique in the outstanding requests.
     750                 :            :          */
     751                 :          0 :         task_idx = vhost_vring_packed_desc_get_buffer_id(vq, req_idx, &num_descs);
     752                 :            : 
     753                 :          0 :         task = &((struct spdk_vhost_user_blk_task *)vq->tasks)[task_idx];
     754                 :          0 :         blk_task = &task->blk_task;
     755   [ #  #  #  # ]:          0 :         if (spdk_unlikely(task->used)) {
     756                 :          0 :                 SPDK_ERRLOG("%s: request with idx '%"PRIu16"' is already pending.\n",
     757                 :            :                             task->bvsession->vsession.name, task_idx);
     758                 :          0 :                 blk_task->used_len = 0;
     759                 :          0 :                 blk_task_enqueue(task);
     760                 :          0 :                 return;
     761                 :            :         }
     762                 :            : 
     763                 :          0 :         task->req_idx = req_idx;
     764                 :          0 :         task->num_descs = num_descs;
     765                 :          0 :         task->buffer_id = task_idx;
     766                 :            : 
     767                 :          0 :         rte_vhost_set_inflight_desc_packed(task->bvsession->vsession.vid, vq->vring_idx,
     768         [ #  # ]:          0 :                                            req_idx, (req_idx + num_descs - 1) % vq->vring.size,
     769                 :            :                                            &task->inflight_head);
     770                 :            : 
     771                 :          0 :         blk_task_inc_task_cnt(task);
     772                 :            : 
     773                 :          0 :         blk_task_init(task);
     774                 :            : 
     775                 :          0 :         rc = blk_iovs_packed_queue_setup(task->bvsession, vq, task->req_idx, blk_task->iovs,
     776                 :            :                                          &blk_task->iovcnt,
     777                 :            :                                          &blk_task->payload_size);
     778         [ #  # ]:          0 :         if (rc) {
     779   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
     780                 :            :                 /* Only READ and WRITE are supported for now. */
     781                 :          0 :                 vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task, NULL);
     782                 :          0 :                 return;
     783                 :            :         }
     784                 :            : 
     785         [ #  # ]:          0 :         if (vhost_user_process_blk_request(task) == 0) {
     786   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "====== Task %p req_idx %d submitted ======\n", task,
     787                 :            :                               task_idx);
     788                 :            :         } else {
     789                 :          0 :                 SPDK_ERRLOG("====== Task %p req_idx %d failed ======\n", task, task_idx);
     790                 :            :         }
     791                 :            : }
     792                 :            : 
     793                 :            : static void
     794                 :          0 : process_packed_inflight_blk_task(struct spdk_vhost_virtqueue *vq,
     795                 :            :                                  uint16_t req_idx)
     796                 :            : {
     797                 :          0 :         spdk_vhost_inflight_desc *desc_array = vq->vring_inflight.inflight_packed->desc;
     798                 :          0 :         spdk_vhost_inflight_desc *desc = &desc_array[req_idx];
     799                 :            :         struct spdk_vhost_user_blk_task *task;
     800                 :            :         struct spdk_vhost_blk_task *blk_task;
     801                 :            :         uint16_t task_idx, num_descs;
     802                 :            :         int rc;
     803                 :            : 
     804                 :          0 :         task_idx = desc_array[desc->last].id;
     805                 :          0 :         num_descs = desc->num;
     806                 :            :         /* In packed ring reconnection, we use the last_used_idx as the
     807                 :            :          * initial value. So when we process the inflight descs we still
     808                 :            :          * need to update the available ring index.
     809                 :            :          */
     810                 :          0 :         vq->last_avail_idx += num_descs;
     811         [ #  # ]:          0 :         if (vq->last_avail_idx >= vq->vring.size) {
     812                 :          0 :                 vq->last_avail_idx -= vq->vring.size;
     813                 :          0 :                 vq->packed.avail_phase = !vq->packed.avail_phase;
     814                 :            :         }
     815                 :            : 
     816                 :          0 :         task = &((struct spdk_vhost_user_blk_task *)vq->tasks)[task_idx];
     817                 :          0 :         blk_task = &task->blk_task;
     818   [ #  #  #  # ]:          0 :         if (spdk_unlikely(task->used)) {
     819                 :          0 :                 SPDK_ERRLOG("%s: request with idx '%"PRIu16"' is already pending.\n",
     820                 :            :                             task->bvsession->vsession.name, task_idx);
     821                 :          0 :                 blk_task->used_len = 0;
     822                 :          0 :                 blk_task_enqueue(task);
     823                 :          0 :                 return;
     824                 :            :         }
     825                 :            : 
     826                 :          0 :         task->req_idx = req_idx;
     827                 :          0 :         task->num_descs = num_descs;
     828                 :          0 :         task->buffer_id = task_idx;
     829                 :            :         /* It's for cleaning inflight entries */
     830                 :          0 :         task->inflight_head = req_idx;
     831                 :            : 
     832                 :          0 :         blk_task_inc_task_cnt(task);
     833                 :            : 
     834                 :          0 :         blk_task_init(task);
     835                 :            : 
     836                 :          0 :         rc = blk_iovs_inflight_queue_setup(task->bvsession, vq, task->req_idx, blk_task->iovs,
     837                 :            :                                            &blk_task->iovcnt,
     838                 :            :                                            &blk_task->payload_size);
     839         [ #  # ]:          0 :         if (rc) {
     840   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
     841                 :            :                 /* Only READ and WRITE are supported for now. */
     842                 :          0 :                 vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task, NULL);
     843                 :          0 :                 return;
     844                 :            :         }
     845                 :            : 
     846         [ #  # ]:          0 :         if (vhost_user_process_blk_request(task) == 0) {
     847   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "====== Task %p req_idx %d submitted ======\n", task,
     848                 :            :                               task_idx);
     849                 :            :         } else {
     850                 :          0 :                 SPDK_ERRLOG("====== Task %p req_idx %d failed ======\n", task, task_idx);
     851                 :            :         }
     852                 :            : }
     853                 :            : 
     854                 :            : static int
     855                 :  123698784 : submit_inflight_desc(struct spdk_vhost_blk_session *bvsession,
     856                 :            :                      struct spdk_vhost_virtqueue *vq)
     857                 :            : {
     858                 :            :         struct spdk_vhost_session *vsession;
     859                 :            :         spdk_vhost_resubmit_info *resubmit;
     860                 :            :         spdk_vhost_resubmit_desc *resubmit_list;
     861                 :            :         uint16_t req_idx;
     862                 :            :         int i, resubmit_cnt;
     863                 :            : 
     864                 :  123698784 :         resubmit = vq->vring_inflight.resubmit_inflight;
     865   [ -  +  -  -  :  123698784 :         if (spdk_likely(resubmit == NULL || resubmit->resubmit_list == NULL ||
             -  +  -  - ]
     866                 :            :                         resubmit->resubmit_num == 0)) {
     867                 :  123698784 :                 return 0;
     868                 :            :         }
     869                 :            : 
     870                 :          0 :         resubmit_list = resubmit->resubmit_list;
     871                 :          0 :         vsession = &bvsession->vsession;
     872                 :            : 
     873         [ #  # ]:          0 :         for (i = resubmit->resubmit_num - 1; i >= 0; --i) {
     874                 :          0 :                 req_idx = resubmit_list[i].index;
     875   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "====== Start processing resubmit request idx %"PRIu16"======\n",
     876                 :            :                               req_idx);
     877                 :            : 
     878         [ #  # ]:          0 :                 if (spdk_unlikely(req_idx >= vq->vring.size)) {
     879                 :          0 :                         SPDK_ERRLOG("%s: request idx '%"PRIu16"' exceeds virtqueue size (%"PRIu16").\n",
     880                 :            :                                     vsession->name, req_idx, vq->vring.size);
     881                 :          0 :                         vhost_vq_used_ring_enqueue(vsession, vq, req_idx, 0);
     882                 :          0 :                         continue;
     883                 :            :                 }
     884                 :            : 
     885         [ #  # ]:          0 :                 if (vq->packed.packed_ring) {
     886                 :          0 :                         process_packed_inflight_blk_task(vq, req_idx);
     887                 :            :                 } else {
     888                 :          0 :                         process_blk_task(vq, req_idx);
     889                 :            :                 }
     890                 :            :         }
     891                 :          0 :         resubmit_cnt = resubmit->resubmit_num;
     892                 :          0 :         resubmit->resubmit_num = 0;
     893                 :          0 :         return resubmit_cnt;
     894                 :            : }
     895                 :            : 
     896                 :            : static int
     897                 :  123698784 : process_vq(struct spdk_vhost_blk_session *bvsession, struct spdk_vhost_virtqueue *vq)
     898                 :            : {
     899                 :  123698784 :         struct spdk_vhost_session *vsession = &bvsession->vsession;
     900                 :  123698784 :         uint16_t reqs[SPDK_VHOST_VQ_MAX_SUBMISSIONS];
     901                 :            :         uint16_t reqs_cnt, i;
     902                 :  123698784 :         int resubmit_cnt = 0;
     903                 :            : 
     904                 :  123698784 :         resubmit_cnt = submit_inflight_desc(bvsession, vq);
     905                 :            : 
     906                 :  123698784 :         reqs_cnt = vhost_vq_avail_ring_get(vq, reqs, SPDK_COUNTOF(reqs));
     907         [ +  + ]:  123698784 :         if (!reqs_cnt) {
     908                 :  122539840 :                 return resubmit_cnt;
     909                 :            :         }
     910                 :            : 
     911         [ +  + ]:    3607311 :         for (i = 0; i < reqs_cnt; i++) {
     912   [ -  +  -  + ]:    2448367 :                 SPDK_DEBUGLOG(vhost_blk, "====== Starting processing request idx %"PRIu16"======\n",
     913                 :            :                               reqs[i]);
     914                 :            : 
     915         [ -  + ]:    2448367 :                 if (spdk_unlikely(reqs[i] >= vq->vring.size)) {
     916                 :          0 :                         SPDK_ERRLOG("%s: request idx '%"PRIu16"' exceeds virtqueue size (%"PRIu16").\n",
     917                 :            :                                     vsession->name, reqs[i], vq->vring.size);
     918                 :          0 :                         vhost_vq_used_ring_enqueue(vsession, vq, reqs[i], 0);
     919                 :          0 :                         continue;
     920                 :            :                 }
     921                 :            : 
     922                 :    2448367 :                 rte_vhost_set_inflight_desc_split(vsession->vid, vq->vring_idx, reqs[i]);
     923                 :            : 
     924                 :    2448367 :                 process_blk_task(vq, reqs[i]);
     925                 :            :         }
     926                 :            : 
     927                 :    1158944 :         return reqs_cnt;
     928                 :            : }
     929                 :            : 
     930                 :            : static int
     931                 :          0 : process_packed_vq(struct spdk_vhost_blk_session *bvsession, struct spdk_vhost_virtqueue *vq)
     932                 :            : {
     933                 :          0 :         uint16_t i = 0;
     934                 :          0 :         uint16_t count = 0;
     935                 :          0 :         int resubmit_cnt = 0;
     936                 :            : 
     937                 :          0 :         resubmit_cnt = submit_inflight_desc(bvsession, vq);
     938                 :            : 
     939   [ #  #  #  # ]:          0 :         while (i++ < SPDK_VHOST_VQ_MAX_SUBMISSIONS &&
     940                 :          0 :                vhost_vq_packed_ring_is_avail(vq)) {
     941   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "====== Starting processing request idx %"PRIu16"======\n",
     942                 :            :                               vq->last_avail_idx);
     943                 :          0 :                 count++;
     944                 :          0 :                 process_packed_blk_task(vq, vq->last_avail_idx);
     945                 :            :         }
     946                 :            : 
     947         [ #  # ]:          0 :         return count > 0 ? count : resubmit_cnt;
     948                 :            : }
     949                 :            : 
     950                 :            : static int
     951                 :  123698784 : _vdev_vq_worker(struct spdk_vhost_virtqueue *vq)
     952                 :            : {
     953                 :  123698784 :         struct spdk_vhost_session *vsession = vq->vsession;
     954                 :  123698784 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
     955                 :            :         bool packed_ring;
     956                 :  123698784 :         int rc = 0;
     957                 :            : 
     958                 :  123698784 :         packed_ring = vq->packed.packed_ring;
     959         [ -  + ]:  123698784 :         if (packed_ring) {
     960                 :          0 :                 rc = process_packed_vq(bvsession, vq);
     961                 :            :         } else {
     962                 :  123698784 :                 rc = process_vq(bvsession, vq);
     963                 :            :         }
     964                 :            : 
     965                 :  123698784 :         vhost_session_vq_used_signal(vq);
     966                 :            : 
     967                 :  123698784 :         return rc;
     968                 :            : 
     969                 :            : }
     970                 :            : 
     971                 :            : static int
     972                 :          0 : vdev_vq_worker(void *arg)
     973                 :            : {
     974                 :          0 :         struct spdk_vhost_virtqueue *vq = arg;
     975                 :            : 
     976                 :          0 :         return _vdev_vq_worker(vq);
     977                 :            : }
     978                 :            : 
     979                 :            : static int
     980                 :  110693048 : vdev_worker(void *arg)
     981                 :            : {
     982                 :  110693048 :         struct vhost_user_poll_group *pg = arg;
     983                 :            :         struct vhost_user_pg_vq_info *vq_info;
     984                 :            :         struct spdk_vhost_virtqueue *vq;
     985                 :  110693048 :         int rc = 0;
     986                 :            : 
     987         [ +  + ]:  234391832 :         TAILQ_FOREACH(vq_info, &pg->vqs, link) {
     988                 :  123698784 :                 vq = vq_info->vq;
     989         [ -  + ]:  123698784 :                 assert(vq->poll_group == pg);
     990                 :  123698784 :                 rc = _vdev_vq_worker(vq);
     991                 :            :         }
     992                 :            : 
     993                 :  110693048 :         return rc > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
     994                 :            : }
     995                 :            : 
     996                 :            : static void
     997                 :          0 : no_bdev_process_vq(struct spdk_vhost_blk_session *bvsession, struct spdk_vhost_virtqueue *vq)
     998                 :            : {
     999                 :          0 :         struct spdk_vhost_session *vsession = &bvsession->vsession;
    1000                 :          0 :         struct iovec iovs[SPDK_VHOST_IOVS_MAX];
    1001                 :          0 :         uint32_t length;
    1002                 :          0 :         uint16_t iovcnt, req_idx;
    1003                 :            : 
    1004         [ #  # ]:          0 :         if (vhost_vq_avail_ring_get(vq, &req_idx, 1) != 1) {
    1005                 :          0 :                 return;
    1006                 :            :         }
    1007                 :            : 
    1008                 :          0 :         iovcnt = SPDK_COUNTOF(iovs);
    1009         [ #  # ]:          0 :         if (blk_iovs_split_queue_setup(bvsession, vq, req_idx, iovs, &iovcnt, &length) == 0) {
    1010                 :          0 :                 *(volatile uint8_t *)iovs[iovcnt - 1].iov_base = VIRTIO_BLK_S_IOERR;
    1011   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk_data, "Aborting request %" PRIu16"\n", req_idx);
    1012                 :            :         }
    1013                 :            : 
    1014                 :          0 :         vhost_vq_used_ring_enqueue(vsession, vq, req_idx, 0);
    1015                 :            : }
    1016                 :            : 
    1017                 :            : static void
    1018                 :          0 : no_bdev_process_packed_vq(struct spdk_vhost_blk_session *bvsession, struct spdk_vhost_virtqueue *vq)
    1019                 :            : {
    1020                 :          0 :         struct spdk_vhost_session *vsession = &bvsession->vsession;
    1021                 :            :         struct spdk_vhost_user_blk_task *task;
    1022                 :            :         struct spdk_vhost_blk_task *blk_task;
    1023                 :          0 :         uint32_t length;
    1024                 :          0 :         uint16_t req_idx = vq->last_avail_idx;
    1025                 :          0 :         uint16_t task_idx, num_descs;
    1026                 :            : 
    1027         [ #  # ]:          0 :         if (!vhost_vq_packed_ring_is_avail(vq)) {
    1028                 :          0 :                 return;
    1029                 :            :         }
    1030                 :            : 
    1031                 :          0 :         task_idx = vhost_vring_packed_desc_get_buffer_id(vq, req_idx, &num_descs);
    1032                 :          0 :         task = &((struct spdk_vhost_user_blk_task *)vq->tasks)[task_idx];
    1033                 :          0 :         blk_task = &task->blk_task;
    1034   [ #  #  #  # ]:          0 :         if (spdk_unlikely(task->used)) {
    1035                 :          0 :                 SPDK_ERRLOG("%s: request with idx '%"PRIu16"' is already pending.\n",
    1036                 :            :                             vsession->name, req_idx);
    1037                 :          0 :                 vhost_vq_packed_ring_enqueue(vsession, vq, num_descs,
    1038                 :          0 :                                              task->buffer_id, blk_task->used_len,
    1039                 :          0 :                                              task->inflight_head);
    1040                 :          0 :                 return;
    1041                 :            :         }
    1042                 :            : 
    1043                 :          0 :         task->req_idx = req_idx;
    1044                 :          0 :         task->num_descs = num_descs;
    1045                 :          0 :         task->buffer_id = task_idx;
    1046                 :          0 :         blk_task_init(task);
    1047                 :            : 
    1048         [ #  # ]:          0 :         if (blk_iovs_packed_queue_setup(bvsession, vq, task->req_idx, blk_task->iovs, &blk_task->iovcnt,
    1049                 :            :                                         &length)) {
    1050                 :          0 :                 *(volatile uint8_t *)(blk_task->iovs[blk_task->iovcnt - 1].iov_base) = VIRTIO_BLK_S_IOERR;
    1051   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk_data, "Aborting request %" PRIu16"\n", req_idx);
    1052                 :            :         }
    1053                 :            : 
    1054                 :          0 :         task->used = false;
    1055                 :          0 :         vhost_vq_packed_ring_enqueue(vsession, vq, num_descs,
    1056                 :          0 :                                      task->buffer_id, blk_task->used_len,
    1057                 :          0 :                                      task->inflight_head);
    1058                 :            : }
    1059                 :            : 
    1060                 :            : static int
    1061                 :          0 : _no_bdev_vdev_vq_worker(struct spdk_vhost_virtqueue *vq)
    1062                 :            : {
    1063                 :          0 :         struct spdk_vhost_session *vsession = vq->vsession;
    1064                 :          0 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
    1065                 :          0 :         struct vhost_user_poll_group *pg = (struct vhost_user_poll_group *)vq->poll_group;
    1066                 :            : 
    1067                 :            :         bool packed_ring;
    1068                 :            : 
    1069                 :          0 :         packed_ring = vq->packed.packed_ring;
    1070         [ #  # ]:          0 :         if (packed_ring) {
    1071                 :          0 :                 no_bdev_process_packed_vq(bvsession, vq);
    1072                 :            :         } else {
    1073                 :          0 :                 no_bdev_process_vq(bvsession, vq);
    1074                 :            :         }
    1075                 :            : 
    1076                 :          0 :         vhost_session_vq_used_signal(vq);
    1077                 :            : 
    1078   [ #  #  #  # ]:          0 :         if (pg->task_cnt == 0 && pg->io_channel) {
    1079                 :          0 :                 vhost_blk_put_io_channel(pg->io_channel);
    1080                 :          0 :                 pg->io_channel = NULL;
    1081                 :            :         }
    1082                 :            : 
    1083                 :          0 :         return SPDK_POLLER_BUSY;
    1084                 :            : }
    1085                 :            : 
    1086                 :            : static int
    1087                 :          0 : no_bdev_vdev_vq_worker(void *arg)
    1088                 :            : {
    1089                 :          0 :         struct spdk_vhost_virtqueue *vq = arg;
    1090                 :            : 
    1091                 :          0 :         return _no_bdev_vdev_vq_worker(vq);
    1092                 :            : }
    1093                 :            : 
    1094                 :            : static int
    1095                 :          0 : no_bdev_vdev_worker(void *arg)
    1096                 :            : {
    1097                 :          0 :         struct vhost_user_poll_group *pg = arg;
    1098                 :            :         struct vhost_user_pg_vq_info *vq_info;
    1099                 :          0 :         int rc = 0;
    1100                 :            : 
    1101         [ #  # ]:          0 :         TAILQ_FOREACH(vq_info, &pg->vqs, link) {
    1102                 :          0 :                 rc = _no_bdev_vdev_vq_worker(vq_info->vq);
    1103                 :            :         }
    1104                 :            : 
    1105                 :          0 :         return rc > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
    1106                 :            : }
    1107                 :            : 
    1108                 :            : static void
    1109                 :         67 : vhost_blk_pg_unregister_interrupts(struct vhost_user_poll_group *pg)
    1110                 :            : {
    1111                 :            :         struct vhost_user_pg_vq_info *vq_info;
    1112                 :            :         struct spdk_vhost_virtqueue *vq;
    1113                 :            : 
    1114         [ +  + ]:         67 :         TAILQ_FOREACH(vq_info, &pg->vqs, link) {
    1115                 :         52 :                 vq = vq_info->vq;
    1116         [ +  - ]:         52 :                 if (vq->intr == NULL) {
    1117                 :         52 :                         break;
    1118                 :            :                 }
    1119                 :            : 
    1120   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "unregister vq[%d]'s kickfd is %d\n",
    1121                 :            :                               vq->vring_idx, vq->vring.kickfd);
    1122                 :          0 :                 spdk_interrupt_unregister(&vq->intr);
    1123                 :            :         }
    1124                 :         67 : }
    1125                 :            : 
    1126                 :            : static void
    1127                 :          0 : vhost_blk_vq_register_interrupt(struct spdk_vhost_virtqueue *vq)
    1128                 :            : {
    1129                 :          0 :         struct spdk_vhost_session *vsession = vq->vsession;
    1130                 :          0 :         struct spdk_vhost_blk_dev *bvdev =  to_blk_dev(vsession->vdev);
    1131                 :            : 
    1132         [ #  # ]:          0 :         assert(bvdev != NULL);
    1133                 :            : 
    1134         [ #  # ]:          0 :         if (bvdev->bdev) {
    1135                 :          0 :                 vq->intr = spdk_interrupt_register(vq->vring.kickfd, vdev_vq_worker, vq, "vdev_vq_worker");
    1136                 :            :         } else {
    1137                 :          0 :                 vq->intr = spdk_interrupt_register(vq->vring.kickfd, no_bdev_vdev_vq_worker, vq,
    1138                 :            :                                                    "no_bdev_vdev_vq_worker");
    1139                 :            :         }
    1140                 :            : 
    1141         [ #  # ]:          0 :         if (vq->intr == NULL) {
    1142                 :          0 :                 SPDK_ERRLOG("Fail to register req notifier handler.\n");
    1143                 :          0 :                 assert(false);
    1144                 :            :         }
    1145                 :          0 : }
    1146                 :            : 
    1147                 :            : static void
    1148                 :         66 : add_vq_to_poll_group(void *arg)
    1149                 :            : {
    1150                 :         66 :         struct vhost_user_pg_vq_info *vq_info = arg;
    1151                 :         66 :         struct vhost_user_poll_group *pg = vq_info->pg;
    1152                 :            : 
    1153   [ -  +  -  + ]:         66 :         SPDK_DEBUGLOG(vhost_blk, "%s: vring %u is added to pg %p, thread %s, lcore %u\n",
    1154                 :            :                       pg->vsession->name,
    1155                 :            :                       vq_info->vq->vring_idx, pg, spdk_thread_get_name(spdk_get_thread()), spdk_env_get_current_core());
    1156                 :            : 
    1157                 :         66 :         TAILQ_INSERT_TAIL(&pg->vqs, vq_info, link);
    1158                 :            : 
    1159         [ -  + ]:         66 :         if (spdk_interrupt_mode_is_enabled()) {
    1160                 :          0 :                 vhost_blk_vq_register_interrupt(vq_info->vq);
    1161                 :            :         }
    1162                 :         66 : }
    1163                 :            : 
    1164                 :            : static struct vhost_user_poll_group *
    1165                 :        109 : get_optimal_poll_group(struct spdk_vhost_blk_session *bvsession)
    1166                 :            : {
    1167                 :            :         struct vhost_user_poll_group *pg;
    1168                 :            :         struct spdk_vhost_blk_dev *bvdev;
    1169                 :            : 
    1170         [ -  + ]:        109 :         if (bvsession->bvdev == NULL) {
    1171                 :          0 :                 return NULL;
    1172                 :            :         }
    1173                 :            : 
    1174                 :            :         /* round robin */
    1175                 :        109 :         bvdev = bvsession->bvdev;
    1176         [ +  + ]:        109 :         if (bvdev->next_pg_index >= bvsession->num_poll_groups) {
    1177                 :         62 :                 bvdev->next_pg_index = 0;
    1178                 :            :         }
    1179                 :            : 
    1180                 :        109 :         pg = &bvsession->poll_groups[bvdev->next_pg_index];
    1181                 :        109 :         bvdev->next_pg_index++;
    1182                 :            : 
    1183                 :        109 :         return pg;
    1184                 :            : }
    1185                 :            : 
    1186                 :            : static int
    1187                 :        109 : vhost_blk_vq_enable(struct spdk_vhost_session *vsession, struct spdk_vhost_virtqueue *vq)
    1188                 :            : {
    1189                 :        109 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
    1190                 :            :         struct spdk_vhost_dev *vdev;
    1191                 :            :         struct spdk_vhost_user_dev *user_dev;
    1192                 :            :         struct vhost_user_pg_vq_info *vq_info;
    1193                 :            : 
    1194                 :        109 :         vdev = vsession->vdev;
    1195                 :        109 :         user_dev = to_user_dev(vdev);
    1196                 :            : 
    1197   [ -  +  -  + ]:        109 :         SPDK_DEBUGLOG(vhost_blk, "%s: enable vq %u\n", vsession->name, vq->vring_idx);
    1198                 :            : 
    1199         [ -  + ]:        109 :         pthread_mutex_lock(&user_dev->lock);
    1200   [ -  +  +  +  :        109 :         if (vsession->started || vsession->starting) {
             -  +  -  + ]
    1201         [ -  + ]:         66 :                 pthread_mutex_unlock(&user_dev->lock);
    1202                 :         66 :                 vq_info = calloc(1, sizeof(*vq_info));
    1203         [ -  + ]:         66 :                 if (!vq_info) {
    1204                 :          0 :                         SPDK_ERRLOG("Failed to allocate vq_info\n");
    1205                 :          0 :                         return -ENOMEM;
    1206                 :            :                 }
    1207                 :         66 :                 vq_info->vq = vq;
    1208                 :         66 :                 vq_info->pg = get_optimal_poll_group(bvsession);
    1209         [ -  + ]:         66 :                 if (vq_info->pg == NULL) {
    1210                 :          0 :                         free(vq_info);
    1211                 :          0 :                         return -EFAULT;
    1212                 :            :                 }
    1213                 :         66 :                 vq->poll_group = (void *)vq_info->pg;
    1214                 :         66 :                 spdk_thread_send_msg(vq_info->pg->thread, add_vq_to_poll_group, vq_info);
    1215                 :         66 :                 return 0;
    1216                 :            :         }
    1217         [ -  + ]:         43 :         pthread_mutex_unlock(&user_dev->lock);
    1218                 :            : 
    1219                 :         43 :         return 0;
    1220                 :            : }
    1221                 :            : 
    1222                 :            : static int
    1223                 :          0 : vhost_blk_pg_register_no_bdev_interrupts(struct vhost_user_poll_group *pg)
    1224                 :            : {
    1225                 :            :         struct vhost_user_pg_vq_info *vq_info;
    1226                 :            :         struct spdk_vhost_virtqueue *vq;
    1227                 :            : 
    1228         [ #  # ]:          0 :         TAILQ_FOREACH(vq_info, &pg->vqs, link) {
    1229                 :          0 :                 vq = vq_info->vq;
    1230   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "Register vq[%d]'s kickfd is %d\n",
    1231                 :            :                               vq->vring_idx, vq->vring.kickfd);
    1232                 :          0 :                 vq->intr = spdk_interrupt_register(vq->vring.kickfd, no_bdev_vdev_vq_worker, vq,
    1233                 :            :                                                    "no_bdev_vdev_vq_worker");
    1234         [ #  # ]:          0 :                 if (vq->intr == NULL) {
    1235                 :          0 :                         goto err;
    1236                 :            :                 }
    1237                 :            : 
    1238                 :            :         }
    1239                 :            : 
    1240                 :          0 :         return 0;
    1241                 :            : 
    1242                 :          0 : err:
    1243                 :          0 :         vhost_blk_pg_unregister_interrupts(pg);
    1244                 :          0 :         return -1;
    1245                 :            : }
    1246                 :            : 
    1247                 :            : static void
    1248                 :          0 : vhost_blk_poller_set_interrupt_mode(struct spdk_poller *poller, void *cb_arg, bool interrupt_mode)
    1249                 :            : {
    1250                 :          0 :         struct spdk_vhost_blk_session *bvsession = cb_arg;
    1251                 :            : 
    1252                 :          0 :         vhost_user_session_set_interrupt_mode(&bvsession->vsession, interrupt_mode);
    1253                 :          0 : }
    1254                 :            : 
    1255                 :            : static void
    1256                 :          4 : bdev_event_cpl_cb(struct spdk_vhost_dev *vdev, void *ctx)
    1257                 :            : {
    1258                 :          4 :         enum spdk_bdev_event_type type = (enum spdk_bdev_event_type)(uintptr_t)ctx;
    1259                 :            :         struct spdk_vhost_blk_dev *bvdev;
    1260                 :            : 
    1261         [ +  - ]:          4 :         if (type == SPDK_BDEV_EVENT_REMOVE) {
    1262                 :            :                 /* All sessions have been notified, time to close the bdev */
    1263                 :          4 :                 bvdev = to_blk_dev(vdev);
    1264         [ -  + ]:          4 :                 assert(bvdev != NULL);
    1265                 :          4 :                 spdk_bdev_close(bvdev->bdev_desc);
    1266                 :          4 :                 bvdev->bdev_desc = NULL;
    1267                 :          4 :                 bvdev->bdev = NULL;
    1268                 :            :         }
    1269                 :          4 : }
    1270                 :            : 
    1271                 :            : static int
    1272                 :          0 : vhost_session_bdev_resize_cb(struct spdk_vhost_dev *vdev,
    1273                 :            :                              struct spdk_vhost_session *vsession,
    1274                 :            :                              void *ctx)
    1275                 :            : {
    1276                 :          0 :         SPDK_NOTICELOG("bdev send slave msg to vid(%d)\n", vsession->vid);
    1277                 :            : #if RTE_VERSION >= RTE_VERSION_NUM(23, 03, 0, 0)
    1278                 :          0 :         rte_vhost_backend_config_change(vsession->vid, false);
    1279                 :            : #else
    1280                 :            :         rte_vhost_slave_config_change(vsession->vid, false);
    1281                 :            : #endif
    1282                 :            : 
    1283                 :          0 :         return 0;
    1284                 :            : }
    1285                 :            : 
    1286                 :            : static void
    1287                 :          0 : vhost_user_blk_resize_cb(struct spdk_vhost_dev *vdev, bdev_event_cb_complete cb, void *cb_arg)
    1288                 :            : {
    1289                 :          0 :         vhost_user_dev_foreach_session(vdev, vhost_session_bdev_resize_cb,
    1290                 :            :                                        cb, cb_arg);
    1291                 :          0 : }
    1292                 :            : 
    1293                 :            : static void
    1294                 :          0 : _vhost_user_session_bdev_remove_cb(void *arg)
    1295                 :            : {
    1296                 :          0 :         struct vhost_user_poll_group *pg = arg;
    1297                 :          0 :         struct spdk_vhost_session *vsession = pg->vsession;
    1298                 :          0 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
    1299                 :            :         int rc;
    1300                 :            : 
    1301         [ #  # ]:          0 :         if (pg->requestq_poller == NULL) {
    1302                 :          0 :                 return;
    1303                 :            :         }
    1304                 :            : 
    1305                 :          0 :         spdk_poller_unregister(&pg->requestq_poller);
    1306         [ #  # ]:          0 :         if (spdk_interrupt_mode_is_enabled()) {
    1307                 :          0 :                 vhost_blk_pg_unregister_interrupts(pg);
    1308                 :          0 :                 rc = vhost_blk_pg_register_no_bdev_interrupts(pg);
    1309         [ #  # ]:          0 :                 if (rc) {
    1310                 :          0 :                         SPDK_ERRLOG("Interrupt register failed\n");
    1311                 :          0 :                         return;
    1312                 :            :                 }
    1313                 :            :         }
    1314                 :            : 
    1315                 :          0 :         pg->requestq_poller = SPDK_POLLER_REGISTER(no_bdev_vdev_worker, pg, 0);
    1316                 :          0 :         spdk_poller_register_interrupt(pg->requestq_poller, vhost_blk_poller_set_interrupt_mode, bvsession);
    1317                 :            : }
    1318                 :            : 
    1319                 :            : static int
    1320                 :          0 : vhost_user_session_bdev_remove_cb(struct spdk_vhost_dev *vdev,
    1321                 :            :                                   struct spdk_vhost_session *vsession,
    1322                 :            :                                   void *ctx)
    1323                 :            : {
    1324                 :          0 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
    1325                 :            :         struct vhost_user_poll_group *pg;
    1326                 :            :         uint32_t i;
    1327                 :            : 
    1328         [ #  # ]:          0 :         for (i = 0; i < bvsession->num_poll_groups; i++) {
    1329                 :          0 :                 pg = &bvsession->poll_groups[i];
    1330                 :          0 :                 spdk_thread_send_msg(pg->thread, _vhost_user_session_bdev_remove_cb, pg);
    1331                 :            :         }
    1332                 :            : 
    1333                 :          0 :         return 0;
    1334                 :            : }
    1335                 :            : 
    1336                 :            : static void
    1337                 :          4 : vhost_user_bdev_remove_cb(struct spdk_vhost_dev *vdev, bdev_event_cb_complete cb, void *cb_arg)
    1338                 :            : {
    1339                 :          4 :         SPDK_WARNLOG("%s: hot-removing bdev - all further requests will fail.\n",
    1340                 :            :                      vdev->name);
    1341                 :            : 
    1342                 :          4 :         vhost_user_dev_foreach_session(vdev, vhost_user_session_bdev_remove_cb,
    1343                 :            :                                        cb, cb_arg);
    1344                 :          4 : }
    1345                 :            : 
    1346                 :            : static void
    1347                 :          4 : vhost_user_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_vhost_dev *vdev,
    1348                 :            :                          bdev_event_cb_complete cb, void *cb_arg)
    1349                 :            : {
    1350      [ +  -  - ]:          4 :         switch (type) {
    1351                 :          4 :         case SPDK_BDEV_EVENT_REMOVE:
    1352                 :          4 :                 vhost_user_bdev_remove_cb(vdev, cb, cb_arg);
    1353                 :          4 :                 break;
    1354                 :          0 :         case SPDK_BDEV_EVENT_RESIZE:
    1355                 :          0 :                 vhost_user_blk_resize_cb(vdev, cb, cb_arg);
    1356                 :          0 :                 break;
    1357                 :          0 :         default:
    1358                 :          0 :                 assert(false);
    1359                 :            :                 return;
    1360                 :            :         }
    1361                 :          0 : }
    1362                 :            : 
    1363                 :            : static void
    1364                 :          4 : bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
    1365                 :            :               void *event_ctx)
    1366                 :            : {
    1367                 :          4 :         struct spdk_vhost_dev *vdev = (struct spdk_vhost_dev *)event_ctx;
    1368                 :          4 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
    1369                 :            : 
    1370         [ -  + ]:          4 :         assert(bvdev != NULL);
    1371                 :            : 
    1372   [ -  +  -  + ]:          4 :         SPDK_DEBUGLOG(vhost_blk, "Bdev event: type %d, name %s\n",
    1373                 :            :                       type,
    1374                 :            :                       bdev->name);
    1375                 :            : 
    1376         [ +  - ]:          4 :         switch (type) {
    1377                 :          4 :         case SPDK_BDEV_EVENT_REMOVE:
    1378                 :            :         case SPDK_BDEV_EVENT_RESIZE:
    1379                 :          4 :                 bvdev->ops->bdev_event(type, vdev, bdev_event_cpl_cb, (void *)type);
    1380                 :          4 :                 break;
    1381                 :          0 :         default:
    1382                 :          0 :                 SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
    1383                 :          0 :                 break;
    1384                 :            :         }
    1385                 :          4 : }
    1386                 :            : 
    1387                 :            : static void
    1388                 :         43 : free_task_pool(struct spdk_vhost_blk_session *bvsession)
    1389                 :            : {
    1390                 :         43 :         struct spdk_vhost_session *vsession = &bvsession->vsession;
    1391                 :            :         struct spdk_vhost_virtqueue *vq;
    1392                 :            :         uint16_t i;
    1393                 :            : 
    1394         [ +  + ]:        152 :         for (i = 0; i < vsession->max_queues; i++) {
    1395                 :        109 :                 vq = &vsession->virtqueue[i];
    1396         [ -  + ]:        109 :                 if (vq->tasks == NULL) {
    1397                 :          0 :                         continue;
    1398                 :            :                 }
    1399                 :            : 
    1400                 :        109 :                 spdk_free(vq->tasks);
    1401                 :        109 :                 vq->tasks = NULL;
    1402                 :            :         }
    1403                 :         43 : }
    1404                 :            : 
    1405                 :            : static int
    1406                 :        109 : alloc_vq_task_pool(struct spdk_vhost_session *vsession, uint16_t qid)
    1407                 :            : {
    1408                 :        109 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
    1409                 :            :         struct spdk_vhost_virtqueue *vq;
    1410                 :            :         struct spdk_vhost_user_blk_task *task;
    1411                 :            :         uint32_t task_cnt;
    1412                 :            :         uint32_t j;
    1413                 :            : 
    1414         [ -  + ]:        109 :         if (qid >= SPDK_VHOST_MAX_VQUEUES) {
    1415                 :          0 :                 return -EINVAL;
    1416                 :            :         }
    1417                 :            : 
    1418                 :        109 :         vq = &vsession->virtqueue[qid];
    1419         [ -  + ]:        109 :         if (vq->vring.desc == NULL) {
    1420                 :          0 :                 return 0;
    1421                 :            :         }
    1422                 :            : 
    1423                 :        109 :         task_cnt = vq->vring.size;
    1424         [ -  + ]:        109 :         if (task_cnt > SPDK_VHOST_MAX_VQ_SIZE) {
    1425                 :            :                 /* sanity check */
    1426                 :          0 :                 SPDK_ERRLOG("%s: virtqueue %"PRIu16" is too big. (size = %"PRIu32", max = %"PRIu32")\n",
    1427                 :            :                             vsession->name, qid, task_cnt, SPDK_VHOST_MAX_VQ_SIZE);
    1428                 :          0 :                 return -1;
    1429                 :            :         }
    1430                 :        109 :         vq->tasks = spdk_zmalloc(sizeof(struct spdk_vhost_user_blk_task) * task_cnt,
    1431                 :            :                                  SPDK_CACHE_LINE_SIZE, NULL,
    1432                 :            :                                  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
    1433         [ -  + ]:        109 :         if (vq->tasks == NULL) {
    1434                 :          0 :                 SPDK_ERRLOG("%s: failed to allocate %"PRIu32" tasks for virtqueue %"PRIu16"\n",
    1435                 :            :                             vsession->name, task_cnt, qid);
    1436                 :          0 :                 return -1;
    1437                 :            :         }
    1438                 :            : 
    1439         [ +  + ]:      40557 :         for (j = 0; j < task_cnt; j++) {
    1440                 :      40448 :                 task = &((struct spdk_vhost_user_blk_task *)vq->tasks)[j];
    1441                 :      40448 :                 task->bvsession = bvsession;
    1442                 :      40448 :                 task->req_idx = j;
    1443                 :      40448 :                 task->vq = vq;
    1444                 :            :         }
    1445                 :            : 
    1446                 :        109 :         return 0;
    1447                 :            : }
    1448                 :            : 
    1449                 :            : static void
    1450                 :         67 : session_start_poll_group(void *args)
    1451                 :            : {
    1452                 :            :         struct vhost_user_pg_vq_info *vq_info;
    1453                 :         67 :         struct vhost_user_poll_group *pg = args;
    1454                 :         67 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(pg->vdev);
    1455                 :         67 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(pg->vsession);
    1456                 :            : 
    1457         [ -  + ]:         67 :         assert(bvdev != NULL);
    1458                 :            : 
    1459         [ +  - ]:         67 :         if (bvdev->bdev) {
    1460                 :         67 :                 pg->io_channel = vhost_blk_get_io_channel(pg->vdev);
    1461   [ -  +  -  + ]:         67 :                 SPDK_DEBUGLOG(vhost_blk, "%s: pg %p, pg io channel %p, thread %s, lcore %u\n",
    1462                 :            :                               bvsession->vsession.name, pg,
    1463                 :            :                               pg->io_channel, spdk_thread_get_name(spdk_get_thread()), spdk_env_get_current_core());
    1464         [ -  + ]:         67 :                 if (!pg->io_channel) {
    1465                 :          0 :                         SPDK_ERRLOG("%s: I/O channel allocation failed\n", bvsession->vsession.name);
    1466                 :          0 :                         return;
    1467                 :            :                 }
    1468                 :            :         }
    1469                 :            : 
    1470         [ -  + ]:         67 :         if (spdk_interrupt_mode_is_enabled()) {
    1471         [ #  # ]:          0 :                 TAILQ_FOREACH(vq_info, &pg->vqs, link) {
    1472                 :          0 :                         vhost_blk_vq_register_interrupt(vq_info->vq);
    1473                 :            :                 }
    1474                 :            :         }
    1475                 :            : 
    1476         [ +  - ]:         67 :         if (bvdev->bdev) {
    1477                 :         67 :                 pg->requestq_poller = SPDK_POLLER_REGISTER(vdev_worker, pg, 0);
    1478                 :            :         } else {
    1479                 :          0 :                 pg->requestq_poller = SPDK_POLLER_REGISTER(no_bdev_vdev_worker, pg, 0);
    1480                 :            :         }
    1481   [ -  +  -  + ]:         67 :         SPDK_INFOLOG(vhost, "%s: poller started on lcore %d\n",
    1482                 :            :                      bvsession->vsession.name, spdk_env_get_current_core());
    1483                 :            : 
    1484                 :         67 :         spdk_poller_register_interrupt(pg->requestq_poller, vhost_blk_poller_set_interrupt_mode, bvsession);
    1485                 :            : }
    1486                 :            : 
    1487                 :            : static int
    1488                 :         43 : session_start_poll_groups(struct spdk_vhost_dev *vdev, struct spdk_vhost_session *vsession)
    1489                 :            : {
    1490                 :         43 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
    1491                 :            :         struct vhost_user_poll_group *pg;
    1492                 :            :         struct vhost_user_pg_vq_info *vq_info;
    1493                 :            :         struct spdk_cpuset *cpumask;
    1494                 :         43 :         char thread_name[128];
    1495                 :         43 :         uint32_t i, index = 0;
    1496                 :         43 :         int rc = 0;
    1497                 :            : 
    1498                 :         43 :         bvsession->thread = vdev->thread;
    1499                 :         43 :         cpumask = spdk_thread_get_cpumask(vdev->thread);
    1500                 :            :         /* If no cpumask is input by user, we still start one thread for the device */
    1501   [ -  +  +  + ]:         43 :         if (vdev->use_default_cpumask) {
    1502                 :         30 :                 bvsession->num_poll_groups = 1;
    1503                 :            :         } else {
    1504                 :         13 :                 bvsession->num_poll_groups = spdk_cpuset_count(cpumask);
    1505                 :            :         }
    1506                 :         43 :         bvsession->poll_groups = calloc(bvsession->num_poll_groups, sizeof(struct vhost_user_poll_group));
    1507         [ -  + ]:         43 :         if (!bvsession->poll_groups) {
    1508                 :          0 :                 SPDK_ERRLOG("Failed to allocate poll groups\n");
    1509                 :          0 :                 return -ENOMEM;
    1510                 :            :         }
    1511                 :            : 
    1512         [ +  + ]:        110 :         for (i = 0; i < bvsession->num_poll_groups; i++) {
    1513                 :         67 :                 pg = &bvsession->poll_groups[i];
    1514                 :         67 :                 TAILQ_INIT(&pg->vqs);
    1515                 :            :         }
    1516                 :            : 
    1517         [ +  + ]:         86 :         for (i = 0; i < vsession->max_queues; i++) {
    1518                 :         43 :                 vq_info = calloc(1, sizeof(*vq_info));
    1519         [ -  + ]:         43 :                 if (!vq_info) {
    1520                 :          0 :                         SPDK_ERRLOG("Failed to allocate vq_info\n");
    1521                 :          0 :                         rc = -ENOMEM;
    1522                 :          0 :                         goto err;
    1523                 :            :                 }
    1524                 :         43 :                 vq_info->vq = &vsession->virtqueue[i];
    1525                 :         43 :                 vq_info->vsession = vsession;
    1526                 :            : 
    1527                 :         43 :                 pg = get_optimal_poll_group(bvsession);
    1528         [ -  + ]:         43 :                 if (pg == NULL) {
    1529                 :          0 :                         free(vq_info);
    1530                 :          0 :                         rc = -EFAULT;
    1531                 :          0 :                         goto err;
    1532                 :            :                 }
    1533                 :         43 :                 vq_info->pg = pg;
    1534                 :         43 :                 vq_info->vq->poll_group = pg;
    1535                 :            : 
    1536   [ -  +  -  + ]:         43 :                 SPDK_DEBUGLOG(vhost_blk, "%s: vring %u is added to pg %p\n", vsession->name, i, pg);
    1537                 :         43 :                 TAILQ_INSERT_TAIL(&pg->vqs, vq_info, link);
    1538                 :            :         }
    1539                 :            : 
    1540         [ +  - ]:         70 :         SPDK_ENV_FOREACH_CORE(i) {
    1541         [ +  + ]:         70 :                 if (!spdk_cpuset_get_cpu(cpumask, i)) {
    1542                 :          3 :                         continue;
    1543                 :            :                 }
    1544                 :            : 
    1545         [ -  + ]:         67 :                 snprintf(thread_name, sizeof(thread_name), "%s.%u_%u", vdev->name, vsession->vid, i);
    1546                 :         67 :                 pg = &bvsession->poll_groups[index];
    1547                 :         67 :                 pg->vdev = vdev;
    1548                 :         67 :                 pg->vsession = vsession;
    1549                 :         67 :                 pg->thread = spdk_thread_create(thread_name, cpumask);
    1550         [ -  + ]:         67 :                 if (!pg->thread) {
    1551                 :          0 :                         SPDK_ERRLOG("Failed to create %s session %d poll groups\n", vdev->name, vsession->vid);
    1552                 :          0 :                         rc = -EFAULT;
    1553                 :          0 :                         goto err;
    1554                 :            :                 }
    1555                 :         67 :                 spdk_thread_send_msg(pg->thread, session_start_poll_group, pg);
    1556                 :         67 :                 index++;
    1557         [ +  + ]:         67 :                 if (index == bvsession->num_poll_groups) {
    1558                 :         43 :                         break;
    1559                 :            :                 }
    1560                 :            :         }
    1561                 :            : 
    1562                 :         43 :         return 0;
    1563                 :            : 
    1564                 :          0 : err:
    1565                 :          0 :         session_stop_poll_groups(bvsession);
    1566                 :          0 :         return rc;
    1567                 :            : }
    1568                 :            : 
    1569                 :            : static int
    1570                 :         43 : vhost_blk_start(struct spdk_vhost_dev *vdev,
    1571                 :            :                 struct spdk_vhost_session *vsession, void *unused)
    1572                 :            : {
    1573                 :         43 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
    1574                 :            :         struct spdk_vhost_blk_dev *bvdev;
    1575                 :            :         int i;
    1576                 :            : 
    1577                 :            :         /* return if start is already in progress */
    1578   [ -  +  +  -  :         43 :         if (vsession->started || vsession->starting) {
             -  +  -  + ]
    1579   [ #  #  #  # ]:          0 :                 SPDK_INFOLOG(vhost, "%s: is starting or started\n", vsession->name);
    1580                 :          0 :                 return -EINPROGRESS;
    1581                 :            :         }
    1582                 :            : 
    1583                 :            :         /* validate all I/O queues are in a contiguous index range */
    1584         [ +  + ]:         86 :         for (i = 0; i < vsession->max_queues; i++) {
    1585                 :            :                 /* vring.desc and vring.desc_packed are in a union struct
    1586                 :            :                  * so q->vring.desc can replace q->vring.desc_packed.
    1587                 :            :                  */
    1588         [ -  + ]:         43 :                 if (vsession->virtqueue[i].vring.desc == NULL) {
    1589                 :          0 :                         SPDK_ERRLOG("%s: queue %"PRIu32" is empty\n", vsession->name, i);
    1590                 :          0 :                         return -1;
    1591                 :            :                 }
    1592                 :            :         }
    1593                 :            : 
    1594                 :         43 :         bvdev = to_blk_dev(vdev);
    1595         [ -  + ]:         43 :         assert(bvdev != NULL);
    1596                 :         43 :         bvsession->bvdev = bvdev;
    1597                 :            : 
    1598                 :         43 :         return session_start_poll_groups(vdev, vsession);
    1599                 :            : }
    1600                 :            : 
    1601                 :            : static void
    1602                 :         67 : session_stop_poll_group_done(void *arg)
    1603                 :            : {
    1604                 :         67 :         struct spdk_vhost_blk_session *bvession = arg;
    1605                 :            : 
    1606                 :         67 :         bvession->num_stopped_poll_groups++;
    1607                 :         67 : }
    1608                 :            : 
    1609                 :            : static int
    1610                 :         67 : pg_stop_poller_cb(void *args)
    1611                 :            : {
    1612                 :         67 :         struct vhost_user_poll_group *pg = args;
    1613                 :            :         struct spdk_vhost_blk_session *bvsession;
    1614                 :            :         struct vhost_user_pg_vq_info *vq_info, *tmp;
    1615                 :            : 
    1616         [ +  - ]:         67 :         if (!pg->task_cnt) {
    1617         [ +  + ]:        176 :                 TAILQ_FOREACH_SAFE(vq_info, &pg->vqs, link, tmp) {
    1618         [ +  + ]:        109 :                         TAILQ_REMOVE(&pg->vqs, vq_info, link);
    1619                 :        109 :                         vq_info->vq->next_event_time = 0;
    1620                 :        109 :                         vhost_vq_used_signal(pg->vsession, vq_info->vq);
    1621                 :        109 :                         free(vq_info);
    1622                 :            :                 }
    1623                 :         67 :                 goto done;
    1624                 :            :         }
    1625                 :            : 
    1626                 :          0 :         pg->stop_retry_count--;
    1627         [ #  # ]:          0 :         if (pg->stop_retry_count) {
    1628                 :          0 :                 return SPDK_POLLER_IDLE;
    1629                 :            :         }
    1630                 :            : 
    1631                 :          0 : done:
    1632   [ -  +  -  + ]:         67 :         SPDK_INFOLOG(vhost, "%s: stopping poller on lcore %d\n",
    1633                 :            :                      pg->vsession->name, spdk_env_get_current_core());
    1634                 :            : 
    1635                 :         67 :         spdk_poller_unregister(&pg->stop_poller);
    1636         [ +  - ]:         67 :         if (pg->io_channel) {
    1637                 :         67 :                 vhost_blk_put_io_channel(pg->io_channel);
    1638                 :         67 :                 pg->io_channel = NULL;
    1639                 :            :         }
    1640                 :            : 
    1641                 :         67 :         bvsession = to_blk_session(pg->vsession);
    1642                 :         67 :         spdk_thread_exit(pg->thread);
    1643                 :         67 :         spdk_thread_send_msg(bvsession->thread, session_stop_poll_group_done, bvsession);
    1644                 :            : 
    1645                 :         67 :         return SPDK_POLLER_BUSY;
    1646                 :            : }
    1647                 :            : 
    1648                 :            : static void
    1649                 :         67 : session_stop_poll_group(void *args)
    1650                 :            : {
    1651                 :         67 :         struct vhost_user_poll_group *pg = args;
    1652                 :            : 
    1653                 :         67 :         spdk_poller_unregister(&pg->requestq_poller);
    1654                 :         67 :         vhost_blk_pg_unregister_interrupts(pg);
    1655                 :            : 
    1656                 :            :         /* Timeout value should be less than SPDK_VHOST_SESSION_STOP_RETRY_TIMEOUT_IN_SEC */
    1657                 :         67 :         pg->stop_retry_count = (SPDK_VHOST_SESSION_STOP_TIMEOUT_IN_SEC * 1000 *
    1658                 :            :                                 1000) / SPDK_VHOST_SESSION_STOP_RETRY_PERIOD_IN_US;
    1659                 :         67 :         pg->stop_poller = SPDK_POLLER_REGISTER(pg_stop_poller_cb, pg,
    1660                 :            :                                                SPDK_VHOST_SESSION_STOP_RETRY_PERIOD_IN_US);
    1661                 :         67 : }
    1662                 :            : 
    1663                 :            : static void
    1664                 :         43 : session_stop_poll_groups(struct spdk_vhost_blk_session *bvsession)
    1665                 :            : {
    1666                 :            :         uint32_t i;
    1667                 :            :         struct vhost_user_poll_group *pg;
    1668                 :            : 
    1669                 :         43 :         bvsession->num_stopped_poll_groups = 0;
    1670         [ +  + ]:        110 :         for (i = 0; i < bvsession->num_poll_groups; i++) {
    1671                 :         67 :                 pg = &bvsession->poll_groups[i];
    1672         [ +  - ]:         67 :                 if (pg->thread) {
    1673                 :         67 :                         spdk_thread_send_msg(pg->thread, session_stop_poll_group, pg);
    1674                 :            :                 }
    1675                 :            :         }
    1676                 :         43 : }
    1677                 :            : 
    1678                 :            : static int
    1679                 :         85 : destroy_session_poller_cb(void *arg)
    1680                 :            : {
    1681                 :         85 :         struct spdk_vhost_blk_session *bvsession = arg;
    1682                 :         85 :         struct spdk_vhost_session *vsession = &bvsession->vsession;
    1683                 :         85 :         struct spdk_vhost_user_dev *user_dev = to_user_dev(vsession->vdev);
    1684                 :            : 
    1685   [ +  +  -  + ]:        128 :         if ((bvsession->num_stopped_poll_groups != bvsession->num_poll_groups) ||
    1686         [ -  + ]:         43 :             (pthread_mutex_trylock(&user_dev->lock) != 0)) {
    1687         [ -  + ]:         42 :                 assert(vsession->stop_retry_count > 0);
    1688                 :         42 :                 vsession->stop_retry_count--;
    1689         [ -  + ]:         42 :                 if (vsession->stop_retry_count == 0) {
    1690                 :          0 :                         SPDK_ERRLOG("%s: Timedout when destroy session (number of stopped pg %d)\n", vsession->name,
    1691                 :            :                                     bvsession->num_stopped_poll_groups);
    1692                 :          0 :                         spdk_poller_unregister(&bvsession->stop_poller);
    1693                 :          0 :                         vhost_user_session_stop_done(vsession, -ETIMEDOUT);
    1694                 :            :                 }
    1695                 :            : 
    1696                 :         42 :                 return SPDK_POLLER_BUSY;
    1697                 :            :         }
    1698                 :            : 
    1699   [ -  +  -  + ]:         43 :         SPDK_DEBUGLOG(vhost_blk, "%s: session stoppped\n", vsession->name);
    1700                 :         43 :         free(bvsession->poll_groups);
    1701                 :         43 :         free_task_pool(bvsession);
    1702                 :         43 :         spdk_poller_unregister(&bvsession->stop_poller);
    1703                 :         43 :         vhost_user_session_stop_done(vsession, 0);
    1704                 :            : 
    1705         [ -  + ]:         43 :         pthread_mutex_unlock(&user_dev->lock);
    1706                 :         43 :         return SPDK_POLLER_BUSY;
    1707                 :            : }
    1708                 :            : 
    1709                 :            : static int
    1710                 :         43 : vhost_blk_stop(struct spdk_vhost_dev *vdev,
    1711                 :            :                struct spdk_vhost_session *vsession, void *unused)
    1712                 :            : {
    1713                 :         43 :         struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
    1714                 :            : 
    1715                 :            :         /* return if stop is already in progress */
    1716         [ -  + ]:         43 :         if (bvsession->stop_poller) {
    1717                 :          0 :                 return -EINPROGRESS;
    1718                 :            :         }
    1719                 :            : 
    1720                 :         43 :         session_stop_poll_groups(bvsession);
    1721                 :            : 
    1722                 :         43 :         bvsession->vsession.stop_retry_count = (SPDK_VHOST_SESSION_STOP_RETRY_TIMEOUT_IN_SEC * 1000 *
    1723                 :            :                                                 1000) / SPDK_VHOST_SESSION_STOP_RETRY_PERIOD_IN_US;
    1724                 :         43 :         bvsession->stop_poller = SPDK_POLLER_REGISTER(destroy_session_poller_cb,
    1725                 :            :                                  bvsession, SPDK_VHOST_SESSION_STOP_RETRY_PERIOD_IN_US);
    1726                 :         43 :         return 0;
    1727                 :            : }
    1728                 :            : 
    1729                 :            : static void
    1730                 :        437 : vhost_blk_dump_info_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
    1731                 :            : {
    1732                 :            :         struct spdk_vhost_blk_dev *bvdev;
    1733                 :            : 
    1734                 :        437 :         bvdev = to_blk_dev(vdev);
    1735         [ -  + ]:        437 :         assert(bvdev != NULL);
    1736                 :            : 
    1737                 :        437 :         spdk_json_write_named_object_begin(w, "block");
    1738                 :            : 
    1739         [ -  + ]:        437 :         spdk_json_write_named_bool(w, "readonly", bvdev->readonly);
    1740                 :            : 
    1741                 :        437 :         spdk_json_write_name(w, "bdev");
    1742         [ +  - ]:        437 :         if (bvdev->bdev) {
    1743                 :        437 :                 spdk_json_write_string(w, spdk_bdev_get_name(bvdev->bdev));
    1744                 :            :         } else {
    1745                 :          0 :                 spdk_json_write_null(w);
    1746                 :            :         }
    1747                 :        437 :         spdk_json_write_named_string(w, "transport", bvdev->ops->name);
    1748                 :            : 
    1749                 :        437 :         spdk_json_write_object_end(w);
    1750                 :        437 : }
    1751                 :            : 
    1752                 :            : static void
    1753                 :         16 : vhost_blk_write_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
    1754                 :            : {
    1755                 :            :         struct spdk_vhost_blk_dev *bvdev;
    1756                 :            : 
    1757                 :         16 :         bvdev = to_blk_dev(vdev);
    1758         [ -  + ]:         16 :         assert(bvdev != NULL);
    1759                 :            : 
    1760         [ -  + ]:         16 :         if (!bvdev->bdev) {
    1761                 :          0 :                 return;
    1762                 :            :         }
    1763                 :            : 
    1764                 :         16 :         spdk_json_write_object_begin(w);
    1765                 :         16 :         spdk_json_write_named_string(w, "method", "vhost_create_blk_controller");
    1766                 :            : 
    1767                 :         16 :         spdk_json_write_named_object_begin(w, "params");
    1768                 :         16 :         spdk_json_write_named_string(w, "ctrlr", vdev->name);
    1769                 :         16 :         spdk_json_write_named_string(w, "dev_name", spdk_bdev_get_name(bvdev->bdev));
    1770                 :         16 :         spdk_json_write_named_string(w, "cpumask",
    1771                 :            :                                      spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
    1772         [ -  + ]:         16 :         spdk_json_write_named_bool(w, "readonly", bvdev->readonly);
    1773                 :         16 :         spdk_json_write_named_string(w, "transport", bvdev->ops->name);
    1774                 :         16 :         spdk_json_write_object_end(w);
    1775                 :            : 
    1776                 :         16 :         spdk_json_write_object_end(w);
    1777                 :            : }
    1778                 :            : 
    1779                 :            : static int vhost_blk_destroy(struct spdk_vhost_dev *dev);
    1780                 :            : 
    1781                 :            : static int
    1782                 :         73 : vhost_blk_get_config(struct spdk_vhost_dev *vdev, uint8_t *config,
    1783                 :            :                      uint32_t len)
    1784                 :            : {
    1785                 :         73 :         struct virtio_blk_config blkcfg;
    1786                 :            :         struct spdk_bdev *bdev;
    1787                 :            :         uint32_t blk_size;
    1788                 :            :         uint64_t blkcnt;
    1789                 :            : 
    1790         [ -  + ]:         73 :         memset(&blkcfg, 0, sizeof(blkcfg));
    1791                 :         73 :         bdev = vhost_blk_get_bdev(vdev);
    1792         [ -  + ]:         73 :         if (bdev == NULL) {
    1793                 :            :                 /* We can't just return -1 here as this GET_CONFIG message might
    1794                 :            :                  * be caused by a QEMU VM reboot. Returning -1 will indicate an
    1795                 :            :                  * error to QEMU, who might then decide to terminate itself.
    1796                 :            :                  * We don't want that. A simple reboot shouldn't break the system.
    1797                 :            :                  *
    1798                 :            :                  * Presenting a block device with block size 0 and block count 0
    1799                 :            :                  * doesn't cause any problems on QEMU side and the virtio-pci
    1800                 :            :                  * device is even still available inside the VM, but there will
    1801                 :            :                  * be no block device created for it - the kernel drivers will
    1802                 :            :                  * silently reject it.
    1803                 :            :                  */
    1804                 :          0 :                 blk_size = 0;
    1805                 :          0 :                 blkcnt = 0;
    1806                 :            :         } else {
    1807                 :         73 :                 blk_size = spdk_bdev_get_block_size(bdev);
    1808                 :         73 :                 blkcnt = spdk_bdev_get_num_blocks(bdev);
    1809         [ -  + ]:         73 :                 if (spdk_bdev_get_buf_align(bdev) > 1) {
    1810                 :          0 :                         blkcfg.size_max = SPDK_BDEV_LARGE_BUF_MAX_SIZE;
    1811                 :          0 :                         blkcfg.seg_max = spdk_min(SPDK_VHOST_IOVS_MAX - 2 - 1, SPDK_BDEV_IO_NUM_CHILD_IOV - 2 - 1);
    1812                 :            :                 } else {
    1813                 :         73 :                         blkcfg.size_max = 131072;
    1814                 :            :                         /*  -2 for REQ and RESP and -1 for region boundary splitting */
    1815                 :         73 :                         blkcfg.seg_max = SPDK_VHOST_IOVS_MAX - 2 - 1;
    1816                 :            :                 }
    1817                 :            :         }
    1818                 :            : 
    1819                 :         73 :         blkcfg.blk_size = blk_size;
    1820                 :            :         /* minimum I/O size in blocks */
    1821                 :         73 :         blkcfg.min_io_size = 1;
    1822                 :            :         /* expressed in 512 Bytes sectors */
    1823                 :         73 :         blkcfg.capacity = (blkcnt * blk_size) / 512;
    1824                 :            :         /* QEMU can overwrite this value when started */
    1825                 :         73 :         blkcfg.num_queues = SPDK_VHOST_MAX_VQUEUES;
    1826                 :            : 
    1827   [ +  -  +  + ]:         73 :         if (bdev && spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP)) {
    1828                 :            :                 /* 16MiB, expressed in 512 Bytes */
    1829                 :         68 :                 blkcfg.max_discard_sectors = 32768;
    1830                 :         68 :                 blkcfg.max_discard_seg = 1;
    1831                 :         68 :                 blkcfg.discard_sector_alignment = blk_size / 512;
    1832                 :            :         }
    1833   [ +  -  +  - ]:         73 :         if (bdev && spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) {
    1834                 :         73 :                 blkcfg.max_write_zeroes_sectors = 32768;
    1835                 :         73 :                 blkcfg.max_write_zeroes_seg = 1;
    1836                 :            :         }
    1837                 :            : 
    1838   [ -  +  -  + ]:         73 :         memcpy(config, &blkcfg, spdk_min(len, sizeof(blkcfg)));
    1839                 :            : 
    1840                 :         73 :         return 0;
    1841                 :            : }
    1842                 :            : 
    1843                 :            : static int
    1844                 :          0 : vhost_blk_set_coalescing(struct spdk_vhost_dev *vdev, uint32_t delay_base_us,
    1845                 :            :                          uint32_t iops_threshold)
    1846                 :            : {
    1847                 :          0 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
    1848                 :            : 
    1849         [ #  # ]:          0 :         assert(bvdev != NULL);
    1850                 :            : 
    1851                 :          0 :         return bvdev->ops->set_coalescing(vdev, delay_base_us, iops_threshold);
    1852                 :            : }
    1853                 :            : 
    1854                 :            : static void
    1855                 :        453 : vhost_blk_get_coalescing(struct spdk_vhost_dev *vdev, uint32_t *delay_base_us,
    1856                 :            :                          uint32_t *iops_threshold)
    1857                 :            : {
    1858                 :        453 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
    1859                 :            : 
    1860         [ -  + ]:        453 :         assert(bvdev != NULL);
    1861                 :            : 
    1862                 :        453 :         bvdev->ops->get_coalescing(vdev, delay_base_us, iops_threshold);
    1863                 :        453 : }
    1864                 :            : 
    1865                 :            : static const struct spdk_vhost_user_dev_backend vhost_blk_user_device_backend = {
    1866                 :            :         .session_ctx_size = sizeof(struct spdk_vhost_blk_session) - sizeof(struct spdk_vhost_session),
    1867                 :            :         .start_session =  vhost_blk_start,
    1868                 :            :         .stop_session = vhost_blk_stop,
    1869                 :            :         .alloc_vq_tasks = alloc_vq_task_pool,
    1870                 :            :         .enable_vq = vhost_blk_vq_enable,
    1871                 :            : };
    1872                 :            : 
    1873                 :            : static const struct spdk_vhost_dev_backend vhost_blk_device_backend = {
    1874                 :            :         .type = VHOST_BACKEND_BLK,
    1875                 :            :         .vhost_get_config = vhost_blk_get_config,
    1876                 :            :         .dump_info_json = vhost_blk_dump_info_json,
    1877                 :            :         .write_config_json = vhost_blk_write_config_json,
    1878                 :            :         .remove_device = vhost_blk_destroy,
    1879                 :            :         .set_coalescing = vhost_blk_set_coalescing,
    1880                 :            :         .get_coalescing = vhost_blk_get_coalescing,
    1881                 :            : };
    1882                 :            : 
    1883                 :            : int
    1884                 :         41 : virtio_blk_construct_ctrlr(struct spdk_vhost_dev *vdev, const char *address,
    1885                 :            :                            struct spdk_cpuset *cpumask, const struct spdk_json_val *params,
    1886                 :            :                            const struct spdk_vhost_user_dev_backend *user_backend)
    1887                 :            : {
    1888                 :         41 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
    1889                 :            : 
    1890         [ -  + ]:         41 :         assert(bvdev != NULL);
    1891                 :            : 
    1892                 :         41 :         return bvdev->ops->create_ctrlr(vdev, cpumask, address, params, (void *)user_backend);
    1893                 :            : }
    1894                 :            : 
    1895                 :            : int
    1896                 :         45 : spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_name,
    1897                 :            :                          const char *transport, const struct spdk_json_val *params)
    1898                 :            : {
    1899                 :         45 :         struct spdk_vhost_blk_dev *bvdev = NULL;
    1900                 :            :         struct spdk_vhost_dev *vdev;
    1901                 :            :         struct spdk_bdev *bdev;
    1902                 :         45 :         const char *transport_name = VIRTIO_BLK_DEFAULT_TRANSPORT;
    1903                 :         45 :         int ret = 0;
    1904                 :            : 
    1905                 :         45 :         bvdev = calloc(1, sizeof(*bvdev));
    1906         [ -  + ]:         45 :         if (bvdev == NULL) {
    1907                 :          0 :                 ret = -ENOMEM;
    1908                 :          0 :                 goto out;
    1909                 :            :         }
    1910                 :            : 
    1911         [ +  + ]:         45 :         if (transport != NULL) {
    1912                 :          6 :                 transport_name = transport;
    1913                 :            :         }
    1914                 :            : 
    1915                 :         45 :         bvdev->ops = virtio_blk_get_transport_ops(transport_name);
    1916         [ -  + ]:         45 :         if (!bvdev->ops) {
    1917                 :          0 :                 ret = -EINVAL;
    1918                 :          0 :                 SPDK_ERRLOG("Transport type '%s' unavailable.\n", transport_name);
    1919                 :          0 :                 goto out;
    1920                 :            :         }
    1921                 :            : 
    1922                 :         45 :         ret = spdk_bdev_open_ext(dev_name, true, bdev_event_cb, bvdev, &bvdev->bdev_desc);
    1923         [ +  + ]:         45 :         if (ret != 0) {
    1924                 :          2 :                 SPDK_ERRLOG("%s: could not open bdev '%s', error=%d\n",
    1925                 :            :                             name, dev_name, ret);
    1926                 :          2 :                 goto out;
    1927                 :            :         }
    1928                 :         43 :         bdev = spdk_bdev_desc_get_bdev(bvdev->bdev_desc);
    1929                 :            : 
    1930                 :         43 :         vdev = &bvdev->vdev;
    1931                 :         43 :         vdev->virtio_features = SPDK_VHOST_BLK_FEATURES_BASE;
    1932                 :         43 :         vdev->disabled_features = SPDK_VHOST_BLK_DISABLED_FEATURES;
    1933                 :         43 :         vdev->protocol_features = SPDK_VHOST_BLK_PROTOCOL_FEATURES;
    1934                 :            : 
    1935         [ +  + ]:         43 :         if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP)) {
    1936                 :         38 :                 vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_DISCARD);
    1937                 :            :         }
    1938         [ +  - ]:         43 :         if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) {
    1939                 :         43 :                 vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_WRITE_ZEROES);
    1940                 :            :         }
    1941                 :            : 
    1942         [ +  + ]:         43 :         if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_FLUSH)) {
    1943                 :         33 :                 vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_FLUSH);
    1944                 :            :         }
    1945                 :            : 
    1946                 :         43 :         bvdev->bdev = bdev;
    1947                 :         43 :         bvdev->readonly = false;
    1948                 :         43 :         ret = vhost_dev_register(vdev, name, cpumask, params, &vhost_blk_device_backend,
    1949                 :            :                                  &vhost_blk_user_device_backend, false);
    1950         [ +  + ]:         43 :         if (ret != 0) {
    1951                 :          3 :                 spdk_bdev_close(bvdev->bdev_desc);
    1952                 :          3 :                 goto out;
    1953                 :            :         }
    1954                 :            : 
    1955   [ -  +  +  - ]:         40 :         SPDK_INFOLOG(vhost, "%s: using bdev '%s'\n", name, dev_name);
    1956                 :         40 : out:
    1957   [ +  +  +  - ]:         45 :         if (ret != 0 && bvdev) {
    1958                 :          5 :                 free(bvdev);
    1959                 :            :         }
    1960                 :         45 :         return ret;
    1961                 :            : }
    1962                 :            : 
    1963                 :            : int
    1964                 :         40 : virtio_blk_destroy_ctrlr(struct spdk_vhost_dev *vdev)
    1965                 :            : {
    1966                 :         40 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
    1967                 :            : 
    1968         [ -  + ]:         40 :         assert(bvdev != NULL);
    1969                 :            : 
    1970                 :         40 :         return bvdev->ops->destroy_ctrlr(vdev);
    1971                 :            : }
    1972                 :            : 
    1973                 :            : static int
    1974                 :         40 : vhost_blk_destroy(struct spdk_vhost_dev *vdev)
    1975                 :            : {
    1976                 :         40 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
    1977                 :            :         int rc;
    1978                 :            : 
    1979         [ -  + ]:         40 :         assert(bvdev != NULL);
    1980                 :            : 
    1981                 :         40 :         rc = vhost_dev_unregister(&bvdev->vdev);
    1982         [ -  + ]:         40 :         if (rc != 0) {
    1983                 :          0 :                 return rc;
    1984                 :            :         }
    1985                 :            : 
    1986         [ +  + ]:         40 :         if (bvdev->bdev_desc) {
    1987                 :         32 :                 spdk_bdev_close(bvdev->bdev_desc);
    1988                 :         32 :                 bvdev->bdev_desc = NULL;
    1989                 :            :         }
    1990                 :         40 :         bvdev->bdev = NULL;
    1991                 :            : 
    1992                 :         40 :         free(bvdev);
    1993                 :         40 :         return 0;
    1994                 :            : }
    1995                 :            : 
    1996                 :            : struct spdk_io_channel *
    1997                 :         67 : vhost_blk_get_io_channel(struct spdk_vhost_dev *vdev)
    1998                 :            : {
    1999                 :         67 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
    2000                 :            : 
    2001         [ -  + ]:         67 :         assert(bvdev != NULL);
    2002                 :            : 
    2003                 :         67 :         return spdk_bdev_get_io_channel(bvdev->bdev_desc);
    2004                 :            : }
    2005                 :            : 
    2006                 :            : void
    2007                 :         67 : vhost_blk_put_io_channel(struct spdk_io_channel *ch)
    2008                 :            : {
    2009                 :         67 :         spdk_put_io_channel(ch);
    2010                 :         67 : }
    2011                 :            : 
    2012                 :            : static struct spdk_virtio_blk_transport *
    2013                 :        671 : vhost_user_blk_create(const struct spdk_json_val *params)
    2014                 :            : {
    2015                 :            :         int ret;
    2016                 :            :         struct spdk_virtio_blk_transport *vhost_user_blk;
    2017                 :            : 
    2018                 :        671 :         vhost_user_blk = calloc(1, sizeof(*vhost_user_blk));
    2019         [ -  + ]:        671 :         if (!vhost_user_blk) {
    2020                 :          0 :                 return NULL;
    2021                 :            :         }
    2022                 :            : 
    2023                 :        671 :         ret = vhost_user_init();
    2024         [ -  + ]:        671 :         if (ret != 0) {
    2025                 :          0 :                 free(vhost_user_blk);
    2026                 :          0 :                 return NULL;
    2027                 :            :         }
    2028                 :            : 
    2029                 :        671 :         return vhost_user_blk;
    2030                 :            : }
    2031                 :            : 
    2032                 :            : static int
    2033                 :        671 : vhost_user_blk_destroy(struct spdk_virtio_blk_transport *transport,
    2034                 :            :                        spdk_vhost_fini_cb cb_fn)
    2035                 :            : {
    2036                 :        671 :         vhost_user_fini(cb_fn);
    2037                 :        671 :         free(transport);
    2038                 :        671 :         return 0;
    2039                 :            : }
    2040                 :            : 
    2041                 :            : struct rpc_vhost_blk {
    2042                 :            :         bool readonly;
    2043                 :            :         bool packed_ring;
    2044                 :            : };
    2045                 :            : 
    2046                 :            : static const struct spdk_json_object_decoder rpc_construct_vhost_blk[] = {
    2047                 :            :         {"readonly", offsetof(struct rpc_vhost_blk, readonly), spdk_json_decode_bool, true},
    2048                 :            :         {"packed_ring", offsetof(struct rpc_vhost_blk, packed_ring), spdk_json_decode_bool, true},
    2049                 :            : };
    2050                 :            : 
    2051                 :            : static int
    2052                 :         41 : vhost_user_blk_create_ctrlr(struct spdk_vhost_dev *vdev, struct spdk_cpuset *cpumask,
    2053                 :            :                             const char *address, const struct spdk_json_val *params, void *custom_opts)
    2054                 :            : {
    2055                 :         41 :         struct rpc_vhost_blk req = {0};
    2056                 :         41 :         struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
    2057                 :            : 
    2058         [ -  + ]:         41 :         assert(bvdev != NULL);
    2059                 :            : 
    2060         [ -  + ]:         41 :         if (spdk_json_decode_object_relaxed(params, rpc_construct_vhost_blk,
    2061                 :            :                                             SPDK_COUNTOF(rpc_construct_vhost_blk),
    2062                 :            :                                             &req)) {
    2063   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vhost_blk, "spdk_json_decode_object failed\n");
    2064                 :          0 :                 return -EINVAL;
    2065                 :            :         }
    2066                 :            : 
    2067   [ -  +  -  + ]:         41 :         if (req.packed_ring) {
    2068         [ #  # ]:          0 :                 vdev->virtio_features |= (uint64_t)req.packed_ring << VIRTIO_F_RING_PACKED;
    2069                 :            :         }
    2070   [ -  +  +  + ]:         41 :         if (req.readonly) {
    2071                 :          7 :                 vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_RO);
    2072         [ -  + ]:          7 :                 bvdev->readonly = req.readonly;
    2073                 :            :         }
    2074                 :            : 
    2075                 :         41 :         return vhost_user_dev_create(vdev, address, cpumask, custom_opts, false);
    2076                 :            : }
    2077                 :            : 
    2078                 :            : static int
    2079                 :         40 : vhost_user_blk_destroy_ctrlr(struct spdk_vhost_dev *vdev)
    2080                 :            : {
    2081                 :         40 :         return vhost_user_dev_unregister(vdev);
    2082                 :            : }
    2083                 :            : 
    2084                 :            : static void
    2085                 :          0 : vhost_user_blk_dump_opts(struct spdk_virtio_blk_transport *transport, struct spdk_json_write_ctx *w)
    2086                 :            : {
    2087         [ #  # ]:          0 :         assert(w != NULL);
    2088                 :            : 
    2089                 :          0 :         spdk_json_write_named_string(w, "name", transport->ops->name);
    2090                 :          0 : }
    2091                 :            : 
    2092                 :            : static const struct spdk_virtio_blk_transport_ops vhost_user_blk = {
    2093                 :            :         .name = "vhost_user_blk",
    2094                 :            : 
    2095                 :            :         .dump_opts = vhost_user_blk_dump_opts,
    2096                 :            : 
    2097                 :            :         .create = vhost_user_blk_create,
    2098                 :            :         .destroy = vhost_user_blk_destroy,
    2099                 :            : 
    2100                 :            :         .create_ctrlr = vhost_user_blk_create_ctrlr,
    2101                 :            :         .destroy_ctrlr = vhost_user_blk_destroy_ctrlr,
    2102                 :            : 
    2103                 :            :         .bdev_event = vhost_user_bdev_event_cb,
    2104                 :            :         .set_coalescing = vhost_user_set_coalescing,
    2105                 :            :         .get_coalescing = vhost_user_get_coalescing,
    2106                 :            : };
    2107                 :            : 
    2108                 :        761 : SPDK_VIRTIO_BLK_TRANSPORT_REGISTER(vhost_user_blk, &vhost_user_blk);
    2109                 :            : 
    2110                 :        761 : SPDK_LOG_REGISTER_COMPONENT(vhost_blk)
    2111                 :        761 : SPDK_LOG_REGISTER_COMPONENT(vhost_blk_data)

Generated by: LCOV version 1.14