mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +00:00
qemu: add support for shmem-{plain, doorbell} role
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@redhat.com> Signed-off-by: Yang Hang <yanghang44@huawei.com> Signed-off-by: Wang Xin <wangxinxin.wang@huawei.com> Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
This commit is contained in:
parent
77296c807b
commit
493d2769f2
@ -9142,7 +9142,7 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
<devices>
|
<devices>
|
||||||
<shmem name='my_shmem0'>
|
<shmem name='my_shmem0' role='peer'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
<size unit='M'>4</size>
|
<size unit='M'>4</size>
|
||||||
</shmem>
|
</shmem>
|
||||||
@ -9163,6 +9163,17 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
<code>name</code> to identify the shared memory. This attribute cannot
|
<code>name</code> to identify the shared memory. This attribute cannot
|
||||||
be directory specific to <code>.</code> or <code>..</code> as well as
|
be directory specific to <code>.</code> or <code>..</code> as well as
|
||||||
it cannot involve path separator <code>/</code>.
|
it cannot involve path separator <code>/</code>.
|
||||||
|
The optional <code>role</code> (<span class="since">since 6.6.0</span>)
|
||||||
|
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
|
||||||
|
<code>model</code> type <code>ivshmem-plain</code> and
|
||||||
|
<code>ivshmem-doorbell</code>.
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>model</code></dt>
|
<dt><code>model</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
@ -4422,6 +4422,14 @@
|
|||||||
<param name="pattern">[^/]*</param>
|
<param name="pattern">[^/]*</param>
|
||||||
</data>
|
</data>
|
||||||
</attribute>
|
</attribute>
|
||||||
|
<optional>
|
||||||
|
<attribute name="role">
|
||||||
|
<choice>
|
||||||
|
<value>master</value>
|
||||||
|
<value>peer</value>
|
||||||
|
</choice>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
<interleave>
|
<interleave>
|
||||||
<optional>
|
<optional>
|
||||||
<element name="model">
|
<element name="model">
|
||||||
|
@ -1325,6 +1325,13 @@ VIR_ENUM_IMPL(virDomainShmemModel,
|
|||||||
"ivshmem-doorbell",
|
"ivshmem-doorbell",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(virDomainShmemRole,
|
||||||
|
VIR_DOMAIN_SHMEM_ROLE_LAST,
|
||||||
|
"default",
|
||||||
|
"master",
|
||||||
|
"peer",
|
||||||
|
);
|
||||||
|
|
||||||
VIR_ENUM_IMPL(virDomainLaunchSecurity,
|
VIR_ENUM_IMPL(virDomainLaunchSecurity,
|
||||||
VIR_DOMAIN_LAUNCH_SECURITY_LAST,
|
VIR_DOMAIN_LAUNCH_SECURITY_LAST,
|
||||||
"",
|
"",
|
||||||
@ -15366,6 +15373,19 @@ virDomainShmemDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|||||||
goto cleanup;
|
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,
|
if (virParseScaledValue("./size[1]", NULL, ctxt,
|
||||||
&def->size, 1, ULLONG_MAX, false) < 0)
|
&def->size, 1, ULLONG_MAX, false) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -18585,6 +18605,9 @@ virDomainShmemDefEquals(virDomainShmemDefPtr src,
|
|||||||
if (src->model != dst->model)
|
if (src->model != dst->model)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (src->role != dst->role)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (src->server.enabled != dst->server.enabled)
|
if (src->server.enabled != dst->server.enabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -23771,6 +23794,15 @@ virDomainShmemDefCheckABIStability(virDomainShmemDefPtr src,
|
|||||||
return false;
|
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) {
|
if (src->model != dst->model) {
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("Target shared memory model '%s' does not match "
|
_("Target shared memory model '%s' does not match "
|
||||||
@ -27423,8 +27455,12 @@ virDomainShmemDefFormat(virBufferPtr buf,
|
|||||||
virDomainShmemDefPtr def,
|
virDomainShmemDefPtr def,
|
||||||
unsigned int flags)
|
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);
|
virBufferAdjustIndent(buf, 2);
|
||||||
|
|
||||||
virBufferAsprintf(buf, "<model type='%s'/>\n",
|
virBufferAsprintf(buf, "<model type='%s'/>\n",
|
||||||
|
@ -1772,10 +1772,19 @@ typedef enum {
|
|||||||
VIR_DOMAIN_SHMEM_MODEL_LAST
|
VIR_DOMAIN_SHMEM_MODEL_LAST
|
||||||
} virDomainShmemModel;
|
} 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 {
|
struct _virDomainShmemDef {
|
||||||
char *name;
|
char *name;
|
||||||
unsigned long long size;
|
unsigned long long size;
|
||||||
int model; /* enum virDomainShmemModel */
|
int model; /* enum virDomainShmemModel */
|
||||||
|
int role; /* enum virDomainShmemRole */
|
||||||
struct {
|
struct {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
virDomainChrSourceDef chr;
|
virDomainChrSourceDef chr;
|
||||||
@ -3625,6 +3634,7 @@ VIR_ENUM_DECL(virDomainMemoryAllocation);
|
|||||||
VIR_ENUM_DECL(virDomainIOMMUModel);
|
VIR_ENUM_DECL(virDomainIOMMUModel);
|
||||||
VIR_ENUM_DECL(virDomainVsockModel);
|
VIR_ENUM_DECL(virDomainVsockModel);
|
||||||
VIR_ENUM_DECL(virDomainShmemModel);
|
VIR_ENUM_DECL(virDomainShmemModel);
|
||||||
|
VIR_ENUM_DECL(virDomainShmemRole);
|
||||||
VIR_ENUM_DECL(virDomainLaunchSecurity);
|
VIR_ENUM_DECL(virDomainLaunchSecurity);
|
||||||
/* from libvirt.h */
|
/* from libvirt.h */
|
||||||
VIR_ENUM_DECL(virDomainState);
|
VIR_ENUM_DECL(virDomainState);
|
||||||
|
@ -597,6 +597,8 @@ virDomainShmemDefInsert;
|
|||||||
virDomainShmemDefRemove;
|
virDomainShmemDefRemove;
|
||||||
virDomainShmemModelTypeFromString;
|
virDomainShmemModelTypeFromString;
|
||||||
virDomainShmemModelTypeToString;
|
virDomainShmemModelTypeToString;
|
||||||
|
virDomainShmemRoleTypeFromString;
|
||||||
|
virDomainShmemRoleTypeToString;
|
||||||
virDomainShutdownReasonTypeFromString;
|
virDomainShutdownReasonTypeFromString;
|
||||||
virDomainShutdownReasonTypeToString;
|
virDomainShutdownReasonTypeToString;
|
||||||
virDomainShutoffReasonTypeFromString;
|
virDomainShutoffReasonTypeFromString;
|
||||||
|
@ -8539,11 +8539,24 @@ qemuBuildShmemDevStr(virDomainDefPtr def,
|
|||||||
virBufferAdd(&buf, virDomainShmemModelTypeToString(shmem->model), -1);
|
virBufferAdd(&buf, virDomainShmemModelTypeToString(shmem->model), -1);
|
||||||
virBufferAsprintf(&buf, ",id=%s", shmem->info.alias);
|
virBufferAsprintf(&buf, ",id=%s", shmem->info.alias);
|
||||||
|
|
||||||
if (shmem->server.enabled)
|
if (shmem->server.enabled) {
|
||||||
virBufferAsprintf(&buf, ",chardev=char%s", shmem->info.alias);
|
virBufferAsprintf(&buf, ",chardev=char%s", shmem->info.alias);
|
||||||
else
|
} else {
|
||||||
virBufferAsprintf(&buf, ",memdev=shmmem-%s", shmem->info.alias);
|
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)
|
if (shmem->msi.vectors)
|
||||||
virBufferAsprintf(&buf, ",vectors=%u", shmem->msi.vectors);
|
virBufferAsprintf(&buf, ",vectors=%u", shmem->msi.vectors);
|
||||||
if (shmem->msi.ioeventfd) {
|
if (shmem->msi.ioeventfd) {
|
||||||
|
@ -1261,10 +1261,22 @@ qemuMigrationSrcIsAllowed(virQEMUDriverPtr driver,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vm->def->nshmems) {
|
for (i = 0; i < vm->def->nshmems; i++) {
|
||||||
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
virDomainShmemDefPtr shmem = vm->def->shmems[i];
|
||||||
_("migration with shmem device is not supported"));
|
|
||||||
return false;
|
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++) {
|
for (i = 0; i < vm->def->nnets; i++) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<shmem name='shmem0'>
|
<shmem name='shmem0' role='peer'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
<size unit='M'>4</size>
|
<size unit='M'>4</size>
|
||||||
<alias name='shmem0'/>
|
<alias name='shmem0'/>
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<shmem name='shmem0'>
|
<shmem name='shmem0' role='peer'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
</shmem>
|
</shmem>
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
<alias name='input1'/>
|
<alias name='input1'/>
|
||||||
</input>
|
</input>
|
||||||
<memballoon model='none'/>
|
<memballoon model='none'/>
|
||||||
<shmem name='shmem0'>
|
<shmem name='shmem0' role='peer'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
<size unit='M'>4</size>
|
<size unit='M'>4</size>
|
||||||
<alias name='shmem0'/>
|
<alias name='shmem0'/>
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
<alias name='input1'/>
|
<alias name='input1'/>
|
||||||
</input>
|
</input>
|
||||||
<memballoon model='none'/>
|
<memballoon model='none'/>
|
||||||
<shmem name='shmem0'>
|
<shmem name='shmem0' role='peer'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
<size unit='M'>4</size>
|
<size unit='M'>4</size>
|
||||||
<alias name='shmem0'/>
|
<alias name='shmem0'/>
|
||||||
|
@ -30,10 +30,12 @@ size=4194304,share=yes \
|
|||||||
-device ivshmem-plain,id=shmem0,memdev=shmmem-shmem0,bus=pci.0,addr=0x3 \
|
-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,\
|
-object memory-backend-file,id=shmmem-shmem1,mem-path=/dev/shm/shmem1,\
|
||||||
size=134217728,share=yes \
|
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,\
|
-object memory-backend-file,id=shmmem-shmem2,mem-path=/dev/shm/shmem2,\
|
||||||
size=268435456,share=yes \
|
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,\
|
-device ivshmem-doorbell,id=shmem3,chardev=charshmem3,ioeventfd=on,bus=pci.0,\
|
||||||
addr=0x6 \
|
addr=0x6 \
|
||||||
-chardev socket,id=charshmem3,path=/var/lib/libvirt/shmem-shmem3-sock \
|
-chardev socket,id=charshmem3,path=/var/lib/libvirt/shmem-shmem3-sock \
|
||||||
|
@ -22,11 +22,11 @@
|
|||||||
<shmem name='shmem0'>
|
<shmem name='shmem0'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
</shmem>
|
</shmem>
|
||||||
<shmem name='shmem1'>
|
<shmem name='shmem1' role='peer'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
<size unit='M'>128</size>
|
<size unit='M'>128</size>
|
||||||
</shmem>
|
</shmem>
|
||||||
<shmem name='shmem2'>
|
<shmem name='shmem2' role='master'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
<size unit='M'>256</size>
|
<size unit='M'>256</size>
|
||||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
||||||
|
@ -26,12 +26,12 @@
|
|||||||
<size unit='M'>4</size>
|
<size unit='M'>4</size>
|
||||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
|
||||||
</shmem>
|
</shmem>
|
||||||
<shmem name='shmem1'>
|
<shmem name='shmem1' role='peer'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
<size unit='M'>128</size>
|
<size unit='M'>128</size>
|
||||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
|
||||||
</shmem>
|
</shmem>
|
||||||
<shmem name='shmem2'>
|
<shmem name='shmem2' role='master'>
|
||||||
<model type='ivshmem-plain'/>
|
<model type='ivshmem-plain'/>
|
||||||
<size unit='M'>256</size>
|
<size unit='M'>256</size>
|
||||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
||||||
|
@ -1135,7 +1135,8 @@ mymain(void)
|
|||||||
DO_TEST("tap-vhost", NONE);
|
DO_TEST("tap-vhost", NONE);
|
||||||
DO_TEST("tap-vhost-incorrect", NONE);
|
DO_TEST("tap-vhost-incorrect", NONE);
|
||||||
DO_TEST("shmem", 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", NONE);
|
||||||
DO_TEST("smbios-multiple-type2", NONE);
|
DO_TEST("smbios-multiple-type2", NONE);
|
||||||
DO_TEST("smbios-type-fwcfg", NONE);
|
DO_TEST("smbios-type-fwcfg", NONE);
|
||||||
|
Loading…
Reference in New Issue
Block a user