LCOV - code coverage report
Current view: top level - spdk/test/unit/lib/vhost/vhost.c - vhost_ut.c (source / functions) Hit Total Coverage
Test: Combined Lines: 357 394 90.6 %
Date: 2024-07-13 11:15:58 Functions: 34 69 49.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 88 150 58.7 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2017 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  *   Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include "spdk/stdinc.h"
       8                 :            : 
       9                 :            : #include "CUnit/Basic.h"
      10                 :            : #include "spdk_internal/cunit.h"
      11                 :            : #include "spdk/thread.h"
      12                 :            : #include "spdk_internal/mock.h"
      13                 :            : #include "common/lib/ut_multithread.c"
      14                 :            : #include "unit/lib/json_mock.c"
      15                 :            : 
      16                 :            : #include "vhost/vhost.c"
      17                 :            : #include "vhost/vhost_blk.c"
      18                 :            : #include <rte_version.h>
      19                 :            : #include "vhost/rte_vhost_user.c"
      20                 :            : 
      21                 :          0 : DEFINE_STUB(rte_vhost_set_vring_base, int, (int vid, uint16_t queue_id,
      22                 :            :                 uint16_t last_avail_idx, uint16_t last_used_idx), 0);
      23                 :          0 : DEFINE_STUB(rte_vhost_get_vring_base, int, (int vid, uint16_t queue_id,
      24                 :            :                 uint16_t *last_avail_idx, uint16_t *last_used_idx), 0);
      25                 :          0 : DEFINE_STUB(spdk_mem_register, int, (void *vaddr, size_t len), 0);
      26                 :          0 : DEFINE_STUB(spdk_mem_unregister, int, (void *vaddr, size_t len), 0);
      27                 :            : #if RTE_VERSION < RTE_VERSION_NUM(22, 11, 0, 0)
      28                 :            : DEFINE_STUB(rte_vhost_vring_call, int, (int vid, uint16_t vring_idx), 0);
      29                 :            : #else
      30                 :          0 : DEFINE_STUB(rte_vhost_vring_call_nonblock, int, (int vid, uint16_t vring_idx), 0);
      31                 :            : #endif
      32                 :          0 : DEFINE_STUB_V(rte_vhost_log_used_vring, (int vid, uint16_t vring_idx,
      33                 :            :                 uint64_t offset, uint64_t len));
      34                 :            : 
      35                 :          0 : DEFINE_STUB(rte_vhost_get_mem_table, int, (int vid, struct rte_vhost_memory **mem), 0);
      36                 :          0 : DEFINE_STUB(rte_vhost_get_negotiated_features, int, (int vid, uint64_t *features), 0);
      37                 :          0 : DEFINE_STUB(rte_vhost_get_vhost_vring, int,
      38                 :            :             (int vid, uint16_t vring_idx, struct rte_vhost_vring *vring), 0);
      39                 :          0 : DEFINE_STUB(rte_vhost_enable_guest_notification, int,
      40                 :            :             (int vid, uint16_t queue_id, int enable), 0);
      41                 :          0 : DEFINE_STUB(rte_vhost_get_ifname, int, (int vid, char *buf, size_t len), 0);
      42                 :         54 : DEFINE_STUB(rte_vhost_driver_start, int, (const char *name), 0);
      43                 :         54 : DEFINE_STUB(rte_vhost_driver_callback_register, int,
      44                 :            :             (const char *path, struct rte_vhost_device_ops const *const ops), 0);
      45                 :         54 : DEFINE_STUB(rte_vhost_driver_disable_features, int, (const char *path, uint64_t features), 0);
      46                 :         54 : DEFINE_STUB(rte_vhost_driver_set_features, int, (const char *path, uint64_t features), 0);
      47                 :         54 : DEFINE_STUB(rte_vhost_driver_register, int, (const char *path, uint64_t flags), 0);
      48                 :         54 : DEFINE_STUB(rte_vhost_driver_unregister, int, (const char *path), 0);
      49                 :         54 : DEFINE_STUB(rte_vhost_driver_get_protocol_features, int,
      50                 :            :             (const char *path, uint64_t *protocol_features), 0);
      51                 :         54 : DEFINE_STUB(rte_vhost_driver_set_protocol_features, int,
      52                 :            :             (const char *path, uint64_t protocol_features), 0);
      53                 :            : 
      54                 :          0 : DEFINE_STUB(rte_vhost_set_last_inflight_io_split, int,
      55                 :            :             (int vid, uint16_t vring_idx, uint16_t idx), 0);
      56                 :          0 : DEFINE_STUB(rte_vhost_clr_inflight_desc_split, int,
      57                 :            :             (int vid, uint16_t vring_idx, uint16_t last_used_idx, uint16_t idx), 0);
      58                 :         42 : DEFINE_STUB(rte_vhost_set_last_inflight_io_packed, int,
      59                 :            :             (int vid, uint16_t vring_idx, uint16_t head), 0);
      60                 :         42 : DEFINE_STUB(rte_vhost_clr_inflight_desc_packed, int,
      61                 :            :             (int vid, uint16_t vring_idx, uint16_t head), 0);
      62                 :          0 : DEFINE_STUB_V(rte_vhost_log_write, (int vid, uint64_t addr, uint64_t len));
      63                 :          0 : DEFINE_STUB(rte_vhost_get_vhost_ring_inflight, int,
      64                 :            :             (int vid, uint16_t vring_idx, struct rte_vhost_ring_inflight *vring), 0);
      65                 :          0 : DEFINE_STUB(rte_vhost_get_vring_base_from_inflight, int,
      66                 :            :             (int vid, uint16_t queue_id, uint16_t *last_avail_idx, uint16_t *last_used_idx), 0);
      67                 :          0 : DEFINE_STUB(rte_vhost_extern_callback_register, int,
      68                 :            :             (int vid, struct rte_vhost_user_extern_ops const *const ops, void *ctx), 0);
      69         [ -  + ]:         54 : DEFINE_STUB(spdk_iommu_is_enabled, bool, (void), 0);
      70                 :            : 
      71                 :            : /* rte_vhost_user.c shutdowns vhost_user sessions in a separate pthread */
      72                 :            : DECLARE_WRAPPER(pthread_create, int, (pthread_t *thread, const pthread_attr_t *attr,
      73                 :            :                                       void *(*start_routine)(void *), void *arg));
      74                 :            : int
      75                 :            : pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *),
      76                 :            :                void *arg)
      77                 :            : {
      78                 :          6 :         start_routine(arg);
      79                 :          6 :         return 0;
      80                 :            : }
      81                 :          6 : DEFINE_STUB(pthread_detach, int, (pthread_t thread), 0);
      82                 :            : 
      83                 :          0 : DEFINE_STUB(spdk_bdev_writev, int,
      84                 :            :             (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
      85                 :            :              struct iovec *iov, int iovcnt, uint64_t offset, uint64_t len,
      86                 :            :              spdk_bdev_io_completion_cb cb, void *cb_arg),
      87                 :            :             0);
      88                 :            : 
      89                 :          0 : DEFINE_STUB(spdk_bdev_unmap, int,
      90                 :            :             (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
      91                 :            :              uint64_t offset, uint64_t nbytes,
      92                 :            :              spdk_bdev_io_completion_cb cb, void *cb_arg),
      93                 :            :             0);
      94                 :            : 
      95                 :          0 : DEFINE_STUB(spdk_bdev_write_zeroes, int,
      96                 :            :             (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
      97                 :            :              uint64_t offset, uint64_t nbytes,
      98                 :            :              spdk_bdev_io_completion_cb cb, void *cb_arg),
      99                 :            :             0);
     100                 :            : 
     101                 :          0 : DEFINE_STUB(spdk_bdev_get_num_blocks, uint64_t, (const struct spdk_bdev *bdev), 0);
     102                 :            : 
     103                 :          0 : DEFINE_STUB(spdk_bdev_get_block_size, uint32_t, (const struct spdk_bdev *bdev), 512);
     104                 :          0 : DEFINE_STUB(spdk_bdev_get_name, const char *, (const struct spdk_bdev *bdev), "test");
     105                 :          0 : DEFINE_STUB(spdk_bdev_get_buf_align, size_t, (const struct spdk_bdev *bdev), 64);
     106         [ -  + ]:         18 : DEFINE_STUB(spdk_bdev_io_type_supported, bool, (struct spdk_bdev *bdev,
     107                 :            :                 enum spdk_bdev_io_type io_type), true);
     108                 :          6 : DEFINE_STUB(spdk_bdev_open_ext, int,
     109                 :            :             (const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb,
     110                 :            :              void *event_ctx, struct spdk_bdev_desc **desc), 0);
     111                 :          6 : DEFINE_STUB(spdk_bdev_desc_get_bdev, struct spdk_bdev *,
     112                 :            :             (struct spdk_bdev_desc *desc), NULL);
     113                 :          0 : DEFINE_STUB_V(spdk_bdev_close, (struct spdk_bdev_desc *desc));
     114                 :          0 : DEFINE_STUB(spdk_bdev_queue_io_wait, int, (struct spdk_bdev *bdev, struct spdk_io_channel *ch,
     115                 :            :                 struct spdk_bdev_io_wait_entry *entry), 0);
     116                 :          0 : DEFINE_STUB_V(spdk_bdev_free_io, (struct spdk_bdev_io *bdev_io));
     117                 :          0 : DEFINE_STUB(spdk_bdev_get_io_channel, struct spdk_io_channel *, (struct spdk_bdev_desc *desc), 0);
     118                 :          0 : DEFINE_STUB(spdk_bdev_readv, int,
     119                 :            :             (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
     120                 :            :              struct iovec *iov, int iovcnt, uint64_t offset, uint64_t nbytes,
     121                 :            :              spdk_bdev_io_completion_cb cb, void *cb_arg),
     122                 :            :             0);
     123                 :          0 : DEFINE_STUB(spdk_bdev_flush, int,
     124                 :            :             (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
     125                 :            :              uint64_t offset, uint64_t nbytes,
     126                 :            :              spdk_bdev_io_completion_cb cb, void *cb_arg),
     127                 :            :             0);
     128                 :          0 : DEFINE_STUB(rte_vhost_set_inflight_desc_split, int, (int vid, uint16_t vring_idx, uint16_t idx), 0);
     129                 :          0 : DEFINE_STUB(rte_vhost_set_inflight_desc_packed, int, (int vid, uint16_t vring_idx, uint16_t head,
     130                 :            :                 uint16_t last, uint16_t *inflight_entry), 0);
     131                 :            : #if RTE_VERSION >= RTE_VERSION_NUM(23, 03, 0, 0)
     132                 :          0 : DEFINE_STUB(rte_vhost_backend_config_change, int, (int vid, bool need_reply), 0);
     133                 :            : #else
     134                 :            : DEFINE_STUB(rte_vhost_slave_config_change, int, (int vid, bool need_reply), 0);
     135                 :            : #endif
     136                 :          0 : DEFINE_STUB(spdk_json_decode_bool, int, (const struct spdk_json_val *val, void *out), 0);
     137                 :          6 : DEFINE_STUB(spdk_json_decode_object_relaxed, int,
     138                 :            :             (const struct spdk_json_val *values, const struct spdk_json_object_decoder *decoders,
     139                 :            :              size_t num_decoders, void *out), 0);
     140                 :            : 
     141                 :            : void *
     142                 :          0 : spdk_call_unaffinitized(void *cb(void *arg), void *arg)
     143                 :            : {
     144                 :          0 :         return cb(arg);
     145                 :            : }
     146                 :            : 
     147                 :            : static struct spdk_vhost_dev_backend g_vdev_backend = {.type = VHOST_BACKEND_SCSI};
     148                 :            : static struct spdk_vhost_user_dev_backend g_vdev_user_backend;
     149                 :            : 
     150                 :            : static bool g_init_fail;
     151                 :            : static void
     152                 :         12 : init_cb(int rc)
     153                 :            : {
     154                 :         12 :         g_init_fail = rc;
     155                 :         12 : }
     156                 :            : 
     157                 :            : static int
     158                 :          6 : test_setup(void)
     159                 :            : {
     160                 :          6 :         allocate_cores(1);
     161                 :          6 :         allocate_threads(1);
     162                 :          6 :         set_thread(0);
     163                 :            : 
     164                 :          6 :         g_init_fail = true;
     165                 :          6 :         spdk_vhost_scsi_init(init_cb);
     166   [ -  +  -  + ]:          6 :         assert(g_init_fail == false);
     167                 :            : 
     168                 :          6 :         g_init_fail = true;
     169                 :          6 :         spdk_vhost_blk_init(init_cb);
     170   [ -  +  -  + ]:          6 :         assert(g_init_fail == false);
     171                 :            : 
     172                 :          6 :         return 0;
     173                 :            : }
     174                 :            : 
     175                 :            : static bool g_fini_fail;
     176                 :            : static void
     177                 :         12 : fini_cb(void)
     178                 :            : {
     179                 :         12 :         g_fini_fail = false;
     180                 :         12 : }
     181                 :            : 
     182                 :            : static int
     183                 :          6 : test_cleanup(void)
     184                 :            : {
     185                 :          6 :         g_fini_fail = true;
     186                 :          6 :         spdk_vhost_scsi_fini(fini_cb);
     187                 :          6 :         poll_threads();
     188   [ -  +  -  + ]:          6 :         assert(g_fini_fail == false);
     189                 :            : 
     190                 :          6 :         g_fini_fail = true;
     191                 :          6 :         spdk_vhost_blk_fini(fini_cb);
     192                 :          6 :         poll_threads();
     193   [ -  +  -  + ]:          6 :         assert(g_fini_fail == false);
     194                 :            : 
     195                 :          6 :         free_threads();
     196                 :          6 :         free_cores();
     197                 :            : 
     198                 :          6 :         return 0;
     199                 :            : }
     200                 :            : 
     201                 :            : static int
     202                 :         78 : alloc_vdev(struct spdk_vhost_dev **vdev_p, const char *name, const char *cpumask)
     203                 :            : {
     204                 :         78 :         struct spdk_vhost_dev *vdev = NULL;
     205                 :            :         int rc;
     206                 :            : 
     207                 :            :         /* spdk_vhost_dev must be allocated on a cache line boundary. */
     208         [ -  + ]:         78 :         rc = posix_memalign((void **)&vdev, 64, sizeof(*vdev));
     209                 :         78 :         CU_ASSERT(rc == 0);
     210         [ -  + ]:         78 :         SPDK_CU_ASSERT_FATAL(vdev != NULL);
     211         [ -  + ]:         78 :         memset(vdev, 0, sizeof(*vdev));
     212                 :         78 :         rc = vhost_dev_register(vdev, name, cpumask, NULL, &g_vdev_backend, &g_vdev_user_backend, false);
     213         [ +  + ]:         78 :         if (rc == 0) {
     214                 :         48 :                 *vdev_p = vdev;
     215                 :            :         } else {
     216                 :         30 :                 free(vdev);
     217                 :         30 :                 *vdev_p = NULL;
     218                 :            :         }
     219                 :            : 
     220                 :         78 :         return rc;
     221                 :            : }
     222                 :            : 
     223                 :            : static void
     224                 :         18 : start_vdev(struct spdk_vhost_dev *vdev)
     225                 :            : {
     226                 :         18 :         struct spdk_vhost_user_dev *user_dev = to_user_dev(vdev);
     227                 :            :         struct rte_vhost_memory *mem;
     228                 :         18 :         struct spdk_vhost_session *vsession = NULL;
     229                 :            :         int rc;
     230                 :            : 
     231                 :         18 :         mem = calloc(1, sizeof(*mem) + 2 * sizeof(struct rte_vhost_mem_region));
     232         [ -  + ]:         18 :         SPDK_CU_ASSERT_FATAL(mem != NULL);
     233                 :         18 :         mem->nregions = 2;
     234                 :         18 :         mem->regions[0].guest_phys_addr = 0;
     235                 :         18 :         mem->regions[0].size = 0x400000; /* 4 MB */
     236                 :         18 :         mem->regions[0].host_user_addr = 0x1000000;
     237                 :         18 :         mem->regions[1].guest_phys_addr = 0x400000;
     238                 :         18 :         mem->regions[1].size = 0x400000; /* 4 MB */
     239                 :         18 :         mem->regions[1].host_user_addr = 0x2000000;
     240                 :            : 
     241         [ -  + ]:         18 :         assert(TAILQ_EMPTY(&user_dev->vsessions));
     242                 :            :         /* spdk_vhost_dev must be allocated on a cache line boundary. */
     243         [ -  + ]:         18 :         rc = posix_memalign((void **)&vsession, 64, sizeof(*vsession));
     244                 :         18 :         CU_ASSERT(rc == 0);
     245         [ -  + ]:         18 :         SPDK_CU_ASSERT_FATAL(vsession != NULL);
     246                 :         18 :         vsession->started = true;
     247                 :         18 :         vsession->vid = 0;
     248                 :         18 :         vsession->mem = mem;
     249                 :         18 :         TAILQ_INSERT_TAIL(&user_dev->vsessions, vsession, tailq);
     250                 :         18 : }
     251                 :            : 
     252                 :            : static void
     253                 :         18 : stop_vdev(struct spdk_vhost_dev *vdev)
     254                 :            : {
     255                 :         18 :         struct spdk_vhost_user_dev *user_dev = to_user_dev(vdev);
     256                 :         18 :         struct spdk_vhost_session *vsession = TAILQ_FIRST(&user_dev->vsessions);
     257                 :            : 
     258         [ -  + ]:         18 :         TAILQ_REMOVE(&user_dev->vsessions, vsession, tailq);
     259                 :         18 :         free(vsession->mem);
     260                 :         18 :         free(vsession);
     261                 :         18 : }
     262                 :            : 
     263                 :            : static void
     264                 :         48 : cleanup_vdev(struct spdk_vhost_dev *vdev)
     265                 :            : {
     266                 :         48 :         struct spdk_vhost_user_dev *user_dev = to_user_dev(vdev);
     267                 :            : 
     268         [ +  + ]:         48 :         if (!TAILQ_EMPTY(&user_dev->vsessions)) {
     269                 :         18 :                 stop_vdev(vdev);
     270                 :            :         }
     271                 :         48 :         vhost_dev_unregister(vdev);
     272                 :         48 :         free(vdev);
     273                 :         48 : }
     274                 :            : 
     275                 :            : static void
     276                 :          6 : desc_to_iov_test(void)
     277                 :            : {
     278                 :          5 :         struct spdk_vhost_dev *vdev;
     279                 :            :         struct spdk_vhost_session *vsession;
     280                 :          5 :         struct iovec iov[SPDK_VHOST_IOVS_MAX];
     281                 :          5 :         uint16_t iov_index;
     282                 :          5 :         struct vring_desc desc;
     283                 :            :         int rc;
     284                 :            : 
     285                 :          6 :         spdk_cpuset_set_cpu(&g_vhost_core_mask, 0, true);
     286                 :            : 
     287                 :          6 :         rc = alloc_vdev(&vdev, "vdev_name_0", "0x1");
     288   [ +  -  +  -  :          6 :         SPDK_CU_ASSERT_FATAL(rc == 0 && vdev);
                   -  + ]
     289                 :          6 :         start_vdev(vdev);
     290                 :            : 
     291                 :          6 :         vsession = TAILQ_FIRST(&to_user_dev(vdev)->vsessions);
     292                 :            : 
     293                 :            :         /* Test simple case where iov falls fully within a 2MB page. */
     294                 :          6 :         desc.addr = 0x110000;
     295                 :          6 :         desc.len = 0x1000;
     296                 :          6 :         iov_index = 0;
     297                 :          6 :         rc = vhost_vring_desc_to_iov(vsession, iov, &iov_index, &desc);
     298                 :          6 :         CU_ASSERT(rc == 0);
     299                 :          6 :         CU_ASSERT(iov_index == 1);
     300                 :          6 :         CU_ASSERT(iov[0].iov_base == (void *)0x1110000);
     301                 :          6 :         CU_ASSERT(iov[0].iov_len == 0x1000);
     302                 :            :         /*
     303                 :            :          * Always memset the iov to ensure each test validates data written by its call
     304                 :            :          * to the function under test.
     305                 :            :          */
     306         [ -  + ]:          6 :         memset(iov, 0, sizeof(iov));
     307                 :            : 
     308                 :            :         /* Same test, but ensure it respects the non-zero starting iov_index. */
     309                 :          6 :         iov_index = SPDK_VHOST_IOVS_MAX - 1;
     310                 :          6 :         rc = vhost_vring_desc_to_iov(vsession, iov, &iov_index, &desc);
     311                 :          6 :         CU_ASSERT(rc == 0);
     312                 :          6 :         CU_ASSERT(iov_index == SPDK_VHOST_IOVS_MAX);
     313                 :          6 :         CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_base == (void *)0x1110000);
     314                 :          6 :         CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_len == 0x1000);
     315         [ -  + ]:          6 :         memset(iov, 0, sizeof(iov));
     316                 :            : 
     317                 :            :         /* Test for failure if iov_index already equals SPDK_VHOST_IOVS_MAX. */
     318                 :          6 :         iov_index = SPDK_VHOST_IOVS_MAX;
     319                 :          6 :         rc = vhost_vring_desc_to_iov(vsession, iov, &iov_index, &desc);
     320                 :          6 :         CU_ASSERT(rc != 0);
     321         [ -  + ]:          6 :         memset(iov, 0, sizeof(iov));
     322                 :            : 
     323                 :            :         /* Test case where iov spans a 2MB boundary, but does not span a vhost memory region. */
     324                 :          6 :         desc.addr = 0x1F0000;
     325                 :          6 :         desc.len = 0x20000;
     326                 :          6 :         iov_index = 0;
     327                 :          6 :         rc = vhost_vring_desc_to_iov(vsession, iov, &iov_index, &desc);
     328                 :          6 :         CU_ASSERT(rc == 0);
     329                 :          6 :         CU_ASSERT(iov_index == 1);
     330                 :          6 :         CU_ASSERT(iov[0].iov_base == (void *)0x11F0000);
     331                 :          6 :         CU_ASSERT(iov[0].iov_len == 0x20000);
     332         [ -  + ]:          6 :         memset(iov, 0, sizeof(iov));
     333                 :            : 
     334                 :            :         /* Same test, but ensure it respects the non-zero starting iov_index. */
     335                 :          6 :         iov_index = SPDK_VHOST_IOVS_MAX - 1;
     336                 :          6 :         rc = vhost_vring_desc_to_iov(vsession, iov, &iov_index, &desc);
     337                 :          6 :         CU_ASSERT(rc == 0);
     338                 :          6 :         CU_ASSERT(iov_index == SPDK_VHOST_IOVS_MAX);
     339                 :          6 :         CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_base == (void *)0x11F0000);
     340                 :          6 :         CU_ASSERT(iov[SPDK_VHOST_IOVS_MAX - 1].iov_len == 0x20000);
     341         [ -  + ]:          6 :         memset(iov, 0, sizeof(iov));
     342                 :            : 
     343                 :            :         /* Test case where iov spans a vhost memory region. */
     344                 :          6 :         desc.addr = 0x3F0000;
     345                 :          6 :         desc.len = 0x20000;
     346                 :          6 :         iov_index = 0;
     347                 :          6 :         rc = vhost_vring_desc_to_iov(vsession, iov, &iov_index, &desc);
     348                 :          6 :         CU_ASSERT(rc == 0);
     349                 :          6 :         CU_ASSERT(iov_index == 2);
     350                 :          6 :         CU_ASSERT(iov[0].iov_base == (void *)0x13F0000);
     351                 :          6 :         CU_ASSERT(iov[0].iov_len == 0x10000);
     352                 :          6 :         CU_ASSERT(iov[1].iov_base == (void *)0x2000000);
     353                 :          6 :         CU_ASSERT(iov[1].iov_len == 0x10000);
     354         [ -  + ]:          6 :         memset(iov, 0, sizeof(iov));
     355                 :            : 
     356                 :          6 :         cleanup_vdev(vdev);
     357                 :            : 
     358                 :          6 :         CU_ASSERT(true);
     359                 :          6 : }
     360                 :            : 
     361                 :            : static void
     362                 :          6 : create_controller_test(void)
     363                 :            : {
     364                 :          5 :         struct spdk_vhost_dev *vdev, *vdev2;
     365                 :            :         int ret;
     366                 :          5 :         char long_name[PATH_MAX];
     367                 :            : 
     368                 :          6 :         spdk_cpuset_parse(&g_vhost_core_mask, "0xf");
     369                 :            : 
     370                 :            :         /* Create device with cpumask implicitly matching whole application */
     371                 :          6 :         ret = alloc_vdev(&vdev, "vdev_name_0", NULL);
     372   [ +  -  +  -  :          6 :         SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
                   -  + ]
     373   [ -  +  -  + ]:          6 :         SPDK_CU_ASSERT_FATAL(!strcmp(spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)), "f"));
     374                 :          6 :         cleanup_vdev(vdev);
     375                 :            : 
     376                 :            :         /* Create device with cpumask matching whole application */
     377                 :          6 :         ret = alloc_vdev(&vdev, "vdev_name_0", "0xf");
     378   [ +  -  +  -  :          6 :         SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
                   -  + ]
     379   [ -  +  -  + ]:          6 :         SPDK_CU_ASSERT_FATAL(!strcmp(spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)), "f"));
     380                 :          6 :         cleanup_vdev(vdev);
     381                 :            : 
     382                 :            :         /* Create device with single core in cpumask */
     383                 :          6 :         ret = alloc_vdev(&vdev, "vdev_name_0", "0x2");
     384   [ +  -  +  -  :          6 :         SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
                   -  + ]
     385   [ -  +  -  + ]:          6 :         SPDK_CU_ASSERT_FATAL(!strcmp(spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)), "2"));
     386                 :          6 :         cleanup_vdev(vdev);
     387                 :            : 
     388                 :            :         /* Create device with cpumask spanning two cores */
     389                 :          6 :         ret = alloc_vdev(&vdev, "vdev_name_0", "0x3");
     390   [ +  -  +  -  :          6 :         SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
                   -  + ]
     391   [ -  +  -  + ]:          6 :         SPDK_CU_ASSERT_FATAL(!strcmp(spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)), "3"));
     392                 :          6 :         cleanup_vdev(vdev);
     393                 :            : 
     394                 :            :         /* Create device with incorrect cpumask outside of application cpumask */
     395                 :          6 :         ret = alloc_vdev(&vdev, "vdev_name_0", "0xf0");
     396         [ -  + ]:          6 :         SPDK_CU_ASSERT_FATAL(ret != 0);
     397                 :            : 
     398                 :            :         /* Create device with incorrect cpumask partially outside of application cpumask */
     399                 :          6 :         ret = alloc_vdev(&vdev, "vdev_name_0", "0xff");
     400         [ -  + ]:          6 :         SPDK_CU_ASSERT_FATAL(ret != 0);
     401                 :            : 
     402                 :            :         /* Create device with no name */
     403                 :          6 :         ret = alloc_vdev(&vdev, NULL, NULL);
     404                 :          6 :         CU_ASSERT(ret != 0);
     405                 :            : 
     406                 :            :         /* Create device with too long name and path */
     407                 :          6 :         memset(long_name, 'x', sizeof(long_name));
     408                 :          6 :         long_name[PATH_MAX - 1] = 0;
     409                 :          6 :         snprintf(g_vhost_user_dev_dirname, sizeof(g_vhost_user_dev_dirname), "some_path/");
     410                 :          6 :         ret = alloc_vdev(&vdev, long_name, NULL);
     411                 :          6 :         CU_ASSERT(ret != 0);
     412                 :          6 :         g_vhost_user_dev_dirname[0] = 0;
     413                 :            : 
     414                 :            :         /* Create device when device name is already taken */
     415                 :          6 :         ret = alloc_vdev(&vdev, "vdev_name_0", NULL);
     416   [ +  -  +  -  :          6 :         SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
                   -  + ]
     417                 :          6 :         ret = alloc_vdev(&vdev2, "vdev_name_0", NULL);
     418                 :          6 :         CU_ASSERT(ret != 0);
     419                 :          6 :         cleanup_vdev(vdev);
     420                 :          6 : }
     421                 :            : 
     422                 :            : static void
     423                 :          6 : session_find_by_vid_test(void)
     424                 :            : {
     425                 :          5 :         struct spdk_vhost_dev *vdev;
     426                 :            :         struct spdk_vhost_session *vsession;
     427                 :            :         struct spdk_vhost_session *tmp;
     428                 :            :         int rc;
     429                 :            : 
     430                 :          6 :         rc = alloc_vdev(&vdev, "vdev_name_0", "0x1");
     431   [ +  -  +  -  :          6 :         SPDK_CU_ASSERT_FATAL(rc == 0 && vdev);
                   -  + ]
     432                 :          6 :         start_vdev(vdev);
     433                 :            : 
     434                 :          6 :         vsession = TAILQ_FIRST(&to_user_dev(vdev)->vsessions);
     435                 :            : 
     436                 :          6 :         tmp = vhost_session_find_by_vid(vsession->vid);
     437                 :          6 :         CU_ASSERT(tmp == vsession);
     438                 :            : 
     439                 :            :         /* Search for a device with incorrect vid */
     440                 :          6 :         tmp = vhost_session_find_by_vid(vsession->vid + 0xFF);
     441                 :          6 :         CU_ASSERT(tmp == NULL);
     442                 :            : 
     443                 :          6 :         cleanup_vdev(vdev);
     444                 :          6 : }
     445                 :            : 
     446                 :            : static void
     447                 :          6 : remove_controller_test(void)
     448                 :            : {
     449                 :          5 :         struct spdk_vhost_dev *vdev;
     450                 :            :         int ret;
     451                 :            : 
     452                 :          6 :         ret = alloc_vdev(&vdev, "vdev_name_0", "0x1");
     453   [ +  -  +  -  :          6 :         SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
                   -  + ]
     454                 :            : 
     455                 :            :         /* Remove device when controller is in use */
     456                 :          6 :         start_vdev(vdev);
     457         [ -  + ]:          6 :         SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&to_user_dev(vdev)->vsessions));
     458                 :          6 :         ret = vhost_dev_unregister(vdev);
     459                 :          6 :         CU_ASSERT(ret != 0);
     460                 :            : 
     461                 :          6 :         cleanup_vdev(vdev);
     462                 :          6 : }
     463                 :            : 
     464                 :            : static void
     465                 :          6 : vq_avail_ring_get_test(void)
     466                 :            : {
     467                 :          6 :         struct spdk_vhost_virtqueue vq = {};
     468                 :          5 :         uint16_t avail_mem[34];
     469                 :          5 :         uint16_t reqs[32];
     470                 :            :         uint16_t reqs_len, ret, i;
     471                 :            : 
     472                 :            :         /* Basic example reap all requests */
     473                 :          6 :         vq.vring.avail = (struct vring_avail *)avail_mem;
     474                 :          6 :         vq.vring.size = 32;
     475                 :          6 :         vq.last_avail_idx = 24;
     476                 :          6 :         vq.vring.avail->idx = 29;
     477                 :          6 :         reqs_len = 6;
     478                 :            : 
     479         [ +  + ]:        198 :         for (i = 0; i < 32; i++) {
     480                 :        192 :                 vq.vring.avail->ring[i] = i;
     481                 :            :         }
     482                 :            : 
     483                 :          6 :         ret = vhost_vq_avail_ring_get(&vq, reqs, reqs_len);
     484                 :          6 :         CU_ASSERT(ret == 5);
     485                 :          6 :         CU_ASSERT(vq.last_avail_idx == 29);
     486         [ +  + ]:         36 :         for (i = 0; i < ret; i++) {
     487                 :         30 :                 CU_ASSERT(reqs[i] == vq.vring.avail->ring[i + 24]);
     488                 :            :         }
     489                 :            : 
     490                 :            :         /* Basic example reap only some requests */
     491                 :          6 :         vq.last_avail_idx = 20;
     492                 :          6 :         vq.vring.avail->idx = 29;
     493                 :          6 :         reqs_len = 6;
     494                 :            : 
     495                 :          6 :         ret = vhost_vq_avail_ring_get(&vq, reqs, reqs_len);
     496                 :          6 :         CU_ASSERT(ret == reqs_len);
     497                 :          6 :         CU_ASSERT(vq.last_avail_idx == 26);
     498         [ +  + ]:         42 :         for (i = 0; i < ret; i++) {
     499                 :         36 :                 CU_ASSERT(reqs[i] == vq.vring.avail->ring[i + 20]);
     500                 :            :         }
     501                 :            : 
     502                 :            :         /* Test invalid example */
     503                 :          6 :         vq.last_avail_idx = 20;
     504                 :          6 :         vq.vring.avail->idx = 156;
     505                 :          6 :         reqs_len = 6;
     506                 :            : 
     507                 :          6 :         ret = vhost_vq_avail_ring_get(&vq, reqs, reqs_len);
     508                 :          6 :         CU_ASSERT(ret == 0);
     509                 :            : 
     510                 :            :         /* Test overflow in the avail->idx variable. */
     511                 :          6 :         vq.last_avail_idx = 65535;
     512                 :          6 :         vq.vring.avail->idx = 4;
     513                 :          6 :         reqs_len = 6;
     514                 :          6 :         ret = vhost_vq_avail_ring_get(&vq, reqs, reqs_len);
     515                 :          6 :         CU_ASSERT(ret == 5);
     516                 :          6 :         CU_ASSERT(vq.last_avail_idx == 4);
     517                 :          6 :         CU_ASSERT(reqs[0] == vq.vring.avail->ring[31]);
     518         [ +  + ]:         30 :         for (i = 1; i < ret; i++) {
     519                 :         24 :                 CU_ASSERT(reqs[i] == vq.vring.avail->ring[i - 1]);
     520                 :            :         }
     521                 :          6 : }
     522                 :            : 
     523                 :            : static bool
     524                 :         42 : vq_desc_guest_is_used(struct spdk_vhost_virtqueue *vq, int16_t guest_last_used_idx,
     525                 :            :                       int16_t guest_used_phase)
     526                 :            : {
     527                 :         56 :         return (!!(vq->vring.desc_packed[guest_last_used_idx].flags & VRING_DESC_F_USED) ==
     528                 :         42 :                 !!guest_used_phase);
     529                 :            : }
     530                 :            : 
     531                 :            : static void
     532                 :         42 : vq_desc_guest_set_avail(struct spdk_vhost_virtqueue *vq, int16_t *guest_last_avail_idx,
     533                 :            :                         int16_t *guest_avail_phase)
     534                 :            : {
     535         [ +  + ]:         42 :         if (*guest_avail_phase) {
     536                 :         24 :                 vq->vring.desc_packed[*guest_last_avail_idx].flags |= VRING_DESC_F_AVAIL;
     537                 :         24 :                 vq->vring.desc_packed[*guest_last_avail_idx].flags &= ~VRING_DESC_F_USED;
     538                 :            :         } else {
     539                 :         18 :                 vq->vring.desc_packed[*guest_last_avail_idx].flags &= ~VRING_DESC_F_AVAIL;
     540                 :         18 :                 vq->vring.desc_packed[*guest_last_avail_idx].flags |= VRING_DESC_F_USED;
     541                 :            :         }
     542                 :            : 
     543         [ +  + ]:         42 :         if (++(*guest_last_avail_idx) >= vq->vring.size) {
     544                 :          6 :                 *guest_last_avail_idx -= vq->vring.size;
     545                 :          6 :                 *guest_avail_phase = !(*guest_avail_phase);
     546                 :            :         }
     547                 :         42 : }
     548                 :            : 
     549                 :            : static int16_t
     550                 :         42 : vq_desc_guest_handle_completed_desc(struct spdk_vhost_virtqueue *vq, int16_t *guest_last_used_idx,
     551                 :            :                                     int16_t *guest_used_phase)
     552                 :            : {
     553                 :         42 :         int16_t buffer_id = -1;
     554                 :            : 
     555         [ +  - ]:         42 :         if (vq_desc_guest_is_used(vq, *guest_last_used_idx, *guest_used_phase)) {
     556                 :         42 :                 buffer_id = vq->vring.desc_packed[*guest_last_used_idx].id;
     557         [ +  + ]:         42 :                 if (++(*guest_last_used_idx) >= vq->vring.size) {
     558                 :          6 :                         *guest_last_used_idx -= vq->vring.size;
     559                 :          6 :                         *guest_used_phase = !(*guest_used_phase);
     560                 :            :                 }
     561                 :            : 
     562                 :         42 :                 return buffer_id;
     563                 :            :         }
     564                 :            : 
     565                 :          0 :         return -1;
     566                 :            : }
     567                 :            : 
     568                 :            : static void
     569                 :          6 : vq_packed_ring_test(void)
     570                 :            : {
     571                 :          6 :         struct spdk_vhost_session vs = {};
     572                 :          6 :         struct spdk_vhost_virtqueue vq = {};
     573                 :          5 :         struct vring_packed_desc descs[4];
     574                 :          6 :         uint16_t guest_last_avail_idx = 0, guest_last_used_idx = 0;
     575                 :          6 :         uint16_t guest_avail_phase = 1, guest_used_phase = 1;
     576                 :            :         int i;
     577                 :          5 :         int16_t chain_num;
     578                 :            : 
     579                 :          6 :         vq.vring.desc_packed = descs;
     580                 :          6 :         vq.vring.size = 4;
     581                 :            : 
     582                 :            :         /* avail and used wrap counter are initialized to 1 */
     583                 :          6 :         vq.packed.avail_phase = 1;
     584                 :          6 :         vq.packed.used_phase = 1;
     585                 :          6 :         vq.packed.packed_ring = true;
     586         [ -  + ]:          6 :         memset(descs, 0, sizeof(descs));
     587                 :            : 
     588                 :          6 :         CU_ASSERT(vhost_vq_packed_ring_is_avail(&vq) == false);
     589                 :            : 
     590                 :            :         /* Guest send requests */
     591         [ +  + ]:         30 :         for (i = 0; i < vq.vring.size; i++) {
     592                 :         24 :                 descs[guest_last_avail_idx].id = i;
     593                 :            :                 /* Set the desc available */
     594                 :         24 :                 vq_desc_guest_set_avail(&vq, &guest_last_avail_idx, &guest_avail_phase);
     595                 :            :         }
     596                 :          6 :         CU_ASSERT(guest_last_avail_idx == 0);
     597                 :          6 :         CU_ASSERT(guest_avail_phase == 0);
     598                 :            : 
     599                 :            :         /* Host handle available descs */
     600                 :          6 :         CU_ASSERT(vhost_vq_packed_ring_is_avail(&vq) == true);
     601                 :          6 :         i = 0;
     602         [ +  + ]:         30 :         while (vhost_vq_packed_ring_is_avail(&vq)) {
     603                 :         24 :                 CU_ASSERT(vhost_vring_packed_desc_get_buffer_id(&vq, vq.last_avail_idx, &chain_num) == i++);
     604                 :         24 :                 CU_ASSERT(chain_num == 1);
     605                 :            :         }
     606                 :            : 
     607                 :            :         /* Host complete them out of order: 1, 0, 2. */
     608                 :          6 :         vhost_vq_packed_ring_enqueue(&vs, &vq, 1, 1, 1, 0);
     609                 :          6 :         vhost_vq_packed_ring_enqueue(&vs, &vq, 1, 0, 1, 0);
     610                 :          6 :         vhost_vq_packed_ring_enqueue(&vs, &vq, 1, 2, 1, 0);
     611                 :            : 
     612                 :            :         /* Host has got all the available request but only complete three requests */
     613                 :          6 :         CU_ASSERT(vq.last_avail_idx == 0);
     614                 :          6 :         CU_ASSERT(vq.packed.avail_phase == 0);
     615                 :          6 :         CU_ASSERT(vq.last_used_idx == 3);
     616                 :          6 :         CU_ASSERT(vq.packed.used_phase == 1);
     617                 :            : 
     618                 :            :         /* Guest handle completed requests */
     619                 :          6 :         CU_ASSERT(vq_desc_guest_handle_completed_desc(&vq, &guest_last_used_idx, &guest_used_phase) == 1);
     620                 :          6 :         CU_ASSERT(vq_desc_guest_handle_completed_desc(&vq, &guest_last_used_idx, &guest_used_phase) == 0);
     621                 :          6 :         CU_ASSERT(vq_desc_guest_handle_completed_desc(&vq, &guest_last_used_idx, &guest_used_phase) == 2);
     622                 :          6 :         CU_ASSERT(guest_last_used_idx == 3);
     623                 :          6 :         CU_ASSERT(guest_used_phase == 1);
     624                 :            : 
     625                 :            :         /* There are three descs available the guest can send three request again */
     626         [ +  + ]:         24 :         for (i = 0; i < 3; i++) {
     627                 :         18 :                 descs[guest_last_avail_idx].id = 2 - i;
     628                 :            :                 /* Set the desc available */
     629                 :         18 :                 vq_desc_guest_set_avail(&vq, &guest_last_avail_idx, &guest_avail_phase);
     630                 :            :         }
     631                 :            : 
     632                 :            :         /* Host handle available descs */
     633                 :          6 :         CU_ASSERT(vhost_vq_packed_ring_is_avail(&vq) == true);
     634                 :          6 :         i = 2;
     635         [ +  + ]:         24 :         while (vhost_vq_packed_ring_is_avail(&vq)) {
     636                 :         18 :                 CU_ASSERT(vhost_vring_packed_desc_get_buffer_id(&vq, vq.last_avail_idx, &chain_num) == i--);
     637                 :         18 :                 CU_ASSERT(chain_num == 1);
     638                 :            :         }
     639                 :            : 
     640                 :            :         /* There are four requests in Host, the new three ones and left one */
     641                 :          6 :         CU_ASSERT(vq.last_avail_idx == 3);
     642                 :            :         /* Available wrap conter should overturn */
     643                 :          6 :         CU_ASSERT(vq.packed.avail_phase == 0);
     644                 :            : 
     645                 :            :         /* Host complete all the requests */
     646                 :          6 :         vhost_vq_packed_ring_enqueue(&vs, &vq, 1, 1, 1, 0);
     647                 :          6 :         vhost_vq_packed_ring_enqueue(&vs, &vq, 1, 0, 1, 0);
     648                 :          6 :         vhost_vq_packed_ring_enqueue(&vs, &vq, 1, 3, 1, 0);
     649                 :          6 :         vhost_vq_packed_ring_enqueue(&vs, &vq, 1, 2, 1, 0);
     650                 :            : 
     651                 :          6 :         CU_ASSERT(vq.last_used_idx == vq.last_avail_idx);
     652                 :          6 :         CU_ASSERT(vq.packed.used_phase == vq.packed.avail_phase);
     653                 :            : 
     654                 :            :         /* Guest handle completed requests */
     655                 :          6 :         CU_ASSERT(vq_desc_guest_handle_completed_desc(&vq, &guest_last_used_idx, &guest_used_phase) == 1);
     656                 :          6 :         CU_ASSERT(vq_desc_guest_handle_completed_desc(&vq, &guest_last_used_idx, &guest_used_phase) == 0);
     657                 :          6 :         CU_ASSERT(vq_desc_guest_handle_completed_desc(&vq, &guest_last_used_idx, &guest_used_phase) == 3);
     658                 :          6 :         CU_ASSERT(vq_desc_guest_handle_completed_desc(&vq, &guest_last_used_idx, &guest_used_phase) == 2);
     659                 :            : 
     660                 :          6 :         CU_ASSERT(guest_last_avail_idx == guest_last_used_idx);
     661                 :          6 :         CU_ASSERT(guest_avail_phase == guest_used_phase);
     662                 :          6 : }
     663                 :            : 
     664                 :            : static void
     665                 :          6 : vhost_blk_construct_test(void)
     666                 :            : {
     667                 :            :         int ret;
     668                 :          6 :         struct spdk_vhost_dev *vdev = NULL;
     669                 :            : 
     670                 :          6 :         ret = spdk_vhost_blk_construct("Malloc0", "0x1", "vhost.blk.0", NULL, NULL);
     671                 :          6 :         CU_ASSERT(ret == 0);
     672                 :            : 
     673                 :          6 :         vdev = spdk_vhost_dev_find("Malloc0");
     674                 :          6 :         CU_ASSERT(vdev != NULL);
     675         [ -  + ]:          6 :         CU_ASSERT(strcmp("Malloc0", spdk_vhost_dev_get_name(vdev)) == 0);
     676                 :            : 
     677                 :          6 :         ret = spdk_vhost_dev_remove(vdev);
     678                 :          6 :         CU_ASSERT(ret == 0);
     679                 :          6 : }
     680                 :            : 
     681                 :            : int
     682                 :          6 : main(int argc, char **argv)
     683                 :            : {
     684                 :          6 :         CU_pSuite       suite = NULL;
     685                 :            :         unsigned int    num_failures;
     686                 :            : 
     687                 :          6 :         CU_initialize_registry();
     688                 :            : 
     689                 :          6 :         suite = CU_add_suite("vhost_suite", test_setup, test_cleanup);
     690                 :            : 
     691                 :          6 :         CU_ADD_TEST(suite, desc_to_iov_test);
     692                 :          6 :         CU_ADD_TEST(suite, create_controller_test);
     693                 :          6 :         CU_ADD_TEST(suite, session_find_by_vid_test);
     694                 :          6 :         CU_ADD_TEST(suite, remove_controller_test);
     695                 :          6 :         CU_ADD_TEST(suite, vq_avail_ring_get_test);
     696                 :          6 :         CU_ADD_TEST(suite, vq_packed_ring_test);
     697                 :          6 :         CU_ADD_TEST(suite, vhost_blk_construct_test);
     698                 :            : 
     699                 :          6 :         num_failures = spdk_ut_run_tests(argc, argv, NULL);
     700                 :          6 :         CU_cleanup_registry();
     701                 :            : 
     702                 :          6 :         return num_failures;
     703                 :            : }

Generated by: LCOV version 1.14