[libvirt] [PATCH 6/7] qemu: Support newer ivshmem device variants

Martin Kletzander mkletzan at redhat.com
Wed Sep 21 13:30:55 UTC 2016


QEMU added support for ivshmem-plain and ivshmem-doorbell.  Those are
reworked varians of legacy ivshmem that are compatible from the guest
POV, but not from host's POV and have sane specification and handling.

Details about the newer device type can be found in qemu's commit
5400c02b90bb:

  http://git.qemu.org/?p=qemu.git;a=commit;h=5400c02b90bb

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
---
 docs/formatdomain.html.in                          |   5 +-
 src/qemu/qemu_command.c                            | 109 ++++++++++++++++++++-
 src/qemu/qemu_command.h                            |  10 ++
 .../qemuxml2argv-shmem-plain-doorbell.args         |  46 +++++++++
 .../qemuxml2argv-shmem-plain-doorbell.xml          |   1 +
 tests/qemuxml2argvtest.c                           |   3 +
 6 files changed, 172 insertions(+), 2 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args
 create mode 120000 tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index b9163584d9f5..c614caf5f47f 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -6740,7 +6740,10 @@ qemu-kvm -net nic,model=? /dev/null

     <p>
       A shared memory device allows to share a memory region between
-      different virtual machines and the host.
+      different virtual machines and the host.  Note that memory in
+      this region will be migrated, if that's not desired, the device
+      needs to be unplugged before migration and plugged back again
+      after that.
       <span class="since">Since 1.2.10, QEMU and KVM only</span>
     </p>

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 2130a7e2e8cf..3f7dfc4a46b9 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -8550,6 +8550,44 @@ qemuBuildShmemDevLegacyStr(virDomainDefPtr def,
     return NULL;
 }

+char *
+qemuBuildShmemDevStr(virDomainDefPtr def,
+                     virDomainShmemDefPtr shmem,
+                     virQEMUCapsPtr qemuCaps)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (shmem->server.enabled) {
+        virBufferAddLit(&buf, "ivshmem-doorbell");
+        virBufferAsprintf(&buf, ",id=%s,chardev=char%s",
+                          shmem->info.alias, shmem->info.alias);
+        if (shmem->msi.vectors)
+            virBufferAsprintf(&buf, ",vectors=%u", shmem->msi.vectors);
+        if (shmem->msi.ioeventfd)
+            virBufferAsprintf(&buf, ",ioeventfd=%s",
+                              virTristateSwitchTypeToString(shmem->msi.ioeventfd));
+    } else {
+        virBufferAddLit(&buf, "ivshmem-plain");
+        virBufferAsprintf(&buf, ",id=%s,memdev=shmmem-%s",
+                          shmem->info.alias, shmem->info.alias);
+
+        /* For now we default to master=on, users are adviced to
+         * unplug the ivshmem if they don't want to migrate the data
+         * in the shmem (see docs). */
+        virBufferAddLit(&buf, ",master=on");
+    }
+
+    if (qemuBuildDeviceAddressStr(&buf, def, &shmem->info, qemuCaps) < 0) {
+        virBufferFreeAndReset(&buf);
+        return NULL;
+    }
+
+    if (virBufferCheckError(&buf) < 0)
+        return NULL;
+
+    return virBufferContentAndReset(&buf);
+}
+
 static char *
 qemuBuildShmemBackendChrStr(virLogManagerPtr logManager,
                             virCommandPtr cmd,
@@ -8570,6 +8608,51 @@ qemuBuildShmemBackendChrStr(virLogManagerPtr logManager,
     return devstr;
 }

+
+virJSONValuePtr
+qemuBuildShmemBackendMemProps(virDomainShmemDefPtr shmem)
+{
+    char *mem_path = NULL;
+    virJSONValuePtr ret = NULL;
+
+    if (virAsprintf(&mem_path, "/dev/shm/%s", shmem->name) < 0)
+        return NULL;
+
+    virJSONValueObjectCreate(&ret,
+                             "U:size", shmem->size,
+                             "s:mem-path", mem_path,
+                             NULL);
+
+    VIR_FREE(mem_path);
+
+    return ret;
+}
+
+
+static char *
+qemuBuildShmemBackendMemStr(virDomainShmemDefPtr shmem)
+{
+    char *ret = NULL;
+    char *alias = NULL;
+    virJSONValuePtr props = qemuBuildShmemBackendMemProps(shmem);
+
+    if (!props)
+        return NULL;
+
+    if (virAsprintf(&alias, "shmmem-%s", shmem->info.alias) < 0)
+        goto cleanup;
+
+    ret = virQEMUBuildObjectCommandlineFromJSON("memory-backend-file",
+                                                alias,
+                                                props);
+ cleanup:
+    VIR_FREE(alias);
+    virJSONValueFree(props);
+
+    return ret;
+}
+
+
 static int
 qemuBuildShmemCommandLine(virLogManagerPtr logManager,
                           virCommandPtr cmd,
@@ -8579,6 +8662,18 @@ qemuBuildShmemCommandLine(virLogManagerPtr logManager,
                           virQEMUCapsPtr qemuCaps)
 {
     char *devstr = NULL;
+    bool legacy = false;
+
+    if (!qemuDomainSupportsNonLegacyShmem(qemuCaps, shmem)) {
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("shmem device is not supported with this "
+                             "QEMU binary"));
+            return -1;
+        }
+
+        legacy = true;
+    }

     if (shmem->size) {
         /*
@@ -8606,8 +8701,14 @@ qemuBuildShmemCommandLine(virLogManagerPtr logManager,
         return -1;
     }

-    if (!(devstr = qemuBuildShmemDevLegacyStr(def, shmem, qemuCaps)))
+    if (legacy)
+        devstr = qemuBuildShmemDevLegacyStr(def, shmem, qemuCaps);
+    else
+        devstr = qemuBuildShmemDevStr(def, shmem, qemuCaps);
+
+    if (!devstr)
         return -1;
+
     virCommandAddArgList(cmd, "-device", devstr, NULL);
     VIR_FREE(devstr);

@@ -8618,6 +8719,12 @@ qemuBuildShmemCommandLine(virLogManagerPtr logManager,

         virCommandAddArgList(cmd, "-chardev", devstr, NULL);
         VIR_FREE(devstr);
+    } else if (!legacy) {
+        if (!(devstr = qemuBuildShmemBackendMemStr(shmem)))
+            return -1;
+
+        virCommandAddArgList(cmd, "-object", devstr, NULL);
+        VIR_FREE(devstr);
     }

     return 0;
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 2f2a6ff877e7..facc833bf886 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -186,4 +186,14 @@ bool qemuCheckCCWS390AddressSupport(const virDomainDef *def,
 virJSONValuePtr qemuBuildHotpluggableCPUProps(const virDomainVcpuDef *vcpu)
     ATTRIBUTE_NONNULL(1);

+virJSONValuePtr qemuBuildShmemBackendMemProps(virDomainShmemDefPtr shmem)
+    ATTRIBUTE_NONNULL(1);
+
+char *qemuBuildShmemDevStr(virDomainDefPtr def,
+                           virDomainShmemDefPtr shmem,
+                           virQEMUCapsPtr qemuCaps)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+
+
+
 #endif /* __QEMU_COMMAND_H__*/
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args b/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args
new file mode 100644
index 000000000000..cb57c41ede76
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.args
@@ -0,0 +1,46 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest1 \
+-S \
+-M pc \
+-m 214 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-usb \
+-device ivshmem-plain,id=shmem0,memdev=shmmem-shmem0,master=on,bus=pci.0,\
+addr=0x3 \
+-object memory-backend-file,id=shmmem-shmem0,size=4194304,\
+mem-path=/dev/shm/shmem0 \
+-device ivshmem-plain,id=shmem1,memdev=shmmem-shmem1,master=on,bus=pci.0,\
+addr=0x5 \
+-object memory-backend-file,id=shmmem-shmem1,size=134217728,\
+mem-path=/dev/shm/shmem1 \
+-device ivshmem-plain,id=shmem2,memdev=shmmem-shmem2,master=on,bus=pci.0,\
+addr=0x4 \
+-object memory-backend-file,id=shmmem-shmem2,size=268435456,\
+mem-path=/dev/shm/shmem2 \
+-device ivshmem-doorbell,id=shmem3,chardev=charshmem3,ioeventfd=on,bus=pci.0,\
+addr=0x6 \
+-chardev socket,id=charshmem3,path=/var/lib/libvirt/shmem-shmem3-sock \
+-device ivshmem-doorbell,id=shmem4,chardev=charshmem4,ioeventfd=on,bus=pci.0,\
+addr=0x7 \
+-chardev socket,id=charshmem4,path=/tmp/shmem4-sock \
+-device ivshmem-doorbell,id=shmem5,chardev=charshmem5,ioeventfd=off,bus=pci.0,\
+addr=0x8 \
+-chardev socket,id=charshmem5,path=/tmp/shmem5-sock \
+-device ivshmem-doorbell,id=shmem6,chardev=charshmem6,vectors=16,ioeventfd=on,\
+bus=pci.0,addr=0x9 \
+-chardev socket,id=charshmem6,path=/tmp/shmem6-sock \
+-device ivshmem-doorbell,id=shmem7,chardev=charshmem7,vectors=32,ioeventfd=on,\
+bus=pci.0,addr=0xa \
+-chardev socket,id=charshmem7,path=/tmp/shmem7-sock
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.xml
new file mode 120000
index 000000000000..8f2f0f71776a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-plain-doorbell.xml
@@ -0,0 +1 @@
+qemuxml2argv-shmem.xml
\ No newline at end of file
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index e8540779a4b5..484c36ecc6c7 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1992,6 +1992,9 @@ mymain(void)
     DO_TEST("fips-enabled", QEMU_CAPS_ENABLE_FIPS);

     DO_TEST("shmem", QEMU_CAPS_DEVICE_IVSHMEM);
+    DO_TEST("shmem-plain-doorbell", QEMU_CAPS_DEVICE_IVSHMEM,
+            QEMU_CAPS_DEVICE_IVSHMEM_PLAIN,
+            QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
     DO_TEST_FAILURE("shmem", NONE);
     DO_TEST_FAILURE("shmem-invalid-size",
                     QEMU_CAPS_DEVICE_IVSHMEM);
-- 
2.10.0




More information about the libvir-list mailing list