All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alex Fishman <afishman@redhat.com>
To: qemu-devel@nongnu.org
Cc: mst@redhat.com, sgarzare@redhat.com, farosas@suse.de,
	lvivier@redhat.com, pbonzini@redhat.com,
	Alex Fishman <afishman@redhat.com>
Subject: [PATCH v1 2/2] tests/qtest: Add vhost-user memslot boundary test
Date: Wed,  9 Sep 2026 15:59:23 +0300	[thread overview]
Message-ID: <20260909125923.75340-3-afishman@redhat.com> (raw)
In-Reply-To: <20260909125923.75340-1-afishman@redhat.com>

Extend the fake vhost-user backend with configurable memory slot
support and add a virtio-mem test that places a vring across adjacent
dynamic memslots.

Activate another memslot after configuring the boundary-crossing vring
to trigger a vhost memory table update. Verify that the new slot is
advertised as a separate region instead of extending the merge required
by the vring.

Buglink: https://redhat.atlassian.net/browse/RHEL-146583

Signed-off-by: Alex Fishman <afishman@redhat.com>
---
 tests/qtest/vhost-user-test.c | 395 +++++++++++++++++++++++++++++++++-
 1 file changed, 385 insertions(+), 10 deletions(-)

diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c
index c8b5f8ff71..db57d3695f 100644
--- a/tests/qtest/vhost-user-test.c
+++ b/tests/qtest/vhost-user-test.c
@@ -13,16 +13,19 @@
 #include "libqtest-single.h"
 #include "qapi/error.h"
 #include "qobject/qdict.h"
+#include "qemu/bswap.h"
 #include "qemu/config-file.h"
 #include "qemu/option.h"
 #include "qemu/range.h"
 #include "qemu/sockets.h"
+#include "qemu/units.h"
 #include "chardev/char-fe.h"
 #include "qemu/memfd.h"
 #include "qemu/module.h"
 #include "system/system.h"
 #include "libqos/libqos.h"
 #include "libqos/pci-pc.h"
+#include "libqos/virtio-net.h"
 #include "libqos/virtio-pci.h"
 
 #include "libqos/malloc-pc.h"
@@ -31,6 +34,8 @@
 #include "standard-headers/linux/vhost_types.h"
 #include "standard-headers/linux/virtio_ids.h"
 #include "standard-headers/linux/virtio_net.h"
+#include "standard-headers/linux/virtio_mem.h"
+#include "standard-headers/linux/virtio_pci.h"
 #include "standard-headers/linux/virtio_gpio.h"
 #include "standard-headers/linux/virtio_scmi.h"
 
@@ -39,11 +44,13 @@
 #endif
 
 
-#define QEMU_CMD_MEM    " -m %d -object memory-backend-file,id=mem,size=%dM," \
-                        "mem-path=%s,share=on -numa node,memdev=mem"
-#define QEMU_CMD_MEMFD  " -m %d -object memory-backend-memfd,id=mem,size=%dM," \
-                        " -numa node,memdev=mem"
-#define QEMU_CMD_SHM    " -m %d -object memory-backend-shm,id=mem,size=%dM," \
+#define QEMU_CMD_MEM \
+    " -m %d%s -object memory-backend-file,id=mem,size=%dM," \
+    "mem-path=%s,share=on -numa node,memdev=mem"
+#define QEMU_CMD_MEMFD \
+    " -m %d%s -object memory-backend-memfd,id=mem,size=%dM," \
+    " -numa node,memdev=mem"
+#define QEMU_CMD_SHM    " -m %d%s -object memory-backend-shm,id=mem,size=%dM," \
                         " -numa node,memdev=mem"
 #define QEMU_CMD_CHR    " -chardev socket,id=%s,path=%s%s"
 #define QEMU_CMD_NETDEV " -netdev vhost-user,id=hs0,chardev=%s,vhostforce=on"
@@ -62,8 +69,11 @@
 #define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
 #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN   6
 #define VHOST_USER_PROTOCOL_F_CONFIG 9
+#define VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS 15
 
 #define VHOST_LOG_PAGE 0x1000
+#define TEST_VHOST_USER_MAX_MEM_SLOTS 1024
+#define TEST_VHOST_USER_MEM_REGS 64
 
 typedef enum VhostUserRequest {
     VHOST_USER_NONE = 0,
@@ -87,6 +97,9 @@ typedef enum VhostUserRequest {
     VHOST_USER_SET_VRING_ENABLE = 18,
     VHOST_USER_GET_CONFIG = 24,
     VHOST_USER_SET_CONFIG = 25,
+    VHOST_USER_GET_MAX_MEM_SLOTS = 36,
+    VHOST_USER_ADD_MEM_REG = 37,
+    VHOST_USER_REM_MEM_REG = 38,
     VHOST_USER_MAX
 } VhostUserRequest;
 
@@ -103,6 +116,11 @@ typedef struct VhostUserMemory {
     VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
 } VhostUserMemory;
 
+typedef struct VhostUserMemRegMsg {
+    uint64_t padding;
+    VhostUserMemoryRegion region;
+} VhostUserMemRegMsg;
+
 typedef struct VhostUserLog {
     uint64_t mmap_size;
     uint64_t mmap_offset;
@@ -122,6 +140,7 @@ typedef struct VhostUserMsg {
         struct vhost_vring_state state;
         struct vhost_vring_addr addr;
         VhostUserMemory memory;
+        VhostUserMemRegMsg mem_reg;
         VhostUserLog log;
     } payload;
 } QEMU_PACKED VhostUserMsg;
@@ -169,6 +188,11 @@ typedef struct TestServer {
     bool test_fail;
     int test_flags;
     int queues;
+    bool configure_mem_slots;
+    unsigned int get_max_mem_slots_count;
+    unsigned int add_mem_reg_count;
+    unsigned int rem_mem_reg_count;
+    VhostUserMemoryRegion add_mem_regs[TEST_VHOST_USER_MEM_REGS];
     struct vhost_user_ops *vu_ops;
 } TestServer;
 
@@ -220,8 +244,9 @@ static void append_vhost_gpio_opts(TestServer *s, GString *cmd_line,
                            chr_opts);
 }
 
-static void append_mem_opts(TestServer *server, GString *cmd_line,
-                            int size, enum test_memfd memfd)
+static void append_mem_opts_full(TestServer *server, GString *cmd_line,
+                                 int size, enum test_memfd memfd,
+                                 const char *size_opts)
 {
     if (memfd == TEST_MEMFD_AUTO) {
         memfd = qemu_memfd_check(MFD_ALLOW_SEALING) ? TEST_MEMFD_YES
@@ -229,16 +254,25 @@ static void append_mem_opts(TestServer *server, GString *cmd_line,
     }
 
     if (memfd == TEST_MEMFD_YES) {
-        g_string_append_printf(cmd_line, QEMU_CMD_MEMFD, size, size);
+        g_string_append_printf(cmd_line, QEMU_CMD_MEMFD,
+                               size, size_opts, size);
     } else if (memfd == TEST_MEMFD_SHM) {
-        g_string_append_printf(cmd_line, QEMU_CMD_SHM, size, size);
+        g_string_append_printf(cmd_line, QEMU_CMD_SHM,
+                               size, size_opts, size);
     } else {
         const char *root = init_hugepagefs() ? : server->tmpfs;
 
-        g_string_append_printf(cmd_line, QEMU_CMD_MEM, size, size, root);
+        g_string_append_printf(cmd_line, QEMU_CMD_MEM,
+                               size, size_opts, size, root);
     }
 }
 
+static void append_mem_opts(TestServer *server, GString *cmd_line,
+                            int size, enum test_memfd memfd)
+{
+    append_mem_opts_full(server, cmd_line, size, memfd, "");
+}
+
 static bool wait_for_fds(TestServer *s)
 {
     gint64 end_time;
@@ -501,6 +535,40 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
         qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
         break;
 
+    case VHOST_USER_GET_MAX_MEM_SLOTS:
+        s->get_max_mem_slots_count++;
+        msg.flags |= VHOST_USER_REPLY_MASK;
+        msg.size = sizeof(m.payload.u64);
+        msg.payload.u64 = TEST_VHOST_USER_MAX_MEM_SLOTS;
+        p = (uint8_t *) &msg;
+        qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
+        g_cond_broadcast(&s->data_cond);
+        break;
+
+    case VHOST_USER_ADD_MEM_REG:
+        g_assert_cmpuint(msg.size, ==, sizeof(msg.payload.mem_reg));
+        g_assert_cmpint(qemu_chr_fe_get_msgfds(chr, &fd, 1), ==, 1);
+        g_assert_cmpint(fd, >=, 0);
+        close(fd);
+        g_assert_cmpuint(s->add_mem_reg_count, <,
+                         G_N_ELEMENTS(s->add_mem_regs));
+        s->add_mem_regs[s->add_mem_reg_count] = msg.payload.mem_reg.region;
+        s->add_mem_reg_count++;
+        g_test_message("add_mem_reg: gpa=0x%" PRIx64 " size=0x%" PRIx64,
+                       msg.payload.mem_reg.region.guest_phys_addr,
+                       msg.payload.mem_reg.region.memory_size);
+        g_cond_broadcast(&s->data_cond);
+        break;
+
+    case VHOST_USER_REM_MEM_REG:
+        g_assert_cmpuint(msg.size, ==, sizeof(msg.payload.mem_reg));
+        s->rem_mem_reg_count++;
+        g_test_message("rem_mem_reg: gpa=0x%" PRIx64 " size=0x%" PRIx64,
+                       msg.payload.mem_reg.region.guest_phys_addr,
+                       msg.payload.mem_reg.region.memory_size);
+        g_cond_broadcast(&s->data_cond);
+        break;
+
     case VHOST_USER_SET_VRING_ENABLE:
         /*
          * Another case we ignore as we don't need to respond. With a
@@ -1048,6 +1116,301 @@ static void *vhost_user_test_setup_multiqueue(GString *cmd_line, void *arg)
     return s;
 }
 
+static void *vhost_user_test_setup_mem_slots(GString *cmd_line, void *arg)
+{
+    TestServer *s = test_server_new("mem-slots", arg);
+
+    s->configure_mem_slots = true;
+    test_server_listen(s);
+
+    append_mem_opts_full(s, cmd_line, 256, TEST_MEMFD_YES,
+                         ",maxmem=4G,slots=32");
+    g_string_append(cmd_line,
+                    " -object memory-backend-memfd,id=vmem,size=3G,share=on"
+                    " -device virtio-mem-pci,memdev=vmem,dynamic-memslots=on,"
+                    "requested-size=3G,unplugged-inaccessible=on,addr=05.0");
+    s->vu_ops->append_opts(s, cmd_line, "");
+
+    g_test_queue_destroy(vhost_user_test_cleanup, s);
+
+    return s;
+}
+
+static QVirtioPCIDevice *virtio_mem_init(QPCIBus *bus,
+                                         QGuestAllocator *alloc,
+                                         QVirtQueue **vq)
+{
+    QPCIAddress addr = { .devfn = QPCI_DEVFN(5, 0) };
+    QVirtioPCIDevice *dev = virtio_pci_new(bus, &addr);
+    uint64_t features;
+
+    g_assert_nonnull(dev);
+    g_assert_cmpuint(dev->vdev.device_type, ==, VIRTIO_ID_MEM);
+
+    qvirtio_pci_device_enable(dev);
+    qvirtio_start_device(&dev->vdev);
+
+    features = qvirtio_get_features(&dev->vdev);
+    g_assert_true(features & (1ULL << VIRTIO_F_VERSION_1));
+    g_assert_true(features &
+                  (1ULL << VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE));
+    features = (1ULL << VIRTIO_F_VERSION_1) |
+               (1ULL << VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE);
+    qvirtio_set_features(&dev->vdev, features);
+
+    *vq = qvirtqueue_setup(&dev->vdev, alloc, 0);
+    qvirtio_set_driver_ok(&dev->vdev);
+
+    return dev;
+}
+
+static void virtio_mem_request(QVirtioPCIDevice *dev, QVirtQueue *vq,
+                               QGuestAllocator *alloc, uint16_t type,
+                               uint64_t addr, uint16_t nb_blocks)
+{
+    QTestState *qts = global_qtest;
+    struct virtio_mem_req req = {
+        .type = cpu_to_le16(type),
+    };
+    struct virtio_mem_resp resp;
+    uint64_t req_addr, resp_addr;
+    uint32_t free_head;
+
+    if (type == VIRTIO_MEM_REQ_PLUG) {
+        req.u.plug.addr = cpu_to_le64(addr);
+        req.u.plug.nb_blocks = cpu_to_le16(nb_blocks);
+    } else {
+        g_assert_cmpuint(type, ==, VIRTIO_MEM_REQ_UNPLUG);
+        req.u.unplug.addr = cpu_to_le64(addr);
+        req.u.unplug.nb_blocks = cpu_to_le16(nb_blocks);
+    }
+
+    req_addr = guest_alloc(alloc, sizeof(req));
+    resp_addr = guest_alloc(alloc, sizeof(resp));
+    memwrite(req_addr, &req, sizeof(req));
+
+    free_head = qvirtqueue_add(qts, vq, req_addr, sizeof(req), false, true);
+    qvirtqueue_add(qts, vq, resp_addr, sizeof(resp), true, false);
+    qvirtqueue_kick(qts, &dev->vdev, vq, free_head);
+    qvirtio_wait_used_elem(qts, &dev->vdev, vq, free_head, NULL,
+                           5 * G_TIME_SPAN_SECOND);
+
+    memread(resp_addr, &resp, sizeof(resp));
+    g_assert_cmpuint(le16_to_cpu(resp.type), ==, VIRTIO_MEM_RESP_ACK);
+
+    guest_free(alloc, resp_addr);
+    guest_free(alloc, req_addr);
+}
+
+static bool gpa_covered_by_mem_regs(const VhostUserMemoryRegion *regs,
+                                    unsigned int count,
+                                    uint64_t gpa, uint64_t size)
+{
+    uint64_t covered = gpa;
+    uint64_t end = gpa + size;
+
+    while (covered < end) {
+        uint64_t next = covered;
+        unsigned int i;
+
+        for (i = 0; i < count; i++) {
+            uint64_t reg_start = regs[i].guest_phys_addr;
+            uint64_t reg_end = reg_start + regs[i].memory_size;
+
+            if (reg_start <= covered && reg_end > next) {
+                next = reg_end;
+            }
+        }
+
+        if (next == covered) {
+            return false;
+        }
+        covered = next;
+    }
+
+    return true;
+}
+
+static bool has_mem_reg(const VhostUserMemoryRegion *regs,
+                        unsigned int count, uint64_t gpa, uint64_t size)
+{
+    unsigned int i;
+
+    for (i = 0; i < count; i++) {
+        if (regs[i].guest_phys_addr == gpa &&
+            regs[i].memory_size == size) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static void wait_for_mem_coverage(TestServer *s, unsigned int from,
+                                  uint64_t gpa, uint64_t size)
+{
+    gint64 end_time;
+
+    g_mutex_lock(&s->data_mutex);
+    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+    while (!gpa_covered_by_mem_regs(&s->add_mem_regs[from],
+                                    s->add_mem_reg_count - from,
+                                    gpa, size)) {
+        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
+            break;
+        }
+    }
+    g_assert_true(gpa_covered_by_mem_regs(&s->add_mem_regs[from],
+                                          s->add_mem_reg_count - from,
+                                          gpa, size));
+    g_mutex_unlock(&s->data_mutex);
+}
+
+static void wait_for_mem_reg(TestServer *s, unsigned int from,
+                             uint64_t gpa, uint64_t size)
+{
+    gint64 end_time;
+
+    g_mutex_lock(&s->data_mutex);
+    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+    while (!has_mem_reg(&s->add_mem_regs[from],
+                        s->add_mem_reg_count - from, gpa, size)) {
+        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
+            break;
+        }
+    }
+    g_assert_true(has_mem_reg(&s->add_mem_regs[from],
+                              s->add_mem_reg_count - from, gpa, size));
+    g_mutex_unlock(&s->data_mutex);
+}
+
+static QVirtioPCIDevice *recreate_net_with_boundary_vring(QVirtioNet *net,
+                                                           uint64_t boundary)
+{
+    QVirtioPCIDevice *old_pdev = container_of(net->vdev,
+                                              QVirtioPCIDevice, vdev);
+    QPCIBus *bus = old_pdev->pdev->bus;
+    QPCIAddress addr = { .devfn = QPCI_DEVFN(4, 0) };
+    QVirtioPCIDevice *pdev;
+    QVirtioDevice *vdev;
+    QVirtQueue vq = { };
+    uint64_t features;
+
+    qpci_unplug_acpi_device_test(global_qtest, "net0", 4);
+    qtest_qmp_device_add(global_qtest, "virtio-net-pci", "net1",
+                         "{'netdev': 'hs0', 'addr': '04.0'}");
+
+    pdev = virtio_pci_new(bus, &addr);
+    g_assert_nonnull(pdev);
+    vdev = &pdev->vdev;
+
+    qvirtio_pci_device_enable(pdev);
+    qvirtio_start_device(vdev);
+    features = qvirtio_get_features(vdev);
+    features &= ~(QVIRTIO_F_BAD_FEATURE |
+                  (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
+                  (1ULL << VIRTIO_RING_F_EVENT_IDX));
+    qvirtio_set_features(vdev, features);
+
+    vdev->bus->queue_select(vdev, 0);
+    vq.vdev = vdev;
+    vq.index = 0;
+    vq.size = vdev->bus->get_queue_size(vdev);
+    vq.free_head = 0;
+    vq.num_free = vq.size;
+    vq.align = VIRTIO_PCI_VRING_ALIGN;
+
+    /*
+     * Place the new queue's descriptor table so that the first descriptor is
+     * in the lower memslot and all following descriptors are in the upper
+     * memslot.
+     */
+    qvring_init(global_qtest, NULL, &vq,
+                boundary - sizeof(struct vring_desc));
+    vdev->bus->set_queue_address(vdev, &vq);
+
+    /* qvirtqueue_setup() normally performs this final modern PCI step. */
+    qpci_io_writew(pdev->pdev, pdev->bar,
+                   pdev->common_cfg_offset +
+                   offsetof(struct virtio_pci_common_cfg, queue_enable), 1);
+    qvirtio_set_driver_ok(vdev);
+
+    return pdev;
+}
+
+static void test_mem_slots_boundary(void *obj, void *arg,
+                                    QGuestAllocator *alloc)
+{
+    TestServer *s = arg;
+    QVirtioNet *net = obj;
+    QPCIBus *bus;
+    QVirtioPCIDevice *dev;
+    QVirtioPCIDevice *net_dev;
+    QVirtQueue *vq;
+    gint64 end_time;
+    uint64_t block_size, mem_addr, region_size;
+    unsigned int initial_add_count;
+    unsigned int third_slot_add_from;
+    unsigned int i;
+
+    g_mutex_lock(&s->data_mutex);
+    end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+    while (!s->get_max_mem_slots_count || !s->add_mem_reg_count) {
+        if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) {
+            break;
+        }
+    }
+    g_assert_cmpuint(s->get_max_mem_slots_count, ==, 1);
+    g_assert_cmpuint(s->add_mem_reg_count, >, 0);
+    initial_add_count = s->add_mem_reg_count;
+    g_mutex_unlock(&s->data_mutex);
+
+    bus = qpci_new_pc(global_qtest, alloc);
+    dev = virtio_mem_init(bus, alloc, &vq);
+    block_size = qvirtio_config_readq(&dev->vdev,
+                                      offsetof(struct virtio_mem_config,
+                                               block_size));
+    mem_addr = qvirtio_config_readq(&dev->vdev,
+                                    offsetof(struct virtio_mem_config, addr));
+    region_size = qvirtio_config_readq(&dev->vdev,
+                                       offsetof(struct virtio_mem_config,
+                                                region_size));
+    g_assert_cmpuint(region_size, ==, 3 * GiB);
+
+    g_assert_cmpuint(block_size, <=, GiB);
+    g_assert_true(QEMU_IS_ALIGNED(GiB, block_size));
+
+    /* One request crossing the boundary has to activate slots 0 and 1. */
+    virtio_mem_request(dev, vq, alloc, VIRTIO_MEM_REQ_PLUG,
+                       mem_addr + GiB - block_size, 2);
+    wait_for_mem_coverage(s, initial_add_count, mem_addr, 2 * GiB);
+
+    net_dev = recreate_net_with_boundary_vring(net, mem_addr + GiB);
+
+    g_mutex_lock(&s->data_mutex);
+    third_slot_add_from = s->add_mem_reg_count;
+    g_mutex_unlock(&s->data_mutex);
+
+    /* The third slot must remain separate from the merged first two slots. */
+    virtio_mem_request(dev, vq, alloc, VIRTIO_MEM_REQ_PLUG,
+                       mem_addr + 2 * GiB, 1);
+    wait_for_mem_reg(s, third_slot_add_from, mem_addr + 2 * GiB, GiB);
+
+    g_mutex_lock(&s->data_mutex);
+    for (i = 0; i < 3; i++) {
+        g_assert_true(gpa_covered_by_mem_regs(
+            &s->add_mem_regs[initial_add_count],
+            s->add_mem_reg_count - initial_add_count,
+            mem_addr + i * GiB, GiB));
+    }
+    g_mutex_unlock(&s->data_mutex);
+
+    qvirtqueue_cleanup(dev->vdev.bus, vq, alloc);
+    qos_object_destroy(&dev->obj);
+    qos_object_destroy(&net_dev->obj);
+    qpci_free_pc(bus);
+}
+
 static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc)
 {
     TestServer *s = arg;
@@ -1090,6 +1453,10 @@ static void vu_net_get_protocol_features(TestServer *s, CharFrontend *chr,
     if (s->queues > 1) {
         msg->payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ;
     }
+    if (s->configure_mem_slots) {
+        msg->payload.u64 |= 1ULL <<
+                            VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS;
+    }
     qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size);
 }
 
@@ -1151,6 +1518,14 @@ static void register_vhost_user_test(void)
     qos_add_test("vhost-user/multiqueue",
                  "virtio-net",
                  test_multiqueue, &opts);
+
+    if (qemu_memfd_check(MFD_ALLOW_SEALING) &&
+        qtest_has_device("virtio-mem-pci")) {
+        opts.before = vhost_user_test_setup_mem_slots;
+        opts.edge.extra_device_opts = "id=net0";
+        qos_add_test("vhost-user/mem-slots/boundary",
+                     "virtio-net", test_mem_slots_boundary, &opts);
+    }
 }
 libqos_init(register_vhost_user_test);
 
-- 
2.52.0



  parent reply	other threads:[~2026-09-09 13:05 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-09 12:59 [PATCH v1 0/2] vhost: Handle vrings crossing virtio-mem slots Alex Fishman
2026-09-09 12:59 ` [PATCH v1 1/2] vhost: coalesce unmergeable sections across vring boundaries Alex Fishman
2026-09-09 13:31   ` Michael S. Tsirkin
2026-09-09 13:54     ` Alex Fishman
2026-09-09 15:24       ` Michael S. Tsirkin
2026-09-10  7:45       ` Michael S. Tsirkin
2026-09-09 12:59 ` Alex Fishman [this message]
2026-09-09 13:01 ` [PATCH v1 0/2] vhost: Handle vrings crossing virtio-mem slots Michael S. Tsirkin
2026-09-09 13:13   ` Alex Fishman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260909125923.75340-3-afishman@redhat.com \
    --to=afishman@redhat.com \
    --cc=farosas@suse.de \
    --cc=lvivier@redhat.com \
    --cc=mst@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=sgarzare@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.