diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 6b67a09bb3..3fc41801a4 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -9142,7 +9142,7 @@ qemu-kvm -net nic,model=? /dev/null
...
<devices>
- <shmem name='my_shmem0'>
+ <shmem name='my_shmem0' role='peer'>
<model type='ivshmem-plain'/>
<size unit='M'>4</size>
</shmem>
@@ -9163,6 +9163,17 @@ qemu-kvm -net nic,model=? /dev/null
name
to identify the shared memory. This attribute cannot
be directory specific to .
or ..
as well as
it cannot involve path separator /
.
+ The optional role
(since 6.6.0)
+ attribute specifies the shared memory is migratable or not. The value can
+ be either "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. If the role not specified, the hypervisor
+ default is used. This attribute is currently available only for
+ model
type ivshmem-plain
and
+ ivshmem-doorbell
.
model
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 8cbbd7e6e9..c196a97511 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4422,6 +4422,14 @@
[^/]*
+
+
+
+ master
+ peer
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 1179a27a00..4a47dc8d0a 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,
"",
@@ -15366,6 +15373,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;
@@ -18585,6 +18605,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;
@@ -23771,6 +23794,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 "
@@ -27423,8 +27455,12 @@ virDomainShmemDefFormat(virBufferPtr buf,
virDomainShmemDefPtr def,
unsigned int flags)
{
- virBufferEscapeString(buf, "\n", def->name);
+ virBufferEscapeString(buf, "name);
+ if (def->role)
+ virBufferEscapeString(buf, " role='%s'",
+ virDomainShmemRoleTypeToString(def->role));
+ virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
virBufferAsprintf(buf, "\n",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 6e9da298b4..011bf66cb4 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1772,10 +1772,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;
@@ -3625,6 +3634,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 eea31a736d..bdc1563300 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 2c7bf349c3..0f2f92b211 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_MASTER) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("shmem device '%s' cannot be migrated, "
+ "only shmem with role='%s' can be migrated"),
+ shmem->name,
+ virDomainShmemRoleTypeToString(VIR_DOMAIN_SHMEM_ROLE_MASTER));
+ 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 @@
-
+
4
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 @@
-
+
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 @@
-
+
4
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 @@
-
+
4
diff --git a/tests/qemuxml2argvdata/shmem-plain-doorbell.args b/tests/qemuxml2argvdata/shmem-plain-doorbell.args
index 6ed86b7448..93d089c27a 100644
--- a/tests/qemuxml2argvdata/shmem-plain-doorbell.args
+++ b/tests/qemuxml2argvdata/shmem-plain-doorbell.args
@@ -30,10 +30,12 @@ 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 @@
-
+
128
-
+
256
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 @@
4
-
+
128
-
+
256
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 74b6959408..a07e2b7553 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);