diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c index d37e1c30bd..8796c74ca4 100644 --- a/tests/qtest/vhost-user-blk-test.c +++ b/tests/qtest/vhost-user-blk-test.c @@ -94,6 +94,124 @@ static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d, return addr; } +static void test_invalid_discard_write_zeroes(QVirtioDevice *dev, + QGuestAllocator *alloc, + QTestState *qts, + QVirtQueue *vq, + uint32_t type) +{ + QVirtioBlkReq req; + struct virtio_blk_discard_write_zeroes dwz_hdr; + struct virtio_blk_discard_write_zeroes dwz_hdr2[2]; + uint64_t req_addr; + uint32_t free_head; + uint8_t status; + + /* More than one dwz is not supported */ + req.type = type; + req.data = (char *) dwz_hdr2; + dwz_hdr2[0].sector = 0; + dwz_hdr2[0].num_sectors = 1; + dwz_hdr2[0].flags = 0; + dwz_hdr2[1].sector = 1; + dwz_hdr2[1].num_sectors = 1; + dwz_hdr2[1].flags = 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[0]); + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[1]); + + req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr2)); + + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr2), false, true); + qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr2), 1, true, + false); + + qvirtqueue_kick(qts, dev, vq, free_head); + + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status = readb(req_addr + 16 + sizeof(dwz_hdr2)); + g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP); + + guest_free(alloc, req_addr); + + /* num_sectors must be less than config->max_write_zeroes_sectors */ + req.type = type; + req.data = (char *) &dwz_hdr; + dwz_hdr.sector = 0; + dwz_hdr.num_sectors = 0xffffffff; + dwz_hdr.flags = 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true); + qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, + false); + + qvirtqueue_kick(qts, dev, vq, free_head); + + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status = readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR); + + guest_free(alloc, req_addr); + + /* sector must be less than the device capacity */ + req.type = type; + req.data = (char *) &dwz_hdr; + dwz_hdr.sector = TEST_IMAGE_SIZE / 512 + 1; + dwz_hdr.num_sectors = 1; + dwz_hdr.flags = 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true); + qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, + false); + + qvirtqueue_kick(qts, dev, vq, free_head); + + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status = readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR); + + guest_free(alloc, req_addr); + + /* reserved flag bits must be zero */ + req.type = type; + req.data = (char *) &dwz_hdr; + dwz_hdr.sector = 0; + dwz_hdr.num_sectors = 1; + dwz_hdr.flags = ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true); + qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, + false); + + qvirtqueue_kick(qts, dev, vq, free_head); + + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status = readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP); + + guest_free(alloc, req_addr); +} + /* Returns the request virtqueue so the caller can perform further tests */ static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc) { @@ -235,6 +353,9 @@ static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc) g_free(data); guest_free(alloc, req_addr); + + test_invalid_discard_write_zeroes(dev, alloc, qts, vq, + VIRTIO_BLK_T_WRITE_ZEROES); } if (features & (1u << VIRTIO_BLK_F_DISCARD)) { @@ -263,6 +384,9 @@ static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc) g_assert_cmpint(status, ==, 0); guest_free(alloc, req_addr); + + test_invalid_discard_write_zeroes(dev, alloc, qts, vq, + VIRTIO_BLK_T_DISCARD); } if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {