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: 366 403 90.8 %
Date: 2024-08-13 08:37:22 Functions: 34 115 29.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 110 256 43.0 %

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

Generated by: LCOV version 1.14