cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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


      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
     28typedef struct {
     29    pid_t pid;
     30} QemuStorageDaemonState;
     31
     32typedef 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#ifdef HOST_WORDS_BIGENDIAN
     41static const bool host_is_big_endian = true;
     42#else
     43static const bool host_is_big_endian; /* false */
     44#endif
     45
     46static 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
     55static 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
     65static 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
     97static 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 */
    216static 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
    447static 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
    457static 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
    542static 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
    673static 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    /* plug secondary disk */
    680    qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
    681                         "{'addr': %s, 'chardev': 'char2'}",
    682                         stringify(PCI_SLOT_HP) ".0");
    683
    684    dev = virtio_pci_new(dev1->pdev->bus,
    685                         &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
    686                                        });
    687    g_assert_nonnull(dev);
    688    g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
    689    qvirtio_pci_device_disable(dev);
    690    qos_object_destroy((QOSGraphObject *)dev);
    691
    692    /* unplug secondary disk */
    693    qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
    694}
    695
    696static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
    697{
    698    QVirtioPCIDevice *pdev1 = obj;
    699    QVirtioDevice *dev1 = &pdev1->vdev;
    700    QVirtioPCIDevice *pdev8;
    701    QVirtioDevice *dev8;
    702    QTestState *qts = pdev1->pdev->bus->qts;
    703    uint64_t features;
    704    uint16_t num_queues;
    705
    706    /*
    707     * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
    708     * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
    709     * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (which
    710     * is also spec-compliant).
    711     */
    712    features = qvirtio_get_features(dev1);
    713    g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), ==, 0);
    714    features = features & ~(QVIRTIO_F_BAD_FEATURE |
    715                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    716                            (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
    717                            (1u << VIRTIO_BLK_F_SCSI));
    718    qvirtio_set_features(dev1, features);
    719
    720    /* Hotplug a secondary device with 8 queues */
    721    qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
    722                         "{'addr': %s, 'chardev': 'char2', 'num-queues': 8}",
    723                         stringify(PCI_SLOT_HP) ".0");
    724
    725    pdev8 = virtio_pci_new(pdev1->pdev->bus,
    726                           &(QPCIAddress) {
    727                               .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
    728                           });
    729    g_assert_nonnull(pdev8);
    730    g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK);
    731
    732    qos_object_start_hw(&pdev8->obj);
    733
    734    dev8 = &pdev8->vdev;
    735    features = qvirtio_get_features(dev8);
    736    g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ),
    737                    ==,
    738                    (1u << VIRTIO_BLK_F_MQ));
    739    features = features & ~(QVIRTIO_F_BAD_FEATURE |
    740                            (1u << VIRTIO_RING_F_INDIRECT_DESC) |
    741                            (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
    742                            (1u << VIRTIO_BLK_F_SCSI) |
    743                            (1u << VIRTIO_BLK_F_MQ));
    744    qvirtio_set_features(dev8, features);
    745
    746    num_queues = qvirtio_config_readw(dev8,
    747            offsetof(struct virtio_blk_config, num_queues));
    748    g_assert_cmpint(num_queues, ==, 8);
    749
    750    qvirtio_pci_device_disable(pdev8);
    751    qos_object_destroy(&pdev8->obj);
    752
    753    /* unplug secondary disk */
    754    qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
    755}
    756
    757/*
    758 * Check that setting the vring addr on a non-existent virtqueue does
    759 * not crash.
    760 */
    761static void test_nonexistent_virtqueue(void *obj, void *data,
    762                                       QGuestAllocator *t_alloc)
    763{
    764    QVhostUserBlkPCI *blk = obj;
    765    QVirtioPCIDevice *pdev = &blk->pci_vdev;
    766    QPCIBar bar0;
    767    QPCIDevice *dev;
    768
    769    dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
    770    g_assert(dev != NULL);
    771    qpci_device_enable(dev);
    772
    773    bar0 = qpci_iomap(dev, 0, NULL);
    774
    775    qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
    776    qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
    777
    778    g_free(dev);
    779}
    780
    781static const char *qtest_qemu_storage_daemon_binary(void)
    782{
    783    const char *qemu_storage_daemon_bin;
    784
    785    qemu_storage_daemon_bin = getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY");
    786    if (!qemu_storage_daemon_bin) {
    787        fprintf(stderr, "Environment variable "
    788                        "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n");
    789        exit(0);
    790    }
    791
    792    /* If we've got a path to the binary, check whether we can access it */
    793    if (strchr(qemu_storage_daemon_bin, '/') &&
    794        access(qemu_storage_daemon_bin, X_OK) != 0) {
    795        fprintf(stderr, "ERROR: '%s' is not accessible\n",
    796                qemu_storage_daemon_bin);
    797        exit(1);
    798    }
    799
    800    return qemu_storage_daemon_bin;
    801}
    802
    803/* g_test_queue_destroy() cleanup function for files */
    804static void destroy_file(void *path)
    805{
    806    unlink(path);
    807    g_free(path);
    808    qos_invalidate_command_line();
    809}
    810
    811static char *drive_create(void)
    812{
    813    int fd, ret;
    814    /** vhost-user-blk won't recognize drive located in /tmp */
    815    char *t_path = g_strdup("qtest.XXXXXX");
    816
    817    /** Create a temporary raw image */
    818    fd = mkstemp(t_path);
    819    g_assert_cmpint(fd, >=, 0);
    820    ret = ftruncate(fd, TEST_IMAGE_SIZE);
    821    g_assert_cmpint(ret, ==, 0);
    822    close(fd);
    823
    824    g_test_queue_destroy(destroy_file, t_path);
    825    return t_path;
    826}
    827
    828static char *create_listen_socket(int *fd)
    829{
    830    int tmp_fd;
    831    char *path;
    832
    833    /* No race because our pid makes the path unique */
    834    path = g_strdup_printf("/tmp/qtest-%d-sock.XXXXXX", getpid());
    835    tmp_fd = mkstemp(path);
    836    g_assert_cmpint(tmp_fd, >=, 0);
    837    close(tmp_fd);
    838    unlink(path);
    839
    840    *fd = qtest_socket_server(path);
    841    g_test_queue_destroy(destroy_file, path);
    842    return path;
    843}
    844
    845/*
    846 * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for
    847 * qemu-storage-daemon.
    848 */
    849static void quit_storage_daemon(void *data)
    850{
    851    QemuStorageDaemonState *qsd = data;
    852    int wstatus;
    853    pid_t pid;
    854
    855    /*
    856     * If we were invoked as a g_test_queue_destroy() cleanup function we need
    857     * to remove the abrt handler to avoid being called again if the code below
    858     * aborts. Also, we must not leave the abrt handler installed after
    859     * cleanup.
    860     */
    861    qtest_remove_abrt_handler(data);
    862
    863    /* Before quitting storage-daemon, quit qemu to avoid dubious messages */
    864    qtest_kill_qemu(global_qtest);
    865
    866    kill(qsd->pid, SIGTERM);
    867    pid = waitpid(qsd->pid, &wstatus, 0);
    868    g_assert_cmpint(pid, ==, qsd->pid);
    869    if (!WIFEXITED(wstatus)) {
    870        fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n",
    871                __func__);
    872        abort();
    873    }
    874    if (WEXITSTATUS(wstatus) != 0) {
    875        fprintf(stderr, "%s: expected qemu-storage-daemon to exit "
    876                "successfully, got %d\n",
    877                __func__, WEXITSTATUS(wstatus));
    878        abort();
    879    }
    880
    881    g_free(data);
    882}
    883
    884static void start_vhost_user_blk(GString *cmd_line, int vus_instances,
    885                                 int num_queues)
    886{
    887    const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
    888    int i;
    889    gchar *img_path;
    890    GString *storage_daemon_command = g_string_new(NULL);
    891    QemuStorageDaemonState *qsd;
    892
    893    g_string_append_printf(storage_daemon_command,
    894                           "exec %s ",
    895                           vhost_user_blk_bin);
    896
    897    g_string_append_printf(cmd_line,
    898            " -object memory-backend-memfd,id=mem,size=256M,share=on "
    899            " -M memory-backend=mem -m 256M ");
    900
    901    for (i = 0; i < vus_instances; i++) {
    902        int fd;
    903        char *sock_path = create_listen_socket(&fd);
    904
    905        /* create image file */
    906        img_path = drive_create();
    907        g_string_append_printf(storage_daemon_command,
    908            "--blockdev driver=file,node-name=disk%d,filename=%s "
    909            "--export type=vhost-user-blk,id=disk%d,addr.type=unix,addr.path=%s,"
    910            "node-name=disk%i,writable=on,num-queues=%d ",
    911            i, img_path, i, sock_path, i, num_queues);
    912
    913        g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
    914                               i + 1, sock_path);
    915    }
    916
    917    g_test_message("starting vhost-user backend: %s",
    918                   storage_daemon_command->str);
    919    pid_t pid = fork();
    920    if (pid == 0) {
    921        /*
    922         * Close standard file descriptors so tap-driver.pl pipe detects when
    923         * our parent terminates.
    924         */
    925        close(0);
    926        close(1);
    927        open("/dev/null", O_RDONLY);
    928        open("/dev/null", O_WRONLY);
    929
    930        execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL);
    931        exit(1);
    932    }
    933    g_string_free(storage_daemon_command, true);
    934
    935    qsd = g_new(QemuStorageDaemonState, 1);
    936    qsd->pid = pid;
    937
    938    /* Make sure qemu-storage-daemon is stopped */
    939    qtest_add_abrt_handler(quit_storage_daemon, qsd);
    940    g_test_queue_destroy(quit_storage_daemon, qsd);
    941}
    942
    943static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
    944{
    945    start_vhost_user_blk(cmd_line, 1, 1);
    946    return arg;
    947}
    948
    949/*
    950 * Setup for hotplug.
    951 *
    952 * Since vhost-user server only serves one vhost-user client one time,
    953 * another exprot
    954 *
    955 */
    956static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
    957{
    958    /* "-chardev socket,id=char2" is used for pci_hotplug*/
    959    start_vhost_user_blk(cmd_line, 2, 1);
    960    return arg;
    961}
    962
    963static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg)
    964{
    965    start_vhost_user_blk(cmd_line, 2, 8);
    966    return arg;
    967}
    968
    969static void register_vhost_user_blk_test(void)
    970{
    971    QOSGraphTestOptions opts = {
    972        .before = vhost_user_blk_test_setup,
    973    };
    974
    975    /*
    976     * tests for vhost-user-blk and vhost-user-blk-pci
    977     * The tests are borrowed from tests/virtio-blk-test.c. But some tests
    978     * regarding block_resize don't work for vhost-user-blk.
    979     * vhost-user-blk device doesn't have -drive, so tests containing
    980     * block_resize are also abandoned,
    981     *  - config
    982     *  - resize
    983     */
    984    qos_add_test("basic", "vhost-user-blk", basic, &opts);
    985    qos_add_test("indirect", "vhost-user-blk", indirect, &opts);
    986    qos_add_test("idx", "vhost-user-blk-pci", idx, &opts);
    987    qos_add_test("nxvirtq", "vhost-user-blk-pci",
    988                 test_nonexistent_virtqueue, &opts);
    989
    990    opts.before = vhost_user_blk_hotplug_test_setup;
    991    qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
    992
    993    opts.before = vhost_user_blk_multiqueue_test_setup;
    994    qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts);
    995}
    996
    997libqos_init(register_vhost_user_blk_test);