From nobody Mon May 6 15:32:18 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1616405220; cv=none; d=zohomail.com; s=zohoarc; b=f1TjLoxbr/KwqmIMUHyJ4d3I/1026Dq1FApwQSAAE6zyVeuPUb4cP0f4/6EV6fCW9QYAM1KSUFMB6UoOlXehFEnJQvw8a0eNoy2MjlKUJZy7oLos+NnHutZG2VZjPrQbNNdXkE+8FacKnvcg53KJrqTa2qxfVqTgjuqpLRN0cT8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1616405220; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=q7wzhKntCVWLNhu4ySL/uRAzqsYHHbT+VkCpL5MSgeI=; b=SPHBbzY0vNSsB7W4F6zb1EdaklHOvwYNcUvRAdn2gcA22RuFzYgOCzRaD9+9vusbrS+GksZBNAk3yx92RilVtx5ud8IKIHc7g8JsYWhd0LSTtSJ7cBt26o/CKBynloey6V14eV8wTCjr2V7WJta/G2/SlH+RcVMQoIsDYPxAt9M= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1616405220602150.92124170805982; Mon, 22 Mar 2021 02:27:00 -0700 (PDT) Received: from localhost ([::1]:44182 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lOGpv-00079j-As for importer@patchew.org; Mon, 22 Mar 2021 05:26:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45154) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lOGmt-0005c2-EG for qemu-devel@nongnu.org; Mon, 22 Mar 2021 05:23:51 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:23371) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lOGml-0000mm-QK for qemu-devel@nongnu.org; Mon, 22 Mar 2021 05:23:51 -0400 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-199-ZNG24sqnNOKTUVv3himJBw-1; Mon, 22 Mar 2021 05:23:39 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 562A71922961; Mon, 22 Mar 2021 09:23:38 +0000 (UTC) Received: from localhost (ovpn-114-89.ams2.redhat.com [10.36.114.89]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6B83C2B3B9; Mon, 22 Mar 2021 09:23:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616405022; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=q7wzhKntCVWLNhu4ySL/uRAzqsYHHbT+VkCpL5MSgeI=; b=VG0JOw8aa1Y5qpbxnGgMGy3bORPlDG8AnXxeOIcPAfFsV0CBj7Ch9YYnvBrHqA5syEdCbB 6FrrCS64mG6mgo4IWkYaJGCKDPNdlqL6VqNDELpmd16C7oEL4niL7XoEDa/nXay5QHv2Ry Ei3cITaYqBhbdMGo41x3v++EhOasFls= X-MC-Unique: ZNG24sqnNOKTUVv3himJBw-1 From: Stefan Hajnoczi To: qemu-devel@nongnu.org Subject: [PATCH 1/3] test: new qTest case to test the vhost-user-blk-server Date: Mon, 22 Mar 2021 09:23:25 +0000 Message-Id: <20210322092327.150720-2-stefanha@redhat.com> In-Reply-To: <20210322092327.150720-1-stefanha@redhat.com> References: <20210322092327.150720-1-stefanha@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=stefanha@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=216.205.24.124; envelope-from=stefanha@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Laurent Vivier , Thomas Huth , qemu-block@nongnu.org, Coiby Xu , Stefan Hajnoczi , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" From: Coiby Xu This test case has the same tests as tests/virtio-blk-test.c except for tests have block_resize. Since the vhost-user-blk export only serves one client one time, two exports are started by qemu-storage-daemon for the hotplug test. Suggested-by: Thomas Huth Signed-off-by: Coiby Xu Signed-off-by: Stefan Hajnoczi Message-Id: <20210309094106.196911-3-stefanha@redhat.com> Signed-off-by: Kevin Wolf --- MAINTAINERS | 2 + tests/qtest/libqos/vhost-user-blk.h | 48 ++ tests/qtest/libqos/vhost-user-blk.c | 130 +++++ tests/qtest/vhost-user-blk-test.c | 794 ++++++++++++++++++++++++++++ tests/qtest/libqos/meson.build | 1 + tests/qtest/meson.build | 4 + 6 files changed, 979 insertions(+) create mode 100644 tests/qtest/libqos/vhost-user-blk.h create mode 100644 tests/qtest/libqos/vhost-user-blk.c create mode 100644 tests/qtest/vhost-user-blk-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 25fc49d1dc..34cfe468f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3251,6 +3251,8 @@ F: block/export/vhost-user-blk-server.c F: block/export/vhost-user-blk-server.h F: include/qemu/vhost-user-server.h F: tests/qtest/libqos/vhost-user-blk.c +F: tests/qtest/libqos/vhost-user-blk.h +F: tests/qtest/vhost-user-blk-test.c F: util/vhost-user-server.c =20 FUSE block device exports diff --git a/tests/qtest/libqos/vhost-user-blk.h b/tests/qtest/libqos/vhost= -user-blk.h new file mode 100644 index 0000000000..2a03456a45 --- /dev/null +++ b/tests/qtest/libqos/vhost-user-blk.h @@ -0,0 +1,48 @@ +/* + * libqos driver framework + * + * Based on tests/qtest/libqos/virtio-blk.c + * + * Copyright (c) 2020 Coiby Xu + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#ifndef TESTS_LIBQOS_VHOST_USER_BLK_H +#define TESTS_LIBQOS_VHOST_USER_BLK_H + +#include "qgraph.h" +#include "virtio.h" +#include "virtio-pci.h" + +typedef struct QVhostUserBlk QVhostUserBlk; +typedef struct QVhostUserBlkPCI QVhostUserBlkPCI; +typedef struct QVhostUserBlkDevice QVhostUserBlkDevice; + +struct QVhostUserBlk { + QVirtioDevice *vdev; +}; + +struct QVhostUserBlkPCI { + QVirtioPCIDevice pci_vdev; + QVhostUserBlk blk; +}; + +struct QVhostUserBlkDevice { + QOSGraphObject obj; + QVhostUserBlk blk; +}; + +#endif diff --git a/tests/qtest/libqos/vhost-user-blk.c b/tests/qtest/libqos/vhost= -user-blk.c new file mode 100644 index 0000000000..568c3426ed --- /dev/null +++ b/tests/qtest/libqos/vhost-user-blk.c @@ -0,0 +1,130 @@ +/* + * libqos driver framework + * + * Based on tests/qtest/libqos/virtio-blk.c + * + * Copyright (c) 2020 Coiby Xu + * + * Copyright (c) 2018 Emanuele Giuseppe Esposito + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/module.h" +#include "standard-headers/linux/virtio_blk.h" +#include "vhost-user-blk.h" + +#define PCI_SLOT 0x04 +#define PCI_FN 0x00 + +/* virtio-blk-device */ +static void *qvhost_user_blk_get_driver(QVhostUserBlk *v_blk, + const char *interface) +{ + if (!g_strcmp0(interface, "vhost-user-blk")) { + return v_blk; + } + if (!g_strcmp0(interface, "virtio")) { + return v_blk->vdev; + } + + fprintf(stderr, "%s not present in vhost-user-blk-device\n", interface= ); + g_assert_not_reached(); +} + +static void *qvhost_user_blk_device_get_driver(void *object, + const char *interface) +{ + QVhostUserBlkDevice *v_blk =3D object; + return qvhost_user_blk_get_driver(&v_blk->blk, interface); +} + +static void *vhost_user_blk_device_create(void *virtio_dev, + QGuestAllocator *t_alloc, + void *addr) +{ + QVhostUserBlkDevice *vhost_user_blk =3D g_new0(QVhostUserBlkDevice, 1); + QVhostUserBlk *interface =3D &vhost_user_blk->blk; + + interface->vdev =3D virtio_dev; + + vhost_user_blk->obj.get_driver =3D qvhost_user_blk_device_get_driver; + + return &vhost_user_blk->obj; +} + +/* virtio-blk-pci */ +static void *qvhost_user_blk_pci_get_driver(void *object, const char *inte= rface) +{ + QVhostUserBlkPCI *v_blk =3D object; + if (!g_strcmp0(interface, "pci-device")) { + return v_blk->pci_vdev.pdev; + } + return qvhost_user_blk_get_driver(&v_blk->blk, interface); +} + +static void *vhost_user_blk_pci_create(void *pci_bus, QGuestAllocator *t_a= lloc, + void *addr) +{ + QVhostUserBlkPCI *vhost_user_blk =3D g_new0(QVhostUserBlkPCI, 1); + QVhostUserBlk *interface =3D &vhost_user_blk->blk; + QOSGraphObject *obj =3D &vhost_user_blk->pci_vdev.obj; + + virtio_pci_init(&vhost_user_blk->pci_vdev, pci_bus, addr); + interface->vdev =3D &vhost_user_blk->pci_vdev.vdev; + + g_assert_cmphex(interface->vdev->device_type, =3D=3D, VIRTIO_ID_BLOCK); + + obj->get_driver =3D qvhost_user_blk_pci_get_driver; + + return obj; +} + +static void vhost_user_blk_register_nodes(void) +{ + /* + * FIXME: every test using these two nodes needs to setup a + * -drive,id=3Ddrive0 otherwise QEMU is not going to start. + * Therefore, we do not include "produces" edge for virtio + * and pci-device yet. + */ + + char *arg =3D g_strdup_printf("id=3Ddrv0,chardev=3Dchar1,addr=3D%x.%x", + PCI_SLOT, PCI_FN); + + QPCIAddress addr =3D { + .devfn =3D QPCI_DEVFN(PCI_SLOT, PCI_FN), + }; + + QOSGraphEdgeOptions opts =3D { }; + + /* virtio-blk-device */ + /** opts.extra_device_opts =3D "drive=3Ddrive0"; */ + qos_node_create_driver("vhost-user-blk-device", + vhost_user_blk_device_create); + qos_node_consumes("vhost-user-blk-device", "virtio-bus", &opts); + qos_node_produces("vhost-user-blk-device", "vhost-user-blk"); + + /* virtio-blk-pci */ + opts.extra_device_opts =3D arg; + add_qpci_address(&opts, &addr); + qos_node_create_driver("vhost-user-blk-pci", vhost_user_blk_pci_create= ); + qos_node_consumes("vhost-user-blk-pci", "pci-bus", &opts); + qos_node_produces("vhost-user-blk-pci", "vhost-user-blk"); + + g_free(arg); +} + +libqos_init(vhost_user_blk_register_nodes); diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk= -test.c new file mode 100644 index 0000000000..3e79549899 --- /dev/null +++ b/tests/qtest/vhost-user-blk-test.c @@ -0,0 +1,794 @@ +/* + * QTest testcase for Vhost-user Block Device + * + * Based on tests/qtest//virtio-blk-test.c + + * Copyright (c) 2014 SUSE LINUX Products GmbH + * Copyright (c) 2014 Marc Mar=C3=AD + * Copyright (c) 2020 Coiby Xu + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest-single.h" +#include "qemu/bswap.h" +#include "qemu/module.h" +#include "standard-headers/linux/virtio_blk.h" +#include "standard-headers/linux/virtio_pci.h" +#include "libqos/qgraph.h" +#include "libqos/vhost-user-blk.h" +#include "libqos/libqos-pc.h" + +#define TEST_IMAGE_SIZE (64 * 1024 * 1024) +#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000) +#define PCI_SLOT_HP 0x06 + +typedef struct { + pid_t pid; +} QemuStorageDaemonState; + +typedef struct QVirtioBlkReq { + uint32_t type; + uint32_t ioprio; + uint64_t sector; + char *data; + uint8_t status; +} QVirtioBlkReq; + +#ifdef HOST_WORDS_BIGENDIAN +static const bool host_is_big_endian =3D true; +#else +static const bool host_is_big_endian; /* false */ +#endif + +static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq = *req) +{ + if (qvirtio_is_big_endian(d) !=3D host_is_big_endian) { + req->type =3D bswap32(req->type); + req->ioprio =3D bswap32(req->ioprio); + req->sector =3D bswap64(req->sector); + } +} + +static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d, + struct virtio_blk_discard_write_zeroes *dwz_hdr) +{ + if (qvirtio_is_big_endian(d) !=3D host_is_big_endian) { + dwz_hdr->sector =3D bswap64(dwz_hdr->sector); + dwz_hdr->num_sectors =3D bswap32(dwz_hdr->num_sectors); + dwz_hdr->flags =3D bswap32(dwz_hdr->flags); + } +} + +static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *= d, + QVirtioBlkReq *req, uint64_t data_size) +{ + uint64_t addr; + uint8_t status =3D 0xFF; + QTestState *qts =3D global_qtest; + + switch (req->type) { + case VIRTIO_BLK_T_IN: + case VIRTIO_BLK_T_OUT: + g_assert_cmpuint(data_size % 512, =3D=3D, 0); + break; + case VIRTIO_BLK_T_DISCARD: + case VIRTIO_BLK_T_WRITE_ZEROES: + g_assert_cmpuint(data_size % + sizeof(struct virtio_blk_discard_write_zeroes), = =3D=3D, 0); + break; + default: + g_assert_cmpuint(data_size, =3D=3D, 0); + } + + addr =3D guest_alloc(alloc, sizeof(*req) + data_size); + + virtio_blk_fix_request(d, req); + + qtest_memwrite(qts, addr, req, 16); + qtest_memwrite(qts, addr + 16, req->data, data_size); + qtest_memwrite(qts, addr + 16 + data_size, &status, sizeof(status)); + + return addr; +} + +/* Returns the request virtqueue so the caller can perform further tests */ +static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc) +{ + QVirtioBlkReq req; + uint64_t req_addr; + uint64_t capacity; + uint64_t features; + uint32_t free_head; + uint8_t status; + char *data; + QTestState *qts =3D global_qtest; + QVirtQueue *vq; + + features =3D qvirtio_get_features(dev); + features =3D features & ~(QVIRTIO_F_BAD_FEATURE | + (1u << VIRTIO_RING_F_INDIRECT_DESC) | + (1u << VIRTIO_RING_F_EVENT_IDX) | + (1u << VIRTIO_BLK_F_SCSI)); + qvirtio_set_features(dev, features); + + capacity =3D qvirtio_config_readq(dev, 0); + g_assert_cmpint(capacity, =3D=3D, TEST_IMAGE_SIZE / 512); + + vq =3D qvirtqueue_setup(dev, alloc, 0); + + qvirtio_set_driver_ok(dev); + + /* Write and read with 3 descriptor layout */ + /* Write request */ + req.type =3D VIRTIO_BLK_T_OUT; + req.ioprio =3D 1; + req.sector =3D 0; + req.data =3D g_malloc0(512); + strcpy(req.data, "TEST"); + + req_addr =3D virtio_blk_request(alloc, dev, &req, 512); + + g_free(req.data); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 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 =3D readb(req_addr + 528); + g_assert_cmpint(status, =3D=3D, 0); + + guest_free(alloc, req_addr); + + /* Read request */ + req.type =3D VIRTIO_BLK_T_IN; + req.ioprio =3D 1; + req.sector =3D 0; + req.data =3D g_malloc0(512); + + req_addr =3D virtio_blk_request(alloc, dev, &req, 512); + + g_free(req.data); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true); + qvirtqueue_add(qts, vq, req_addr + 528, 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 =3D readb(req_addr + 528); + g_assert_cmpint(status, =3D=3D, 0); + + data =3D g_malloc0(512); + qtest_memread(qts, req_addr + 16, data, 512); + g_assert_cmpstr(data, =3D=3D, "TEST"); + g_free(data); + + guest_free(alloc, req_addr); + + if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) { + struct virtio_blk_discard_write_zeroes dwz_hdr; + void *expected; + + /* + * WRITE_ZEROES request on the same sector of previous test where + * we wrote "TEST". + */ + req.type =3D VIRTIO_BLK_T_WRITE_ZEROES; + req.data =3D (char *) &dwz_hdr; + dwz_hdr.sector =3D 0; + dwz_hdr.num_sectors =3D 1; + dwz_hdr.flags =3D 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr =3D virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, tru= e); + 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 =3D readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, =3D=3D, 0); + + guest_free(alloc, req_addr); + + /* Read request to check if the sector contains all zeroes */ + req.type =3D VIRTIO_BLK_T_IN; + req.ioprio =3D 1; + req.sector =3D 0; + req.data =3D g_malloc0(512); + + req_addr =3D virtio_blk_request(alloc, dev, &req, 512); + + g_free(req.data); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true); + qvirtqueue_add(qts, vq, req_addr + 528, 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 =3D readb(req_addr + 528); + g_assert_cmpint(status, =3D=3D, 0); + + data =3D g_malloc(512); + expected =3D g_malloc0(512); + qtest_memread(qts, req_addr + 16, data, 512); + g_assert_cmpmem(data, 512, expected, 512); + g_free(expected); + g_free(data); + + guest_free(alloc, req_addr); + } + + if (features & (1u << VIRTIO_BLK_F_DISCARD)) { + struct virtio_blk_discard_write_zeroes dwz_hdr; + + req.type =3D VIRTIO_BLK_T_DISCARD; + req.data =3D (char *) &dwz_hdr; + dwz_hdr.sector =3D 0; + dwz_hdr.num_sectors =3D 1; + dwz_hdr.flags =3D 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr =3D virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, tru= e); + 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 =3D readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, =3D=3D, 0); + + guest_free(alloc, req_addr); + } + + if (features & (1u << VIRTIO_F_ANY_LAYOUT)) { + /* Write and read with 2 descriptor layout */ + /* Write request */ + req.type =3D VIRTIO_BLK_T_OUT; + req.ioprio =3D 1; + req.sector =3D 1; + req.data =3D g_malloc0(512); + strcpy(req.data, "TEST"); + + req_addr =3D virtio_blk_request(alloc, dev, &req, 512); + + g_free(req.data); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 528, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 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 =3D readb(req_addr + 528); + g_assert_cmpint(status, =3D=3D, 0); + + guest_free(alloc, req_addr); + + /* Read request */ + req.type =3D VIRTIO_BLK_T_IN; + req.ioprio =3D 1; + req.sector =3D 1; + req.data =3D g_malloc0(512); + + req_addr =3D virtio_blk_request(alloc, dev, &req, 512); + + g_free(req.data); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false); + + qvirtqueue_kick(qts, dev, vq, free_head); + + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status =3D readb(req_addr + 528); + g_assert_cmpint(status, =3D=3D, 0); + + data =3D g_malloc0(512); + qtest_memread(qts, req_addr + 16, data, 512); + g_assert_cmpstr(data, =3D=3D, "TEST"); + g_free(data); + + guest_free(alloc, req_addr); + } + + return vq; +} + +static void basic(void *obj, void *data, QGuestAllocator *t_alloc) +{ + QVhostUserBlk *blk_if =3D obj; + QVirtQueue *vq; + + vq =3D test_basic(blk_if->vdev, t_alloc); + qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc); + +} + +static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc) +{ + QVirtQueue *vq; + QVhostUserBlk *blk_if =3D obj; + QVirtioDevice *dev =3D blk_if->vdev; + QVirtioBlkReq req; + QVRingIndirectDesc *indirect; + uint64_t req_addr; + uint64_t capacity; + uint64_t features; + uint32_t free_head; + uint8_t status; + char *data; + QTestState *qts =3D global_qtest; + + features =3D qvirtio_get_features(dev); + g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=3D, = 0); + features =3D features & ~(QVIRTIO_F_BAD_FEATURE | + (1u << VIRTIO_RING_F_EVENT_IDX) | + (1u << VIRTIO_BLK_F_SCSI)); + qvirtio_set_features(dev, features); + + capacity =3D qvirtio_config_readq(dev, 0); + g_assert_cmpint(capacity, =3D=3D, TEST_IMAGE_SIZE / 512); + + vq =3D qvirtqueue_setup(dev, t_alloc, 0); + qvirtio_set_driver_ok(dev); + + /* Write request */ + req.type =3D VIRTIO_BLK_T_OUT; + req.ioprio =3D 1; + req.sector =3D 0; + req.data =3D g_malloc0(512); + strcpy(req.data, "TEST"); + + req_addr =3D virtio_blk_request(t_alloc, dev, &req, 512); + + g_free(req.data); + + indirect =3D qvring_indirect_desc_setup(qts, dev, t_alloc, 2); + qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false); + qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true); + free_head =3D qvirtqueue_add_indirect(qts, vq, indirect); + qvirtqueue_kick(qts, dev, vq, free_head); + + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status =3D readb(req_addr + 528); + g_assert_cmpint(status, =3D=3D, 0); + + g_free(indirect); + guest_free(t_alloc, req_addr); + + /* Read request */ + req.type =3D VIRTIO_BLK_T_IN; + req.ioprio =3D 1; + req.sector =3D 0; + req.data =3D g_malloc0(512); + strcpy(req.data, "TEST"); + + req_addr =3D virtio_blk_request(t_alloc, dev, &req, 512); + + g_free(req.data); + + indirect =3D qvring_indirect_desc_setup(qts, dev, t_alloc, 2); + qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false); + qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true); + free_head =3D qvirtqueue_add_indirect(qts, vq, indirect); + qvirtqueue_kick(qts, dev, vq, free_head); + + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + status =3D readb(req_addr + 528); + g_assert_cmpint(status, =3D=3D, 0); + + data =3D g_malloc0(512); + qtest_memread(qts, req_addr + 16, data, 512); + g_assert_cmpstr(data, =3D=3D, "TEST"); + g_free(data); + + g_free(indirect); + guest_free(t_alloc, req_addr); + qvirtqueue_cleanup(dev->bus, vq, t_alloc); +} + +static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc) +{ + QVirtQueue *vq; + QVhostUserBlkPCI *blk =3D obj; + QVirtioPCIDevice *pdev =3D &blk->pci_vdev; + QVirtioDevice *dev =3D &pdev->vdev; + QVirtioBlkReq req; + uint64_t req_addr; + uint64_t capacity; + uint64_t features; + uint32_t free_head; + uint32_t write_head; + uint32_t desc_idx; + uint8_t status; + char *data; + QOSGraphObject *blk_object =3D obj; + QPCIDevice *pci_dev =3D blk_object->get_driver(blk_object, "pci-device= "); + QTestState *qts =3D global_qtest; + + if (qpci_check_buggy_msi(pci_dev)) { + return; + } + + qpci_msix_enable(pdev->pdev); + qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0); + + features =3D qvirtio_get_features(dev); + features =3D features & ~(QVIRTIO_F_BAD_FEATURE | + (1u << VIRTIO_RING_F_INDIRECT_DESC) | + (1u << VIRTIO_F_NOTIFY_ON_EMPTY) | + (1u << VIRTIO_BLK_F_SCSI)); + qvirtio_set_features(dev, features); + + capacity =3D qvirtio_config_readq(dev, 0); + g_assert_cmpint(capacity, =3D=3D, TEST_IMAGE_SIZE / 512); + + vq =3D qvirtqueue_setup(dev, t_alloc, 0); + qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1); + + qvirtio_set_driver_ok(dev); + + /* + * libvhost-user signals the call fd in VHOST_USER_SET_VRING_CALL, make + * sure to wait for the isr here so we don't race and confuse it later= on. + */ + qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US); + + /* Write request */ + req.type =3D VIRTIO_BLK_T_OUT; + req.ioprio =3D 1; + req.sector =3D 0; + req.data =3D g_malloc0(512); + strcpy(req.data, "TEST"); + + req_addr =3D virtio_blk_request(t_alloc, dev, &req, 512); + + g_free(req.data); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); + qvirtqueue_kick(qts, dev, vq, free_head); + + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + + /* Write request */ + req.type =3D VIRTIO_BLK_T_OUT; + req.ioprio =3D 1; + req.sector =3D 1; + req.data =3D g_malloc0(512); + strcpy(req.data, "TEST"); + + req_addr =3D virtio_blk_request(t_alloc, dev, &req, 512); + + g_free(req.data); + + /* Notify after processing the third request */ + qvirtqueue_set_used_event(qts, vq, 2); + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); + qvirtqueue_kick(qts, dev, vq, free_head); + write_head =3D free_head; + + /* No notification expected */ + status =3D qvirtio_wait_status_byte_no_isr(qts, dev, + vq, req_addr + 528, + QVIRTIO_BLK_TIMEOUT_US); + g_assert_cmpint(status, =3D=3D, 0); + + guest_free(t_alloc, req_addr); + + /* Read request */ + req.type =3D VIRTIO_BLK_T_IN; + req.ioprio =3D 1; + req.sector =3D 1; + req.data =3D g_malloc0(512); + + req_addr =3D virtio_blk_request(t_alloc, dev, &req, 512); + + g_free(req.data); + + free_head =3D qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); + + qvirtqueue_kick(qts, dev, vq, free_head); + + /* We get just one notification for both requests */ + qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); + g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL)); + g_assert_cmpint(desc_idx, =3D=3D, free_head); + + status =3D readb(req_addr + 528); + g_assert_cmpint(status, =3D=3D, 0); + + data =3D g_malloc0(512); + qtest_memread(qts, req_addr + 16, data, 512); + g_assert_cmpstr(data, =3D=3D, "TEST"); + g_free(data); + + guest_free(t_alloc, req_addr); + + /* End test */ + qpci_msix_disable(pdev->pdev); + + qvirtqueue_cleanup(dev->bus, vq, t_alloc); +} + +static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc) +{ + QVirtioPCIDevice *dev1 =3D obj; + QVirtioPCIDevice *dev; + QTestState *qts =3D dev1->pdev->bus->qts; + + /* plug secondary disk */ + qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1", + "{'addr': %s, 'chardev': 'char2'}", + stringify(PCI_SLOT_HP) ".0"); + + dev =3D virtio_pci_new(dev1->pdev->bus, + &(QPCIAddress) { .devfn =3D QPCI_DEVFN(PCI_SLOT_H= P, 0) + }); + g_assert_nonnull(dev); + g_assert_cmpint(dev->vdev.device_type, =3D=3D, VIRTIO_ID_BLOCK); + qvirtio_pci_device_disable(dev); + qos_object_destroy((QOSGraphObject *)dev); + + /* unplug secondary disk */ + qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP); +} + +/* + * Check that setting the vring addr on a non-existent virtqueue does + * not crash. + */ +static void test_nonexistent_virtqueue(void *obj, void *data, + QGuestAllocator *t_alloc) +{ + QVhostUserBlkPCI *blk =3D obj; + QVirtioPCIDevice *pdev =3D &blk->pci_vdev; + QPCIBar bar0; + QPCIDevice *dev; + + dev =3D qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0)); + g_assert(dev !=3D NULL); + qpci_device_enable(dev); + + bar0 =3D qpci_iomap(dev, 0, NULL); + + qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2); + qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1); + + g_free(dev); +} + +static const char *qtest_qemu_storage_daemon_binary(void) +{ + const char *qemu_storage_daemon_bin; + + qemu_storage_daemon_bin =3D getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY"); + if (!qemu_storage_daemon_bin) { + fprintf(stderr, "Environment variable " + "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n"); + exit(0); + } + + return qemu_storage_daemon_bin; +} + +/* g_test_queue_destroy() cleanup function for files */ +static void destroy_file(void *path) +{ + unlink(path); + g_free(path); + qos_invalidate_command_line(); +} + +static char *drive_create(void) +{ + int fd, ret; + /** vhost-user-blk won't recognize drive located in /tmp */ + char *t_path =3D g_strdup("qtest.XXXXXX"); + + /** Create a temporary raw image */ + fd =3D mkstemp(t_path); + g_assert_cmpint(fd, >=3D, 0); + ret =3D ftruncate(fd, TEST_IMAGE_SIZE); + g_assert_cmpint(ret, =3D=3D, 0); + close(fd); + + g_test_queue_destroy(destroy_file, t_path); + return t_path; +} + +static char *create_listen_socket(int *fd) +{ + int tmp_fd; + char *path; + + /* No race because our pid makes the path unique */ + path =3D g_strdup_printf("/tmp/qtest-%d-sock.XXXXXX", getpid()); + tmp_fd =3D mkstemp(path); + g_assert_cmpint(tmp_fd, >=3D, 0); + close(tmp_fd); + unlink(path); + + *fd =3D qtest_socket_server(path); + g_test_queue_destroy(destroy_file, path); + return path; +} + +/* + * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for + * qemu-storage-daemon. + */ +static void quit_storage_daemon(void *data) +{ + QemuStorageDaemonState *qsd =3D data; + int wstatus; + pid_t pid; + + /* + * If we were invoked as a g_test_queue_destroy() cleanup function we = need + * to remove the abrt handler to avoid being called again if the code = below + * aborts. Also, we must not leave the abrt handler installed after + * cleanup. + */ + qtest_remove_abrt_handler(data); + + /* Before quitting storage-daemon, quit qemu to avoid dubious messages= */ + qtest_kill_qemu(global_qtest); + + kill(qsd->pid, SIGTERM); + pid =3D waitpid(qsd->pid, &wstatus, 0); + g_assert_cmpint(pid, =3D=3D, qsd->pid); + if (!WIFEXITED(wstatus)) { + fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n", + __func__); + abort(); + } + if (WEXITSTATUS(wstatus) !=3D 0) { + fprintf(stderr, "%s: expected qemu-storage-daemon to exit " + "successfully, got %d\n", + __func__, WEXITSTATUS(wstatus)); + abort(); + } + + g_free(data); +} + +static void start_vhost_user_blk(GString *cmd_line, int vus_instances) +{ + const char *vhost_user_blk_bin =3D qtest_qemu_storage_daemon_binary(); + int i; + gchar *img_path; + GString *storage_daemon_command =3D g_string_new(NULL); + QemuStorageDaemonState *qsd; + + g_string_append_printf(storage_daemon_command, + "exec %s ", + vhost_user_blk_bin); + + g_string_append_printf(cmd_line, + " -object memory-backend-memfd,id=3Dmem,size=3D256M,share=3Don= " + " -M memory-backend=3Dmem -m 256M "); + + for (i =3D 0; i < vus_instances; i++) { + int fd; + char *sock_path =3D create_listen_socket(&fd); + + /* create image file */ + img_path =3D drive_create(); + g_string_append_printf(storage_daemon_command, + "--blockdev driver=3Dfile,node-name=3Ddisk%d,filename=3D%s " + "--export type=3Dvhost-user-blk,id=3Ddisk%d,addr.type=3Dunix,a= ddr.path=3D%s," + "node-name=3Ddisk%i,writable=3Don ", + i, img_path, i, sock_path, i); + + g_string_append_printf(cmd_line, "-chardev socket,id=3Dchar%d,path= =3D%s ", + i + 1, sock_path); + } + + g_test_message("starting vhost-user backend: %s", + storage_daemon_command->str); + pid_t pid =3D fork(); + if (pid =3D=3D 0) { + /* + * Close standard file descriptors so tap-driver.pl pipe detects w= hen + * our parent terminates. + */ + close(0); + close(1); + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + + execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL); + exit(1); + } + g_string_free(storage_daemon_command, true); + + qsd =3D g_new(QemuStorageDaemonState, 1); + qsd->pid =3D pid; + + /* Make sure qemu-storage-daemon is stopped */ + qtest_add_abrt_handler(quit_storage_daemon, qsd); + g_test_queue_destroy(quit_storage_daemon, qsd); +} + +static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg) +{ + start_vhost_user_blk(cmd_line, 1); + return arg; +} + +/* + * Setup for hotplug. + * + * Since vhost-user server only serves one vhost-user client one time, + * another exprot + * + */ +static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *ar= g) +{ + /* "-chardev socket,id=3Dchar2" is used for pci_hotplug*/ + start_vhost_user_blk(cmd_line, 2); + return arg; +} + +static void register_vhost_user_blk_test(void) +{ + QOSGraphTestOptions opts =3D { + .before =3D vhost_user_blk_test_setup, + }; + + /* + * tests for vhost-user-blk and vhost-user-blk-pci + * The tests are borrowed from tests/virtio-blk-test.c. But some tests + * regarding block_resize don't work for vhost-user-blk. + * vhost-user-blk device doesn't have -drive, so tests containing + * block_resize are also abandoned, + * - config + * - resize + */ + qos_add_test("basic", "vhost-user-blk", basic, &opts); + qos_add_test("indirect", "vhost-user-blk", indirect, &opts); + qos_add_test("idx", "vhost-user-blk-pci", idx, &opts); + qos_add_test("nxvirtq", "vhost-user-blk-pci", + test_nonexistent_virtqueue, &opts); + + opts.before =3D vhost_user_blk_hotplug_test_setup; + qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts); +} + +libqos_init(register_vhost_user_blk_test); diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build index 1cddf5bdaa..1f5c8f1053 100644 --- a/tests/qtest/libqos/meson.build +++ b/tests/qtest/libqos/meson.build @@ -32,6 +32,7 @@ libqos_srcs =3D files('../libqtest.c', 'virtio-9p.c', 'virtio-balloon.c', 'virtio-blk.c', + 'vhost-user-blk.c', 'virtio-mmio.c', 'virtio-net.c', 'virtio-pci.c', diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 9731606c31..190399d7b6 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -231,6 +231,9 @@ if have_virtfs qos_test_ss.add(files('virtio-9p-test.c')) endif qos_test_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-test= .c')) +if have_vhost_user_blk_server + qos_test_ss.add(files('vhost-user-blk-test.c')) +endif =20 tpmemu_files =3D ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c'] =20 @@ -269,6 +272,7 @@ foreach dir : target_dirs endif qtest_env.set('G_TEST_DBUS_DAEMON', meson.source_root() / 'tests/dbus-vm= state-daemon.sh') qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base) + qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu= -storage-daemon') =20 foreach test : target_qtests # Executables are shared across targets, declare them only the first t= ime we --=20 2.30.2 From nobody Mon May 6 15:32:18 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1616405344; cv=none; d=zohomail.com; s=zohoarc; b=GgtfPMUzotBPsrrmxeQ+WiIVB3Fza3oCPC3k6TJQJOAGzHY3B7d0WB2Qut/ixi+exVQvH2iI7ccAghbG5hCPtRd0RUPMYCiQ3s9Y7NxMJ9pvgDqbB1ldeTAr2Vt/FKtqbzVNknk4FljfSngmg5fpIAA4uZHPrzPcjHLb+VuMX8U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1616405344; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=zdVuEiON+AbjZM5/mW41muWKS3kjJOiw2Dx01d+t+Ls=; b=dyyH3yw63rgRbEPpQZV/L4rhkLuXmjQAiG+OLTKdObojkowdK2FAM7HFq4ICubtlU++C92Kyb4zJ6Q30yYImDn/1w6SeXmNedysZeO+y+B0TIw+Jnx6xialcgZZTvRFpfMhjKnlTv8b4LQiEmQQsYx42y48vTRBK9qkNXDmey+M= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1616405344219777.3678455892422; Mon, 22 Mar 2021 02:29:04 -0700 (PDT) Received: from localhost ([::1]:50066 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lOGrv-0001Cm-7g for importer@patchew.org; Mon, 22 Mar 2021 05:29:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45196) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lOGmv-0005e2-3r for qemu-devel@nongnu.org; Mon, 22 Mar 2021 05:23:53 -0400 Received: from us-smtp-delivery-124.mimecast.com ([63.128.21.124]:20634) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lOGmt-0000px-0P for qemu-devel@nongnu.org; Mon, 22 Mar 2021 05:23:52 -0400 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-424-4l9mF9SlPYG6H3GPR9JGAA-1; Mon, 22 Mar 2021 05:23:45 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 773B31922965; Mon, 22 Mar 2021 09:23:44 +0000 (UTC) Received: from localhost (ovpn-114-89.ams2.redhat.com [10.36.114.89]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9B9F32CE8A; Mon, 22 Mar 2021 09:23:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616405027; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zdVuEiON+AbjZM5/mW41muWKS3kjJOiw2Dx01d+t+Ls=; b=EA5oIFbTd0pR6EY/MVIbTOvqHxIhoINIJINUSqHLwow7eyl7PhtFNej/6qA094U0RKBc7U +YbY+IJKbATJKXiTryDVG8VceA0R4TFXZI/gm2CpoOCkUgsVta7jC66Id6Mh+/VyguSYc4 Ngwczxr4xXY/lvljM5XGJN2oAVcdn5c= X-MC-Unique: 4l9mF9SlPYG6H3GPR9JGAA-1 From: Stefan Hajnoczi To: qemu-devel@nongnu.org Subject: [PATCH 2/3] tests/qtest: add multi-queue test case to vhost-user-blk-test Date: Mon, 22 Mar 2021 09:23:26 +0000 Message-Id: <20210322092327.150720-3-stefanha@redhat.com> In-Reply-To: <20210322092327.150720-1-stefanha@redhat.com> References: <20210322092327.150720-1-stefanha@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=stefanha@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=63.128.21.124; envelope-from=stefanha@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, MIME_BASE64_TEXT=1.741, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Laurent Vivier , Thomas Huth , qemu-block@nongnu.org, Coiby Xu , Stefan Hajnoczi , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Signed-off-by: Stefan Hajnoczi Message-Id: <20210309094106.196911-4-stefanha@redhat.com> Signed-off-by: Kevin Wolf --- tests/qtest/vhost-user-blk-test.c | 81 +++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk= -test.c index 3e79549899..d37e1c30bd 100644 --- a/tests/qtest/vhost-user-blk-test.c +++ b/tests/qtest/vhost-user-blk-test.c @@ -569,6 +569,67 @@ static void pci_hotplug(void *obj, void *data, QGuestA= llocator *t_alloc) qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP); } =20 +static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc) +{ + QVirtioPCIDevice *pdev1 =3D obj; + QVirtioDevice *dev1 =3D &pdev1->vdev; + QVirtioPCIDevice *pdev8; + QVirtioDevice *dev8; + QTestState *qts =3D pdev1->pdev->bus->qts; + uint64_t features; + uint16_t num_queues; + + /* + * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. = The + * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when ther= e is + * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (= which + * is also spec-compliant). + */ + features =3D qvirtio_get_features(dev1); + g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), =3D=3D, 0); + features =3D features & ~(QVIRTIO_F_BAD_FEATURE | + (1u << VIRTIO_RING_F_INDIRECT_DESC) | + (1u << VIRTIO_F_NOTIFY_ON_EMPTY) | + (1u << VIRTIO_BLK_F_SCSI)); + qvirtio_set_features(dev1, features); + + /* Hotplug a secondary device with 8 queues */ + qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1", + "{'addr': %s, 'chardev': 'char2', 'num-queues': 8= }", + stringify(PCI_SLOT_HP) ".0"); + + pdev8 =3D virtio_pci_new(pdev1->pdev->bus, + &(QPCIAddress) { + .devfn =3D QPCI_DEVFN(PCI_SLOT_HP, 0) + }); + g_assert_nonnull(pdev8); + g_assert_cmpint(pdev8->vdev.device_type, =3D=3D, VIRTIO_ID_BLOCK); + + qos_object_start_hw(&pdev8->obj); + + dev8 =3D &pdev8->vdev; + features =3D qvirtio_get_features(dev8); + g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), + =3D=3D, + (1u << VIRTIO_BLK_F_MQ)); + features =3D features & ~(QVIRTIO_F_BAD_FEATURE | + (1u << VIRTIO_RING_F_INDIRECT_DESC) | + (1u << VIRTIO_F_NOTIFY_ON_EMPTY) | + (1u << VIRTIO_BLK_F_SCSI) | + (1u << VIRTIO_BLK_F_MQ)); + qvirtio_set_features(dev8, features); + + num_queues =3D qvirtio_config_readw(dev8, + offsetof(struct virtio_blk_config, num_queues)); + g_assert_cmpint(num_queues, =3D=3D, 8); + + qvirtio_pci_device_disable(pdev8); + qos_object_destroy(&pdev8->obj); + + /* unplug secondary disk */ + qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP); +} + /* * Check that setting the vring addr on a non-existent virtqueue does * not crash. @@ -688,7 +749,8 @@ static void quit_storage_daemon(void *data) g_free(data); } =20 -static void start_vhost_user_blk(GString *cmd_line, int vus_instances) +static void start_vhost_user_blk(GString *cmd_line, int vus_instances, + int num_queues) { const char *vhost_user_blk_bin =3D qtest_qemu_storage_daemon_binary(); int i; @@ -713,8 +775,8 @@ static void start_vhost_user_blk(GString *cmd_line, int= vus_instances) g_string_append_printf(storage_daemon_command, "--blockdev driver=3Dfile,node-name=3Ddisk%d,filename=3D%s " "--export type=3Dvhost-user-blk,id=3Ddisk%d,addr.type=3Dunix,a= ddr.path=3D%s," - "node-name=3Ddisk%i,writable=3Don ", - i, img_path, i, sock_path, i); + "node-name=3Ddisk%i,writable=3Don,num-queues=3D%d ", + i, img_path, i, sock_path, i, num_queues); =20 g_string_append_printf(cmd_line, "-chardev socket,id=3Dchar%d,path= =3D%s ", i + 1, sock_path); @@ -748,7 +810,7 @@ static void start_vhost_user_blk(GString *cmd_line, int= vus_instances) =20 static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg) { - start_vhost_user_blk(cmd_line, 1); + start_vhost_user_blk(cmd_line, 1, 1); return arg; } =20 @@ -762,7 +824,13 @@ static void *vhost_user_blk_test_setup(GString *cmd_li= ne, void *arg) static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *ar= g) { /* "-chardev socket,id=3Dchar2" is used for pci_hotplug*/ - start_vhost_user_blk(cmd_line, 2); + start_vhost_user_blk(cmd_line, 2, 1); + return arg; +} + +static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void = *arg) +{ + start_vhost_user_blk(cmd_line, 2, 8); return arg; } =20 @@ -789,6 +857,9 @@ static void register_vhost_user_blk_test(void) =20 opts.before =3D vhost_user_blk_hotplug_test_setup; qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts); + + opts.before =3D vhost_user_blk_multiqueue_test_setup; + qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts); } =20 libqos_init(register_vhost_user_blk_test); --=20 2.30.2 From nobody Mon May 6 15:32:18 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1616405516; cv=none; d=zohomail.com; s=zohoarc; b=kQLCfwnlqt/RaiTHX4hKqCnSCyu2wvGAkDGbIRUVlvEZA8RUCItpqEJB9Wsqk+MP3Ulhj2nPcIgIe7nUOGO8s742uMPgeS7UBY5eWyPiKsg8dIaH1lzMIqLXAtdzwR/yslLIMykidfVUg+/ifLyMQYXBdOfZCCUINWwmhpnGm5M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1616405516; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=ZDli/BBWRjbNgJ/c0MN/kHbemMqZeCXtJfEDZQ/s0yE=; b=mkiuwtk5L1bZu1iSWi0HIErVBBg8xhh1WAPDB1udCx1st6mdbRV+uJbMGZqm71rAbtT2eS66f4M3RGsMm9kbNCkJI9qaZPoO7OQjzm4Nn0WbYX4Z0P8JqJ6JrXTN3kaQ6wX7cx0mgVnsBGD3zf+OwDriotjZaKxsNih+NOH9hfU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1616405516624402.6362080291061; Mon, 22 Mar 2021 02:31:56 -0700 (PDT) Received: from localhost ([::1]:53002 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lOGug-0002Ws-PA for importer@patchew.org; Mon, 22 Mar 2021 05:31:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45208) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lOGmv-0005fO-Rb for qemu-devel@nongnu.org; Mon, 22 Mar 2021 05:23:53 -0400 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:58255) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1lOGmt-0000qF-05 for qemu-devel@nongnu.org; Mon, 22 Mar 2021 05:23:53 -0400 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-537-cqispat6P-SQA66yzMBlsA-1; Mon, 22 Mar 2021 05:23:47 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4431280006E; Mon, 22 Mar 2021 09:23:46 +0000 (UTC) Received: from localhost (ovpn-114-89.ams2.redhat.com [10.36.114.89]) by smtp.corp.redhat.com (Postfix) with ESMTP id B6F8921ECB; Mon, 22 Mar 2021 09:23:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1616405029; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZDli/BBWRjbNgJ/c0MN/kHbemMqZeCXtJfEDZQ/s0yE=; b=PUOAz68YaDFgJAP8HDbwO3PNGnwX7OqmYkuNXT/Xs3qKa6674awtT9mhDXazBWRqfM74Uh 5rs1YI6fhObbqc2AQ/uXu+zWuVCN8zsyT6+EoLD08gf1QGlR5SHj42rpJHhE5H6m4C8jlD NH+qOzt1/pKa8x99U1LNLR6H8Kq1gpo= X-MC-Unique: cqispat6P-SQA66yzMBlsA-1 From: Stefan Hajnoczi To: qemu-devel@nongnu.org Subject: [PATCH 3/3] vhost-user-blk-test: test discard/write zeroes invalid inputs Date: Mon, 22 Mar 2021 09:23:27 +0000 Message-Id: <20210322092327.150720-4-stefanha@redhat.com> In-Reply-To: <20210322092327.150720-1-stefanha@redhat.com> References: <20210322092327.150720-1-stefanha@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=stefanha@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=216.205.24.124; envelope-from=stefanha@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, MIME_BASE64_TEXT=1.741, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Laurent Vivier , Thomas Huth , qemu-block@nongnu.org, Coiby Xu , Stefan Hajnoczi , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Exercise input validation code paths in block/export/vhost-user-blk-server.c. Signed-off-by: Stefan Hajnoczi Message-Id: <20210309094106.196911-5-stefanha@redhat.com> Signed-off-by: Kevin Wolf --- tests/qtest/vhost-user-blk-test.c | 124 ++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) 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 *all= oc, QVirtioDevice *d, return addr; } =20 +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 =3D type; + req.data =3D (char *) dwz_hdr2; + dwz_hdr2[0].sector =3D 0; + dwz_hdr2[0].num_sectors =3D 1; + dwz_hdr2[0].flags =3D 0; + dwz_hdr2[1].sector =3D 1; + dwz_hdr2[1].num_sectors =3D 1; + dwz_hdr2[1].flags =3D 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[0]); + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[1]); + + req_addr =3D virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr2)); + + free_head =3D 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 =3D readb(req_addr + 16 + sizeof(dwz_hdr2)); + g_assert_cmpint(status, =3D=3D, VIRTIO_BLK_S_UNSUPP); + + guest_free(alloc, req_addr); + + /* num_sectors must be less than config->max_write_zeroes_sectors */ + req.type =3D type; + req.data =3D (char *) &dwz_hdr; + dwz_hdr.sector =3D 0; + dwz_hdr.num_sectors =3D 0xffffffff; + dwz_hdr.flags =3D 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr =3D virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head =3D 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 =3D readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, =3D=3D, VIRTIO_BLK_S_IOERR); + + guest_free(alloc, req_addr); + + /* sector must be less than the device capacity */ + req.type =3D type; + req.data =3D (char *) &dwz_hdr; + dwz_hdr.sector =3D TEST_IMAGE_SIZE / 512 + 1; + dwz_hdr.num_sectors =3D 1; + dwz_hdr.flags =3D 0; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr =3D virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head =3D 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 =3D readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, =3D=3D, VIRTIO_BLK_S_IOERR); + + guest_free(alloc, req_addr); + + /* reserved flag bits must be zero */ + req.type =3D type; + req.data =3D (char *) &dwz_hdr; + dwz_hdr.sector =3D 0; + dwz_hdr.num_sectors =3D 1; + dwz_hdr.flags =3D ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP; + + virtio_blk_fix_dwz_hdr(dev, &dwz_hdr); + + req_addr =3D virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); + + free_head =3D 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 =3D readb(req_addr + 16 + sizeof(dwz_hdr)); + g_assert_cmpint(status, =3D=3D, 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, QGues= tAllocator *alloc) g_free(data); =20 guest_free(alloc, req_addr); + + test_invalid_discard_write_zeroes(dev, alloc, qts, vq, + VIRTIO_BLK_T_WRITE_ZEROES); } =20 if (features & (1u << VIRTIO_BLK_F_DISCARD)) { @@ -263,6 +384,9 @@ static QVirtQueue *test_basic(QVirtioDevice *dev, QGues= tAllocator *alloc) g_assert_cmpint(status, =3D=3D, 0); =20 guest_free(alloc, req_addr); + + test_invalid_discard_write_zeroes(dev, alloc, qts, vq, + VIRTIO_BLK_T_DISCARD); } =20 if (features & (1u << VIRTIO_F_ANY_LAYOUT)) { --=20 2.30.2