[PATCH v2 1/2] qemu: add support for shmem-{plain, doorbell} role

Wang Xin wangxinxin.wang at huawei.com
Fri Jul 17 13:04:50 UTC 2020


Role(master or peer) controls how the domain behaves on migration.
For more details about migration with ivshmem, see
https://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/system/ivshmem.rst;hb=HEAD

It's a optional attribute in libvirt, and qemu will choose default
role for ivshmem device if the user is not specified.

With device property 'role', the value can be 'master' or 'peer'.
 - 'master' (means 'master=on' in qemu), the guest will copy
   the shared memory on migration to the destination host.
 - 'peer' (means 'master=off' in qemu), the migration is disabled.

Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
Signed-off-by: Yang Hang <yanghang44 at huawei.com>
Signed-off-by: Wang Xin <wangxinxin.wang at huawei.com>

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index f5ee97de81..d4d90ad44d 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -9141,7 +9141,7 @@ qemu-kvm -net nic,model=? /dev/null
 <pre>
 ...
 <devices>
-  <shmem name='my_shmem0'>
+  <shmem name='my_shmem0' role='peer'>
     <model type='ivshmem-plain'/>
     <size unit='M'>4</size>
   </shmem>
@@ -9159,9 +9159,15 @@ qemu-kvm -net nic,model=? /dev/null
     <dt><code>shmem</code></dt>
     <dd>
       The <code>shmem</code> element has one mandatory attribute,
-      <code>name</code> to identify the shared memory. This attribute cannot
-      be directory specific to <code>.</code> or <code>..</code> as well as
-      it cannot involve path separator <code>/</code>.
+      <code>name</code> to identify the shared memory. Optional attribute
+      <code>role</code> can be set to values "master" or "peer". The former
+      will mean that upon migration, the data in the shared memory is migrated
+      with the domain. There should be only one "master" per shared memory object.
+      Migration with "peer" role is disabled. If migration of such domain is required,
+      the shmem device needs to be unplugged before migration and plugged in at the
+      destination upon successful migration. This attribute cannot be directory
+      specific to <code>.</code> or <code>..</code> as well as it cannot involve path
+      separator <code>/</code>.
     </dd>
     <dt><code>model</code></dt>
     <dd>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index a810f569c6..09d4ad3e96 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4417,6 +4417,14 @@
           <param name="pattern">[^/]*</param>
         </data>
       </attribute>
+      <optional>
+        <attribute name="role">
+          <choice>
+            <value>master</value>
+            <value>peer</value>
+          </choice>
+        </attribute>
+      </optional>
       <interleave>
         <optional>
           <element name="model">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 7ecd2818b9..6e67c7ebe0 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1325,6 +1325,13 @@ VIR_ENUM_IMPL(virDomainShmemModel,
               "ivshmem-doorbell",
 );
 
+VIR_ENUM_IMPL(virDomainShmemRole,
+              VIR_DOMAIN_SHMEM_ROLE_LAST,
+              "default",
+              "master",
+              "peer",
+);
+
 VIR_ENUM_IMPL(virDomainLaunchSecurity,
               VIR_DOMAIN_LAUNCH_SECURITY_LAST,
               "",
@@ -15357,6 +15364,19 @@ virDomainShmemDefParseXML(virDomainXMLOptionPtr xmlopt,
         goto cleanup;
     }
 
+    if (def->model != VIR_DOMAIN_SHMEM_MODEL_IVSHMEM) {
+        tmp = virXMLPropString(node, "role");
+        if (tmp) {
+            if ((def->role = virDomainShmemRoleTypeFromString(tmp)) <= 0) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("Unknown shmem role type '%s'"), tmp);
+                goto cleanup;
+            }
+
+            VIR_FREE(tmp);
+        }
+    }
+
     if (virParseScaledValue("./size[1]", NULL, ctxt,
                             &def->size, 1, ULLONG_MAX, false) < 0)
         goto cleanup;
@@ -18579,6 +18599,9 @@ virDomainShmemDefEquals(virDomainShmemDefPtr src,
     if (src->model != dst->model)
         return false;
 
+    if (src->role != dst->role)
+        return false;
+
     if (src->server.enabled != dst->server.enabled)
         return false;
 
@@ -23758,6 +23781,15 @@ virDomainShmemDefCheckABIStability(virDomainShmemDefPtr src,
         return false;
     }
 
+    if (src->role != dst->role) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target shared memory role '%s' does not match "
+                         "source role '%s'"),
+                       virDomainShmemRoleTypeToString(dst->role),
+                       virDomainShmemRoleTypeToString(src->role));
+        return false;
+    }
+
     if (src->model != dst->model) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Target shared memory model '%s' does not match "
@@ -27408,8 +27440,12 @@ virDomainShmemDefFormat(virBufferPtr buf,
                         virDomainShmemDefPtr def,
                         unsigned int flags)
 {
-    virBufferEscapeString(buf, "<shmem name='%s'>\n", def->name);
+    virBufferEscapeString(buf, "<shmem name='%s'", def->name);
+    if (def->role)
+        virBufferEscapeString(buf, " role='%s'",
+                              virDomainShmemRoleTypeToString(def->role));
 
+    virBufferAddLit(buf, ">\n");
     virBufferAdjustIndent(buf, 2);
 
     virBufferAsprintf(buf, "<model type='%s'/>\n",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 241149af24..855c144ddb 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1771,10 +1771,19 @@ typedef enum {
     VIR_DOMAIN_SHMEM_MODEL_LAST
 } virDomainShmemModel;
 
+typedef enum {
+    VIR_DOMAIN_SHMEM_ROLE_DEFAULT,
+    VIR_DOMAIN_SHMEM_ROLE_MASTER,
+    VIR_DOMAIN_SHMEM_ROLE_PEER,
+
+    VIR_DOMAIN_SHMEM_ROLE_LAST
+} virDomainShmemRole;
+
 struct _virDomainShmemDef {
     char *name;
     unsigned long long size;
     int model; /* enum virDomainShmemModel */
+    int role; /* enum virDomainShmemRole */
     struct {
         bool enabled;
         virDomainChrSourceDef chr;
@@ -3624,6 +3633,7 @@ VIR_ENUM_DECL(virDomainMemoryAllocation);
 VIR_ENUM_DECL(virDomainIOMMUModel);
 VIR_ENUM_DECL(virDomainVsockModel);
 VIR_ENUM_DECL(virDomainShmemModel);
+VIR_ENUM_DECL(virDomainShmemRole);
 VIR_ENUM_DECL(virDomainLaunchSecurity);
 /* from libvirt.h */
 VIR_ENUM_DECL(virDomainState);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 73b72c9e10..3f28943575 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -597,6 +597,8 @@ virDomainShmemDefInsert;
 virDomainShmemDefRemove;
 virDomainShmemModelTypeFromString;
 virDomainShmemModelTypeToString;
+virDomainShmemRoleTypeFromString;
+virDomainShmemRoleTypeToString;
 virDomainShutdownReasonTypeFromString;
 virDomainShutdownReasonTypeToString;
 virDomainShutoffReasonTypeFromString;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 839c93bfb4..0655d8359d 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -8539,11 +8539,24 @@ qemuBuildShmemDevStr(virDomainDefPtr def,
     virBufferAdd(&buf, virDomainShmemModelTypeToString(shmem->model), -1);
     virBufferAsprintf(&buf, ",id=%s", shmem->info.alias);
 
-    if (shmem->server.enabled)
+    if (shmem->server.enabled) {
         virBufferAsprintf(&buf, ",chardev=char%s", shmem->info.alias);
-    else
+    } else {
         virBufferAsprintf(&buf, ",memdev=shmmem-%s", shmem->info.alias);
 
+        switch ((virDomainShmemRole) shmem->role) {
+        case VIR_DOMAIN_SHMEM_ROLE_MASTER:
+            virBufferAddLit(&buf, ",master=on");
+            break;
+        case VIR_DOMAIN_SHMEM_ROLE_PEER:
+            virBufferAddLit(&buf, ",master=off");
+            break;
+        case VIR_DOMAIN_SHMEM_ROLE_DEFAULT:
+        case VIR_DOMAIN_SHMEM_ROLE_LAST:
+            break;
+        }
+    }
+
     if (shmem->msi.vectors)
         virBufferAsprintf(&buf, ",vectors=%u", shmem->msi.vectors);
     if (shmem->msi.ioeventfd) {
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 78e64344f6..5ae85c7ae7 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1261,10 +1261,22 @@ qemuMigrationSrcIsAllowed(virQEMUDriverPtr driver,
             }
         }
 
-        if (vm->def->nshmems) {
-            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                           _("migration with shmem device is not supported"));
-            return false;
+        for (i = 0; i < vm->def->nshmems; i++) {
+            virDomainShmemDefPtr shmem = vm->def->shmems[i];
+
+            if (shmem->model == VIR_DOMAIN_SHMEM_MODEL_IVSHMEM) {
+                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                               _("migration with legacy shmem device is not supported"));
+                return false;
+            }
+            if (shmem->role == VIR_DOMAIN_SHMEM_ROLE_PEER) {
+                virReportError(VIR_ERR_OPERATION_INVALID,
+                               _("domain's shmem device '%s' has role='%s', "
+                                 "try unplugging it first"),
+                               shmem->name,
+                               virDomainShmemRoleTypeToString(shmem->role));
+                return false;
+            }
         }
 
         for (i = 0; i < vm->def->nnets; i++) {
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml
index 68f592fb21..338017aa28 100644
--- a/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain-detach.xml
@@ -1,4 +1,4 @@
-<shmem name='shmem0'>
+<shmem name='shmem0' role='peer'>
   <model type='ivshmem-plain'/>
   <size unit='M'>4</size>
   <alias name='shmem0'/>
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml
index 6bd96ff167..780e49de23 100644
--- a/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-ivshmem-plain.xml
@@ -1,3 +1,3 @@
-<shmem name='shmem0'>
+<shmem name='shmem0' role='peer'>
   <model type='ivshmem-plain'/>
 </shmem>
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml
index a6930bfa69..8013264989 100644
--- a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-doorbell.xml
@@ -45,7 +45,7 @@
       <alias name='input1'/>
     </input>
     <memballoon model='none'/>
-    <shmem name='shmem0'>
+    <shmem name='shmem0' role='peer'>
       <model type='ivshmem-plain'/>
       <size unit='M'>4</size>
       <alias name='shmem0'/>
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml
index 757b6b0980..0490310760 100644
--- a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+ivshmem-plain.xml
@@ -45,7 +45,7 @@
       <alias name='input1'/>
     </input>
     <memballoon model='none'/>
-    <shmem name='shmem0'>
+    <shmem name='shmem0' role='peer'>
       <model type='ivshmem-plain'/>
       <size unit='M'>4</size>
       <alias name='shmem0'/>
diff --git a/tests/qemuxml2argvdata/shmem-plain-doorbell.args b/tests/qemuxml2argvdata/shmem-plain-doorbell.args
index 6ed86b7448..aa41d5391a 100644
--- a/tests/qemuxml2argvdata/shmem-plain-doorbell.args
+++ b/tests/qemuxml2argvdata/shmem-plain-doorbell.args
@@ -30,10 +30,10 @@ size=4194304,share=yes \
 -device ivshmem-plain,id=shmem0,memdev=shmmem-shmem0,bus=pci.0,addr=0x3 \
 -object memory-backend-file,id=shmmem-shmem1,mem-path=/dev/shm/shmem1,\
 size=134217728,share=yes \
--device ivshmem-plain,id=shmem1,memdev=shmmem-shmem1,bus=pci.0,addr=0x5 \
+-device ivshmem-plain,id=shmem1,memdev=shmmem-shmem1,master=off,bus=pci.0,addr=0x5 \
 -object memory-backend-file,id=shmmem-shmem2,mem-path=/dev/shm/shmem2,\
 size=268435456,share=yes \
--device ivshmem-plain,id=shmem2,memdev=shmmem-shmem2,bus=pci.0,addr=0x4 \
+-device ivshmem-plain,id=shmem2,memdev=shmmem-shmem2,master=on,bus=pci.0,addr=0x4 \
 -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 \
diff --git a/tests/qemuxml2argvdata/shmem-plain-doorbell.xml b/tests/qemuxml2argvdata/shmem-plain-doorbell.xml
index e248d637a5..7c76e0fbba 100644
--- a/tests/qemuxml2argvdata/shmem-plain-doorbell.xml
+++ b/tests/qemuxml2argvdata/shmem-plain-doorbell.xml
@@ -22,11 +22,11 @@
     <shmem name='shmem0'>
       <model type='ivshmem-plain'/>
     </shmem>
-    <shmem name='shmem1'>
+    <shmem name='shmem1' role='peer'>
       <model type='ivshmem-plain'/>
       <size unit='M'>128</size>
     </shmem>
-    <shmem name='shmem2'>
+    <shmem name='shmem2' role='master'>
       <model type='ivshmem-plain'/>
       <size unit='M'>256</size>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
diff --git a/tests/qemuxml2xmloutdata/shmem-plain-doorbell.xml b/tests/qemuxml2xmloutdata/shmem-plain-doorbell.xml
index c5dd0f4598..64c0a7d753 100644
--- a/tests/qemuxml2xmloutdata/shmem-plain-doorbell.xml
+++ b/tests/qemuxml2xmloutdata/shmem-plain-doorbell.xml
@@ -26,12 +26,12 @@
       <size unit='M'>4</size>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
     </shmem>
-    <shmem name='shmem1'>
+    <shmem name='shmem1' role='peer'>
       <model type='ivshmem-plain'/>
       <size unit='M'>128</size>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
     </shmem>
-    <shmem name='shmem2'>
+    <shmem name='shmem2' role='master'>
       <model type='ivshmem-plain'/>
       <size unit='M'>256</size>
       <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index c17e3303b0..6cb2718767 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1135,7 +1135,8 @@ mymain(void)
     DO_TEST("tap-vhost", NONE);
     DO_TEST("tap-vhost-incorrect", NONE);
     DO_TEST("shmem", NONE);
-    DO_TEST("shmem-plain-doorbell", NONE);
+    DO_TEST("shmem-plain-doorbell",
+            QEMU_CAPS_DEVICE_IVSHMEM_PLAIN, QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
     DO_TEST("smbios", NONE);
     DO_TEST("smbios-multiple-type2", NONE);
     DO_TEST("smbios-type-fwcfg", NONE);
-- 
2.26.0.windows.1






More information about the libvir-list mailing list