diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index e7b585cfed..8e50b8caac 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -5582,6 +5582,58 @@ qemu-kvm -net nic,model=? /dev/null
+
+
+
+ A shared memory device allows to share a memory region between
+ different virtual machines and the host.
+ Since 1.2.9, QEMU and KVM only
+
+
+
+ ...
+ <devices>
+ <shmem name='my_shmem0'>
+ <size unit='M'>4</size>
+ </shmem>
+ <shmem name='shmem_server'>
+ <size unit='M'>2</size>
+ <server path='/tmp/socket-shmem'/>
+ <msi vectors='32' ioeventfd='on'/>
+ </shmem>
+ </devices>
+ ...
+
+
+
+ shmem
+ -
+ The
shmem
element has one mandatory attribute,
+ name
to identify the shared memory.
+
+ size
+ -
+ The optional
size
element specifies the size of the shared
+ memory. This must be power of 2 and greater than or equal to 1 MiB.
+
+ server
+ -
+ The optional
server
element can be used to configure a server
+ socket the device is supposed to connect to. The optional
+ path
attribute specifies the path to the unix socket and
+ defaults to /var/lib/libvirt/shmem/$shmem-$name-sock
.
+
+ msi
+ -
+ The optional
msi
element enables/disables (values "on"/"off",
+ respectively) MSI interrupts. This option can currently be used only
+ together with the server
element. The vectors
+ attribute can be used to specify the number of interrupt
+ vectors. The ioeventd
attribute enables/disables (values
+ "on"/"off", respectively) ioeventfd.
+
+
+
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 1a266e571c..6b69fd1bac 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3278,6 +3278,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3864,6 +3902,7 @@
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 6ea25df401..b74782f42f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -255,7 +255,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
"chr",
"memballoon",
"nvram",
- "rng")
+ "rng",
+ "shmem")
VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
"none",
@@ -1720,6 +1721,17 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
VIR_FREE(def);
}
+void virDomainShmemDefFree(virDomainShmemDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainDeviceInfoClear(&def->info);
+ VIR_FREE(def->server.path);
+ VIR_FREE(def->name);
+ VIR_FREE(def);
+}
+
void virDomainVideoDefFree(virDomainVideoDefPtr def)
{
if (!def)
@@ -1921,6 +1933,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
case VIR_DOMAIN_DEVICE_NVRAM:
virDomainNVRAMDefFree(def->data.nvram);
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ virDomainShmemDefFree(def->data.shmem);
+ break;
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_NONE:
break;
@@ -2181,6 +2196,10 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainRedirFilterDefFree(def->redirfilter);
+ for (i = 0; i < def->nshmems; i++)
+ virDomainShmemDefFree(def->shmems[i]);
+ VIR_FREE(def->shmems);
+
if (def->namespaceData && def->ns.free)
(def->ns.free)(def->namespaceData);
@@ -2613,6 +2632,8 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
return &device->data.memballoon->info;
case VIR_DOMAIN_DEVICE_NVRAM:
return &device->data.nvram->info;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ return &device->data.shmem->info;
case VIR_DOMAIN_DEVICE_RNG:
return &device->data.rng->info;
@@ -2828,6 +2849,12 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
if (cb(def, &device, &def->hubs[i]->info, opaque) < 0)
return -1;
}
+ device.type = VIR_DOMAIN_DEVICE_SHMEM;
+ for (i = 0; i < def->nshmems; i++) {
+ device.data.shmem = def->shmems[i];
+ if (cb(def, &device, &def->shmems[i]->info, opaque) < 0)
+ return -1;
+ }
/* Coverity is not very happy with this - all dead_error_condition */
#if !STATIC_ANALYSIS
@@ -2856,6 +2883,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
+ case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_RNG:
break;
@@ -9702,6 +9730,84 @@ virDomainNVRAMDefParseXML(xmlNodePtr node,
return NULL;
}
+static virDomainShmemDefPtr
+virDomainShmemDefParseXML(xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ unsigned int flags)
+{
+ char *tmp = NULL;
+ virDomainShmemDefPtr def = NULL;
+ virDomainShmemDefPtr ret = NULL;
+ xmlNodePtr msi = NULL;
+ xmlNodePtr save = ctxt->node;
+ xmlNodePtr server = NULL;
+
+
+ if (VIR_ALLOC(def) < 0)
+ return NULL;
+
+ ctxt->node = node;
+
+ if (!(def->name = virXMLPropString(node, "name"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("shmem element must contain 'name' attribute"));
+ goto cleanup;
+ }
+
+ if (virDomainParseScaledValue("./size[1]", ctxt, &def->size,
+ 1, ULLONG_MAX, false) < 0)
+ goto cleanup;
+
+ if ((server = virXPathNode("./server", ctxt))) {
+ def->server.enabled = true;
+
+ if ((tmp = virXMLPropString(server, "path")))
+ def->server.path = virFileSanitizePath(tmp);
+ VIR_FREE(tmp);
+ }
+
+ if ((msi = virXPathNode("./msi", ctxt))) {
+ def->msi.enabled = true;
+
+ if ((tmp = virXMLPropString(msi, "vectors")) &&
+ virStrToLong_uip(tmp, NULL, 0, &def->msi.vectors) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid number of vectors for shmem: '%s'"),
+ tmp);
+ goto cleanup;
+ }
+ VIR_FREE(tmp);
+
+ if ((tmp = virXMLPropString(msi, "ioeventfd")) &&
+ (def->msi.ioeventfd = virTristateSwitchTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid msi ioeventfd setting for shmem: '%s'"),
+ tmp);
+ goto cleanup;
+ }
+ VIR_FREE(tmp);
+ }
+
+ /* msi option is only relevant with a server */
+ if (def->msi.enabled && !def->server.enabled) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("msi option is only supported with a server"));
+ goto cleanup;
+ }
+
+ if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
+ goto cleanup;
+
+
+ ret = def;
+ def = NULL;
+ cleanup:
+ ctxt->node = save;
+ VIR_FREE(tmp);
+ virDomainShmemDefFree(def);
+ return ret;
+}
+
static virSysinfoDefPtr
virSysinfoParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
@@ -10558,6 +10664,10 @@ virDomainDeviceDefParse(const char *xmlStr,
if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
goto error;
break;
+ case VIR_DOMAIN_DEVICE_SHMEM:
+ if (!(dev->data.shmem = virDomainShmemDefParseXML(node, ctxt, flags)))
+ goto error;
+ break;
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LAST:
break;
@@ -13686,6 +13796,25 @@ virDomainDefParseXML(xmlDocPtr xml,
VIR_FREE(nodes);
}
+ /* analysis of the shmem devices */
+ if ((n = virXPathNodeSet("./devices/shmem", ctxt, &nodes)) < 0) {
+ goto error;
+ }
+ if (n && VIR_ALLOC_N(def->shmems, n) < 0)
+ goto error;
+
+ node = ctxt->node;
+ for (i = 0; i < n; i++) {
+ virDomainShmemDefPtr shmem;
+ ctxt->node = nodes[i];
+ shmem = virDomainShmemDefParseXML(nodes[i], ctxt, flags);
+ if (!shmem)
+ goto error;
+
+ def->shmems[def->nshmems++] = shmem;
+ }
+ ctxt->node = node;
+ VIR_FREE(nodes);
/* analysis of the user namespace mapping */
if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
@@ -17469,6 +17598,54 @@ static int virDomainPanicDefFormat(virBufferPtr buf,
return 0;
}
+static int
+virDomainShmemDefFormat(virBufferPtr buf,
+ virDomainShmemDefPtr def,
+ unsigned int flags)
+{
+ virBufferAsprintf(buf, "name);
+
+ if (!def->size &&
+ !def->server.enabled &&
+ !def->msi.enabled &&
+ !virDomainDeviceInfoIsSet(&def->info, flags)) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ } else {
+ virBufferAddLit(buf, ">\n");
+ }
+
+ virBufferAdjustIndent(buf, 2);
+
+ if (def->size)
+ virBufferAsprintf(buf, "%llu\n",
+ VIR_DIV_UP(def->size, 1024 * 1024));
+
+ if (def->server.enabled) {
+ virBufferAddLit(buf, "server.path);
+ virBufferAddLit(buf, "/>\n");
+ }
+
+ if (def->msi.enabled) {
+ virBufferAddLit(buf, "msi.vectors)
+ virBufferAsprintf(buf, " vectors='%u'", def->msi.vectors);
+ if (def->msi.ioeventfd)
+ virBufferAsprintf(buf, " ioeventfd='%s'",
+ virTristateSwitchTypeToString(def->msi.ioeventfd));
+ virBufferAddLit(buf, "/>\n");
+ }
+
+ if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+ return -1;
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "\n");
+
+ return 0;
+}
+
static int
virDomainRNGDefFormat(virBufferPtr buf,
virDomainRNGDefPtr def,
@@ -19089,6 +19266,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virDomainPanicDefFormat(buf, def->panic) < 0)
goto error;
+ for (n = 0; n < def->nshmems; n++)
+ if (virDomainShmemDefFormat(buf, def->shmems[n], flags) < 0)
+ goto error;
+
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "\n");
@@ -20454,6 +20635,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
+ case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Copying definition of '%d' type "
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ea201b3a33..d73d654282 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -136,6 +136,9 @@ typedef virDomainPanicDef *virDomainPanicDefPtr;
typedef struct _virDomainChrSourceDef virDomainChrSourceDef;
typedef virDomainChrSourceDef *virDomainChrSourceDefPtr;
+typedef struct _virDomainShmemDef virDomainShmemDef;
+typedef virDomainShmemDef *virDomainShmemDefPtr;
+
/* Flags for the 'type' field in virDomainDeviceDef */
typedef enum {
VIR_DOMAIN_DEVICE_NONE = 0,
@@ -157,6 +160,7 @@ typedef enum {
VIR_DOMAIN_DEVICE_MEMBALLOON,
VIR_DOMAIN_DEVICE_NVRAM,
VIR_DOMAIN_DEVICE_RNG,
+ VIR_DOMAIN_DEVICE_SHMEM,
VIR_DOMAIN_DEVICE_LAST
} virDomainDeviceType;
@@ -184,6 +188,7 @@ struct _virDomainDeviceDef {
virDomainMemballoonDefPtr memballoon;
virDomainNVRAMDefPtr nvram;
virDomainRNGDefPtr rng;
+ virDomainShmemDefPtr shmem;
} data;
};
@@ -1506,6 +1511,21 @@ struct _virDomainNVRAMDef {
virDomainDeviceInfo info;
};
+struct _virDomainShmemDef {
+ char *name;
+ unsigned long long size;
+ struct {
+ bool enabled;
+ char *path;
+ } server;
+ struct {
+ bool enabled;
+ unsigned vectors;
+ virTristateSwitch ioeventfd;
+ } msi;
+ virDomainDeviceInfo info;
+};
+
typedef enum {
VIR_DOMAIN_SMBIOS_NONE = 0,
VIR_DOMAIN_SMBIOS_EMULATE,
@@ -2082,6 +2102,9 @@ struct _virDomainDef {
size_t nrngs;
virDomainRNGDefPtr *rngs;
+ size_t nshmems;
+ virDomainShmemDefPtr *shmems;
+
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
@@ -2279,6 +2302,7 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
void virDomainHubDefFree(virDomainHubDefPtr def);
void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def);
void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def);
+void virDomainShmemDefFree(virDomainShmemDefPtr def);
void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
virDomainDeviceDefPtr virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
const virDomainDef *def,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index d63188749c..3a654e436f 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2859,6 +2859,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_RNG:
+ case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("don't know how to remove a %s device"),
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml
new file mode 100644
index 0000000000..d70279c21f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml
@@ -0,0 +1,24 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
new file mode 100644
index 0000000000..fd79c89c1a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
@@ -0,0 +1,51 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+
+ 128
+
+
+ 256
+
+
+ 512
+
+
+
+ 1024
+
+
+
+ 2048
+
+
+
+
+ 4096
+
+
+
+
+ 8192
+
+
+
+
+
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 483ca90324..58153db0df 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1466,6 +1466,8 @@ mymain(void)
DO_TEST("fips-enabled", QEMU_CAPS_ENABLE_FIPS);
+ DO_TEST_PARSE_ERROR("shmem-msi-only", NONE);
+
virObjectUnref(driver.config);
virObjectUnref(driver.caps);
virObjectUnref(driver.xmlopt);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 9a568806d7..978e5f1c6a 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -404,6 +404,7 @@ mymain(void)
DO_TEST("bios-nvram");
DO_TEST("tap-vhost");
+ DO_TEST("shmem");
virObjectUnref(driver.caps);
virObjectUnref(driver.xmlopt);