qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vhost-user-blk-test.c (31787B)


      1 /*
      2  * QTest testcase for Vhost-user Block Device
      3  *
      4  * Based on tests/qtest//virtio-blk-test.c
      5 
      6  * Copyright (c) 2014 SUSE LINUX Products GmbH
      7  * Copyright (c) 2014 Marc MarĂ­
      8  * Copyright (c) 2020 Coiby Xu
      9  *
     10  * This work is licensed under the terms of the GNU GPL, version 2 or later.
     11  * See the COPYING file in the top-level directory.
     12  */
     13 
     14 #include "qemu/osdep.h"
     15 #include "libqtest-single.h"
     16 #include "qemu/bswap.h"
     17 #include "qemu/module.h"
     18 #include "standard-headers/linux/virtio_blk.h"
     19 #include "standard-headers/linux/virtio_pci.h"
     20 #include "libqos/qgraph.h"
     21 #include "libqos/vhost-user-blk.h"
     22 #include "libqos/libqos-pc.h"
     23 
     24 #define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
     25 #define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
     26 #define PCI_SLOT_HP             0x06
     27 
     28 typedef struct {
     29     pid_t pid;
     30 } QemuStorageDaemonState;
     31 
     32 typedef struct QVirtioBlkReq {
     33     uint32_t type;
     34     uint32_t ioprio;
     35     uint64_t sector;
     36     char *data;
     37     uint8_t status;
     38 } QVirtioBlkReq;
     39 
     40 #if HOST_BIG_ENDIAN
     41 static const bool host_is_big_endian = true;
     42 #else
     43 static const bool host_is_big_endian; /* false */
     44 #endif
     45 
     46 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
     47 {
     48     if (qvirtio_is_big_endian(d) != host_is_big_endian) {
     49         req->type = bswap32(req->type);
     50         req->ioprio = bswap32(req->ioprio);
     51         req->sector = bswap64(req->sector);
     52     }
     53 }
     54 
     55 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
     56     struct virtio_blk_discard_write_zeroes *dwz_hdr)
     57 {
     58     if (qvirtio_is_big_endian(d) != host_is_big_endian) {
     59         dwz_hdr->sector = bswap64(dwz_hdr->sector);
     60         dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
     61         dwz_hdr->flags = bswap32(dwz_hdr->flags);
     62     }
     63 }
     64 
     65 static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
     66                                    QVirtioBlkReq *req, uint64_t data_size)
     67 {
     68     uint64_t addr;
     69     uint8_t status = 0xFF;
     70     QTestState *qts = global_qtest;
     71 
     72     switch (req->type) {
     73     case VIRTIO_BLK_T_IN:
     74     case VIRTIO_BLK_T_OUT:
     75         g_assert_cmpuint(data_size % 512, ==, 0);
     76         break;
     77     case VIRTIO_BLK_T_DISCARD:
     78     case VIRTIO_BLK_T_WRITE_ZEROES:
     79         g_assert_cmpuint(data_size %
     80                          sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
     81         break;
     82     default:
     83         g_assert_cmpuint(data_size, ==, 0);
     84     }
     85 
     86     addr = guest_alloc(alloc, sizeof(*req) + data_size);
     87 
     88     virtio_blk_fix_request(d, req);
     89 
     90     qtest_memwrite(qts, addr, req, 16);
     91     qtest_memwrite(qts, addr + 16, req->data, data_size);
     92     qtest_memwrite(qts, addr + 16 + data_size, &status, sizeof(status));
     93 
     94     return addr;
     95 }
     96 
     97 static void test_invalid_discard_write_zeroes(QVirtioDevice *dev,
     98                                               QGuestAllocator *alloc,
     99                                               QTestState *qts,
    100                                               QVirtQueue *vq,
    101                                               uint32_t type)
    102 {
    103     QVirtioBlkReq req;
    104     struct virtio_blk_discard_write_zeroes dwz_hdr;
    105     struct virtio_blk_discard_write_zeroes dwz_hdr2[2];
    106     uint64_t req_addr;
    107     uint32_t free_head;
    108     uint8_t status;
    109 
    110     /* More than one dwz is not supported */
    111     req.type = type;
    112     req.data = (char *) dwz_hdr2;
    113     dwz_hdr2[0].sector = 0;
    114     dwz_hdr2[0].num_sectors = 1;
    115     dwz_hdr2[0].flags = 0;
    116     dwz_hdr2[1].sector = 1;
    117     dwz_hdr2[1].num_sectors = 1;
    118     dwz_hdr2[1].flags = 0;
    119 
    120     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[0]);
    121     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[1]);
    122 
    123     req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr2));
    124 
    125     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    126     qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr2), false, true);
    127     qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr2), 1, true,
    128                    false);
    129 
    130     qvirtqueue_kick(qts, dev, vq, free_head);
    131 
    132     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    133                            QVIRTIO_BLK_TIMEOUT_US);
    134     status = readb(req_addr + 16 + sizeof(dwz_hdr2));
    135     g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
    136 
    137     guest_free(alloc, req_addr);
    138 
    139     /* num_sectors must be less than config->max_write_zeroes_sectors */
    140     req.type = type;
    141     req.data = (char *) &dwz_hdr;
    142     dwz_hdr.sector = 0;
    143     dwz_hdr.num_sectors = 0xffffffff;
    144     dwz_hdr.flags = 0;
    145 
    146     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
    147 
    148     req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
    149 
    150     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    151     qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
    152     qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
    153                    false);
    154 
    155     qvirtqueue_kick(qts, dev, vq, free_head);
    156 
    157     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    158                            QVIRTIO_BLK_TIMEOUT_US);
    159     status = readb(req_addr + 16 + sizeof(dwz_hdr));
    160     g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
    161 
    162     guest_free(alloc, req_addr);
    163 
    164     /* sector must be less than the device capacity */
    165     req.type = type;
    166     req.data = (char *) &dwz_hdr;
    167     dwz_hdr.sector = TEST_IMAGE_SIZE / 512 + 1;
    168     dwz_hdr.num_sectors = 1;
    169     dwz_hdr.flags = 0;
    170 
    171     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
    172 
    173     req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
    174 
    175     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    176     qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
    177     qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
    178                    false);
    179 
    180     qvirtqueue_kick(qts, dev, vq, free_head);
    181 
    182     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    183                            QVIRTIO_BLK_TIMEOUT_US);
    184     status = readb(req_addr + 16 + sizeof(dwz_hdr));
    185     g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
    186 
    187     guest_free(alloc, req_addr);
    188 
    189     /* reserved flag bits must be zero */
    190     req.type = type;
    191     req.data = (char *) &dwz_hdr;
    192     dwz_hdr.sector = 0;
    193     dwz_hdr.num_sectors = 1;
    194     dwz_hdr.flags = ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP;
    195 
    196     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
    197 
    198     req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
    199 
    200     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    201     qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
    202     qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
    203                    false);
    204 
    205     qvirtqueue_kick(qts, dev, vq, free_head);
    206 
    207     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    208                            QVIRTIO_BLK_TIMEOUT_US);
    209     status = readb(req_addr + 16 + sizeof(dwz_hdr));
    210     g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
    211 
    212     guest_free(alloc, req_addr);
    213 }
    214 
    215 /* Returns the request virtqueue so the caller can perform further tests */
    216 static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
    217 {
    218     QVirtioBlkReq req;
    219     uint64_t req_addr;
    220     uint64_t capacity;
    221     uint64_t features;
    222     uint32_t free_head;
    223     uint8_t status;
    224     char *data;
    225     QTestState *qts = global_qtest;
    226     QVirtQueue *vq;
    227 
    228     features = qvirtio_get_features(dev);
    229     features = features & ~(QVIRTIO_F_BAD_FEATURE |
    230                     (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    231                     (1u << VIRTIO_RING_F_EVENT_IDX) |
    232                     (1u << VIRTIO_BLK_F_SCSI));
    233     qvirtio_set_features(dev, features);
    234 
    235     capacity = qvirtio_config_readq(dev, 0);
    236     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
    237 
    238     vq = qvirtqueue_setup(dev, alloc, 0);
    239 
    240     qvirtio_set_driver_ok(dev);
    241 
    242     /* Write and read with 3 descriptor layout */
    243     /* Write request */
    244     req.type = VIRTIO_BLK_T_OUT;
    245     req.ioprio = 1;
    246     req.sector = 0;
    247     req.data = g_malloc0(512);
    248     strcpy(req.data, "TEST");
    249 
    250     req_addr = virtio_blk_request(alloc, dev, &req, 512);
    251 
    252     g_free(req.data);
    253 
    254     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    255     qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
    256     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    257 
    258     qvirtqueue_kick(qts, dev, vq, free_head);
    259 
    260     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    261                            QVIRTIO_BLK_TIMEOUT_US);
    262     status = readb(req_addr + 528);
    263     g_assert_cmpint(status, ==, 0);
    264 
    265     guest_free(alloc, req_addr);
    266 
    267     /* Read request */
    268     req.type = VIRTIO_BLK_T_IN;
    269     req.ioprio = 1;
    270     req.sector = 0;
    271     req.data = g_malloc0(512);
    272 
    273     req_addr = virtio_blk_request(alloc, dev, &req, 512);
    274 
    275     g_free(req.data);
    276 
    277     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    278     qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
    279     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    280 
    281     qvirtqueue_kick(qts, dev, vq, free_head);
    282 
    283     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    284                            QVIRTIO_BLK_TIMEOUT_US);
    285     status = readb(req_addr + 528);
    286     g_assert_cmpint(status, ==, 0);
    287 
    288     data = g_malloc0(512);
    289     qtest_memread(qts, req_addr + 16, data, 512);
    290     g_assert_cmpstr(data, ==, "TEST");
    291     g_free(data);
    292 
    293     guest_free(alloc, req_addr);
    294 
    295     if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
    296         struct virtio_blk_discard_write_zeroes dwz_hdr;
    297         void *expected;
    298 
    299         /*
    300          * WRITE_ZEROES request on the same sector of previous test where
    301          * we wrote "TEST".
    302          */
    303         req.type = VIRTIO_BLK_T_WRITE_ZEROES;
    304         req.data = (char *) &dwz_hdr;
    305         dwz_hdr.sector = 0;
    306         dwz_hdr.num_sectors = 1;
    307         dwz_hdr.flags = 0;
    308 
    309         virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
    310 
    311         req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
    312 
    313         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    314         qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
    315         qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
    316                        false);
    317 
    318         qvirtqueue_kick(qts, dev, vq, free_head);
    319 
    320         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    321                                QVIRTIO_BLK_TIMEOUT_US);
    322         status = readb(req_addr + 16 + sizeof(dwz_hdr));
    323         g_assert_cmpint(status, ==, 0);
    324 
    325         guest_free(alloc, req_addr);
    326 
    327         /* Read request to check if the sector contains all zeroes */
    328         req.type = VIRTIO_BLK_T_IN;
    329         req.ioprio = 1;
    330         req.sector = 0;
    331         req.data = g_malloc0(512);
    332 
    333         req_addr = virtio_blk_request(alloc, dev, &req, 512);
    334 
    335         g_free(req.data);
    336 
    337         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    338         qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
    339         qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    340 
    341         qvirtqueue_kick(qts, dev, vq, free_head);
    342 
    343         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    344                                QVIRTIO_BLK_TIMEOUT_US);
    345         status = readb(req_addr + 528);
    346         g_assert_cmpint(status, ==, 0);
    347 
    348         data = g_malloc(512);
    349         expected = g_malloc0(512);
    350         qtest_memread(qts, req_addr + 16, data, 512);
    351         g_assert_cmpmem(data, 512, expected, 512);
    352         g_free(expected);
    353         g_free(data);
    354 
    355         guest_free(alloc, req_addr);
    356 
    357         test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
    358                                           VIRTIO_BLK_T_WRITE_ZEROES);
    359     }
    360 
    361     if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
    362         struct virtio_blk_discard_write_zeroes dwz_hdr;
    363 
    364         req.type = VIRTIO_BLK_T_DISCARD;
    365         req.data = (char *) &dwz_hdr;
    366         dwz_hdr.sector = 0;
    367         dwz_hdr.num_sectors = 1;
    368         dwz_hdr.flags = 0;
    369 
    370         virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
    371 
    372         req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
    373 
    374         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    375         qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
    376         qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr),
    377                        1, true, false);
    378 
    379         qvirtqueue_kick(qts, dev, vq, free_head);
    380 
    381         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    382                                QVIRTIO_BLK_TIMEOUT_US);
    383         status = readb(req_addr + 16 + sizeof(dwz_hdr));
    384         g_assert_cmpint(status, ==, 0);
    385 
    386         guest_free(alloc, req_addr);
    387 
    388         test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
    389                                           VIRTIO_BLK_T_DISCARD);
    390     }
    391 
    392     if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
    393         /* Write and read with 2 descriptor layout */
    394         /* Write request */
    395         req.type = VIRTIO_BLK_T_OUT;
    396         req.ioprio = 1;
    397         req.sector = 1;
    398         req.data = g_malloc0(512);
    399         strcpy(req.data, "TEST");
    400 
    401         req_addr = virtio_blk_request(alloc, dev, &req, 512);
    402 
    403         g_free(req.data);
    404 
    405         free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
    406         qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    407         qvirtqueue_kick(qts, dev, vq, free_head);
    408 
    409         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    410                                QVIRTIO_BLK_TIMEOUT_US);
    411         status = readb(req_addr + 528);
    412         g_assert_cmpint(status, ==, 0);
    413 
    414         guest_free(alloc, req_addr);
    415 
    416         /* Read request */
    417         req.type = VIRTIO_BLK_T_IN;
    418         req.ioprio = 1;
    419         req.sector = 1;
    420         req.data = g_malloc0(512);
    421 
    422         req_addr = virtio_blk_request(alloc, dev, &req, 512);
    423 
    424         g_free(req.data);
    425 
    426         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    427         qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
    428 
    429         qvirtqueue_kick(qts, dev, vq, free_head);
    430 
    431         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    432                                QVIRTIO_BLK_TIMEOUT_US);
    433         status = readb(req_addr + 528);
    434         g_assert_cmpint(status, ==, 0);
    435 
    436         data = g_malloc0(512);
    437         qtest_memread(qts, req_addr + 16, data, 512);
    438         g_assert_cmpstr(data, ==, "TEST");
    439         g_free(data);
    440 
    441         guest_free(alloc, req_addr);
    442     }
    443 
    444     return vq;
    445 }
    446 
    447 static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
    448 {
    449     QVhostUserBlk *blk_if = obj;
    450     QVirtQueue *vq;
    451 
    452     vq = test_basic(blk_if->vdev, t_alloc);
    453     qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
    454 
    455 }
    456 
    457 static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
    458 {
    459     QVirtQueue *vq;
    460     QVhostUserBlk *blk_if = obj;
    461     QVirtioDevice *dev = blk_if->vdev;
    462     QVirtioBlkReq req;
    463     QVRingIndirectDesc *indirect;
    464     uint64_t req_addr;
    465     uint64_t capacity;
    466     uint64_t features;
    467     uint32_t free_head;
    468     uint8_t status;
    469     char *data;
    470     QTestState *qts = global_qtest;
    471 
    472     features = qvirtio_get_features(dev);
    473     g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
    474     features = features & ~(QVIRTIO_F_BAD_FEATURE |
    475                             (1u << VIRTIO_RING_F_EVENT_IDX) |
    476                             (1u << VIRTIO_BLK_F_SCSI));
    477     qvirtio_set_features(dev, features);
    478 
    479     capacity = qvirtio_config_readq(dev, 0);
    480     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
    481 
    482     vq = qvirtqueue_setup(dev, t_alloc, 0);
    483     qvirtio_set_driver_ok(dev);
    484 
    485     /* Write request */
    486     req.type = VIRTIO_BLK_T_OUT;
    487     req.ioprio = 1;
    488     req.sector = 0;
    489     req.data = g_malloc0(512);
    490     strcpy(req.data, "TEST");
    491 
    492     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    493 
    494     g_free(req.data);
    495 
    496     indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
    497     qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
    498     qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
    499     free_head = qvirtqueue_add_indirect(qts, vq, indirect);
    500     qvirtqueue_kick(qts, dev, vq, free_head);
    501 
    502     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    503                            QVIRTIO_BLK_TIMEOUT_US);
    504     status = readb(req_addr + 528);
    505     g_assert_cmpint(status, ==, 0);
    506 
    507     g_free(indirect);
    508     guest_free(t_alloc, req_addr);
    509 
    510     /* Read request */
    511     req.type = VIRTIO_BLK_T_IN;
    512     req.ioprio = 1;
    513     req.sector = 0;
    514     req.data = g_malloc0(512);
    515     strcpy(req.data, "TEST");
    516 
    517     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    518 
    519     g_free(req.data);
    520 
    521     indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
    522     qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
    523     qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
    524     free_head = qvirtqueue_add_indirect(qts, vq, indirect);
    525     qvirtqueue_kick(qts, dev, vq, free_head);
    526 
    527     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    528                            QVIRTIO_BLK_TIMEOUT_US);
    529     status = readb(req_addr + 528);
    530     g_assert_cmpint(status, ==, 0);
    531 
    532     data = g_malloc0(512);
    533     qtest_memread(qts, req_addr + 16, data, 512);
    534     g_assert_cmpstr(data, ==, "TEST");
    535     g_free(data);
    536 
    537     g_free(indirect);
    538     guest_free(t_alloc, req_addr);
    539     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
    540 }
    541 
    542 static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
    543 {
    544     QVirtQueue *vq;
    545     QVhostUserBlkPCI *blk = obj;
    546     QVirtioPCIDevice *pdev = &blk->pci_vdev;
    547     QVirtioDevice *dev = &pdev->vdev;
    548     QVirtioBlkReq req;
    549     uint64_t req_addr;
    550     uint64_t capacity;
    551     uint64_t features;
    552     uint32_t free_head;
    553     uint32_t write_head;
    554     uint32_t desc_idx;
    555     uint8_t status;
    556     char *data;
    557     QOSGraphObject *blk_object = obj;
    558     QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
    559     QTestState *qts = global_qtest;
    560 
    561     if (qpci_check_buggy_msi(pci_dev)) {
    562         return;
    563     }
    564 
    565     qpci_msix_enable(pdev->pdev);
    566     qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
    567 
    568     features = qvirtio_get_features(dev);
    569     features = features & ~(QVIRTIO_F_BAD_FEATURE |
    570                             (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    571                             (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
    572                             (1u << VIRTIO_BLK_F_SCSI));
    573     qvirtio_set_features(dev, features);
    574 
    575     capacity = qvirtio_config_readq(dev, 0);
    576     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
    577 
    578     vq = qvirtqueue_setup(dev, t_alloc, 0);
    579     qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
    580 
    581     qvirtio_set_driver_ok(dev);
    582 
    583     /*
    584      * libvhost-user signals the call fd in VHOST_USER_SET_VRING_CALL, make
    585      * sure to wait for the isr here so we don't race and confuse it later on.
    586      */
    587     qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
    588 
    589     /* Write request */
    590     req.type = VIRTIO_BLK_T_OUT;
    591     req.ioprio = 1;
    592     req.sector = 0;
    593     req.data = g_malloc0(512);
    594     strcpy(req.data, "TEST");
    595 
    596     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    597 
    598     g_free(req.data);
    599 
    600     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    601     qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
    602     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    603     qvirtqueue_kick(qts, dev, vq, free_head);
    604 
    605     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
    606                            QVIRTIO_BLK_TIMEOUT_US);
    607 
    608     /* Write request */
    609     req.type = VIRTIO_BLK_T_OUT;
    610     req.ioprio = 1;
    611     req.sector = 1;
    612     req.data = g_malloc0(512);
    613     strcpy(req.data, "TEST");
    614 
    615     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    616 
    617     g_free(req.data);
    618 
    619     /* Notify after processing the third request */
    620     qvirtqueue_set_used_event(qts, vq, 2);
    621     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    622     qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
    623     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    624     qvirtqueue_kick(qts, dev, vq, free_head);
    625     write_head = free_head;
    626 
    627     /* No notification expected */
    628     status = qvirtio_wait_status_byte_no_isr(qts, dev,
    629                                              vq, req_addr + 528,
    630                                              QVIRTIO_BLK_TIMEOUT_US);
    631     g_assert_cmpint(status, ==, 0);
    632 
    633     guest_free(t_alloc, req_addr);
    634 
    635     /* Read request */
    636     req.type = VIRTIO_BLK_T_IN;
    637     req.ioprio = 1;
    638     req.sector = 1;
    639     req.data = g_malloc0(512);
    640 
    641     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
    642 
    643     g_free(req.data);
    644 
    645     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
    646     qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
    647     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
    648 
    649     qvirtqueue_kick(qts, dev, vq, free_head);
    650 
    651     /* We get just one notification for both requests */
    652     qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
    653                            QVIRTIO_BLK_TIMEOUT_US);
    654     g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
    655     g_assert_cmpint(desc_idx, ==, free_head);
    656 
    657     status = readb(req_addr + 528);
    658     g_assert_cmpint(status, ==, 0);
    659 
    660     data = g_malloc0(512);
    661     qtest_memread(qts, req_addr + 16, data, 512);
    662     g_assert_cmpstr(data, ==, "TEST");
    663     g_free(data);
    664 
    665     guest_free(t_alloc, req_addr);
    666 
    667     /* End test */
    668     qpci_msix_disable(pdev->pdev);
    669 
    670     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
    671 }
    672 
    673 static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
    674 {
    675     QVirtioPCIDevice *dev1 = obj;
    676     QVirtioPCIDevice *dev;
    677     QTestState *qts = dev1->pdev->bus->qts;
    678 
    679     if (dev1->pdev->bus->not_hotpluggable) {
    680         g_test_skip("pci bus does not support hotplug");
    681         return;
    682     }
    683 
    684     /* plug secondary disk */
    685     qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
    686                          "{'addr': %s, 'chardev': 'char2'}",
    687                          stringify(PCI_SLOT_HP) ".0");
    688 
    689     dev = virtio_pci_new(dev1->pdev->bus,
    690                          &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
    691                                         });
    692     g_assert_nonnull(dev);
    693     g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
    694     qvirtio_pci_device_disable(dev);
    695     qos_object_destroy((QOSGraphObject *)dev);
    696 
    697     /* unplug secondary disk */
    698     qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
    699 }
    700 
    701 static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
    702 {
    703     QVirtioPCIDevice *pdev1 = obj;
    704     QVirtioDevice *dev1 = &pdev1->vdev;
    705     QVirtioPCIDevice *pdev8;
    706     QVirtioDevice *dev8;
    707     QTestState *qts = pdev1->pdev->bus->qts;
    708     uint64_t features;
    709     uint16_t num_queues;
    710 
    711     if (pdev1->pdev->bus->not_hotpluggable) {
    712         g_test_skip("bus pci.0 does not support hotplug");
    713         return;
    714     }
    715 
    716     /*
    717      * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
    718      * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
    719      * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (which
    720      * is also spec-compliant).
    721      */
    722     features = qvirtio_get_features(dev1);
    723     g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), ==, 0);
    724     features = features & ~(QVIRTIO_F_BAD_FEATURE |
    725                             (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    726                             (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
    727                             (1u << VIRTIO_BLK_F_SCSI));
    728     qvirtio_set_features(dev1, features);
    729 
    730     /* Hotplug a secondary device with 8 queues */
    731     qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
    732                          "{'addr': %s, 'chardev': 'char2', 'num-queues': 8}",
    733                          stringify(PCI_SLOT_HP) ".0");
    734 
    735     pdev8 = virtio_pci_new(pdev1->pdev->bus,
    736                            &(QPCIAddress) {
    737                                .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
    738                            });
    739     g_assert_nonnull(pdev8);
    740     g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK);
    741 
    742     qos_object_start_hw(&pdev8->obj);
    743 
    744     dev8 = &pdev8->vdev;
    745     features = qvirtio_get_features(dev8);
    746     g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ),
    747                     ==,
    748                     (1u << VIRTIO_BLK_F_MQ));
    749     features = features & ~(QVIRTIO_F_BAD_FEATURE |
    750                             (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    751                             (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
    752                             (1u << VIRTIO_BLK_F_SCSI) |
    753                             (1u << VIRTIO_BLK_F_MQ));
    754     qvirtio_set_features(dev8, features);
    755 
    756     num_queues = qvirtio_config_readw(dev8,
    757             offsetof(struct virtio_blk_config, num_queues));
    758     g_assert_cmpint(num_queues, ==, 8);
    759 
    760     qvirtio_pci_device_disable(pdev8);
    761     qos_object_destroy(&pdev8->obj);
    762 
    763     /* unplug secondary disk */
    764     qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
    765 }
    766 
    767 /*
    768  * Check that setting the vring addr on a non-existent virtqueue does
    769  * not crash.
    770  */
    771 static void test_nonexistent_virtqueue(void *obj, void *data,
    772                                        QGuestAllocator *t_alloc)
    773 {
    774     QVhostUserBlkPCI *blk = obj;
    775     QVirtioPCIDevice *pdev = &blk->pci_vdev;
    776     QPCIBar bar0;
    777     QPCIDevice *dev;
    778 
    779     dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
    780     g_assert(dev != NULL);
    781     qpci_device_enable(dev);
    782 
    783     bar0 = qpci_iomap(dev, 0, NULL);
    784 
    785     qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
    786     qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
    787 
    788     g_free(dev);
    789 }
    790 
    791 static const char *qtest_qemu_storage_daemon_binary(void)
    792 {
    793     const char *qemu_storage_daemon_bin;
    794 
    795     qemu_storage_daemon_bin = getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY");
    796     if (!qemu_storage_daemon_bin) {
    797         fprintf(stderr, "Environment variable "
    798                         "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n");
    799         exit(0);
    800     }
    801 
    802     /* If we've got a path to the binary, check whether we can access it */
    803     if (strchr(qemu_storage_daemon_bin, '/') &&
    804         access(qemu_storage_daemon_bin, X_OK) != 0) {
    805         fprintf(stderr, "ERROR: '%s' is not accessible\n",
    806                 qemu_storage_daemon_bin);
    807         exit(1);
    808     }
    809 
    810     return qemu_storage_daemon_bin;
    811 }
    812 
    813 /* g_test_queue_destroy() cleanup function for files */
    814 static void destroy_file(void *path)
    815 {
    816     unlink(path);
    817     g_free(path);
    818     qos_invalidate_command_line();
    819 }
    820 
    821 static char *drive_create(void)
    822 {
    823     int fd, ret;
    824     /** vhost-user-blk won't recognize drive located in /tmp */
    825     char *t_path = g_strdup("qtest.XXXXXX");
    826 
    827     /** Create a temporary raw image */
    828     fd = mkstemp(t_path);
    829     g_assert_cmpint(fd, >=, 0);
    830     ret = ftruncate(fd, TEST_IMAGE_SIZE);
    831     g_assert_cmpint(ret, ==, 0);
    832     close(fd);
    833 
    834     g_test_queue_destroy(destroy_file, t_path);
    835     return t_path;
    836 }
    837 
    838 static char *create_listen_socket(int *fd)
    839 {
    840     int tmp_fd;
    841     char *path;
    842 
    843     /* No race because our pid makes the path unique */
    844     path = g_strdup_printf("%s/qtest-%d-sock.XXXXXX",
    845                            g_get_tmp_dir(), getpid());
    846     tmp_fd = mkstemp(path);
    847     g_assert_cmpint(tmp_fd, >=, 0);
    848     close(tmp_fd);
    849     unlink(path);
    850 
    851     *fd = qtest_socket_server(path);
    852     g_test_queue_destroy(destroy_file, path);
    853     return path;
    854 }
    855 
    856 /*
    857  * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for
    858  * qemu-storage-daemon.
    859  */
    860 static void quit_storage_daemon(void *data)
    861 {
    862     QemuStorageDaemonState *qsd = data;
    863     int wstatus;
    864     pid_t pid;
    865 
    866     /*
    867      * If we were invoked as a g_test_queue_destroy() cleanup function we need
    868      * to remove the abrt handler to avoid being called again if the code below
    869      * aborts. Also, we must not leave the abrt handler installed after
    870      * cleanup.
    871      */
    872     qtest_remove_abrt_handler(data);
    873 
    874     /* Before quitting storage-daemon, quit qemu to avoid dubious messages */
    875     qtest_kill_qemu(global_qtest);
    876 
    877     kill(qsd->pid, SIGTERM);
    878     pid = waitpid(qsd->pid, &wstatus, 0);
    879     g_assert_cmpint(pid, ==, qsd->pid);
    880     if (!WIFEXITED(wstatus)) {
    881         fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n",
    882                 __func__);
    883         abort();
    884     }
    885     if (WEXITSTATUS(wstatus) != 0) {
    886         fprintf(stderr, "%s: expected qemu-storage-daemon to exit "
    887                 "successfully, got %d\n",
    888                 __func__, WEXITSTATUS(wstatus));
    889         abort();
    890     }
    891 
    892     g_free(data);
    893 }
    894 
    895 static void start_vhost_user_blk(GString *cmd_line, int vus_instances,
    896                                  int num_queues)
    897 {
    898     const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
    899     int i;
    900     gchar *img_path;
    901     GString *storage_daemon_command = g_string_new(NULL);
    902     QemuStorageDaemonState *qsd;
    903 
    904     g_string_append_printf(storage_daemon_command,
    905                            "exec %s ",
    906                            vhost_user_blk_bin);
    907 
    908     g_string_append_printf(cmd_line,
    909             " -object memory-backend-memfd,id=mem,size=256M,share=on "
    910             " -M memory-backend=mem -m 256M ");
    911 
    912     for (i = 0; i < vus_instances; i++) {
    913         int fd;
    914         char *sock_path = create_listen_socket(&fd);
    915 
    916         /* create image file */
    917         img_path = drive_create();
    918         g_string_append_printf(storage_daemon_command,
    919             "--blockdev driver=file,node-name=disk%d,filename=%s "
    920             "--export type=vhost-user-blk,id=disk%d,addr.type=fd,addr.str=%d,"
    921             "node-name=disk%i,writable=on,num-queues=%d ",
    922             i, img_path, i, fd, i, num_queues);
    923 
    924         g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
    925                                i + 1, sock_path);
    926     }
    927 
    928     g_test_message("starting vhost-user backend: %s",
    929                    storage_daemon_command->str);
    930     pid_t pid = fork();
    931     if (pid == 0) {
    932         /*
    933          * Close standard file descriptors so tap-driver.pl pipe detects when
    934          * our parent terminates.
    935          */
    936         close(0);
    937         close(1);
    938         open("/dev/null", O_RDONLY);
    939         open("/dev/null", O_WRONLY);
    940 
    941         execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL);
    942         exit(1);
    943     }
    944     g_string_free(storage_daemon_command, true);
    945 
    946     qsd = g_new(QemuStorageDaemonState, 1);
    947     qsd->pid = pid;
    948 
    949     /* Make sure qemu-storage-daemon is stopped */
    950     qtest_add_abrt_handler(quit_storage_daemon, qsd);
    951     g_test_queue_destroy(quit_storage_daemon, qsd);
    952 }
    953 
    954 static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
    955 {
    956     start_vhost_user_blk(cmd_line, 1, 1);
    957     return arg;
    958 }
    959 
    960 /*
    961  * Setup for hotplug.
    962  *
    963  * Since vhost-user server only serves one vhost-user client one time,
    964  * another exprot
    965  *
    966  */
    967 static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
    968 {
    969     /* "-chardev socket,id=char2" is used for pci_hotplug*/
    970     start_vhost_user_blk(cmd_line, 2, 1);
    971     return arg;
    972 }
    973 
    974 static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg)
    975 {
    976     start_vhost_user_blk(cmd_line, 2, 8);
    977     return arg;
    978 }
    979 
    980 static void register_vhost_user_blk_test(void)
    981 {
    982     QOSGraphTestOptions opts = {
    983         .before = vhost_user_blk_test_setup,
    984     };
    985 
    986     /*
    987      * tests for vhost-user-blk and vhost-user-blk-pci
    988      * The tests are borrowed from tests/virtio-blk-test.c. But some tests
    989      * regarding block_resize don't work for vhost-user-blk.
    990      * vhost-user-blk device doesn't have -drive, so tests containing
    991      * block_resize are also abandoned,
    992      *  - config
    993      *  - resize
    994      */
    995     qos_add_test("basic", "vhost-user-blk", basic, &opts);
    996     qos_add_test("indirect", "vhost-user-blk", indirect, &opts);
    997     qos_add_test("idx", "vhost-user-blk-pci", idx, &opts);
    998     qos_add_test("nxvirtq", "vhost-user-blk-pci",
    999                  test_nonexistent_virtqueue, &opts);
   1000 
   1001     opts.before = vhost_user_blk_hotplug_test_setup;
   1002     qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
   1003 
   1004     opts.before = vhost_user_blk_multiqueue_test_setup;
   1005     qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts);
   1006 }
   1007 
   1008 libqos_init(register_vhost_user_blk_test);