virtio,pci,pc: features,fixes,cleanups

New virtio mem options.
 A vhost-user cleanup.
 Control over smbios entry point type.
 Config interrupt support for vdpa.
 Fixes, cleanups all over the place.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmHY2zEPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRpCiEH/jv5tHUffDdGz5M2pN7FTWPQ9UAMQZXbn5AS
 PPVutOI/B+ILYBuNjYLvMGeq6ymG4/0DM940/jkQwCWD4ku1OG0ReM5T5klUR8lY
 df5y1SCDv3Yoq0vxpQCnssKqbgm8Kf9tnAFjni7Lvbu3oo6DCq77m6MWEapLoEUu
 IkM+l60NKmHAClnE6RF4KobLa5srIlDTho1iBXH5S39CRF1LvP9NgnYzl7nqiEkq
 ZYQEqkKO5XGxZji9banZPJD2kxt1iL7s24QI6OJG2Lz8Hf86b0Yo7XJpmw4ShP9h
 Vl1SL3m/HhHSMBuXOb7w/EkCm59b7whXCmoyYBF/GqaxtZkvVnM=
 =4VIN
 -----END PGP SIGNATURE-----

Merge tag 'for_upstream' of git://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging

virtio,pci,pc: features,fixes,cleanups

New virtio mem options.
A vhost-user cleanup.
Control over smbios entry point type.
Config interrupt support for vdpa.
Fixes, cleanups all over the place.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Fri 07 Jan 2022 04:30:41 PM PST
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [undefined]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* tag 'for_upstream' of git://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (55 commits)
  tests: acpi: Add updated TPM related tables
  acpi: tpm: Add missing device identification objects
  tests: acpi: prepare for updated TPM related tables
  virtio/vhost-vsock: don't double close vhostfd, remove redundant cleanup
  hw/scsi/vhost-scsi: don't double close vhostfd on error
  hw/scsi/vhost-scsi: don't leak vqs on error
  docs: reSTify virtio-balloon-stats documentation and move to docs/interop
  hw/i386/pc: Add missing property descriptions
  acpihp: simplify acpi_pcihp_disable_root_bus
  tests: acpi: SLIC: update expected blobs
  tests: acpi: add SLIC table test
  tests: acpi: whitelist expected blobs before changing them
  acpi: fix QEMU crash when started with SLIC table
  intel-iommu: correctly check passthrough during translation
  virtio-mem: Set "unplugged-inaccessible=auto" for the 7.0 machine on x86
  virtio-mem: Support VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE
  linux-headers: sync VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE
  MAINTAINERS: Add a separate entry for acpi/VIOT tables
  virtio: signal after wrapping packed used_idx
  virtio-mem: Support "prealloc=on" option
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2022-01-07 17:24:24 -08:00
commit d70075373a
56 changed files with 1209 additions and 500 deletions

View File

@ -1777,6 +1777,13 @@ F: docs/specs/acpi_mem_hotplug.rst
F: docs/specs/acpi_pci_hotplug.rst F: docs/specs/acpi_pci_hotplug.rst
F: docs/specs/acpi_hw_reduced_hotplug.rst F: docs/specs/acpi_hw_reduced_hotplug.rst
ACPI/VIOT
M: Jean-Philippe Brucker <jean-philippe@linaro.org>
R: Ani Sinha <ani@anisinha.ca>
S: Supported
F: hw/acpi/viot.c
F: hw/acpi/viot.h
ACPI/HEST/GHES ACPI/HEST/GHES
R: Dongjiu Geng <gengdongjiu1@gmail.com> R: Dongjiu Geng <gengdongjiu1@gmail.com>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
@ -1925,6 +1932,7 @@ virtio-balloon
M: Michael S. Tsirkin <mst@redhat.com> M: Michael S. Tsirkin <mst@redhat.com>
M: David Hildenbrand <david@redhat.com> M: David Hildenbrand <david@redhat.com>
S: Maintained S: Maintained
F: docs/interop/virtio-balloon-stats.rst
F: hw/virtio/virtio-balloon*.c F: hw/virtio/virtio-balloon*.c
F: include/hw/virtio/virtio-balloon.h F: include/hw/virtio/virtio-balloon.h
F: softmmu/balloon.c F: softmmu/balloon.c

View File

@ -290,13 +290,6 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
NULL); NULL);
} }
if (ret == QIO_CHANNEL_ERR_BLOCK) {
errno = EAGAIN;
ret = -1;
} else if (ret == -1) {
errno = EIO;
}
if (msgfds_num) { if (msgfds_num) {
/* close and clean read_msgfds */ /* close and clean read_msgfds */
for (i = 0; i < s->read_msgfds_num; i++) { for (i = 0; i < s->read_msgfds_num; i++) {
@ -325,6 +318,13 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
#endif #endif
} }
if (ret == QIO_CHANNEL_ERR_BLOCK) {
errno = EAGAIN;
ret = -1;
} else if (ret == -1) {
errno = EIO;
}
return ret; return ret;
} }
@ -525,6 +525,7 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
{ {
SocketChardev *s = SOCKET_CHARDEV(chr); SocketChardev *s = SOCKET_CHARDEV(chr);
int size; int size;
int saved_errno;
if (s->state != TCP_CHARDEV_STATE_CONNECTED) { if (s->state != TCP_CHARDEV_STATE_CONNECTED) {
return 0; return 0;
@ -532,6 +533,7 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
qio_channel_set_blocking(s->ioc, true, NULL); qio_channel_set_blocking(s->ioc, true, NULL);
size = tcp_chr_recv(chr, (void *) buf, len); size = tcp_chr_recv(chr, (void *) buf, len);
saved_errno = errno;
if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) { if (s->state != TCP_CHARDEV_STATE_DISCONNECTED) {
qio_channel_set_blocking(s->ioc, false, NULL); qio_channel_set_blocking(s->ioc, false, NULL);
} }
@ -540,6 +542,7 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
tcp_chr_disconnect(chr); tcp_chr_disconnect(chr);
} }
errno = saved_errno;
return size; return size;
} }

View File

@ -22,3 +22,4 @@ are useful for making QEMU interoperate with other software.
vhost-user vhost-user
vhost-user-gpu vhost-user-gpu
vhost-vdpa vhost-vdpa
virtio-balloon-stats

View File

@ -1,4 +1,4 @@
virtio balloon memory statistics Virtio balloon memory statistics
================================ ================================
The virtio balloon driver supports guest memory statistics reporting. These The virtio balloon driver supports guest memory statistics reporting. These
@ -9,10 +9,12 @@ Before querying the available stats, clients first have to enable polling.
This is done by writing a time interval value (in seconds) to the This is done by writing a time interval value (in seconds) to the
guest-stats-polling-interval property. This value can be: guest-stats-polling-interval property. This value can be:
> 0 enables polling in the specified interval. If polling is already > 0
enables polling in the specified interval. If polling is already
enabled, the polling time interval is changed to the new value enabled, the polling time interval is changed to the new value
0 disables polling. Previous polled statistics are still valid and 0
disables polling. Previous polled statistics are still valid and
can be queried. can be queried.
Once polling is enabled, the virtio-balloon device in QEMU will start Once polling is enabled, the virtio-balloon device in QEMU will start
@ -22,7 +24,7 @@ interval.
To retrieve those stats, clients have to query the guest-stats property, To retrieve those stats, clients have to query the guest-stats property,
which will return a dictionary containing: which will return a dictionary containing:
o A key named 'stats', containing all available stats. If the guest * A key named 'stats', containing all available stats. If the guest
doesn't support a particular stat, or if it couldn't be retrieved, doesn't support a particular stat, or if it couldn't be retrieved,
its value will be -1. Currently, the following stats are supported: its value will be -1. Currently, the following stats are supported:
@ -37,7 +39,7 @@ which will return a dictionary containing:
- stat-htlb-pgalloc - stat-htlb-pgalloc
- stat-htlb-pgfail - stat-htlb-pgfail
o A key named last-update, which contains the last stats update * A key named last-update, which contains the last stats update
timestamp in seconds. Since this timestamp is generated by the host, timestamp in seconds. Since this timestamp is generated by the host,
a buggy guest can't influence its value. The value is 0 if the guest a buggy guest can't influence its value. The value is 0 if the guest
has not updated the stats (yet). has not updated the stats (yet).
@ -61,32 +63,32 @@ It's also important to note the following:
respond to the request the timer will never be re-armed, which has respond to the request the timer will never be re-armed, which has
the same effect as disabling polling the same effect as disabling polling
Here are a few examples. QEMU is started with '-device virtio-balloon', Here are a few examples. QEMU is started with ``-device virtio-balloon``,
which generates '/machine/peripheral-anon/device[1]' as the QOM path for which generates ``/machine/peripheral-anon/device[1]`` as the QOM path for
the balloon device. the balloon device.
Enable polling with 2 seconds interval: Enable polling with 2 seconds interval::
{ "execute": "qom-set", { "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]", "arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 2 } } "property": "guest-stats-polling-interval", "value": 2 } }
{ "return": {} } { "return": {} }
Change polling to 10 seconds: Change polling to 10 seconds::
{ "execute": "qom-set", { "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]", "arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 10 } } "property": "guest-stats-polling-interval", "value": 10 } }
{ "return": {} } { "return": {} }
Get stats: Get stats::
{ "execute": "qom-get", { "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]", "arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } } "property": "guest-stats" } }
{ {
"return": { "return": {
"stats": { "stats": {
"stat-swap-out": 0, "stat-swap-out": 0,
@ -98,12 +100,12 @@ Get stats:
}, },
"last-update": 1358529861 "last-update": 1358529861
} }
} }
Disable polling: Disable polling::
{ "execute": "qom-set", { "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]", "arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "stats-polling-interval", "value": 0 } } "property": "stats-polling-interval", "value": 0 } }
{ "return": {} } { "return": {} }

View File

@ -345,8 +345,8 @@ int acpi_get_slic_oem(AcpiSlicOem *oem)
struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length)); struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length));
if (memcmp(hdr->sig, "SLIC", 4) == 0) { if (memcmp(hdr->sig, "SLIC", 4) == 0) {
oem->id = hdr->oem_id; oem->id = g_strndup(hdr->oem_id, 6);
oem->table_id = hdr->oem_table_id; oem->table_id = g_strndup(hdr->oem_table_id, 8);
return 0; return 0;
} }
} }

View File

@ -128,20 +128,15 @@ static void acpi_set_pci_info(void)
static void acpi_pcihp_disable_root_bus(void) static void acpi_pcihp_disable_root_bus(void)
{ {
static bool root_hp_disabled;
Object *host = acpi_get_i386_pci_host(); Object *host = acpi_get_i386_pci_host();
PCIBus *bus; PCIBus *bus;
if (root_hp_disabled) {
return;
}
bus = PCI_HOST_BRIDGE(host)->bus; bus = PCI_HOST_BRIDGE(host)->bus;
if (bus) { if (bus && qbus_is_hotpluggable(BUS(bus))) {
/* setting the hotplug handler to NULL makes the bus non-hotpluggable */ /* setting the hotplug handler to NULL makes the bus non-hotpluggable */
qbus_set_hotplug_handler(BUS(bus), NULL); qbus_set_hotplug_handler(BUS(bus), NULL);
} }
root_hp_disabled = true;
return; return;
} }
@ -491,6 +486,9 @@ static void pci_write(void *opaque, hwaddr addr, uint64_t data,
} }
bus = acpi_pcihp_find_hotplug_bus(s, s->hotplug_select); bus = acpi_pcihp_find_hotplug_bus(s, s->hotplug_select);
if (!bus) {
break;
}
QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) { QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
Object *o = OBJECT(kid->child); Object *o = OBJECT(kid->child);
PCIDevice *dev = PCI_DEVICE(o); PCIDevice *dev = PCI_DEVICE(o);

View File

@ -229,6 +229,7 @@ static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms)
Aml *dev = aml_device("TPM0"); Aml *dev = aml_device("TPM0");
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device")));
aml_append(dev, aml_name_decl("_UID", aml_int(0))); aml_append(dev, aml_name_decl("_UID", aml_int(0)));
Aml *crs = aml_resource_template(); Aml *crs = aml_resource_template();

View File

@ -1589,7 +1589,7 @@ static void virt_build_smbios(VirtMachineState *vms)
smbios_set_defaults("QEMU", product, smbios_set_defaults("QEMU", product,
vmc->smbios_old_sys_ver ? "1.0" : mc->name, false, vmc->smbios_old_sys_ver ? "1.0" : mc->name, false,
true, SMBIOS_ENTRY_POINT_30); true, SMBIOS_ENTRY_POINT_TYPE_64);
smbios_get_tables(MACHINE(vms), NULL, 0, smbios_get_tables(MACHINE(vms), NULL, 0,
&smbios_tables, &smbios_tables_len, &smbios_tables, &smbios_tables_len,

View File

@ -100,7 +100,7 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
&local_err); &local_err);
if (ret < 0) { if (ret < 0) {
error_report_err(local_err); error_report_err(local_err);
return -1; return ret;
} }
/* valid for resize only */ /* valid for resize only */
@ -252,6 +252,7 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev,
VHostUserBlk *s = VHOST_USER_BLK(vdev); VHostUserBlk *s = VHOST_USER_BLK(vdev);
/* Turn on pre-defined features */ /* Turn on pre-defined features */
virtio_add_feature(&features, VIRTIO_BLK_F_SIZE_MAX);
virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX); virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX);
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
@ -511,7 +512,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
*errp = NULL; *errp = NULL;
} }
ret = vhost_user_blk_realize_connect(s, errp); ret = vhost_user_blk_realize_connect(s, errp);
} while (ret == -EPROTO && retries--); } while (ret < 0 && retries--);
if (ret < 0) { if (ret < 0) {
goto virtio_err; goto virtio_err;

View File

@ -485,6 +485,9 @@ vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx)
{ {
VhostUserGPU *g = VHOST_USER_GPU(vdev); VhostUserGPU *g = VHOST_USER_GPU(vdev);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return false;
}
return vhost_virtqueue_pending(&g->vhost->dev, idx); return vhost_virtqueue_pending(&g->vhost->dev, idx);
} }
@ -493,6 +496,9 @@ vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask)
{ {
VhostUserGPU *g = VHOST_USER_GPU(vdev); VhostUserGPU *g = VHOST_USER_GPU(vdev);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return;
}
vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask);
} }

View File

@ -1812,11 +1812,15 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
dev = aml_device("TPM"); dev = aml_device("TPM");
aml_append(dev, aml_name_decl("_HID", aml_append(dev, aml_name_decl("_HID",
aml_string("MSFT0101"))); aml_string("MSFT0101")));
aml_append(dev,
aml_name_decl("_STR",
aml_string("TPM 2.0 Device")));
} else { } else {
dev = aml_device("ISA.TPM"); dev = aml_device("ISA.TPM");
aml_append(dev, aml_name_decl("_HID", aml_append(dev, aml_name_decl("_HID",
aml_eisaid("PNP0C31"))); aml_eisaid("PNP0C31")));
} }
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
crs = aml_resource_template(); crs = aml_resource_template();
@ -1844,12 +1848,15 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
if (TPM_IS_CRB(tpm)) { if (TPM_IS_CRB(tpm)) {
dev = aml_device("TPM"); dev = aml_device("TPM");
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
aml_append(dev, aml_name_decl("_STR",
aml_string("TPM 2.0 Device")));
crs = aml_resource_template(); crs = aml_resource_template();
aml_append(crs, aml_memory32_fixed(TPM_CRB_ADDR_BASE, aml_append(crs, aml_memory32_fixed(TPM_CRB_ADDR_BASE,
TPM_CRB_ADDR_SIZE, AML_READ_WRITE)); TPM_CRB_ADDR_SIZE, AML_READ_WRITE));
aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(dev, aml_name_decl("_STA", aml_int(0xf))); aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
aml_append(dev, aml_name_decl("_UID", aml_int(1)));
tpm_build_ppi_acpi(tpm, dev); tpm_build_ppi_acpi(tpm, dev);
@ -2723,6 +2730,8 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
/* Cleanup memory that's no longer used. */ /* Cleanup memory that's no longer used. */
g_array_free(table_offsets, true); g_array_free(table_offsets, true);
g_free(slic_oem.id);
g_free(slic_oem.table_id);
} }
static void acpi_ram_update(MemoryRegion *mr, GArray *data) static void acpi_ram_update(MemoryRegion *mr, GArray *data)

View File

@ -1516,11 +1516,29 @@ static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as)
* 1st-level translation or 2nd-level translation, it depends * 1st-level translation or 2nd-level translation, it depends
* on PGTT setting. * on PGTT setting.
*/ */
static bool vtd_dev_pt_enabled(VTDAddressSpace *as) static bool vtd_dev_pt_enabled(IntelIOMMUState *s, VTDContextEntry *ce)
{
VTDPASIDEntry pe;
int ret;
if (s->root_scalable) {
ret = vtd_ce_get_rid2pasid_entry(s, ce, &pe);
if (ret) {
error_report_once("%s: vtd_ce_get_rid2pasid_entry error: %"PRId32,
__func__, ret);
return false;
}
return (VTD_PE_GET_TYPE(&pe) == VTD_SM_PASID_ENTRY_PT);
}
return (vtd_ce_get_type(ce) == VTD_CONTEXT_TT_PASS_THROUGH);
}
static bool vtd_as_pt_enabled(VTDAddressSpace *as)
{ {
IntelIOMMUState *s; IntelIOMMUState *s;
VTDContextEntry ce; VTDContextEntry ce;
VTDPASIDEntry pe;
int ret; int ret;
assert(as); assert(as);
@ -1538,17 +1556,7 @@ static bool vtd_dev_pt_enabled(VTDAddressSpace *as)
return false; return false;
} }
if (s->root_scalable) { return vtd_dev_pt_enabled(s, &ce);
ret = vtd_ce_get_rid2pasid_entry(s, &ce, &pe);
if (ret) {
error_report_once("%s: vtd_ce_get_rid2pasid_entry error: %"PRId32,
__func__, ret);
return false;
}
return (VTD_PE_GET_TYPE(&pe) == VTD_SM_PASID_ENTRY_PT);
}
return (vtd_ce_get_type(&ce) == VTD_CONTEXT_TT_PASS_THROUGH);
} }
/* Return whether the device is using IOMMU translation. */ /* Return whether the device is using IOMMU translation. */
@ -1560,7 +1568,7 @@ static bool vtd_switch_address_space(VTDAddressSpace *as)
assert(as); assert(as);
use_iommu = as->iommu_state->dmar_enabled && !vtd_dev_pt_enabled(as); use_iommu = as->iommu_state->dmar_enabled && !vtd_as_pt_enabled(as);
trace_vtd_switch_address_space(pci_bus_num(as->bus), trace_vtd_switch_address_space(pci_bus_num(as->bus),
VTD_PCI_SLOT(as->devfn), VTD_PCI_SLOT(as->devfn),
@ -1753,7 +1761,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
* We don't need to translate for pass-through context entries. * We don't need to translate for pass-through context entries.
* Also, let's ignore IOTLB caching as well for PT devices. * Also, let's ignore IOTLB caching as well for PT devices.
*/ */
if (vtd_ce_get_type(&ce) == VTD_CONTEXT_TT_PASS_THROUGH) { if (vtd_dev_pt_enabled(s, &ce)) {
entry->iova = addr & VTD_PAGE_MASK_4K; entry->iova = addr & VTD_PAGE_MASK_4K;
entry->translated_addr = entry->iova; entry->translated_addr = entry->iova;
entry->addr_mask = ~VTD_PAGE_MASK_4K; entry->addr_mask = ~VTD_PAGE_MASK_4K;

View File

@ -77,6 +77,7 @@
#include "hw/mem/nvdimm.h" #include "hw/mem/nvdimm.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qapi-visit-common.h" #include "qapi/qapi-visit-common.h"
#include "qapi/qapi-visit-machine.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "hw/core/cpu.h" #include "hw/core/cpu.h"
#include "hw/usb.h" #include "hw/usb.h"
@ -94,7 +95,9 @@
#include "trace.h" #include "trace.h"
#include CONFIG_DEVICES #include CONFIG_DEVICES
GlobalProperty pc_compat_6_2[] = {}; GlobalProperty pc_compat_6_2[] = {
{ "virtio-mem", "unplugged-inaccessible", "off" },
};
const size_t pc_compat_6_2_len = G_N_ELEMENTS(pc_compat_6_2); const size_t pc_compat_6_2_len = G_N_ELEMENTS(pc_compat_6_2);
GlobalProperty pc_compat_6_1[] = { GlobalProperty pc_compat_6_1[] = {
@ -1524,6 +1527,23 @@ static void pc_machine_set_default_bus_bypass_iommu(Object *obj, bool value,
pcms->default_bus_bypass_iommu = value; pcms->default_bus_bypass_iommu = value;
} }
static void pc_machine_get_smbios_ep(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
SmbiosEntryPointType smbios_entry_point_type = pcms->smbios_entry_point_type;
visit_type_SmbiosEntryPointType(v, name, &smbios_entry_point_type, errp);
}
static void pc_machine_set_smbios_ep(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
visit_type_SmbiosEntryPointType(v, name, &pcms->smbios_entry_point_type, errp);
}
static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v, static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v,
const char *name, void *opaque, const char *name, void *opaque,
Error **errp) Error **errp)
@ -1614,6 +1634,8 @@ static void pc_machine_initfn(Object *obj)
pcms->vmport = ON_OFF_AUTO_OFF; pcms->vmport = ON_OFF_AUTO_OFF;
#endif /* CONFIG_VMPORT */ #endif /* CONFIG_VMPORT */
pcms->max_ram_below_4g = 0; /* use default */ pcms->max_ram_below_4g = 0; /* use default */
pcms->smbios_entry_point_type = SMBIOS_ENTRY_POINT_TYPE_32;
/* acpi build is enabled by default if machine supports it */ /* acpi build is enabled by default if machine supports it */
pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build;
pcms->smbus_enabled = true; pcms->smbus_enabled = true;
@ -1737,15 +1759,23 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, PC_MACHINE_SMBUS, object_class_property_add_bool(oc, PC_MACHINE_SMBUS,
pc_machine_get_smbus, pc_machine_set_smbus); pc_machine_get_smbus, pc_machine_set_smbus);
object_class_property_set_description(oc, PC_MACHINE_SMBUS,
"Enable/disable system management bus");
object_class_property_add_bool(oc, PC_MACHINE_SATA, object_class_property_add_bool(oc, PC_MACHINE_SATA,
pc_machine_get_sata, pc_machine_set_sata); pc_machine_get_sata, pc_machine_set_sata);
object_class_property_set_description(oc, PC_MACHINE_SATA,
"Enable/disable Serial ATA bus");
object_class_property_add_bool(oc, PC_MACHINE_PIT, object_class_property_add_bool(oc, PC_MACHINE_PIT,
pc_machine_get_pit, pc_machine_set_pit); pc_machine_get_pit, pc_machine_set_pit);
object_class_property_set_description(oc, PC_MACHINE_PIT,
"Enable/disable Intel 8254 programmable interval timer emulation");
object_class_property_add_bool(oc, "hpet", object_class_property_add_bool(oc, "hpet",
pc_machine_get_hpet, pc_machine_set_hpet); pc_machine_get_hpet, pc_machine_set_hpet);
object_class_property_set_description(oc, "hpet",
"Enable/disable high precision event timer emulation");
object_class_property_add_bool(oc, "default-bus-bypass-iommu", object_class_property_add_bool(oc, "default-bus-bypass-iommu",
pc_machine_get_default_bus_bypass_iommu, pc_machine_get_default_bus_bypass_iommu,
@ -1756,6 +1786,12 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
NULL, NULL); NULL, NULL);
object_class_property_set_description(oc, PC_MACHINE_MAX_FW_SIZE, object_class_property_set_description(oc, PC_MACHINE_MAX_FW_SIZE,
"Maximum combined firmware size"); "Maximum combined firmware size");
object_class_property_add(oc, PC_MACHINE_SMBIOS_EP, "str",
pc_machine_get_smbios_ep, pc_machine_set_smbios_ep,
NULL, NULL);
object_class_property_set_description(oc, PC_MACHINE_SMBIOS_EP,
"SMBIOS Entry Point type [32, 64]");
} }
static const TypeInfo pc_machine_info = { static const TypeInfo pc_machine_info = {

View File

@ -177,7 +177,7 @@ static void pc_init1(MachineState *machine,
smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)", smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
mc->name, pcmc->smbios_legacy_mode, mc->name, pcmc->smbios_legacy_mode,
pcmc->smbios_uuid_encoded, pcmc->smbios_uuid_encoded,
SMBIOS_ENTRY_POINT_21); pcms->smbios_entry_point_type);
} }
/* allocate ram and load rom/bios */ /* allocate ram and load rom/bios */

View File

@ -200,7 +200,7 @@ static void pc_q35_init(MachineState *machine)
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)", smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
mc->name, pcmc->smbios_legacy_mode, mc->name, pcmc->smbios_legacy_mode,
pcmc->smbios_uuid_encoded, pcmc->smbios_uuid_encoded,
SMBIOS_ENTRY_POINT_21); pcms->smbios_entry_point_type);
} }
/* allocate ram and load rom/bios */ /* allocate ram and load rom/bios */

View File

@ -101,3 +101,12 @@ int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
{ {
return 0; return 0;
} }
bool vhost_net_config_pending(VHostNetState *net)
{
return false;
}
void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask)
{
}

View File

@ -457,6 +457,15 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
vhost_virtqueue_mask(&net->dev, dev, idx, mask); vhost_virtqueue_mask(&net->dev, dev, idx, mask);
} }
bool vhost_net_config_pending(VHostNetState *net)
{
return vhost_config_pending(&net->dev);
}
void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask)
{
vhost_config_mask(&net->dev, dev, mask);
}
VHostNetState *get_vhost_net(NetClientState *nc) VHostNetState *get_vhost_net(NetClientState *nc)
{ {
VHostNetState *vhost_net = 0; VHostNetState *vhost_net = 0;

View File

@ -3168,6 +3168,9 @@ static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
VirtIONet *n = VIRTIO_NET(vdev); VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
assert(n->vhost_started); assert(n->vhost_started);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return vhost_net_config_pending(get_vhost_net(nc->peer));
}
return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx); return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx);
} }
@ -3177,8 +3180,11 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
VirtIONet *n = VIRTIO_NET(vdev); VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
assert(n->vhost_started); assert(n->vhost_started);
vhost_net_virtqueue_mask(get_vhost_net(nc->peer), if (idx == VIRTIO_CONFIG_IRQ_IDX) {
vdev, idx, mask); vhost_net_config_mask(get_vhost_net(nc->peer), vdev, mask);
return;
}
vhost_net_virtqueue_mask(get_vhost_net(nc->peer), vdev, idx, mask);
} }
static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features) static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features)

View File

@ -1390,7 +1390,7 @@ static void pci_update_mappings(PCIDevice *d)
/* now do the real mapping */ /* now do the real mapping */
if (r->addr != PCI_BAR_UNMAPPED) { if (r->addr != PCI_BAR_UNMAPPED) {
trace_pci_update_mappings_del(d, pci_dev_bus_num(d), trace_pci_update_mappings_del(d->name, pci_dev_bus_num(d),
PCI_SLOT(d->devfn), PCI_SLOT(d->devfn),
PCI_FUNC(d->devfn), PCI_FUNC(d->devfn),
i, r->addr, r->size); i, r->addr, r->size);
@ -1398,7 +1398,7 @@ static void pci_update_mappings(PCIDevice *d)
} }
r->addr = new_addr; r->addr = new_addr;
if (r->addr != PCI_BAR_UNMAPPED) { if (r->addr != PCI_BAR_UNMAPPED) {
trace_pci_update_mappings_add(d, pci_dev_bus_num(d), trace_pci_update_mappings_add(d->name, pci_dev_bus_num(d),
PCI_SLOT(d->devfn), PCI_SLOT(d->devfn),
PCI_FUNC(d->devfn), PCI_FUNC(d->devfn),
i, r->addr, r->size); i, r->addr, r->size);
@ -1497,11 +1497,6 @@ static void pci_irq_handler(void *opaque, int irq_num, int level)
pci_change_irq_level(pci_dev, irq_num, change); pci_change_irq_level(pci_dev, irq_num, change);
} }
static inline int pci_intx(PCIDevice *pci_dev)
{
return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
}
qemu_irq pci_allocate_irq(PCIDevice *pci_dev) qemu_irq pci_allocate_irq(PCIDevice *pci_dev)
{ {
int intx = pci_intx(pci_dev); int intx = pci_intx(pci_dev);

View File

@ -79,7 +79,8 @@ void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
return; return;
} }
trace_pci_cfg_write(pci_dev->name, PCI_SLOT(pci_dev->devfn), trace_pci_cfg_write(pci_dev->name, pci_dev_bus_num(pci_dev),
PCI_SLOT(pci_dev->devfn),
PCI_FUNC(pci_dev->devfn), addr, val); PCI_FUNC(pci_dev->devfn), addr, val);
pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr)); pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
} }
@ -104,7 +105,8 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
} }
ret = pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr)); ret = pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
trace_pci_cfg_read(pci_dev->name, PCI_SLOT(pci_dev->devfn), trace_pci_cfg_read(pci_dev->name, pci_dev_bus_num(pci_dev),
PCI_SLOT(pci_dev->devfn),
PCI_FUNC(pci_dev->devfn), addr, ret); PCI_FUNC(pci_dev->devfn), addr, ret);
return ret; return ret;

View File

@ -774,7 +774,9 @@ void pcie_aer_root_write_config(PCIDevice *dev,
uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
/* 6.2.4.1.2 Interrupt Generation */ /* 6.2.4.1.2 Interrupt Generation */
if (!msix_enabled(dev) && !msi_enabled(dev)) { if (!msix_enabled(dev) && !msi_enabled(dev)) {
if (pci_intx(dev) != -1) {
pci_set_irq(dev, !!(root_cmd & enabled_cmd)); pci_set_irq(dev, !!(root_cmd & enabled_cmd));
}
return; return;
} }

View File

@ -1,12 +1,12 @@
# See docs/devel/tracing.rst for syntax documentation. # See docs/devel/tracing.rst for syntax documentation.
# pci.c # pci.c
pci_update_mappings_del(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64 pci_update_mappings_del(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "%s %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64
pci_update_mappings_add(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64 pci_update_mappings_add(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "%s %02x:%02x.%x %d,0x%"PRIx64"+0x%"PRIx64
# pci_host.c # pci_host.c
pci_cfg_read(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x -> 0x%x" pci_cfg_read(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, unsigned offs, unsigned val) "%s %02x:%02x.%x @0x%x -> 0x%x"
pci_cfg_write(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x <- 0x%x" pci_cfg_write(const char *dev, uint32_t bus, uint32_t slot, uint32_t func, unsigned offs, unsigned val) "%s %02x:%02x.%x @0x%x <- 0x%x"
# msix.c # msix.c
msix_write_config(char *name, bool enabled, bool masked) "dev %s enabled %d masked %d" msix_write_config(char *name, bool enabled, bool masked) "dev %s enabled %d masked %d"

View File

@ -170,6 +170,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
Error *err = NULL; Error *err = NULL;
int vhostfd = -1; int vhostfd = -1;
int ret; int ret;
struct vhost_virtqueue *vqs = NULL;
if (!vs->conf.wwpn) { if (!vs->conf.wwpn) {
error_setg(errp, "vhost-scsi: missing wwpn"); error_setg(errp, "vhost-scsi: missing wwpn");
@ -213,13 +214,19 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
} }
vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs); vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs);
vsc->dev.vqs = vqs;
vsc->dev.vq_index = 0; vsc->dev.vq_index = 0;
vsc->dev.backend_features = 0; vsc->dev.backend_features = 0;
ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd, ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd,
VHOST_BACKEND_TYPE_KERNEL, 0, errp); VHOST_BACKEND_TYPE_KERNEL, 0, errp);
if (ret < 0) { if (ret < 0) {
/*
* vhost_dev_init calls vhost_dev_cleanup on error, which closes
* vhostfd, don't double close it.
*/
vhostfd = -1;
goto free_vqs; goto free_vqs;
} }
@ -232,7 +239,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
return; return;
free_vqs: free_vqs:
g_free(vsc->dev.vqs); g_free(vqs);
if (!vsc->migratable) { if (!vsc->migratable) {
migrate_del_blocker(vsc->migration_blocker); migrate_del_blocker(vsc->migration_blocker);
} }
@ -240,7 +247,9 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
error_free(vsc->migration_blocker); error_free(vsc->migration_blocker);
virtio_scsi_common_unrealize(dev); virtio_scsi_common_unrealize(dev);
close_fd: close_fd:
if (vhostfd >= 0) {
close(vhostfd); close(vhostfd);
}
return; return;
} }

View File

@ -62,7 +62,7 @@ uint8_t *smbios_tables;
size_t smbios_tables_len; size_t smbios_tables_len;
unsigned smbios_table_max; unsigned smbios_table_max;
unsigned smbios_table_cnt; unsigned smbios_table_cnt;
static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_21; static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32;
static SmbiosEntryPoint ep; static SmbiosEntryPoint ep;
@ -432,7 +432,7 @@ static void smbios_validate_table(MachineState *ms)
exit(1); exit(1);
} }
if (smbios_ep_type == SMBIOS_ENTRY_POINT_21 && if (smbios_ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) { smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) {
error_report("SMBIOS 2.1 table length %zu exceeds %d", error_report("SMBIOS 2.1 table length %zu exceeds %d",
smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN); smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
@ -927,7 +927,7 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
static void smbios_entry_point_setup(void) static void smbios_entry_point_setup(void)
{ {
switch (smbios_ep_type) { switch (smbios_ep_type) {
case SMBIOS_ENTRY_POINT_21: case SMBIOS_ENTRY_POINT_TYPE_32:
memcpy(ep.ep21.anchor_string, "_SM_", 4); memcpy(ep.ep21.anchor_string, "_SM_", 4);
memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5); memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5);
ep.ep21.length = sizeof(struct smbios_21_entry_point); ep.ep21.length = sizeof(struct smbios_21_entry_point);
@ -950,7 +950,7 @@ static void smbios_entry_point_setup(void)
ep.ep21.structure_table_address = cpu_to_le32(0); ep.ep21.structure_table_address = cpu_to_le32(0);
break; break;
case SMBIOS_ENTRY_POINT_30: case SMBIOS_ENTRY_POINT_TYPE_64:
memcpy(ep.ep30.anchor_string, "_SM3_", 5); memcpy(ep.ep30.anchor_string, "_SM3_", 5);
ep.ep30.length = sizeof(struct smbios_30_entry_point); ep.ep30.length = sizeof(struct smbios_30_entry_point);
ep.ep30.entry_point_revision = 1; ep.ep30.entry_point_revision = 1;

View File

@ -53,6 +53,7 @@ vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRI
vhost_vdpa_set_owner(void *dev) "dev: %p" vhost_vdpa_set_owner(void *dev) "dev: %p"
vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64 vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64
vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64 vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 0x%"PRIx64
vhost_vdpa_set_config_call(void *dev, int fd)"dev: %p fd: %d"
# virtio.c # virtio.c
virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"

View File

@ -47,7 +47,7 @@ static int vhost_kernel_cleanup(struct vhost_dev *dev)
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
return close(fd); return close(fd) < 0 ? -errno : 0;
} }
static int vhost_kernel_memslots_limit(struct vhost_dev *dev) static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
@ -58,7 +58,7 @@ static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions", if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions",
&s, NULL, NULL)) { &s, NULL, NULL)) {
uint64_t val = g_ascii_strtoull(s, NULL, 10); uint64_t val = g_ascii_strtoull(s, NULL, 10);
if (!((val == G_MAXUINT64 || !val) && errno)) { if (val < INT_MAX && val > 0) {
g_free(s); g_free(s);
return val; return val;
} }

View File

@ -161,6 +161,9 @@ static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx,
{ {
VHostUserFS *fs = VHOST_USER_FS(vdev); VHostUserFS *fs = VHOST_USER_FS(vdev);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return;
}
vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask); vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask);
} }
@ -168,6 +171,9 @@ static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx)
{ {
VHostUserFS *fs = VHOST_USER_FS(vdev); VHostUserFS *fs = VHOST_USER_FS(vdev);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return false;
}
return vhost_virtqueue_pending(&fs->vhost_dev, idx); return vhost_virtqueue_pending(&fs->vhost_dev, idx);
} }

View File

@ -280,9 +280,10 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg)
r = qemu_chr_fe_read_all(chr, p, size); r = qemu_chr_fe_read_all(chr, p, size);
if (r != size) { if (r != size) {
int saved_errno = errno;
error_report("Failed to read msg header. Read %d instead of %d." error_report("Failed to read msg header. Read %d instead of %d."
" Original request %d.", r, size, msg->hdr.request); " Original request %d.", r, size, msg->hdr.request);
return -1; return r < 0 ? -saved_errno : -EIO;
} }
/* validate received flags */ /* validate received flags */
@ -290,7 +291,7 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg)
error_report("Failed to read msg header." error_report("Failed to read msg header."
" Flags 0x%x instead of 0x%x.", msg->hdr.flags, " Flags 0x%x instead of 0x%x.", msg->hdr.flags,
VHOST_USER_REPLY_MASK | VHOST_USER_VERSION); VHOST_USER_REPLY_MASK | VHOST_USER_VERSION);
return -1; return -EPROTO;
} }
return 0; return 0;
@ -314,8 +315,9 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
uint8_t *p = (uint8_t *) msg; uint8_t *p = (uint8_t *) msg;
int r, size; int r, size;
if (vhost_user_read_header(dev, msg) < 0) { r = vhost_user_read_header(dev, msg);
data->ret = -1; if (r < 0) {
data->ret = r;
goto end; goto end;
} }
@ -324,7 +326,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
error_report("Failed to read msg header." error_report("Failed to read msg header."
" Size %d exceeds the maximum %zu.", msg->hdr.size, " Size %d exceeds the maximum %zu.", msg->hdr.size,
VHOST_USER_PAYLOAD_SIZE); VHOST_USER_PAYLOAD_SIZE);
data->ret = -1; data->ret = -EPROTO;
goto end; goto end;
} }
@ -333,9 +335,10 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
size = msg->hdr.size; size = msg->hdr.size;
r = qemu_chr_fe_read_all(chr, p, size); r = qemu_chr_fe_read_all(chr, p, size);
if (r != size) { if (r != size) {
int saved_errno = errno;
error_report("Failed to read msg payload." error_report("Failed to read msg payload."
" Read %d instead of %d.", r, msg->hdr.size); " Read %d instead of %d.", r, msg->hdr.size);
data->ret = -1; data->ret = r < 0 ? -saved_errno : -EIO;
goto end; goto end;
} }
} }
@ -418,24 +421,26 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
static int process_message_reply(struct vhost_dev *dev, static int process_message_reply(struct vhost_dev *dev,
const VhostUserMsg *msg) const VhostUserMsg *msg)
{ {
int ret;
VhostUserMsg msg_reply; VhostUserMsg msg_reply;
if ((msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) == 0) { if ((msg->hdr.flags & VHOST_USER_NEED_REPLY_MASK) == 0) {
return 0; return 0;
} }
if (vhost_user_read(dev, &msg_reply) < 0) { ret = vhost_user_read(dev, &msg_reply);
return -1; if (ret < 0) {
return ret;
} }
if (msg_reply.hdr.request != msg->hdr.request) { if (msg_reply.hdr.request != msg->hdr.request) {
error_report("Received unexpected msg type. " error_report("Received unexpected msg type. "
"Expected %d received %d", "Expected %d received %d",
msg->hdr.request, msg_reply.hdr.request); msg->hdr.request, msg_reply.hdr.request);
return -1; return -EPROTO;
} }
return msg_reply.payload.u64 ? -1 : 0; return msg_reply.payload.u64 ? -EIO : 0;
} }
static bool vhost_user_one_time_request(VhostUserRequest request) static bool vhost_user_one_time_request(VhostUserRequest request)
@ -472,14 +477,15 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) { if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) {
error_report("Failed to set msg fds."); error_report("Failed to set msg fds.");
return -1; return -EINVAL;
} }
ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size); ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size);
if (ret != size) { if (ret != size) {
int saved_errno = errno;
error_report("Failed to write msg." error_report("Failed to write msg."
" Wrote %d instead of %d.", ret, size); " Wrote %d instead of %d.", ret, size);
return -1; return ret < 0 ? -saved_errno : -EIO;
} }
return 0; return 0;
@ -502,6 +508,7 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
size_t fd_num = 0; size_t fd_num = 0;
bool shmfd = virtio_has_feature(dev->protocol_features, bool shmfd = virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_LOG_SHMFD); VHOST_USER_PROTOCOL_F_LOG_SHMFD);
int ret;
VhostUserMsg msg = { VhostUserMsg msg = {
.hdr.request = VHOST_USER_SET_LOG_BASE, .hdr.request = VHOST_USER_SET_LOG_BASE,
.hdr.flags = VHOST_USER_VERSION, .hdr.flags = VHOST_USER_VERSION,
@ -514,21 +521,23 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
fds[fd_num++] = log->fd; fds[fd_num++] = log->fd;
} }
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { ret = vhost_user_write(dev, &msg, fds, fd_num);
return -1; if (ret < 0) {
return ret;
} }
if (shmfd) { if (shmfd) {
msg.hdr.size = 0; msg.hdr.size = 0;
if (vhost_user_read(dev, &msg) < 0) { ret = vhost_user_read(dev, &msg);
return -1; if (ret < 0) {
return ret;
} }
if (msg.hdr.request != VHOST_USER_SET_LOG_BASE) { if (msg.hdr.request != VHOST_USER_SET_LOG_BASE) {
error_report("Received unexpected msg type. " error_report("Received unexpected msg type. "
"Expected %d received %d", "Expected %d received %d",
VHOST_USER_SET_LOG_BASE, msg.hdr.request); VHOST_USER_SET_LOG_BASE, msg.hdr.request);
return -1; return -EPROTO;
} }
} }
@ -588,7 +597,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u,
u->region_rb[i] = mr->ram_block; u->region_rb[i] = mr->ram_block;
} else if (*fd_num == VHOST_MEMORY_BASELINE_NREGIONS) { } else if (*fd_num == VHOST_MEMORY_BASELINE_NREGIONS) {
error_report("Failed preparing vhost-user memory table msg"); error_report("Failed preparing vhost-user memory table msg");
return -1; return -ENOBUFS;
} }
vhost_user_fill_msg_region(&region_buffer, reg, offset); vhost_user_fill_msg_region(&region_buffer, reg, offset);
msg->payload.memory.regions[*fd_num] = region_buffer; msg->payload.memory.regions[*fd_num] = region_buffer;
@ -604,14 +613,14 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u,
if (!*fd_num) { if (!*fd_num) {
error_report("Failed initializing vhost-user memory map, " error_report("Failed initializing vhost-user memory map, "
"consider using -object memory-backend-file share=on"); "consider using -object memory-backend-file share=on");
return -1; return -EINVAL;
} }
msg->hdr.size = sizeof(msg->payload.memory.nregions); msg->hdr.size = sizeof(msg->payload.memory.nregions);
msg->hdr.size += sizeof(msg->payload.memory.padding); msg->hdr.size += sizeof(msg->payload.memory.padding);
msg->hdr.size += *fd_num * sizeof(VhostUserMemoryRegion); msg->hdr.size += *fd_num * sizeof(VhostUserMemoryRegion);
return 1; return 0;
} }
static inline bool reg_equal(struct vhost_memory_region *shadow_reg, static inline bool reg_equal(struct vhost_memory_region *shadow_reg,
@ -741,8 +750,9 @@ static int send_remove_regions(struct vhost_dev *dev,
vhost_user_fill_msg_region(&region_buffer, shadow_reg, 0); vhost_user_fill_msg_region(&region_buffer, shadow_reg, 0);
msg->payload.mem_reg.region = region_buffer; msg->payload.mem_reg.region = region_buffer;
if (vhost_user_write(dev, msg, &fd, 1) < 0) { ret = vhost_user_write(dev, msg, &fd, 1);
return -1; if (ret < 0) {
return ret;
} }
if (reply_supported) { if (reply_supported) {
@ -801,15 +811,17 @@ static int send_add_regions(struct vhost_dev *dev,
vhost_user_fill_msg_region(&region_buffer, reg, offset); vhost_user_fill_msg_region(&region_buffer, reg, offset);
msg->payload.mem_reg.region = region_buffer; msg->payload.mem_reg.region = region_buffer;
if (vhost_user_write(dev, msg, &fd, 1) < 0) { ret = vhost_user_write(dev, msg, &fd, 1);
return -1; if (ret < 0) {
return ret;
} }
if (track_ramblocks) { if (track_ramblocks) {
uint64_t reply_gpa; uint64_t reply_gpa;
if (vhost_user_read(dev, &msg_reply) < 0) { ret = vhost_user_read(dev, &msg_reply);
return -1; if (ret < 0) {
return ret;
} }
reply_gpa = msg_reply.payload.mem_reg.region.guest_phys_addr; reply_gpa = msg_reply.payload.mem_reg.region.guest_phys_addr;
@ -819,7 +831,7 @@ static int send_add_regions(struct vhost_dev *dev,
"Expected %d received %d", __func__, "Expected %d received %d", __func__,
VHOST_USER_ADD_MEM_REG, VHOST_USER_ADD_MEM_REG,
msg_reply.hdr.request); msg_reply.hdr.request);
return -1; return -EPROTO;
} }
/* /*
@ -830,7 +842,7 @@ static int send_add_regions(struct vhost_dev *dev,
error_report("%s: Unexpected size for postcopy reply " error_report("%s: Unexpected size for postcopy reply "
"%d vs %d", __func__, msg_reply.hdr.size, "%d vs %d", __func__, msg_reply.hdr.size,
msg->hdr.size); msg->hdr.size);
return -1; return -EPROTO;
} }
/* Get the postcopy client base from the backend's reply. */ /* Get the postcopy client base from the backend's reply. */
@ -846,7 +858,7 @@ static int send_add_regions(struct vhost_dev *dev,
"Got guest physical address %" PRIX64 ", expected " "Got guest physical address %" PRIX64 ", expected "
"%" PRIX64, __func__, reply_gpa, "%" PRIX64, __func__, reply_gpa,
dev->mem->regions[reg_idx].guest_phys_addr); dev->mem->regions[reg_idx].guest_phys_addr);
return -1; return -EPROTO;
} }
} else if (reply_supported) { } else if (reply_supported) {
ret = process_message_reply(dev, msg); ret = process_message_reply(dev, msg);
@ -887,6 +899,7 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev,
struct scrub_regions rem_reg[VHOST_USER_MAX_RAM_SLOTS]; struct scrub_regions rem_reg[VHOST_USER_MAX_RAM_SLOTS];
uint64_t shadow_pcb[VHOST_USER_MAX_RAM_SLOTS] = {}; uint64_t shadow_pcb[VHOST_USER_MAX_RAM_SLOTS] = {};
int nr_add_reg, nr_rem_reg; int nr_add_reg, nr_rem_reg;
int ret;
msg->hdr.size = sizeof(msg->payload.mem_reg); msg->hdr.size = sizeof(msg->payload.mem_reg);
@ -894,17 +907,21 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev,
scrub_shadow_regions(dev, add_reg, &nr_add_reg, rem_reg, &nr_rem_reg, scrub_shadow_regions(dev, add_reg, &nr_add_reg, rem_reg, &nr_rem_reg,
shadow_pcb, track_ramblocks); shadow_pcb, track_ramblocks);
if (nr_rem_reg && send_remove_regions(dev, rem_reg, nr_rem_reg, msg, if (nr_rem_reg) {
reply_supported) < 0) ret = send_remove_regions(dev, rem_reg, nr_rem_reg, msg,
{ reply_supported);
if (ret < 0) {
goto err; goto err;
} }
}
if (nr_add_reg && send_add_regions(dev, add_reg, nr_add_reg, msg, if (nr_add_reg) {
shadow_pcb, reply_supported, track_ramblocks) < 0) ret = send_add_regions(dev, add_reg, nr_add_reg, msg, shadow_pcb,
{ reply_supported, track_ramblocks);
if (ret < 0) {
goto err; goto err;
} }
}
if (track_ramblocks) { if (track_ramblocks) {
memcpy(u->postcopy_client_bases, shadow_pcb, memcpy(u->postcopy_client_bases, shadow_pcb,
@ -918,8 +935,9 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev,
msg->hdr.size = sizeof(msg->payload.u64); msg->hdr.size = sizeof(msg->payload.u64);
msg->payload.u64 = 0; /* OK */ msg->payload.u64 = 0; /* OK */
if (vhost_user_write(dev, msg, NULL, 0) < 0) { ret = vhost_user_write(dev, msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
} }
@ -931,7 +949,7 @@ err:
sizeof(uint64_t) * VHOST_USER_MAX_RAM_SLOTS); sizeof(uint64_t) * VHOST_USER_MAX_RAM_SLOTS);
} }
return -1; return ret;
} }
static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
@ -944,6 +962,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
size_t fd_num = 0; size_t fd_num = 0;
VhostUserMsg msg_reply; VhostUserMsg msg_reply;
int region_i, msg_i; int region_i, msg_i;
int ret;
VhostUserMsg msg = { VhostUserMsg msg = {
.hdr.flags = VHOST_USER_VERSION, .hdr.flags = VHOST_USER_VERSION,
@ -961,29 +980,32 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
} }
if (config_mem_slots) { if (config_mem_slots) {
if (vhost_user_add_remove_regions(dev, &msg, reply_supported, ret = vhost_user_add_remove_regions(dev, &msg, reply_supported, true);
true) < 0) { if (ret < 0) {
return -1; return ret;
} }
} else { } else {
if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, ret = vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num,
true) < 0) { true);
return -1; if (ret < 0) {
return ret;
} }
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { ret = vhost_user_write(dev, &msg, fds, fd_num);
return -1; if (ret < 0) {
return ret;
} }
if (vhost_user_read(dev, &msg_reply) < 0) { ret = vhost_user_read(dev, &msg_reply);
return -1; if (ret < 0) {
return ret;
} }
if (msg_reply.hdr.request != VHOST_USER_SET_MEM_TABLE) { if (msg_reply.hdr.request != VHOST_USER_SET_MEM_TABLE) {
error_report("%s: Received unexpected msg type." error_report("%s: Received unexpected msg type."
"Expected %d received %d", __func__, "Expected %d received %d", __func__,
VHOST_USER_SET_MEM_TABLE, msg_reply.hdr.request); VHOST_USER_SET_MEM_TABLE, msg_reply.hdr.request);
return -1; return -EPROTO;
} }
/* /*
@ -994,7 +1016,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
error_report("%s: Unexpected size for postcopy reply " error_report("%s: Unexpected size for postcopy reply "
"%d vs %d", __func__, msg_reply.hdr.size, "%d vs %d", __func__, msg_reply.hdr.size,
msg.hdr.size); msg.hdr.size);
return -1; return -EPROTO;
} }
memset(u->postcopy_client_bases, 0, memset(u->postcopy_client_bases, 0,
@ -1024,7 +1046,7 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
error_report("%s: postcopy reply not fully consumed " error_report("%s: postcopy reply not fully consumed "
"%d vs %zd", "%d vs %zd",
__func__, msg_i, fd_num); __func__, msg_i, fd_num);
return -1; return -EIO;
} }
/* /*
@ -1035,8 +1057,9 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev,
/* TODO: Use this for failure cases as well with a bad value. */ /* TODO: Use this for failure cases as well with a bad value. */
msg.hdr.size = sizeof(msg.payload.u64); msg.hdr.size = sizeof(msg.payload.u64);
msg.payload.u64 = 0; /* OK */ msg.payload.u64 = 0; /* OK */
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
} }
@ -1055,6 +1078,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
bool config_mem_slots = bool config_mem_slots =
virtio_has_feature(dev->protocol_features, virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS); VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS);
int ret;
if (do_postcopy) { if (do_postcopy) {
/* /*
@ -1074,17 +1098,20 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
} }
if (config_mem_slots) { if (config_mem_slots) {
if (vhost_user_add_remove_regions(dev, &msg, reply_supported, ret = vhost_user_add_remove_regions(dev, &msg, reply_supported, false);
false) < 0) { if (ret < 0) {
return -1; return ret;
} }
} else { } else {
if (vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num, ret = vhost_user_fill_set_mem_table_msg(u, dev, &msg, fds, &fd_num,
false) < 0) { false);
return -1; if (ret < 0) {
return ret;
} }
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
return -1; ret = vhost_user_write(dev, &msg, fds, fd_num);
if (ret < 0) {
return ret;
} }
if (reply_supported) { if (reply_supported) {
@ -1109,14 +1136,10 @@ static int vhost_user_set_vring_endian(struct vhost_dev *dev,
if (!cross_endian) { if (!cross_endian) {
error_report("vhost-user trying to send unhandled ioctl"); error_report("vhost-user trying to send unhandled ioctl");
return -1; return -ENOTSUP;
} }
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { return vhost_user_write(dev, &msg, NULL, 0);
return -1;
}
return 0;
} }
static int vhost_set_vring(struct vhost_dev *dev, static int vhost_set_vring(struct vhost_dev *dev,
@ -1130,11 +1153,7 @@ static int vhost_set_vring(struct vhost_dev *dev,
.hdr.size = sizeof(msg.payload.state), .hdr.size = sizeof(msg.payload.state),
}; };
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { return vhost_user_write(dev, &msg, NULL, 0);
return -1;
}
return 0;
} }
static int vhost_user_set_vring_num(struct vhost_dev *dev, static int vhost_user_set_vring_num(struct vhost_dev *dev,
@ -1182,16 +1201,25 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
int i; int i;
if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) { if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) {
return -1; return -EINVAL;
} }
for (i = 0; i < dev->nvqs; ++i) { for (i = 0; i < dev->nvqs; ++i) {
int ret;
struct vhost_vring_state state = { struct vhost_vring_state state = {
.index = dev->vq_index + i, .index = dev->vq_index + i,
.num = enable, .num = enable,
}; };
vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state); ret = vhost_set_vring(dev, VHOST_USER_SET_VRING_ENABLE, &state);
if (ret < 0) {
/*
* Restoring the previous state is likely infeasible, as well as
* proceeding regardless the error, so just bail out and hope for
* the device-level recovery.
*/
return ret;
}
} }
return 0; return 0;
@ -1200,6 +1228,7 @@ static int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
static int vhost_user_get_vring_base(struct vhost_dev *dev, static int vhost_user_get_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring) struct vhost_vring_state *ring)
{ {
int ret;
VhostUserMsg msg = { VhostUserMsg msg = {
.hdr.request = VHOST_USER_GET_VRING_BASE, .hdr.request = VHOST_USER_GET_VRING_BASE,
.hdr.flags = VHOST_USER_VERSION, .hdr.flags = VHOST_USER_VERSION,
@ -1209,23 +1238,25 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
vhost_user_host_notifier_remove(dev, ring->index); vhost_user_host_notifier_remove(dev, ring->index);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
if (vhost_user_read(dev, &msg) < 0) { ret = vhost_user_read(dev, &msg);
return -1; if (ret < 0) {
return ret;
} }
if (msg.hdr.request != VHOST_USER_GET_VRING_BASE) { if (msg.hdr.request != VHOST_USER_GET_VRING_BASE) {
error_report("Received unexpected msg type. Expected %d received %d", error_report("Received unexpected msg type. Expected %d received %d",
VHOST_USER_GET_VRING_BASE, msg.hdr.request); VHOST_USER_GET_VRING_BASE, msg.hdr.request);
return -1; return -EPROTO;
} }
if (msg.hdr.size != sizeof(msg.payload.state)) { if (msg.hdr.size != sizeof(msg.payload.state)) {
error_report("Received bad msg size."); error_report("Received bad msg size.");
return -1; return -EPROTO;
} }
*ring = msg.payload.state; *ring = msg.payload.state;
@ -1252,11 +1283,7 @@ static int vhost_set_vring_file(struct vhost_dev *dev,
msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK; msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
} }
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { return vhost_user_write(dev, &msg, fds, fd_num);
return -1;
}
return 0;
} }
static int vhost_user_set_vring_kick(struct vhost_dev *dev, static int vhost_user_set_vring_kick(struct vhost_dev *dev,
@ -1274,6 +1301,7 @@ static int vhost_user_set_vring_call(struct vhost_dev *dev,
static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
{ {
int ret;
VhostUserMsg msg = { VhostUserMsg msg = {
.hdr.request = request, .hdr.request = request,
.hdr.flags = VHOST_USER_VERSION, .hdr.flags = VHOST_USER_VERSION,
@ -1283,23 +1311,25 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
return 0; return 0;
} }
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
if (vhost_user_read(dev, &msg) < 0) { ret = vhost_user_read(dev, &msg);
return -1; if (ret < 0) {
return ret;
} }
if (msg.hdr.request != request) { if (msg.hdr.request != request) {
error_report("Received unexpected msg type. Expected %d received %d", error_report("Received unexpected msg type. Expected %d received %d",
request, msg.hdr.request); request, msg.hdr.request);
return -1; return -EPROTO;
} }
if (msg.hdr.size != sizeof(msg.payload.u64)) { if (msg.hdr.size != sizeof(msg.payload.u64)) {
error_report("Received bad msg size."); error_report("Received bad msg size.");
return -1; return -EPROTO;
} }
*u64 = msg.payload.u64; *u64 = msg.payload.u64;
@ -1337,6 +1367,7 @@ static int enforce_reply(struct vhost_dev *dev,
static int vhost_user_set_vring_addr(struct vhost_dev *dev, static int vhost_user_set_vring_addr(struct vhost_dev *dev,
struct vhost_vring_addr *addr) struct vhost_vring_addr *addr)
{ {
int ret;
VhostUserMsg msg = { VhostUserMsg msg = {
.hdr.request = VHOST_USER_SET_VRING_ADDR, .hdr.request = VHOST_USER_SET_VRING_ADDR,
.hdr.flags = VHOST_USER_VERSION, .hdr.flags = VHOST_USER_VERSION,
@ -1357,8 +1388,9 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev,
msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
} }
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
if (wait_for_reply) { if (wait_for_reply) {
@ -1377,6 +1409,7 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64,
.payload.u64 = u64, .payload.u64 = u64,
.hdr.size = sizeof(msg.payload.u64), .hdr.size = sizeof(msg.payload.u64),
}; };
int ret;
if (wait_for_reply) { if (wait_for_reply) {
bool reply_supported = virtio_has_feature(dev->protocol_features, bool reply_supported = virtio_has_feature(dev->protocol_features,
@ -1386,8 +1419,9 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64,
} }
} }
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
if (wait_for_reply) { if (wait_for_reply) {
@ -1424,11 +1458,7 @@ static int vhost_user_set_owner(struct vhost_dev *dev)
.hdr.flags = VHOST_USER_VERSION, .hdr.flags = VHOST_USER_VERSION,
}; };
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { return vhost_user_write(dev, &msg, NULL, 0);
return -EPROTO;
}
return 0;
} }
static int vhost_user_get_max_memslots(struct vhost_dev *dev, static int vhost_user_get_max_memslots(struct vhost_dev *dev,
@ -1459,26 +1489,16 @@ static int vhost_user_reset_device(struct vhost_dev *dev)
? VHOST_USER_RESET_DEVICE ? VHOST_USER_RESET_DEVICE
: VHOST_USER_RESET_OWNER; : VHOST_USER_RESET_OWNER;
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { return vhost_user_write(dev, &msg, NULL, 0);
return -1;
}
return 0;
} }
static int vhost_user_slave_handle_config_change(struct vhost_dev *dev) static int vhost_user_slave_handle_config_change(struct vhost_dev *dev)
{ {
int ret = -1; if (!dev->config_ops || !dev->config_ops->vhost_dev_config_notifier) {
return -ENOSYS;
if (!dev->config_ops) {
return -1;
} }
if (dev->config_ops->vhost_dev_config_notifier) { return dev->config_ops->vhost_dev_config_notifier(dev);
ret = dev->config_ops->vhost_dev_config_notifier(dev);
}
return ret;
} }
static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
@ -1497,7 +1517,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
if (!virtio_has_feature(dev->protocol_features, if (!virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) || VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) ||
vdev == NULL || queue_idx >= virtio_get_num_queues(vdev)) { vdev == NULL || queue_idx >= virtio_get_num_queues(vdev)) {
return -1; return -EINVAL;
} }
n = &user->notifier[queue_idx]; n = &user->notifier[queue_idx];
@ -1515,13 +1535,13 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
/* Sanity check. */ /* Sanity check. */
if (area->size != page_size) { if (area->size != page_size) {
return -1; return -EINVAL;
} }
addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, area->offset); fd, area->offset);
if (addr == MAP_FAILED) { if (addr == MAP_FAILED) {
return -1; return -EFAULT;
} }
name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]", name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]",
@ -1534,7 +1554,7 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) { if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) {
object_unparent(OBJECT(&n->mr)); object_unparent(OBJECT(&n->mr));
munmap(addr, page_size); munmap(addr, page_size);
return -1; return -ENXIO;
} }
n->addr = addr; n->addr = addr;
@ -1664,14 +1684,15 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
} }
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
int saved_errno = errno;
error_report("socketpair() failed"); error_report("socketpair() failed");
return -1; return -saved_errno;
} }
ioc = QIO_CHANNEL(qio_channel_socket_new_fd(sv[0], &local_err)); ioc = QIO_CHANNEL(qio_channel_socket_new_fd(sv[0], &local_err));
if (!ioc) { if (!ioc) {
error_report_err(local_err); error_report_err(local_err);
return -1; return -ECONNREFUSED;
} }
u->slave_ioc = ioc; u->slave_ioc = ioc;
slave_update_read_handler(dev, NULL); slave_update_read_handler(dev, NULL);
@ -1778,35 +1799,38 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp)
struct vhost_user *u = dev->opaque; struct vhost_user *u = dev->opaque;
CharBackend *chr = u->user->chr; CharBackend *chr = u->user->chr;
int ufd; int ufd;
int ret;
VhostUserMsg msg = { VhostUserMsg msg = {
.hdr.request = VHOST_USER_POSTCOPY_ADVISE, .hdr.request = VHOST_USER_POSTCOPY_ADVISE,
.hdr.flags = VHOST_USER_VERSION, .hdr.flags = VHOST_USER_VERSION,
}; };
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
if (ret < 0) {
error_setg(errp, "Failed to send postcopy_advise to vhost"); error_setg(errp, "Failed to send postcopy_advise to vhost");
return -1; return ret;
} }
if (vhost_user_read(dev, &msg) < 0) { ret = vhost_user_read(dev, &msg);
if (ret < 0) {
error_setg(errp, "Failed to get postcopy_advise reply from vhost"); error_setg(errp, "Failed to get postcopy_advise reply from vhost");
return -1; return ret;
} }
if (msg.hdr.request != VHOST_USER_POSTCOPY_ADVISE) { if (msg.hdr.request != VHOST_USER_POSTCOPY_ADVISE) {
error_setg(errp, "Unexpected msg type. Expected %d received %d", error_setg(errp, "Unexpected msg type. Expected %d received %d",
VHOST_USER_POSTCOPY_ADVISE, msg.hdr.request); VHOST_USER_POSTCOPY_ADVISE, msg.hdr.request);
return -1; return -EPROTO;
} }
if (msg.hdr.size) { if (msg.hdr.size) {
error_setg(errp, "Received bad msg size."); error_setg(errp, "Received bad msg size.");
return -1; return -EPROTO;
} }
ufd = qemu_chr_fe_get_msgfd(chr); ufd = qemu_chr_fe_get_msgfd(chr);
if (ufd < 0) { if (ufd < 0) {
error_setg(errp, "%s: Failed to get ufd", __func__); error_setg(errp, "%s: Failed to get ufd", __func__);
return -1; return -EIO;
} }
qemu_set_nonblock(ufd); qemu_set_nonblock(ufd);
@ -1820,7 +1844,7 @@ static int vhost_user_postcopy_advise(struct vhost_dev *dev, Error **errp)
return 0; return 0;
#else #else
error_setg(errp, "Postcopy not supported on non-Linux systems"); error_setg(errp, "Postcopy not supported on non-Linux systems");
return -1; return -ENOSYS;
#endif #endif
} }
@ -1836,10 +1860,13 @@ static int vhost_user_postcopy_listen(struct vhost_dev *dev, Error **errp)
.hdr.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK, .hdr.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
}; };
u->postcopy_listen = true; u->postcopy_listen = true;
trace_vhost_user_postcopy_listen(); trace_vhost_user_postcopy_listen();
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
ret = vhost_user_write(dev, &msg, NULL, 0);
if (ret < 0) {
error_setg(errp, "Failed to send postcopy_listen to vhost"); error_setg(errp, "Failed to send postcopy_listen to vhost");
return -1; return ret;
} }
ret = process_message_reply(dev, &msg); ret = process_message_reply(dev, &msg);
@ -1864,9 +1891,11 @@ static int vhost_user_postcopy_end(struct vhost_dev *dev, Error **errp)
struct vhost_user *u = dev->opaque; struct vhost_user *u = dev->opaque;
trace_vhost_user_postcopy_end_entry(); trace_vhost_user_postcopy_end_entry();
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
ret = vhost_user_write(dev, &msg, NULL, 0);
if (ret < 0) {
error_setg(errp, "Failed to send postcopy_end to vhost"); error_setg(errp, "Failed to send postcopy_end to vhost");
return -1; return ret;
} }
ret = process_message_reply(dev, &msg); ret = process_message_reply(dev, &msg);
@ -2115,7 +2144,7 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
return vhost_user_write(dev, &msg, NULL, 0); return vhost_user_write(dev, &msg, NULL, 0);
} }
return -1; return -ENOTSUP;
} }
static bool vhost_user_can_merge(struct vhost_dev *dev, static bool vhost_user_can_merge(struct vhost_dev *dev,
@ -2136,6 +2165,7 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu)
VhostUserMsg msg; VhostUserMsg msg;
bool reply_supported = virtio_has_feature(dev->protocol_features, bool reply_supported = virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_REPLY_ACK); VHOST_USER_PROTOCOL_F_REPLY_ACK);
int ret;
if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) { if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) {
return 0; return 0;
@ -2149,8 +2179,9 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu)
msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
} }
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
/* If reply_ack supported, slave has to ack specified MTU is valid */ /* If reply_ack supported, slave has to ack specified MTU is valid */
@ -2164,6 +2195,7 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu)
static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev, static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev,
struct vhost_iotlb_msg *imsg) struct vhost_iotlb_msg *imsg)
{ {
int ret;
VhostUserMsg msg = { VhostUserMsg msg = {
.hdr.request = VHOST_USER_IOTLB_MSG, .hdr.request = VHOST_USER_IOTLB_MSG,
.hdr.size = sizeof(msg.payload.iotlb), .hdr.size = sizeof(msg.payload.iotlb),
@ -2171,8 +2203,9 @@ static int vhost_user_send_device_iotlb_msg(struct vhost_dev *dev,
.payload.iotlb = *imsg, .payload.iotlb = *imsg,
}; };
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -EFAULT; if (ret < 0) {
return ret;
} }
return process_message_reply(dev, &msg); return process_message_reply(dev, &msg);
@ -2187,6 +2220,7 @@ static void vhost_user_set_iotlb_callback(struct vhost_dev *dev, int enabled)
static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config,
uint32_t config_len, Error **errp) uint32_t config_len, Error **errp)
{ {
int ret;
VhostUserMsg msg = { VhostUserMsg msg = {
.hdr.request = VHOST_USER_GET_CONFIG, .hdr.request = VHOST_USER_GET_CONFIG,
.hdr.flags = VHOST_USER_VERSION, .hdr.flags = VHOST_USER_VERSION,
@ -2203,26 +2237,28 @@ static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config,
msg.payload.config.offset = 0; msg.payload.config.offset = 0;
msg.payload.config.size = config_len; msg.payload.config.size = config_len;
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
error_setg_errno(errp, EPROTO, "vhost_get_config failed"); if (ret < 0) {
return -EPROTO; error_setg_errno(errp, -ret, "vhost_get_config failed");
return ret;
} }
if (vhost_user_read(dev, &msg) < 0) { ret = vhost_user_read(dev, &msg);
error_setg_errno(errp, EPROTO, "vhost_get_config failed"); if (ret < 0) {
return -EPROTO; error_setg_errno(errp, -ret, "vhost_get_config failed");
return ret;
} }
if (msg.hdr.request != VHOST_USER_GET_CONFIG) { if (msg.hdr.request != VHOST_USER_GET_CONFIG) {
error_setg(errp, error_setg(errp,
"Received unexpected msg type. Expected %d received %d", "Received unexpected msg type. Expected %d received %d",
VHOST_USER_GET_CONFIG, msg.hdr.request); VHOST_USER_GET_CONFIG, msg.hdr.request);
return -EINVAL; return -EPROTO;
} }
if (msg.hdr.size != VHOST_USER_CONFIG_HDR_SIZE + config_len) { if (msg.hdr.size != VHOST_USER_CONFIG_HDR_SIZE + config_len) {
error_setg(errp, "Received bad msg size."); error_setg(errp, "Received bad msg size.");
return -EINVAL; return -EPROTO;
} }
memcpy(config, msg.payload.config.region, config_len); memcpy(config, msg.payload.config.region, config_len);
@ -2233,6 +2269,7 @@ static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config,
static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data,
uint32_t offset, uint32_t size, uint32_t flags) uint32_t offset, uint32_t size, uint32_t flags)
{ {
int ret;
uint8_t *p; uint8_t *p;
bool reply_supported = virtio_has_feature(dev->protocol_features, bool reply_supported = virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_REPLY_ACK); VHOST_USER_PROTOCOL_F_REPLY_ACK);
@ -2245,7 +2282,7 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data,
if (!virtio_has_feature(dev->protocol_features, if (!virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_CONFIG)) { VHOST_USER_PROTOCOL_F_CONFIG)) {
return -1; return -ENOTSUP;
} }
if (reply_supported) { if (reply_supported) {
@ -2253,7 +2290,7 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data,
} }
if (size > VHOST_USER_MAX_CONFIG_SIZE) { if (size > VHOST_USER_MAX_CONFIG_SIZE) {
return -1; return -EINVAL;
} }
msg.payload.config.offset = offset, msg.payload.config.offset = offset,
@ -2262,8 +2299,9 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data,
p = msg.payload.config.region; p = msg.payload.config.region;
memcpy(p, data, size); memcpy(p, data, size);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
if (reply_supported) { if (reply_supported) {
@ -2277,6 +2315,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev,
void *session_info, void *session_info,
uint64_t *session_id) uint64_t *session_id)
{ {
int ret;
bool crypto_session = virtio_has_feature(dev->protocol_features, bool crypto_session = virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_CRYPTO_SESSION); VHOST_USER_PROTOCOL_F_CRYPTO_SESSION);
CryptoDevBackendSymSessionInfo *sess_info = session_info; CryptoDevBackendSymSessionInfo *sess_info = session_info;
@ -2290,7 +2329,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev,
if (!crypto_session) { if (!crypto_session) {
error_report("vhost-user trying to send unhandled ioctl"); error_report("vhost-user trying to send unhandled ioctl");
return -1; return -ENOTSUP;
} }
memcpy(&msg.payload.session.session_setup_data, sess_info, memcpy(&msg.payload.session.session_setup_data, sess_info,
@ -2303,31 +2342,35 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev,
memcpy(&msg.payload.session.auth_key, sess_info->auth_key, memcpy(&msg.payload.session.auth_key, sess_info->auth_key,
sess_info->auth_key_len); sess_info->auth_key_len);
} }
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
error_report("vhost_user_write() return -1, create session failed"); if (ret < 0) {
return -1; error_report("vhost_user_write() return %d, create session failed",
ret);
return ret;
} }
if (vhost_user_read(dev, &msg) < 0) { ret = vhost_user_read(dev, &msg);
error_report("vhost_user_read() return -1, create session failed"); if (ret < 0) {
return -1; error_report("vhost_user_read() return %d, create session failed",
ret);
return ret;
} }
if (msg.hdr.request != VHOST_USER_CREATE_CRYPTO_SESSION) { if (msg.hdr.request != VHOST_USER_CREATE_CRYPTO_SESSION) {
error_report("Received unexpected msg type. Expected %d received %d", error_report("Received unexpected msg type. Expected %d received %d",
VHOST_USER_CREATE_CRYPTO_SESSION, msg.hdr.request); VHOST_USER_CREATE_CRYPTO_SESSION, msg.hdr.request);
return -1; return -EPROTO;
} }
if (msg.hdr.size != sizeof(msg.payload.session)) { if (msg.hdr.size != sizeof(msg.payload.session)) {
error_report("Received bad msg size."); error_report("Received bad msg size.");
return -1; return -EPROTO;
} }
if (msg.payload.session.session_id < 0) { if (msg.payload.session.session_id < 0) {
error_report("Bad session id: %" PRId64 "", error_report("Bad session id: %" PRId64 "",
msg.payload.session.session_id); msg.payload.session.session_id);
return -1; return -EINVAL;
} }
*session_id = msg.payload.session.session_id; *session_id = msg.payload.session.session_id;
@ -2337,6 +2380,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev,
static int static int
vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id) vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id)
{ {
int ret;
bool crypto_session = virtio_has_feature(dev->protocol_features, bool crypto_session = virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_CRYPTO_SESSION); VHOST_USER_PROTOCOL_F_CRYPTO_SESSION);
VhostUserMsg msg = { VhostUserMsg msg = {
@ -2348,12 +2392,14 @@ vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id)
if (!crypto_session) { if (!crypto_session) {
error_report("vhost-user trying to send unhandled ioctl"); error_report("vhost-user trying to send unhandled ioctl");
return -1; return -ENOTSUP;
} }
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
error_report("vhost_user_write() return -1, close session failed"); if (ret < 0) {
return -1; error_report("vhost_user_write() return %d, close session failed",
ret);
return ret;
} }
return 0; return 0;
@ -2375,6 +2421,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev,
{ {
void *addr; void *addr;
int fd; int fd;
int ret;
struct vhost_user *u = dev->opaque; struct vhost_user *u = dev->opaque;
CharBackend *chr = u->user->chr; CharBackend *chr = u->user->chr;
VhostUserMsg msg = { VhostUserMsg msg = {
@ -2390,24 +2437,26 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev,
return 0; return 0;
} }
if (vhost_user_write(dev, &msg, NULL, 0) < 0) { ret = vhost_user_write(dev, &msg, NULL, 0);
return -1; if (ret < 0) {
return ret;
} }
if (vhost_user_read(dev, &msg) < 0) { ret = vhost_user_read(dev, &msg);
return -1; if (ret < 0) {
return ret;
} }
if (msg.hdr.request != VHOST_USER_GET_INFLIGHT_FD) { if (msg.hdr.request != VHOST_USER_GET_INFLIGHT_FD) {
error_report("Received unexpected msg type. " error_report("Received unexpected msg type. "
"Expected %d received %d", "Expected %d received %d",
VHOST_USER_GET_INFLIGHT_FD, msg.hdr.request); VHOST_USER_GET_INFLIGHT_FD, msg.hdr.request);
return -1; return -EPROTO;
} }
if (msg.hdr.size != sizeof(msg.payload.inflight)) { if (msg.hdr.size != sizeof(msg.payload.inflight)) {
error_report("Received bad msg size."); error_report("Received bad msg size.");
return -1; return -EPROTO;
} }
if (!msg.payload.inflight.mmap_size) { if (!msg.payload.inflight.mmap_size) {
@ -2417,7 +2466,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev,
fd = qemu_chr_fe_get_msgfd(chr); fd = qemu_chr_fe_get_msgfd(chr);
if (fd < 0) { if (fd < 0) {
error_report("Failed to get mem fd"); error_report("Failed to get mem fd");
return -1; return -EIO;
} }
addr = mmap(0, msg.payload.inflight.mmap_size, PROT_READ | PROT_WRITE, addr = mmap(0, msg.payload.inflight.mmap_size, PROT_READ | PROT_WRITE,
@ -2426,7 +2475,7 @@ static int vhost_user_get_inflight_fd(struct vhost_dev *dev,
if (addr == MAP_FAILED) { if (addr == MAP_FAILED) {
error_report("Failed to mmap mem fd"); error_report("Failed to mmap mem fd");
close(fd); close(fd);
return -1; return -EFAULT;
} }
inflight->addr = addr; inflight->addr = addr;
@ -2456,11 +2505,7 @@ static int vhost_user_set_inflight_fd(struct vhost_dev *dev,
return 0; return 0;
} }
if (vhost_user_write(dev, &msg, &inflight->fd, 1) < 0) { return vhost_user_write(dev, &msg, &inflight->fd, 1);
return -1;
}
return 0;
} }
bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp)

View File

@ -292,18 +292,34 @@ static int vhost_vdpa_call(struct vhost_dev *dev, unsigned long int request,
return ret < 0 ? -errno : ret; return ret < 0 ? -errno : ret;
} }
static void vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status) static int vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status)
{ {
uint8_t s; uint8_t s;
int ret;
trace_vhost_vdpa_add_status(dev, status); trace_vhost_vdpa_add_status(dev, status);
if (vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s)) { ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s);
return; if (ret < 0) {
return ret;
} }
s |= status; s |= status;
vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s); ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s);
if (ret < 0) {
return ret;
}
ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s);
if (ret < 0) {
return ret;
}
if (!(s & status)) {
return -EIO;
}
return 0;
} }
static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v) static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v)
@ -484,7 +500,7 @@ static int vhost_vdpa_set_mem_table(struct vhost_dev *dev,
} }
} }
if (mem->padding) { if (mem->padding) {
return -1; return -EINVAL;
} }
return 0; return 0;
@ -501,14 +517,11 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev,
trace_vhost_vdpa_set_features(dev, features); trace_vhost_vdpa_set_features(dev, features);
ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features); ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features);
uint8_t status = 0;
if (ret) { if (ret) {
return ret; return ret;
} }
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status);
return !(status & VIRTIO_CONFIG_S_FEATURES_OK); return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
} }
static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev)
@ -650,12 +663,8 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
} }
if (started) { if (started) {
uint8_t status = 0;
memory_listener_register(&v->listener, &address_space_memory); memory_listener_register(&v->listener, &address_space_memory);
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status);
return !(status & VIRTIO_CONFIG_S_DRIVER_OK);
} else { } else {
vhost_vdpa_reset_device(dev); vhost_vdpa_reset_device(dev);
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
@ -725,6 +734,12 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd); trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd);
return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file); return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file);
} }
static int vhost_vdpa_set_config_call(struct vhost_dev *dev,
int fd)
{
trace_vhost_vdpa_set_config_call(dev, fd);
return vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG_CALL, &fd);
}
static int vhost_vdpa_get_features(struct vhost_dev *dev, static int vhost_vdpa_get_features(struct vhost_dev *dev,
uint64_t *features) uint64_t *features)
@ -795,4 +810,5 @@ const VhostOps vdpa_ops = {
.vhost_get_device_id = vhost_vdpa_get_device_id, .vhost_get_device_id = vhost_vdpa_get_device_id,
.vhost_vq_get_addr = vhost_vdpa_vq_get_addr, .vhost_vq_get_addr = vhost_vdpa_vq_get_addr,
.vhost_force_iommu = vhost_vdpa_force_iommu, .vhost_force_iommu = vhost_vdpa_force_iommu,
.vhost_set_config_call = vhost_vdpa_set_config_call,
}; };

View File

@ -125,6 +125,9 @@ static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx,
{ {
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return;
}
vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask); vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask);
} }
@ -133,6 +136,9 @@ static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev,
{ {
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return false;
}
return vhost_virtqueue_pending(&vvc->vhost_dev, idx); return vhost_virtqueue_pending(&vvc->vhost_dev, idx);
} }

View File

@ -171,6 +171,10 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd, ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd,
VHOST_BACKEND_TYPE_KERNEL, 0, errp); VHOST_BACKEND_TYPE_KERNEL, 0, errp);
if (ret < 0) { if (ret < 0) {
/*
* vhostfd is closed by vhost_dev_cleanup, which is called
* by vhost_dev_init on initialization error.
*/
goto err_virtio; goto err_virtio;
} }
@ -183,15 +187,10 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
return; return;
err_vhost_dev: err_vhost_dev:
vhost_dev_cleanup(&vvc->vhost_dev);
/* vhost_dev_cleanup() closes the vhostfd passed to vhost_dev_init() */ /* vhost_dev_cleanup() closes the vhostfd passed to vhost_dev_init() */
vhostfd = -1; vhost_dev_cleanup(&vvc->vhost_dev);
err_virtio: err_virtio:
vhost_vsock_common_unrealize(vdev); vhost_vsock_common_unrealize(vdev);
if (vhostfd >= 0) {
close(vhostfd);
}
return;
} }
static void vhost_vsock_device_unrealize(DeviceState *dev) static void vhost_vsock_device_unrealize(DeviceState *dev)

View File

@ -33,11 +33,13 @@
#define _VHOST_DEBUG 1 #define _VHOST_DEBUG 1
#ifdef _VHOST_DEBUG #ifdef _VHOST_DEBUG
#define VHOST_OPS_DEBUG(fmt, ...) \ #define VHOST_OPS_DEBUG(retval, fmt, ...) \
do { error_report(fmt ": %s (%d)", ## __VA_ARGS__, \ do { \
strerror(errno), errno); } while (0) error_report(fmt ": %s (%d)", ## __VA_ARGS__, \
strerror(-retval), -retval); \
} while (0)
#else #else
#define VHOST_OPS_DEBUG(fmt, ...) \ #define VHOST_OPS_DEBUG(retval, fmt, ...) \
do { } while (0) do { } while (0)
#endif #endif
@ -297,7 +299,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
releasing the current log, to ensure no logging is lost */ releasing the current log, to ensure no logging is lost */
r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log); r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_log_base failed"); VHOST_OPS_DEBUG(r, "vhost_set_log_base failed");
} }
vhost_log_put(dev, true); vhost_log_put(dev, true);
@ -550,7 +552,7 @@ static void vhost_commit(MemoryListener *listener)
if (!dev->log_enabled) { if (!dev->log_enabled) {
r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem); r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_mem_table failed"); VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed");
} }
goto out; goto out;
} }
@ -564,7 +566,7 @@ static void vhost_commit(MemoryListener *listener)
} }
r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem); r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_mem_table failed"); VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed");
} }
/* To log less, can only decrease log size after table update. */ /* To log less, can only decrease log size after table update. */
if (dev->log_size > log_size + VHOST_LOG_BUFFER) { if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
@ -803,8 +805,8 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
if (dev->vhost_ops->vhost_vq_get_addr) { if (dev->vhost_ops->vhost_vq_get_addr) {
r = dev->vhost_ops->vhost_vq_get_addr(dev, &addr, vq); r = dev->vhost_ops->vhost_vq_get_addr(dev, &addr, vq);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_vq_get_addr failed"); VHOST_OPS_DEBUG(r, "vhost_vq_get_addr failed");
return -errno; return r;
} }
} else { } else {
addr.desc_user_addr = (uint64_t)(unsigned long)vq->desc; addr.desc_user_addr = (uint64_t)(unsigned long)vq->desc;
@ -816,10 +818,9 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
addr.flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0; addr.flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0;
r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr); r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_vring_addr failed"); VHOST_OPS_DEBUG(r, "vhost_set_vring_addr failed");
return -errno;
} }
return 0; return r;
} }
static int vhost_dev_set_features(struct vhost_dev *dev, static int vhost_dev_set_features(struct vhost_dev *dev,
@ -840,19 +841,19 @@ static int vhost_dev_set_features(struct vhost_dev *dev,
} }
r = dev->vhost_ops->vhost_set_features(dev, features); r = dev->vhost_ops->vhost_set_features(dev, features);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_features failed"); VHOST_OPS_DEBUG(r, "vhost_set_features failed");
goto out; goto out;
} }
if (dev->vhost_ops->vhost_set_backend_cap) { if (dev->vhost_ops->vhost_set_backend_cap) {
r = dev->vhost_ops->vhost_set_backend_cap(dev); r = dev->vhost_ops->vhost_set_backend_cap(dev);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_backend_cap failed"); VHOST_OPS_DEBUG(r, "vhost_set_backend_cap failed");
goto out; goto out;
} }
} }
out: out:
return r < 0 ? -errno : 0; return r;
} }
static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
@ -999,22 +1000,17 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
bool is_big_endian, bool is_big_endian,
int vhost_vq_index) int vhost_vq_index)
{ {
int r;
struct vhost_vring_state s = { struct vhost_vring_state s = {
.index = vhost_vq_index, .index = vhost_vq_index,
.num = is_big_endian .num = is_big_endian
}; };
if (!dev->vhost_ops->vhost_set_vring_endian(dev, &s)) { r = dev->vhost_ops->vhost_set_vring_endian(dev, &s);
return 0; if (r < 0) {
VHOST_OPS_DEBUG(r, "vhost_set_vring_endian failed");
} }
return r;
VHOST_OPS_DEBUG("vhost_set_vring_endian failed");
if (errno == ENOTTY) {
error_report("vhost does not support cross-endian");
return -ENOSYS;
}
return -errno;
} }
static int vhost_memory_region_lookup(struct vhost_dev *hdev, static int vhost_memory_region_lookup(struct vhost_dev *hdev,
@ -1106,15 +1102,15 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
vq->num = state.num = virtio_queue_get_num(vdev, idx); vq->num = state.num = virtio_queue_get_num(vdev, idx);
r = dev->vhost_ops->vhost_set_vring_num(dev, &state); r = dev->vhost_ops->vhost_set_vring_num(dev, &state);
if (r) { if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_num failed"); VHOST_OPS_DEBUG(r, "vhost_set_vring_num failed");
return -errno; return r;
} }
state.num = virtio_queue_get_last_avail_idx(vdev, idx); state.num = virtio_queue_get_last_avail_idx(vdev, idx);
r = dev->vhost_ops->vhost_set_vring_base(dev, &state); r = dev->vhost_ops->vhost_set_vring_base(dev, &state);
if (r) { if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_base failed"); VHOST_OPS_DEBUG(r, "vhost_set_vring_base failed");
return -errno; return r;
} }
if (vhost_needs_vring_endian(vdev)) { if (vhost_needs_vring_endian(vdev)) {
@ -1122,7 +1118,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
virtio_is_big_endian(vdev), virtio_is_big_endian(vdev),
vhost_vq_index); vhost_vq_index);
if (r) { if (r) {
return -errno; return r;
} }
} }
@ -1150,15 +1146,13 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled); r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled);
if (r < 0) { if (r < 0) {
r = -errno;
goto fail_alloc; goto fail_alloc;
} }
file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
r = dev->vhost_ops->vhost_set_vring_kick(dev, &file); r = dev->vhost_ops->vhost_set_vring_kick(dev, &file);
if (r) { if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_kick failed"); VHOST_OPS_DEBUG(r, "vhost_set_vring_kick failed");
r = -errno;
goto fail_kick; goto fail_kick;
} }
@ -1218,7 +1212,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
r = dev->vhost_ops->vhost_get_vring_base(dev, &state); r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost VQ %u ring restore failed: %d", idx, r); VHOST_OPS_DEBUG(r, "vhost VQ %u ring restore failed: %d", idx, r);
/* Connection to the backend is broken, so let's sync internal /* Connection to the backend is broken, so let's sync internal
* last avail idx to the device used idx. * last avail idx to the device used idx.
*/ */
@ -1274,7 +1268,7 @@ static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev,
r = dev->vhost_ops->vhost_set_vring_busyloop_timeout(dev, &state); r = dev->vhost_ops->vhost_set_vring_busyloop_timeout(dev, &state);
if (r) { if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_busyloop_timeout failed"); VHOST_OPS_DEBUG(r, "vhost_set_vring_busyloop_timeout failed");
return r; return r;
} }
@ -1296,8 +1290,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
file.fd = event_notifier_get_fd(&vq->masked_notifier); file.fd = event_notifier_get_fd(&vq->masked_notifier);
r = dev->vhost_ops->vhost_set_vring_call(dev, &file); r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
if (r) { if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_call failed"); VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed");
r = -errno;
goto fail_call; goto fail_call;
} }
@ -1557,7 +1550,68 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n);
r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file); r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_vring_call failed"); VHOST_OPS_DEBUG(r, "vhost_set_vring_call failed");
}
}
bool vhost_config_pending(struct vhost_dev *hdev)
{
assert(hdev->vhost_ops);
if ((hdev->started == false) ||
(hdev->vhost_ops->vhost_set_config_call == NULL)) {
return false;
}
EventNotifier *notifier =
&hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier;
return event_notifier_test_and_clear(notifier);
}
void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask)
{
int fd;
int r;
EventNotifier *notifier =
&hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier;
EventNotifier *config_notifier = &vdev->config_notifier;
assert(hdev->vhost_ops);
if ((hdev->started == false) ||
(hdev->vhost_ops->vhost_set_config_call == NULL)) {
return;
}
if (mask) {
assert(vdev->use_guest_notifier_mask);
fd = event_notifier_get_fd(notifier);
} else {
fd = event_notifier_get_fd(config_notifier);
}
r = hdev->vhost_ops->vhost_set_config_call(hdev, fd);
if (r < 0) {
VHOST_OPS_DEBUG(r, "vhost_set_config_call failed");
}
}
static void vhost_stop_config_intr(struct vhost_dev *dev)
{
int fd = -1;
assert(dev->vhost_ops);
if (dev->vhost_ops->vhost_set_config_call) {
dev->vhost_ops->vhost_set_config_call(dev, fd);
}
}
static void vhost_start_config_intr(struct vhost_dev *dev)
{
int r;
assert(dev->vhost_ops);
int fd = event_notifier_get_fd(&dev->vdev->config_notifier);
if (dev->vhost_ops->vhost_set_config_call) {
r = dev->vhost_ops->vhost_set_config_call(dev, fd);
if (!r) {
event_notifier_set(&dev->vdev->config_notifier);
}
} }
} }
@ -1599,7 +1653,7 @@ int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config,
} }
error_setg(errp, "vhost_get_config not implemented"); error_setg(errp, "vhost_get_config not implemented");
return -ENOTSUP; return -ENOSYS;
} }
int vhost_dev_set_config(struct vhost_dev *hdev, const uint8_t *data, int vhost_dev_set_config(struct vhost_dev *hdev, const uint8_t *data,
@ -1612,7 +1666,7 @@ int vhost_dev_set_config(struct vhost_dev *hdev, const uint8_t *data,
size, flags); size, flags);
} }
return -1; return -ENOSYS;
} }
void vhost_dev_set_config_notifier(struct vhost_dev *hdev, void vhost_dev_set_config_notifier(struct vhost_dev *hdev,
@ -1641,7 +1695,7 @@ static int vhost_dev_resize_inflight(struct vhost_inflight *inflight,
if (err) { if (err) {
error_report_err(err); error_report_err(err);
return -1; return -ENOMEM;
} }
vhost_dev_free_inflight(inflight); vhost_dev_free_inflight(inflight);
@ -1674,8 +1728,9 @@ int vhost_dev_load_inflight(struct vhost_inflight *inflight, QEMUFile *f)
} }
if (inflight->size != size) { if (inflight->size != size) {
if (vhost_dev_resize_inflight(inflight, size)) { int ret = vhost_dev_resize_inflight(inflight, size);
return -1; if (ret < 0) {
return ret;
} }
} }
inflight->queue_size = qemu_get_be16(f); inflight->queue_size = qemu_get_be16(f);
@ -1698,7 +1753,7 @@ int vhost_dev_prepare_inflight(struct vhost_dev *hdev, VirtIODevice *vdev)
r = vhost_dev_set_features(hdev, hdev->log_enabled); r = vhost_dev_set_features(hdev, hdev->log_enabled);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_dev_prepare_inflight failed"); VHOST_OPS_DEBUG(r, "vhost_dev_prepare_inflight failed");
return r; return r;
} }
@ -1713,8 +1768,8 @@ int vhost_dev_set_inflight(struct vhost_dev *dev,
if (dev->vhost_ops->vhost_set_inflight_fd && inflight->addr) { if (dev->vhost_ops->vhost_set_inflight_fd && inflight->addr) {
r = dev->vhost_ops->vhost_set_inflight_fd(dev, inflight); r = dev->vhost_ops->vhost_set_inflight_fd(dev, inflight);
if (r) { if (r) {
VHOST_OPS_DEBUG("vhost_set_inflight_fd failed"); VHOST_OPS_DEBUG(r, "vhost_set_inflight_fd failed");
return -errno; return r;
} }
} }
@ -1729,8 +1784,8 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size,
if (dev->vhost_ops->vhost_get_inflight_fd) { if (dev->vhost_ops->vhost_get_inflight_fd) {
r = dev->vhost_ops->vhost_get_inflight_fd(dev, queue_size, inflight); r = dev->vhost_ops->vhost_get_inflight_fd(dev, queue_size, inflight);
if (r) { if (r) {
VHOST_OPS_DEBUG("vhost_get_inflight_fd failed"); VHOST_OPS_DEBUG(r, "vhost_get_inflight_fd failed");
return -errno; return r;
} }
} }
@ -1759,8 +1814,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem); r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_mem_table failed"); VHOST_OPS_DEBUG(r, "vhost_set_mem_table failed");
r = -errno;
goto fail_mem; goto fail_mem;
} }
for (i = 0; i < hdev->nvqs; ++i) { for (i = 0; i < hdev->nvqs; ++i) {
@ -1773,6 +1827,16 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
} }
} }
r = event_notifier_init(
&hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0);
if (r < 0) {
return r;
}
event_notifier_test_and_clear(
&hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier);
if (!vdev->use_guest_notifier_mask) {
vhost_config_mask(hdev, vdev, true);
}
if (hdev->log_enabled) { if (hdev->log_enabled) {
uint64_t log_base; uint64_t log_base;
@ -1784,8 +1848,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
hdev->log_size ? log_base : 0, hdev->log_size ? log_base : 0,
hdev->log); hdev->log);
if (r < 0) { if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_log_base failed"); VHOST_OPS_DEBUG(r, "vhost_set_log_base failed");
r = -errno;
goto fail_log; goto fail_log;
} }
} }
@ -1806,6 +1869,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
vhost_device_iotlb_miss(hdev, vq->used_phys, true); vhost_device_iotlb_miss(hdev, vq->used_phys, true);
} }
} }
vhost_start_config_intr(hdev);
return 0; return 0;
fail_log: fail_log:
vhost_log_put(hdev, false); vhost_log_put(hdev, false);
@ -1831,6 +1895,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
/* should only be called after backend is connected */ /* should only be called after backend is connected */
assert(hdev->vhost_ops); assert(hdev->vhost_ops);
event_notifier_test_and_clear(
&hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier);
event_notifier_test_and_clear(&vdev->config_notifier);
if (hdev->vhost_ops->vhost_dev_start) { if (hdev->vhost_ops->vhost_dev_start) {
hdev->vhost_ops->vhost_dev_start(hdev, false); hdev->vhost_ops->vhost_dev_start(hdev, false);
@ -1848,6 +1915,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
} }
memory_listener_unregister(&hdev->iommu_listener); memory_listener_unregister(&hdev->iommu_listener);
} }
vhost_stop_config_intr(hdev);
vhost_log_put(hdev, true); vhost_log_put(hdev, true);
hdev->started = false; hdev->started = false;
hdev->vdev = NULL; hdev->vdev = NULL;
@ -1860,5 +1928,5 @@ int vhost_net_set_backend(struct vhost_dev *hdev,
return hdev->vhost_ops->vhost_net_set_backend(hdev, file); return hdev->vhost_ops->vhost_net_set_backend(hdev, file);
} }
return -1; return -ENOSYS;
} }

View File

@ -948,6 +948,9 @@ static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx,
assert(vcrypto->vhost_started); assert(vcrypto->vhost_started);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return;
}
cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask); cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask);
} }
@ -958,6 +961,9 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx)
assert(vcrypto->vhost_started); assert(vcrypto->vhost_started);
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
return false;
}
return cryptodev_vhost_virtqueue_pending(vdev, queue, idx); return cryptodev_vhost_virtqueue_pending(vdev, queue, idx);
} }

View File

@ -32,6 +32,14 @@
#include CONFIG_DEVICES #include CONFIG_DEVICES
#include "trace.h" #include "trace.h"
/*
* We only had legacy x86 guests that did not support
* VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. Other targets don't have legacy guests.
*/
#if defined(TARGET_X86_64) || defined(TARGET_I386)
#define VIRTIO_MEM_HAS_LEGACY_GUESTS
#endif
/* /*
* Let's not allow blocks smaller than 1 MiB, for example, to keep the tracking * Let's not allow blocks smaller than 1 MiB, for example, to keep the tracking
* bitmap small. * bitmap small.
@ -110,6 +118,19 @@ static uint64_t virtio_mem_default_block_size(RAMBlock *rb)
return MAX(page_size, VIRTIO_MEM_MIN_BLOCK_SIZE); return MAX(page_size, VIRTIO_MEM_MIN_BLOCK_SIZE);
} }
#if defined(VIRTIO_MEM_HAS_LEGACY_GUESTS)
static bool virtio_mem_has_shared_zeropage(RAMBlock *rb)
{
/*
* We only have a guaranteed shared zeropage on ordinary MAP_PRIVATE
* anonymous RAM. In any other case, reading unplugged *can* populate a
* fresh page, consuming actual memory.
*/
return !qemu_ram_is_shared(rb) && rb->fd < 0 &&
qemu_ram_pagesize(rb) == qemu_real_host_page_size;
}
#endif /* VIRTIO_MEM_HAS_LEGACY_GUESTS */
/* /*
* Size the usable region bigger than the requested size if possible. Esp. * Size the usable region bigger than the requested size if possible. Esp.
* Linux guests will only add (aligned) memory blocks in case they fully * Linux guests will only add (aligned) memory blocks in case they fully
@ -429,11 +450,41 @@ static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa,
return -EBUSY; return -EBUSY;
} }
virtio_mem_notify_unplug(vmem, offset, size); virtio_mem_notify_unplug(vmem, offset, size);
} else if (virtio_mem_notify_plug(vmem, offset, size)) { } else {
/* Could be a mapping attempt resulted in memory getting populated. */ int ret = 0;
if (vmem->prealloc) {
void *area = memory_region_get_ram_ptr(&vmem->memdev->mr) + offset;
int fd = memory_region_get_fd(&vmem->memdev->mr);
Error *local_err = NULL;
os_mem_prealloc(fd, area, size, 1, &local_err);
if (local_err) {
static bool warned;
/*
* Warn only once, we don't want to fill the log with these
* warnings.
*/
if (!warned) {
warn_report_err(local_err);
warned = true;
} else {
error_free(local_err);
}
ret = -EBUSY;
}
}
if (!ret) {
ret = virtio_mem_notify_plug(vmem, offset, size);
}
if (ret) {
/* Could be preallocation or a notifier populated memory. */
ram_block_discard_range(vmem->memdev->mr.ram_block, offset, size); ram_block_discard_range(vmem->memdev->mr.ram_block, offset, size);
return -EBUSY; return -EBUSY;
} }
}
virtio_mem_set_bitmap(vmem, start_gpa, size, plug); virtio_mem_set_bitmap(vmem, start_gpa, size, plug);
return 0; return 0;
} }
@ -653,15 +704,29 @@ static uint64_t virtio_mem_get_features(VirtIODevice *vdev, uint64_t features,
Error **errp) Error **errp)
{ {
MachineState *ms = MACHINE(qdev_get_machine()); MachineState *ms = MACHINE(qdev_get_machine());
VirtIOMEM *vmem = VIRTIO_MEM(vdev);
if (ms->numa_state) { if (ms->numa_state) {
#if defined(CONFIG_ACPI) #if defined(CONFIG_ACPI)
virtio_add_feature(&features, VIRTIO_MEM_F_ACPI_PXM); virtio_add_feature(&features, VIRTIO_MEM_F_ACPI_PXM);
#endif #endif
} }
assert(vmem->unplugged_inaccessible != ON_OFF_AUTO_AUTO);
if (vmem->unplugged_inaccessible == ON_OFF_AUTO_ON) {
virtio_add_feature(&features, VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE);
}
return features; return features;
} }
static int virtio_mem_validate_features(VirtIODevice *vdev)
{
if (virtio_host_has_feature(vdev, VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE) &&
!virtio_vdev_has_feature(vdev, VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE)) {
return -EFAULT;
}
return 0;
}
static void virtio_mem_system_reset(void *opaque) static void virtio_mem_system_reset(void *opaque)
{ {
VirtIOMEM *vmem = VIRTIO_MEM(opaque); VirtIOMEM *vmem = VIRTIO_MEM(opaque);
@ -716,6 +781,29 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
rb = vmem->memdev->mr.ram_block; rb = vmem->memdev->mr.ram_block;
page_size = qemu_ram_pagesize(rb); page_size = qemu_ram_pagesize(rb);
#if defined(VIRTIO_MEM_HAS_LEGACY_GUESTS)
switch (vmem->unplugged_inaccessible) {
case ON_OFF_AUTO_AUTO:
if (virtio_mem_has_shared_zeropage(rb)) {
vmem->unplugged_inaccessible = ON_OFF_AUTO_OFF;
} else {
vmem->unplugged_inaccessible = ON_OFF_AUTO_ON;
}
break;
case ON_OFF_AUTO_OFF:
if (!virtio_mem_has_shared_zeropage(rb)) {
warn_report("'%s' property set to 'off' with a memdev that does"
" not support the shared zeropage.",
VIRTIO_MEM_UNPLUGGED_INACCESSIBLE_PROP);
}
break;
default:
break;
}
#else /* VIRTIO_MEM_HAS_LEGACY_GUESTS */
vmem->unplugged_inaccessible = ON_OFF_AUTO_ON;
#endif /* VIRTIO_MEM_HAS_LEGACY_GUESTS */
/* /*
* If the block size wasn't configured by the user, use a sane default. This * If the block size wasn't configured by the user, use a sane default. This
* allows using hugetlbfs backends of any page size without manual * allows using hugetlbfs backends of any page size without manual
@ -733,7 +821,8 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
warn_report("'%s' property is smaller than the default block size (%" warn_report("'%s' property is smaller than the default block size (%"
PRIx64 " MiB)", VIRTIO_MEM_BLOCK_SIZE_PROP, PRIx64 " MiB)", VIRTIO_MEM_BLOCK_SIZE_PROP,
virtio_mem_default_block_size(rb) / MiB); virtio_mem_default_block_size(rb) / MiB);
} else if (!QEMU_IS_ALIGNED(vmem->requested_size, vmem->block_size)) { }
if (!QEMU_IS_ALIGNED(vmem->requested_size, vmem->block_size)) {
error_setg(errp, "'%s' property has to be multiples of '%s' (0x%" PRIx64 error_setg(errp, "'%s' property has to be multiples of '%s' (0x%" PRIx64
")", VIRTIO_MEM_REQUESTED_SIZE_PROP, ")", VIRTIO_MEM_REQUESTED_SIZE_PROP,
VIRTIO_MEM_BLOCK_SIZE_PROP, vmem->block_size); VIRTIO_MEM_BLOCK_SIZE_PROP, vmem->block_size);
@ -1107,8 +1196,13 @@ static void virtio_mem_instance_init(Object *obj)
static Property virtio_mem_properties[] = { static Property virtio_mem_properties[] = {
DEFINE_PROP_UINT64(VIRTIO_MEM_ADDR_PROP, VirtIOMEM, addr, 0), DEFINE_PROP_UINT64(VIRTIO_MEM_ADDR_PROP, VirtIOMEM, addr, 0),
DEFINE_PROP_UINT32(VIRTIO_MEM_NODE_PROP, VirtIOMEM, node, 0), DEFINE_PROP_UINT32(VIRTIO_MEM_NODE_PROP, VirtIOMEM, node, 0),
DEFINE_PROP_BOOL(VIRTIO_MEM_PREALLOC_PROP, VirtIOMEM, prealloc, false),
DEFINE_PROP_LINK(VIRTIO_MEM_MEMDEV_PROP, VirtIOMEM, memdev, DEFINE_PROP_LINK(VIRTIO_MEM_MEMDEV_PROP, VirtIOMEM, memdev,
TYPE_MEMORY_BACKEND, HostMemoryBackend *), TYPE_MEMORY_BACKEND, HostMemoryBackend *),
#if defined(VIRTIO_MEM_HAS_LEGACY_GUESTS)
DEFINE_PROP_ON_OFF_AUTO(VIRTIO_MEM_UNPLUGGED_INACCESSIBLE_PROP, VirtIOMEM,
unplugged_inaccessible, ON_OFF_AUTO_AUTO),
#endif
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -1247,6 +1341,7 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data)
vdc->unrealize = virtio_mem_device_unrealize; vdc->unrealize = virtio_mem_device_unrealize;
vdc->get_config = virtio_mem_get_config; vdc->get_config = virtio_mem_get_config;
vdc->get_features = virtio_mem_get_features; vdc->get_features = virtio_mem_get_features;
vdc->validate_features = virtio_mem_validate_features;
vdc->vmsd = &vmstate_virtio_mem_device; vdc->vmsd = &vmstate_virtio_mem_device;
vmc->fill_device_info = virtio_mem_fill_device_info; vmc->fill_device_info = virtio_mem_fill_device_info;

View File

@ -673,7 +673,30 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
return 0; return 0;
} }
static int virtio_mmio_set_config_guest_notifier(DeviceState *d, bool assign)
{
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
bool with_irqfd = false;
EventNotifier *notifier = virtio_config_get_guest_notifier(vdev);
int r = 0;
if (assign) {
r = event_notifier_init(notifier, 0);
if (r < 0) {
return r;
}
virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd);
} else {
virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd);
event_notifier_cleanup(notifier);
}
if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) {
vdc->guest_notifier_mask(vdev, VIRTIO_CONFIG_IRQ_IDX, !assign);
}
return r;
}
static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs, static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs,
bool assign) bool assign)
{ {
@ -695,6 +718,10 @@ static int virtio_mmio_set_guest_notifiers(DeviceState *d, int nvqs,
goto assign_error; goto assign_error;
} }
} }
r = virtio_mmio_set_config_guest_notifier(d, assign);
if (r < 0) {
goto assign_error;
}
return 0; return 0;

View File

@ -677,7 +677,6 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev,
} }
static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
unsigned int queue_no,
unsigned int vector) unsigned int vector)
{ {
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
@ -704,112 +703,160 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
} }
static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
unsigned int queue_no, EventNotifier *n,
unsigned int vector) unsigned int vector)
{ {
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtQueue *vq = virtio_get_queue(vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq);
} }
static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
unsigned int queue_no, EventNotifier *n ,
unsigned int vector) unsigned int vector)
{ {
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtQueue *vq = virtio_get_queue(vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
int ret; int ret;
ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq);
assert(ret == 0); assert(ret == 0);
} }
static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no,
static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) EventNotifier **n, unsigned int *vector)
{ {
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtQueue *vq;
if (queue_no == VIRTIO_CONFIG_IRQ_IDX) {
*n = virtio_config_get_guest_notifier(vdev);
*vector = vdev->config_vector;
} else {
if (!virtio_queue_get_num(vdev, queue_no)) {
return -1;
}
*vector = virtio_queue_vector(vdev, queue_no);
vq = virtio_get_queue(vdev, queue_no);
*n = virtio_queue_get_guest_notifier(vq);
}
return 0;
}
static int kvm_virtio_pci_vector_use_one(VirtIOPCIProxy *proxy, int queue_no)
{
unsigned int vector;
int ret;
EventNotifier *n;
PCIDevice *dev = &proxy->pci_dev; PCIDevice *dev = &proxy->pci_dev;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
unsigned int vector;
int ret, queue_no;
for (queue_no = 0; queue_no < nvqs; queue_no++) { ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector);
if (!virtio_queue_get_num(vdev, queue_no)) { if (ret < 0) {
break; return ret;
} }
vector = virtio_queue_vector(vdev, queue_no);
if (vector >= msix_nr_vectors_allocated(dev)) { if (vector >= msix_nr_vectors_allocated(dev)) {
continue; return 0;
} }
ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); ret = kvm_virtio_pci_vq_vector_use(proxy, vector);
if (ret < 0) { if (ret < 0) {
goto undo; goto undo;
} }
/* If guest supports masking, set up irqfd now. /*
* If guest supports masking, set up irqfd now.
* Otherwise, delay until unmasked in the frontend. * Otherwise, delay until unmasked in the frontend.
*/ */
if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ret = kvm_virtio_pci_irqfd_use(proxy, n, vector);
if (ret < 0) { if (ret < 0) {
kvm_virtio_pci_vq_vector_release(proxy, vector); kvm_virtio_pci_vq_vector_release(proxy, vector);
goto undo; goto undo;
} }
} }
}
return 0;
return 0;
undo: undo:
while (--queue_no >= 0) {
vector = virtio_queue_vector(vdev, queue_no); vector = virtio_queue_vector(vdev, queue_no);
if (vector >= msix_nr_vectors_allocated(dev)) { if (vector >= msix_nr_vectors_allocated(dev)) {
continue; return ret;
} }
if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector);
if (ret < 0) {
return ret;
} }
kvm_virtio_pci_vq_vector_release(proxy, vector); kvm_virtio_pci_irqfd_release(proxy, n, vector);
}
return ret;
}
static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
{
int queue_no;
int ret = 0;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
for (queue_no = 0; queue_no < nvqs; queue_no++) {
if (!virtio_queue_get_num(vdev, queue_no)) {
return -1;
}
ret = kvm_virtio_pci_vector_use_one(proxy, queue_no);
} }
return ret; return ret;
} }
static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) static int kvm_virtio_pci_vector_config_use(VirtIOPCIProxy *proxy)
{
return kvm_virtio_pci_vector_use_one(proxy, VIRTIO_CONFIG_IRQ_IDX);
}
static void kvm_virtio_pci_vector_release_one(VirtIOPCIProxy *proxy,
int queue_no)
{ {
PCIDevice *dev = &proxy->pci_dev;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
unsigned int vector; unsigned int vector;
int queue_no; EventNotifier *n;
int ret;
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
PCIDevice *dev = &proxy->pci_dev;
ret = virtio_pci_get_notifier(proxy, queue_no, &n, &vector);
if (ret < 0) {
return;
}
if (vector >= msix_nr_vectors_allocated(dev)) {
return;
}
if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
kvm_virtio_pci_irqfd_release(proxy, n, vector);
}
kvm_virtio_pci_vq_vector_release(proxy, vector);
}
static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
{
int queue_no;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
for (queue_no = 0; queue_no < nvqs; queue_no++) { for (queue_no = 0; queue_no < nvqs; queue_no++) {
if (!virtio_queue_get_num(vdev, queue_no)) { if (!virtio_queue_get_num(vdev, queue_no)) {
break; break;
} }
vector = virtio_queue_vector(vdev, queue_no); kvm_virtio_pci_vector_release_one(proxy, queue_no);
if (vector >= msix_nr_vectors_allocated(dev)) {
continue;
}
/* If guest supports masking, clean up irqfd now.
* Otherwise, it was cleaned when masked in the frontend.
*/
if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
}
kvm_virtio_pci_vq_vector_release(proxy, vector);
} }
} }
static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, static void kvm_virtio_pci_vector_config_release(VirtIOPCIProxy *proxy)
{
kvm_virtio_pci_vector_release_one(proxy, VIRTIO_CONFIG_IRQ_IDX);
}
static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy,
unsigned int queue_no, unsigned int queue_no,
unsigned int vector, unsigned int vector,
MSIMessage msg) MSIMessage msg,
EventNotifier *n)
{ {
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
VirtQueue *vq = virtio_get_queue(vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
VirtIOIRQFD *irqfd; VirtIOIRQFD *irqfd;
int ret = 0; int ret = 0;
@ -836,14 +883,15 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
event_notifier_set(n); event_notifier_set(n);
} }
} else { } else {
ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); ret = kvm_virtio_pci_irqfd_use(proxy, n, vector);
} }
return ret; return ret;
} }
static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, static void virtio_pci_one_vector_mask(VirtIOPCIProxy *proxy,
unsigned int queue_no, unsigned int queue_no,
unsigned int vector) unsigned int vector,
EventNotifier *n)
{ {
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
@ -854,7 +902,7 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) {
k->guest_notifier_mask(vdev, queue_no, true); k->guest_notifier_mask(vdev, queue_no, true);
} else { } else {
kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); kvm_virtio_pci_irqfd_release(proxy, n, vector);
} }
} }
@ -864,6 +912,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtQueue *vq = virtio_vector_first_queue(vdev, vector); VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
EventNotifier *n;
int ret, index, unmasked = 0; int ret, index, unmasked = 0;
while (vq) { while (vq) {
@ -872,7 +921,8 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
break; break;
} }
if (index < proxy->nvqs_with_notifiers) { if (index < proxy->nvqs_with_notifiers) {
ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); n = virtio_queue_get_guest_notifier(vq);
ret = virtio_pci_one_vector_unmask(proxy, index, vector, msg, n);
if (ret < 0) { if (ret < 0) {
goto undo; goto undo;
} }
@ -880,15 +930,24 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
} }
vq = virtio_vector_next_queue(vq); vq = virtio_vector_next_queue(vq);
} }
/* unmask config intr */
n = virtio_config_get_guest_notifier(vdev);
ret = virtio_pci_one_vector_unmask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector,
msg, n);
if (ret < 0) {
goto undo_config;
}
return 0; return 0;
undo_config:
n = virtio_config_get_guest_notifier(vdev);
virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n);
undo: undo:
vq = virtio_vector_first_queue(vdev, vector); vq = virtio_vector_first_queue(vdev, vector);
while (vq && unmasked >= 0) { while (vq && unmasked >= 0) {
index = virtio_get_queue_index(vq); index = virtio_get_queue_index(vq);
if (index < proxy->nvqs_with_notifiers) { if (index < proxy->nvqs_with_notifiers) {
virtio_pci_vq_vector_mask(proxy, index, vector); n = virtio_queue_get_guest_notifier(vq);
virtio_pci_one_vector_mask(proxy, index, vector, n);
--unmasked; --unmasked;
} }
vq = virtio_vector_next_queue(vq); vq = virtio_vector_next_queue(vq);
@ -901,18 +960,22 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtQueue *vq = virtio_vector_first_queue(vdev, vector); VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
EventNotifier *n;
int index; int index;
while (vq) { while (vq) {
index = virtio_get_queue_index(vq); index = virtio_get_queue_index(vq);
n = virtio_queue_get_guest_notifier(vq);
if (!virtio_queue_get_num(vdev, index)) { if (!virtio_queue_get_num(vdev, index)) {
break; break;
} }
if (index < proxy->nvqs_with_notifiers) { if (index < proxy->nvqs_with_notifiers) {
virtio_pci_vq_vector_mask(proxy, index, vector); virtio_pci_one_vector_mask(proxy, index, vector, n);
} }
vq = virtio_vector_next_queue(vq); vq = virtio_vector_next_queue(vq);
} }
n = virtio_config_get_guest_notifier(vdev);
virtio_pci_one_vector_mask(proxy, VIRTIO_CONFIG_IRQ_IDX, vector, n);
} }
static void virtio_pci_vector_poll(PCIDevice *dev, static void virtio_pci_vector_poll(PCIDevice *dev,
@ -925,19 +988,17 @@ static void virtio_pci_vector_poll(PCIDevice *dev,
int queue_no; int queue_no;
unsigned int vector; unsigned int vector;
EventNotifier *notifier; EventNotifier *notifier;
VirtQueue *vq; int ret;
for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
if (!virtio_queue_get_num(vdev, queue_no)) { ret = virtio_pci_get_notifier(proxy, queue_no, &notifier, &vector);
if (ret < 0) {
break; break;
} }
vector = virtio_queue_vector(vdev, queue_no);
if (vector < vector_start || vector >= vector_end || if (vector < vector_start || vector >= vector_end ||
!msix_is_masked(dev, vector)) { !msix_is_masked(dev, vector)) {
continue; continue;
} }
vq = virtio_get_queue(vdev, queue_no);
notifier = virtio_queue_get_guest_notifier(vq);
if (k->guest_notifier_pending) { if (k->guest_notifier_pending) {
if (k->guest_notifier_pending(vdev, queue_no)) { if (k->guest_notifier_pending(vdev, queue_no)) {
msix_set_pending(dev, vector); msix_set_pending(dev, vector);
@ -946,6 +1007,34 @@ static void virtio_pci_vector_poll(PCIDevice *dev,
msix_set_pending(dev, vector); msix_set_pending(dev, vector);
} }
} }
/* poll the config intr */
ret = virtio_pci_get_notifier(proxy, VIRTIO_CONFIG_IRQ_IDX, &notifier,
&vector);
if (ret < 0) {
return;
}
if (vector < vector_start || vector >= vector_end ||
!msix_is_masked(dev, vector)) {
return;
}
if (k->guest_notifier_pending) {
if (k->guest_notifier_pending(vdev, VIRTIO_CONFIG_IRQ_IDX)) {
msix_set_pending(dev, vector);
}
} else if (event_notifier_test_and_clear(notifier)) {
msix_set_pending(dev, vector);
}
}
void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq,
int n, bool assign,
bool with_irqfd)
{
if (n == VIRTIO_CONFIG_IRQ_IDX) {
virtio_config_set_guest_notifier_fd_handler(vdev, assign, with_irqfd);
} else {
virtio_queue_set_guest_notifier_fd_handler(vq, assign, with_irqfd);
}
} }
static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
@ -954,17 +1043,25 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
VirtQueue *vq = virtio_get_queue(vdev, n); VirtQueue *vq = NULL;
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); EventNotifier *notifier = NULL;
if (n == VIRTIO_CONFIG_IRQ_IDX) {
notifier = virtio_config_get_guest_notifier(vdev);
} else {
vq = virtio_get_queue(vdev, n);
notifier = virtio_queue_get_guest_notifier(vq);
}
if (assign) { if (assign) {
int r = event_notifier_init(notifier, 0); int r = event_notifier_init(notifier, 0);
if (r < 0) { if (r < 0) {
return r; return r;
} }
virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, true, with_irqfd);
} else { } else {
virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); virtio_pci_set_guest_notifier_fd_handler(vdev, vq, n, false,
with_irqfd);
event_notifier_cleanup(notifier); event_notifier_cleanup(notifier);
} }
@ -1006,6 +1103,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
msix_unset_vector_notifiers(&proxy->pci_dev); msix_unset_vector_notifiers(&proxy->pci_dev);
if (proxy->vector_irqfd) { if (proxy->vector_irqfd) {
kvm_virtio_pci_vector_release(proxy, nvqs); kvm_virtio_pci_vector_release(proxy, nvqs);
kvm_virtio_pci_vector_config_release(proxy);
g_free(proxy->vector_irqfd); g_free(proxy->vector_irqfd);
proxy->vector_irqfd = NULL; proxy->vector_irqfd = NULL;
} }
@ -1021,7 +1119,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
goto assign_error; goto assign_error;
} }
} }
r = virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, assign,
with_irqfd);
if (r < 0) {
goto config_assign_error;
}
/* Must set vector notifier after guest notifier has been assigned */ /* Must set vector notifier after guest notifier has been assigned */
if ((with_irqfd || k->guest_notifier_mask) && assign) { if ((with_irqfd || k->guest_notifier_mask) && assign) {
if (with_irqfd) { if (with_irqfd) {
@ -1030,11 +1132,14 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
msix_nr_vectors_allocated(&proxy->pci_dev)); msix_nr_vectors_allocated(&proxy->pci_dev));
r = kvm_virtio_pci_vector_use(proxy, nvqs); r = kvm_virtio_pci_vector_use(proxy, nvqs);
if (r < 0) { if (r < 0) {
goto assign_error; goto config_assign_error;
} }
} }
r = msix_set_vector_notifiers(&proxy->pci_dev, r = kvm_virtio_pci_vector_config_use(proxy);
virtio_pci_vector_unmask, if (r < 0) {
goto config_error;
}
r = msix_set_vector_notifiers(&proxy->pci_dev, virtio_pci_vector_unmask,
virtio_pci_vector_mask, virtio_pci_vector_mask,
virtio_pci_vector_poll); virtio_pci_vector_poll);
if (r < 0) { if (r < 0) {
@ -1049,7 +1154,11 @@ notifiers_error:
assert(assign); assert(assign);
kvm_virtio_pci_vector_release(proxy, nvqs); kvm_virtio_pci_vector_release(proxy, nvqs);
} }
config_error:
kvm_virtio_pci_vector_config_release(proxy);
config_assign_error:
virtio_pci_set_guest_notifier(d, VIRTIO_CONFIG_IRQ_IDX, !assign,
with_irqfd);
assign_error: assign_error:
/* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
assert(assign); assert(assign);

View File

@ -251,5 +251,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t);
* @fixed_queues. * @fixed_queues.
*/ */
unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues); unsigned virtio_pci_optimal_num_queues(unsigned fixed_queues);
void virtio_pci_set_guest_notifier_fd_handler(VirtIODevice *vdev, VirtQueue *vq,
int n, bool assign,
bool with_irqfd);
#endif #endif

View File

@ -885,6 +885,7 @@ static void virtqueue_packed_flush(VirtQueue *vq, unsigned int count)
if (vq->used_idx >= vq->vring.num) { if (vq->used_idx >= vq->vring.num) {
vq->used_idx -= vq->vring.num; vq->used_idx -= vq->vring.num;
vq->used_wrap_counter ^= 1; vq->used_wrap_counter ^= 1;
vq->signalled_used_valid = false;
} }
} }
@ -3493,7 +3494,14 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n)
virtio_irq(vq); virtio_irq(vq);
} }
} }
static void virtio_config_guest_notifier_read(EventNotifier *n)
{
VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier);
if (event_notifier_test_and_clear(n)) {
virtio_notify_config(vdev);
}
}
void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
bool with_irqfd) bool with_irqfd)
{ {
@ -3510,6 +3518,23 @@ void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
} }
} }
void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev,
bool assign, bool with_irqfd)
{
EventNotifier *n;
n = &vdev->config_notifier;
if (assign && !with_irqfd) {
event_notifier_set_handler(n, virtio_config_guest_notifier_read);
} else {
event_notifier_set_handler(n, NULL);
}
if (!assign) {
/* Test and clear notifier before closing it,*/
/* in case poll callback didn't have time to run. */
virtio_config_guest_notifier_read(n);
}
}
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
{ {
return &vq->guest_notifier; return &vq->guest_notifier;
@ -3583,6 +3608,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
return &vq->host_notifier; return &vq->host_notifier;
} }
EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev)
{
return &vdev->config_notifier;
}
void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled)
{ {
vq->host_notifier_enabled = enabled; vq->host_notifier_enabled = enabled;

View File

@ -1,6 +1,8 @@
#ifndef QEMU_SMBIOS_H #ifndef QEMU_SMBIOS_H
#define QEMU_SMBIOS_H #define QEMU_SMBIOS_H
#include "qapi/qapi-types-machine.h"
/* /*
* SMBIOS Support * SMBIOS Support
* *
@ -23,14 +25,6 @@ struct smbios_phys_mem_area {
uint64_t length; uint64_t length;
}; };
/*
* SMBIOS spec defined tables
*/
typedef enum SmbiosEntryPointType {
SMBIOS_ENTRY_POINT_21,
SMBIOS_ENTRY_POINT_30,
} SmbiosEntryPointType;
/* SMBIOS Entry Point /* SMBIOS Entry Point
* There are two types of entry points defined in the SMBIOS specification * There are two types of entry points defined in the SMBIOS specification
* (see below). BIOS must place the entry point(s) at a 16-byte-aligned * (see below). BIOS must place the entry point(s) at a 16-byte-aligned

View File

@ -13,6 +13,7 @@
#include "hw/hotplug.h" #include "hw/hotplug.h"
#include "qom/object.h" #include "qom/object.h"
#include "hw/i386/sgx-epc.h" #include "hw/i386/sgx-epc.h"
#include "hw/firmware/smbios.h"
#define HPET_INTCAP "hpet-intcap" #define HPET_INTCAP "hpet-intcap"
@ -40,6 +41,7 @@ typedef struct PCMachineState {
/* Configuration options: */ /* Configuration options: */
uint64_t max_ram_below_4g; uint64_t max_ram_below_4g;
OnOffAuto vmport; OnOffAuto vmport;
SmbiosEntryPointType smbios_entry_point_type;
bool acpi_build_enabled; bool acpi_build_enabled;
bool smbus_enabled; bool smbus_enabled;
@ -63,6 +65,8 @@ typedef struct PCMachineState {
#define PC_MACHINE_SATA "sata" #define PC_MACHINE_SATA "sata"
#define PC_MACHINE_PIT "pit" #define PC_MACHINE_PIT "pit"
#define PC_MACHINE_MAX_FW_SIZE "max-fw-size" #define PC_MACHINE_MAX_FW_SIZE "max-fw-size"
#define PC_MACHINE_SMBIOS_EP "smbios-entry-point-type"
/** /**
* PCMachineClass: * PCMachineClass:
* *

View File

@ -735,6 +735,11 @@ void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev);
qemu_irq pci_allocate_irq(PCIDevice *pci_dev); qemu_irq pci_allocate_irq(PCIDevice *pci_dev);
void pci_set_irq(PCIDevice *pci_dev, int level); void pci_set_irq(PCIDevice *pci_dev, int level);
static inline int pci_intx(PCIDevice *pci_dev)
{
return pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
}
static inline void pci_irq_assert(PCIDevice *pci_dev) static inline void pci_irq_assert(PCIDevice *pci_dev)
{ {
pci_set_irq(pci_dev, 1); pci_set_irq(pci_dev, 1);

View File

@ -126,6 +126,8 @@ typedef int (*vhost_get_device_id_op)(struct vhost_dev *dev, uint32_t *dev_id);
typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev); typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev);
typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev,
int fd);
typedef struct VhostOps { typedef struct VhostOps {
VhostBackendType backend_type; VhostBackendType backend_type;
vhost_backend_init vhost_backend_init; vhost_backend_init vhost_backend_init;
@ -171,6 +173,7 @@ typedef struct VhostOps {
vhost_vq_get_addr_op vhost_vq_get_addr; vhost_vq_get_addr_op vhost_vq_get_addr;
vhost_get_device_id_op vhost_get_device_id; vhost_get_device_id_op vhost_get_device_id;
vhost_force_iommu_op vhost_force_iommu; vhost_force_iommu_op vhost_force_iommu;
vhost_set_config_call_op vhost_set_config_call;
} VhostOps; } VhostOps;
int vhost_backend_update_device_iotlb(struct vhost_dev *dev, int vhost_backend_update_device_iotlb(struct vhost_dev *dev,

View File

@ -29,6 +29,7 @@ struct vhost_virtqueue {
unsigned long long used_phys; unsigned long long used_phys;
unsigned used_size; unsigned used_size;
EventNotifier masked_notifier; EventNotifier masked_notifier;
EventNotifier masked_config_notifier;
struct vhost_dev *dev; struct vhost_dev *dev;
}; };
@ -37,6 +38,7 @@ typedef unsigned long vhost_log_chunk_t;
#define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t)) #define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t))
#define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS) #define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS)
#define VHOST_INVALID_FEATURE_BIT (0xff) #define VHOST_INVALID_FEATURE_BIT (0xff)
#define VHOST_QUEUE_NUM_CONFIG_INR 0
struct vhost_log { struct vhost_log {
unsigned long long size; unsigned long long size;
@ -116,6 +118,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
bool vhost_config_pending(struct vhost_dev *hdev);
void vhost_config_mask(struct vhost_dev *hdev, VirtIODevice *vdev, bool mask);
/* Test and clear masked event pending status. /* Test and clear masked event pending status.
* Should be called after unmask to avoid losing events. * Should be called after unmask to avoid losing events.

View File

@ -30,6 +30,8 @@ OBJECT_DECLARE_TYPE(VirtIOMEM, VirtIOMEMClass,
#define VIRTIO_MEM_REQUESTED_SIZE_PROP "requested-size" #define VIRTIO_MEM_REQUESTED_SIZE_PROP "requested-size"
#define VIRTIO_MEM_BLOCK_SIZE_PROP "block-size" #define VIRTIO_MEM_BLOCK_SIZE_PROP "block-size"
#define VIRTIO_MEM_ADDR_PROP "memaddr" #define VIRTIO_MEM_ADDR_PROP "memaddr"
#define VIRTIO_MEM_UNPLUGGED_INACCESSIBLE_PROP "unplugged-inaccessible"
#define VIRTIO_MEM_PREALLOC_PROP "prealloc"
struct VirtIOMEM { struct VirtIOMEM {
VirtIODevice parent_obj; VirtIODevice parent_obj;
@ -62,6 +64,16 @@ struct VirtIOMEM {
/* block size and alignment */ /* block size and alignment */
uint64_t block_size; uint64_t block_size;
/*
* Whether we indicate VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE to the guest.
* For !x86 targets this will always be "on" and consequently indicate
* VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE.
*/
OnOffAuto unplugged_inaccessible;
/* whether to prealloc memory when plugging new blocks */
bool prealloc;
/* notifiers to notify when "size" changes */ /* notifiers to notify when "size" changes */
NotifierList size_change_notifiers; NotifierList size_change_notifiers;

View File

@ -67,6 +67,9 @@ typedef struct VirtQueueElement
#define VIRTIO_NO_VECTOR 0xffff #define VIRTIO_NO_VECTOR 0xffff
/* special index value used internally for config irqs */
#define VIRTIO_CONFIG_IRQ_IDX -1
#define TYPE_VIRTIO_DEVICE "virtio-device" #define TYPE_VIRTIO_DEVICE "virtio-device"
OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE) OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)
@ -108,6 +111,7 @@ struct VirtIODevice
bool use_guest_notifier_mask; bool use_guest_notifier_mask;
AddressSpace *dma_as; AddressSpace *dma_as;
QLIST_HEAD(, VirtQueue) *vector_queues; QLIST_HEAD(, VirtQueue) *vector_queues;
EventNotifier config_notifier;
}; };
struct VirtioDeviceClass { struct VirtioDeviceClass {
@ -310,11 +314,14 @@ uint16_t virtio_get_queue_index(VirtQueue *vq);
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
bool with_irqfd); bool with_irqfd);
void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev,
bool assign, bool with_irqfd);
int virtio_device_start_ioeventfd(VirtIODevice *vdev); int virtio_device_start_ioeventfd(VirtIODevice *vdev);
int virtio_device_grab_ioeventfd(VirtIODevice *vdev); int virtio_device_grab_ioeventfd(VirtIODevice *vdev);
void virtio_device_release_ioeventfd(VirtIODevice *vdev); void virtio_device_release_ioeventfd(VirtIODevice *vdev);
bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev); bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev);
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev);
void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled); void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled);
void virtio_queue_host_notifier_read(EventNotifier *n); void virtio_queue_host_notifier_read(EventNotifier *n);
void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx,

View File

@ -39,6 +39,8 @@ int vhost_net_set_config(struct vhost_net *net, const uint8_t *data,
bool vhost_net_virtqueue_pending(VHostNetState *net, int n); bool vhost_net_virtqueue_pending(VHostNetState *net, int n);
void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
int idx, bool mask); int idx, bool mask);
bool vhost_net_config_pending(VHostNetState *net);
void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask);
int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr); int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr);
VHostNetState *get_vhost_net(NetClientState *nc); VHostNetState *get_vhost_net(NetClientState *nc);

View File

@ -471,6 +471,11 @@ static inline void qemu_cleanup_generic_vfree(void *p)
#else #else
#define QEMU_MADV_REMOVE QEMU_MADV_DONTNEED #define QEMU_MADV_REMOVE QEMU_MADV_DONTNEED
#endif #endif
#ifdef MADV_POPULATE_WRITE
#define QEMU_MADV_POPULATE_WRITE MADV_POPULATE_WRITE
#else
#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID
#endif
#elif defined(CONFIG_POSIX_MADVISE) #elif defined(CONFIG_POSIX_MADVISE)
@ -484,6 +489,7 @@ static inline void qemu_cleanup_generic_vfree(void *p)
#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID #define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID
#define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID #define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID
#define QEMU_MADV_REMOVE QEMU_MADV_DONTNEED #define QEMU_MADV_REMOVE QEMU_MADV_DONTNEED
#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID
#else /* no-op */ #else /* no-op */
@ -497,6 +503,7 @@ static inline void qemu_cleanup_generic_vfree(void *p)
#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID #define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID
#define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID #define QEMU_MADV_NOHUGEPAGE QEMU_MADV_INVALID
#define QEMU_MADV_REMOVE QEMU_MADV_INVALID #define QEMU_MADV_REMOVE QEMU_MADV_INVALID
#define QEMU_MADV_POPULATE_WRITE QEMU_MADV_INVALID
#endif #endif

View File

@ -68,9 +68,10 @@
* explicitly triggered (VIRTIO_MEM_REQ_UNPLUG). * explicitly triggered (VIRTIO_MEM_REQ_UNPLUG).
* *
* There are no guarantees what will happen if unplugged memory is * There are no guarantees what will happen if unplugged memory is
* read/written. Such memory should, in general, not be touched. E.g., * read/written. In general, unplugged memory should not be touched, because
* even writing might succeed, but the values will simply be discarded at * the resulting action is undefined. There is one exception: without
* random points in time. * VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, unplugged memory inside the usable
* region can be read, to simplify creation of memory dumps.
* *
* It can happen that the device cannot process a request, because it is * It can happen that the device cannot process a request, because it is
* busy. The device driver has to retry later. * busy. The device driver has to retry later.
@ -87,6 +88,8 @@
/* node_id is an ACPI PXM and is valid */ /* node_id is an ACPI PXM and is valid */
#define VIRTIO_MEM_F_ACPI_PXM 0 #define VIRTIO_MEM_F_ACPI_PXM 0
/* unplugged memory must not be accessed */
#define VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE 1
/* --- virtio-mem: guest -> host requests --- */ /* --- virtio-mem: guest -> host requests --- */

View File

@ -1568,3 +1568,15 @@
{ 'command': 'x-query-usb', { 'command': 'x-query-usb',
'returns': 'HumanReadableText', 'returns': 'HumanReadableText',
'features': [ 'unstable' ] } 'features': [ 'unstable' ] }
##
# @SmbiosEntryPointType:
#
# @32: SMBIOS version 2.1 (32-bit) Entry Point
#
# @64: SMBIOS version 3.0 (64-bit) Entry Point
#
# Since: 7.0
##
{ 'enum': 'SmbiosEntryPointType',
'data': [ '32', '64' ] }

View File

@ -352,6 +352,10 @@ static void qemu_init_sigbus(void)
{ {
struct sigaction action; struct sigaction action;
/*
* ALERT: when modifying this, take care that SIGBUS forwarding in
* os_mem_prealloc() will continue working as expected.
*/
memset(&action, 0, sizeof(action)); memset(&action, 0, sizeof(action));
action.sa_flags = SA_SIGINFO; action.sa_flags = SA_SIGINFO;
action.sa_sigaction = sigbus_handler; action.sa_sigaction = sigbus_handler;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1502,6 +1502,20 @@ static void test_acpi_virt_viot(void)
free_test_data(&data); free_test_data(&data);
} }
static void test_acpi_q35_slic(void)
{
test_data data = {
.machine = MACHINE_Q35,
.variant = ".slic",
};
test_acpi_one("-acpitable sig=SLIC,oem_id='CRASH ',oem_table_id='ME',"
"oem_rev=00002210,asl_compiler_id='qemu',"
"asl_compiler_rev=00000000,data=/dev/null",
&data);
free_test_data(&data);
}
static void test_oem_fields(test_data *data) static void test_oem_fields(test_data *data)
{ {
int i; int i;
@ -1677,6 +1691,7 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar); qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar);
} }
qtest_add_func("acpi/q35/viot", test_acpi_q35_viot); qtest_add_func("acpi/q35/viot", test_acpi_q35_viot);
qtest_add_func("acpi/q35/slic", test_acpi_q35_slic);
} else if (strcmp(arch, "aarch64") == 0) { } else if (strcmp(arch, "aarch64") == 0) {
if (has_tcg) { if (has_tcg) {
qtest_add_func("acpi/virt", test_acpi_virt_tcg); qtest_add_func("acpi/virt", test_acpi_virt_tcg);

View File

@ -35,11 +35,13 @@
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "trace.h" #include "trace.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/sockets.h" #include "qemu/sockets.h"
#include "qemu/thread.h" #include "qemu/thread.h"
#include <libgen.h> #include <libgen.h>
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/compiler.h" #include "qemu/compiler.h"
#include "qemu/units.h"
#ifdef CONFIG_LINUX #ifdef CONFIG_LINUX
#include <sys/syscall.h> #include <sys/syscall.h>
@ -73,22 +75,32 @@
#define MAX_MEM_PREALLOC_THREAD_COUNT 16 #define MAX_MEM_PREALLOC_THREAD_COUNT 16
struct MemsetThread;
typedef struct MemsetContext {
bool all_threads_created;
bool any_thread_failed;
struct MemsetThread *threads;
int num_threads;
} MemsetContext;
struct MemsetThread { struct MemsetThread {
char *addr; char *addr;
size_t numpages; size_t numpages;
size_t hpagesize; size_t hpagesize;
QemuThread pgthread; QemuThread pgthread;
sigjmp_buf env; sigjmp_buf env;
MemsetContext *context;
}; };
typedef struct MemsetThread MemsetThread; typedef struct MemsetThread MemsetThread;
static MemsetThread *memset_thread; /* used by sigbus_handler() */
static int memset_num_threads; static MemsetContext *sigbus_memset_context;
static bool memset_thread_failed; struct sigaction sigbus_oldact;
static QemuMutex sigbus_mutex;
static QemuMutex page_mutex; static QemuMutex page_mutex;
static QemuCond page_cond; static QemuCond page_cond;
static bool threads_created_flag;
int qemu_get_thread_id(void) int qemu_get_thread_id(void)
{ {
@ -436,22 +448,50 @@ const char *qemu_get_exec_dir(void)
return exec_dir; return exec_dir;
} }
#ifdef CONFIG_LINUX
static void sigbus_handler(int signal, siginfo_t *siginfo, void *ctx)
#else /* CONFIG_LINUX */
static void sigbus_handler(int signal) static void sigbus_handler(int signal)
#endif /* CONFIG_LINUX */
{ {
int i; int i;
if (memset_thread) {
for (i = 0; i < memset_num_threads; i++) { if (sigbus_memset_context) {
if (qemu_thread_is_self(&memset_thread[i].pgthread)) { for (i = 0; i < sigbus_memset_context->num_threads; i++) {
siglongjmp(memset_thread[i].env, 1); MemsetThread *thread = &sigbus_memset_context->threads[i];
if (qemu_thread_is_self(&thread->pgthread)) {
siglongjmp(thread->env, 1);
} }
} }
} }
#ifdef CONFIG_LINUX
/*
* We assume that the MCE SIGBUS handler could have been registered. We
* should never receive BUS_MCEERR_AO on any of our threads, but only on
* the main thread registered for PR_MCE_KILL_EARLY. Further, we should not
* receive BUS_MCEERR_AR triggered by action of other threads on one of
* our threads. So, no need to check for unrelated SIGBUS when seeing one
* for our threads.
*
* We will forward to the MCE handler, which will either handle the SIGBUS
* or reinstall the default SIGBUS handler and reraise the SIGBUS. The
* default SIGBUS handler will crash the process, so we don't care.
*/
if (sigbus_oldact.sa_flags & SA_SIGINFO) {
sigbus_oldact.sa_sigaction(signal, siginfo, ctx);
return;
}
#endif /* CONFIG_LINUX */
warn_report("os_mem_prealloc: unrelated SIGBUS detected and ignored");
} }
static void *do_touch_pages(void *arg) static void *do_touch_pages(void *arg)
{ {
MemsetThread *memset_args = (MemsetThread *)arg; MemsetThread *memset_args = (MemsetThread *)arg;
sigset_t set, oldset; sigset_t set, oldset;
int ret = 0;
/* /*
* On Linux, the page faults from the loop below can cause mmap_sem * On Linux, the page faults from the loop below can cause mmap_sem
@ -459,7 +499,7 @@ static void *do_touch_pages(void *arg)
* clearing until all threads have been created. * clearing until all threads have been created.
*/ */
qemu_mutex_lock(&page_mutex); qemu_mutex_lock(&page_mutex);
while(!threads_created_flag){ while (!memset_args->context->all_threads_created) {
qemu_cond_wait(&page_cond, &page_mutex); qemu_cond_wait(&page_cond, &page_mutex);
} }
qemu_mutex_unlock(&page_mutex); qemu_mutex_unlock(&page_mutex);
@ -470,7 +510,7 @@ static void *do_touch_pages(void *arg)
pthread_sigmask(SIG_UNBLOCK, &set, &oldset); pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
if (sigsetjmp(memset_args->env, 1)) { if (sigsetjmp(memset_args->env, 1)) {
memset_thread_failed = true; ret = -EFAULT;
} else { } else {
char *addr = memset_args->addr; char *addr = memset_args->addr;
size_t numpages = memset_args->numpages; size_t numpages = memset_args->numpages;
@ -484,20 +524,37 @@ static void *do_touch_pages(void *arg)
* *
* 'volatile' to stop compiler optimizing this away * 'volatile' to stop compiler optimizing this away
* to a no-op * to a no-op
*
* TODO: get a better solution from kernel so we
* don't need to write at all so we don't cause
* wear on the storage backing the region...
*/ */
*(volatile char *)addr = *addr; *(volatile char *)addr = *addr;
addr += hpagesize; addr += hpagesize;
} }
} }
pthread_sigmask(SIG_SETMASK, &oldset, NULL); pthread_sigmask(SIG_SETMASK, &oldset, NULL);
return NULL; return (void *)(uintptr_t)ret;
} }
static inline int get_memset_num_threads(int smp_cpus) static void *do_madv_populate_write_pages(void *arg)
{
MemsetThread *memset_args = (MemsetThread *)arg;
const size_t size = memset_args->numpages * memset_args->hpagesize;
char * const addr = memset_args->addr;
int ret = 0;
/* See do_touch_pages(). */
qemu_mutex_lock(&page_mutex);
while (!memset_args->context->all_threads_created) {
qemu_cond_wait(&page_cond, &page_mutex);
}
qemu_mutex_unlock(&page_mutex);
if (size && qemu_madvise(addr, size, QEMU_MADV_POPULATE_WRITE)) {
ret = -errno;
}
return (void *)(uintptr_t)ret;
}
static inline int get_memset_num_threads(size_t hpagesize, size_t numpages,
int smp_cpus)
{ {
long host_procs = sysconf(_SC_NPROCESSORS_ONLN); long host_procs = sysconf(_SC_NPROCESSORS_ONLN);
int ret = 1; int ret = 1;
@ -505,17 +562,27 @@ static inline int get_memset_num_threads(int smp_cpus)
if (host_procs > 0) { if (host_procs > 0) {
ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), smp_cpus); ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), smp_cpus);
} }
/* Especially with gigantic pages, don't create more threads than pages. */
ret = MIN(ret, numpages);
/* Don't start threads to prealloc comparatively little memory. */
ret = MIN(ret, MAX(1, hpagesize * numpages / (64 * MiB)));
/* In case sysconf() fails, we fall back to single threaded */ /* In case sysconf() fails, we fall back to single threaded */
return ret; return ret;
} }
static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, static int touch_all_pages(char *area, size_t hpagesize, size_t numpages,
int smp_cpus) int smp_cpus, bool use_madv_populate_write)
{ {
static gsize initialized = 0; static gsize initialized = 0;
MemsetContext context = {
.num_threads = get_memset_num_threads(hpagesize, numpages, smp_cpus),
};
size_t numpages_per_thread, leftover; size_t numpages_per_thread, leftover;
void *(*touch_fn)(void *);
int ret = 0, i = 0;
char *addr = area; char *addr = area;
int i = 0;
if (g_once_init_enter(&initialized)) { if (g_once_init_enter(&initialized)) {
qemu_mutex_init(&page_mutex); qemu_mutex_init(&page_mutex);
@ -523,67 +590,122 @@ static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages,
g_once_init_leave(&initialized, 1); g_once_init_leave(&initialized, 1);
} }
memset_thread_failed = false; if (use_madv_populate_write) {
threads_created_flag = false; /* Avoid creating a single thread for MADV_POPULATE_WRITE */
memset_num_threads = get_memset_num_threads(smp_cpus); if (context.num_threads == 1) {
memset_thread = g_new0(MemsetThread, memset_num_threads); if (qemu_madvise(area, hpagesize * numpages,
numpages_per_thread = numpages / memset_num_threads; QEMU_MADV_POPULATE_WRITE)) {
leftover = numpages % memset_num_threads; return -errno;
for (i = 0; i < memset_num_threads; i++) { }
memset_thread[i].addr = addr; return 0;
memset_thread[i].numpages = numpages_per_thread + (i < leftover); }
memset_thread[i].hpagesize = hpagesize; touch_fn = do_madv_populate_write_pages;
qemu_thread_create(&memset_thread[i].pgthread, "touch_pages", } else {
do_touch_pages, &memset_thread[i], touch_fn = do_touch_pages;
}
context.threads = g_new0(MemsetThread, context.num_threads);
numpages_per_thread = numpages / context.num_threads;
leftover = numpages % context.num_threads;
for (i = 0; i < context.num_threads; i++) {
context.threads[i].addr = addr;
context.threads[i].numpages = numpages_per_thread + (i < leftover);
context.threads[i].hpagesize = hpagesize;
context.threads[i].context = &context;
qemu_thread_create(&context.threads[i].pgthread, "touch_pages",
touch_fn, &context.threads[i],
QEMU_THREAD_JOINABLE); QEMU_THREAD_JOINABLE);
addr += memset_thread[i].numpages * hpagesize; addr += context.threads[i].numpages * hpagesize;
}
if (!use_madv_populate_write) {
sigbus_memset_context = &context;
} }
qemu_mutex_lock(&page_mutex); qemu_mutex_lock(&page_mutex);
threads_created_flag = true; context.all_threads_created = true;
qemu_cond_broadcast(&page_cond); qemu_cond_broadcast(&page_cond);
qemu_mutex_unlock(&page_mutex); qemu_mutex_unlock(&page_mutex);
for (i = 0; i < memset_num_threads; i++) { for (i = 0; i < context.num_threads; i++) {
qemu_thread_join(&memset_thread[i].pgthread); int tmp = (uintptr_t)qemu_thread_join(&context.threads[i].pgthread);
}
g_free(memset_thread);
memset_thread = NULL;
return memset_thread_failed; if (tmp) {
ret = tmp;
}
}
if (!use_madv_populate_write) {
sigbus_memset_context = NULL;
}
g_free(context.threads);
return ret;
}
static bool madv_populate_write_possible(char *area, size_t pagesize)
{
return !qemu_madvise(area, pagesize, QEMU_MADV_POPULATE_WRITE) ||
errno != EINVAL;
} }
void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
Error **errp) Error **errp)
{ {
static gsize initialized;
int ret; int ret;
struct sigaction act, oldact;
size_t hpagesize = qemu_fd_getpagesize(fd); size_t hpagesize = qemu_fd_getpagesize(fd);
size_t numpages = DIV_ROUND_UP(memory, hpagesize); size_t numpages = DIV_ROUND_UP(memory, hpagesize);
bool use_madv_populate_write;
struct sigaction act;
/*
* Sense on every invocation, as MADV_POPULATE_WRITE cannot be used for
* some special mappings, such as mapping /dev/mem.
*/
use_madv_populate_write = madv_populate_write_possible(area, hpagesize);
if (!use_madv_populate_write) {
if (g_once_init_enter(&initialized)) {
qemu_mutex_init(&sigbus_mutex);
g_once_init_leave(&initialized, 1);
}
qemu_mutex_lock(&sigbus_mutex);
memset(&act, 0, sizeof(act)); memset(&act, 0, sizeof(act));
#ifdef CONFIG_LINUX
act.sa_sigaction = &sigbus_handler;
act.sa_flags = SA_SIGINFO;
#else /* CONFIG_LINUX */
act.sa_handler = &sigbus_handler; act.sa_handler = &sigbus_handler;
act.sa_flags = 0; act.sa_flags = 0;
#endif /* CONFIG_LINUX */
ret = sigaction(SIGBUS, &act, &oldact); ret = sigaction(SIGBUS, &act, &sigbus_oldact);
if (ret) { if (ret) {
error_setg_errno(errp, errno, error_setg_errno(errp, errno,
"os_mem_prealloc: failed to install signal handler"); "os_mem_prealloc: failed to install signal handler");
return; return;
} }
/* touch pages simultaneously */
if (touch_all_pages(area, hpagesize, numpages, smp_cpus)) {
error_setg(errp, "os_mem_prealloc: Insufficient free host memory "
"pages available to allocate guest RAM");
} }
ret = sigaction(SIGBUS, &oldact, NULL); /* touch pages simultaneously */
ret = touch_all_pages(area, hpagesize, numpages, smp_cpus,
use_madv_populate_write);
if (ret) {
error_setg_errno(errp, -ret,
"os_mem_prealloc: preallocating memory failed");
}
if (!use_madv_populate_write) {
ret = sigaction(SIGBUS, &sigbus_oldact, NULL);
if (ret) { if (ret) {
/* Terminate QEMU since it can't recover from error */ /* Terminate QEMU since it can't recover from error */
perror("os_mem_prealloc: failed to reinstall signal handler"); perror("os_mem_prealloc: failed to reinstall signal handler");
exit(1); exit(1);
} }
qemu_mutex_unlock(&sigbus_mutex);
}
} }
char *qemu_get_pid_name(pid_t pid) char *qemu_get_pid_name(pid_t pid)