diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-12-09 20:08:54 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-12-09 20:08:54 +0000 |
commit | 5e7b204dbfae9a562fc73684986f936b97f63877 (patch) | |
tree | 6cbdd59e56f5b9342c8252deed085f21485ac0fb /hw/net | |
parent | 28db503fd7a750861aa4381653800d4eb28b5426 (diff) | |
parent | fdfa3b1d6f9edd97c807df496a0d8e9ea49240da (diff) | |
download | qemu-5e7b204dbfae9a562fc73684986f936b97f63877.zip qemu-5e7b204dbfae9a562fc73684986f936b97f63877.tar.gz qemu-5e7b204dbfae9a562fc73684986f936b97f63877.tar.bz2 |
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc,pci,virtio: fixes, cleanups
Lots of fixes, cleanups.
CPU hot-unplug improvements.
A new AER property for virtio devices, adding a dummy AER capability.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Wed 09 Dec 2020 18:04:28 GMT
# gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg: issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# 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
* remotes/mst/tags/for_upstream: (65 commits)
hw/virtio-pci Added AER capability.
hw/virtio-pci Added counter for pcie capabilities offsets.
pcie_aer: Fix help message of pcie_aer_inject_error command
x86: ich9: let firmware negotiate 'CPU hot-unplug with SMI' feature
x86: ich9: factor out "guest_cpu_hotplug_features"
tests/acpi: update expected files
x86: acpi: let the firmware handle pending "CPU remove" events in SMM
tests/acpi: allow expected files change
x86: acpi: introduce AcpiPmInfo::smi_on_cpu_unplug
acpi: cpuhp: introduce 'firmware performs eject' status/control bits
hw/i386/pc: add max combined fw size as machine configuration option
block/export: avoid g_return_val_if() input validation
contrib/vhost-user-input: avoid g_return_val_if() input validation
contrib/vhost-user-gpu: avoid g_return_val_if() input validation
contrib/vhost-user-blk: avoid g_return_val_if() input validation
.gitlab-ci: add build-libvhost-user
libvhost-user: add a simple link test without glib
libvhost-user: make it a meson subproject
libvhost-user: drop qemu/osdep.h dependency
libvhost-user: remove qemu/compiler.h usage
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/net')
-rw-r--r-- | hw/net/virtio-net.c | 282 |
1 files changed, 110 insertions, 172 deletions
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 9179013..044ac95 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -788,93 +788,95 @@ static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n) return virtio_net_guest_offloads_by_features(vdev->guest_features); } -static void failover_add_primary(VirtIONet *n, Error **errp) -{ - Error *err = NULL; - - if (n->primary_dev) { - return; - } - - n->primary_device_opts = qemu_opts_find(qemu_find_opts("device"), - n->primary_device_id); - if (n->primary_device_opts) { - n->primary_dev = qdev_device_add(n->primary_device_opts, &err); - if (err) { - qemu_opts_del(n->primary_device_opts); - } - if (n->primary_dev) { - n->primary_bus = n->primary_dev->parent_bus; - if (err) { - qdev_unplug(n->primary_dev, &err); - qdev_set_id(n->primary_dev, ""); - - } - } - } else { - error_setg(errp, "Primary device not found"); - error_append_hint(errp, "Virtio-net failover will not work. Make " - "sure primary device has parameter" - " failover_pair_id=<virtio-net-id>\n"); -} - error_propagate(errp, err); -} +typedef struct { + VirtIONet *n; + char *id; +} FailoverId; -static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) +/** + * Set the id of the failover primary device + * + * @opaque: FailoverId to setup + * @opts: opts for device we are handling + * @errp: returns an error if this function fails + */ +static int failover_set_primary(void *opaque, QemuOpts *opts, Error **errp) { - VirtIONet *n = opaque; - int ret = 0; - + FailoverId *fid = opaque; const char *standby_id = qemu_opt_get(opts, "failover_pair_id"); - if (standby_id != NULL && (g_strcmp0(standby_id, n->netclient_name) == 0)) { - n->primary_device_id = g_strdup(opts->id); - ret = 1; + if (g_strcmp0(standby_id, fid->n->netclient_name) == 0) { + fid->id = g_strdup(opts->id); + return 1; } - return ret; + return 0; } -static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) +/** + * Find the primary device id for this failover virtio-net + * + * @n: VirtIONet device + * @errp: returns an error if this function fails + */ +static char *failover_find_primary_device_id(VirtIONet *n) { - DeviceState *dev = NULL; Error *err = NULL; + FailoverId fid; - if (qemu_opts_foreach(qemu_find_opts("device"), - is_my_primary, n, &err)) { - if (err) { - error_propagate(errp, err); - return NULL; - } - if (n->primary_device_id) { - dev = qdev_find_recursive(sysbus_get_default(), - n->primary_device_id); - } else { - error_setg(errp, "Primary device id not found"); - return NULL; - } + fid.n = n; + if (!qemu_opts_foreach(qemu_find_opts("device"), + failover_set_primary, &fid, &err)) { + return NULL; } - return dev; + return fid.id; } +/** + * Find the primary device for this failover virtio-net + * + * @n: VirtIONet device + * @errp: returns an error if this function fails + */ +static DeviceState *failover_find_primary_device(VirtIONet *n) +{ + char *id = failover_find_primary_device_id(n); + + if (!id) { + return NULL; + } + return qdev_find_recursive(sysbus_get_default(), id); +} -static DeviceState *virtio_connect_failover_devices(VirtIONet *n, - DeviceState *dev, - Error **errp) +static void failover_add_primary(VirtIONet *n, Error **errp) { - DeviceState *prim_dev = NULL; Error *err = NULL; + QemuOpts *opts; + char *id; + DeviceState *dev = failover_find_primary_device(n); - prim_dev = virtio_net_find_primary(n, &err); - if (prim_dev) { - n->primary_device_id = g_strdup(prim_dev->id); - n->primary_device_opts = prim_dev->opts; - } else { - error_propagate(errp, err); + if (dev) { + return; } - return prim_dev; + id = failover_find_primary_device_id(n); + if (!id) { + return; + } + opts = qemu_opts_find(qemu_find_opts("device"), id); + if (opts) { + dev = qdev_device_add(opts, &err); + if (err) { + qemu_opts_del(opts); + } + } else { + error_setg(errp, "Primary device not found"); + error_append_hint(errp, "Virtio-net failover will not work. Make " + "sure primary device has parameter" + " failover_pair_id=<virtio-net-id>\n"); + } + error_propagate(errp, err); } static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) @@ -929,25 +931,12 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) if (virtio_has_feature(features, VIRTIO_NET_F_STANDBY)) { qapi_event_send_failover_negotiated(n->netclient_name); - qatomic_set(&n->primary_should_be_hidden, false); + qatomic_set(&n->failover_primary_hidden, false); failover_add_primary(n, &err); if (err) { - n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); - if (err) { - goto out_err; - } - failover_add_primary(n, &err); - if (err) { - goto out_err; - } + warn_report_err(err); } } - return; - -out_err: - if (err) { - warn_report_err(err); - } } static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, @@ -3095,17 +3084,17 @@ void virtio_net_set_netclient_name(VirtIONet *n, const char *name, n->netclient_type = g_strdup(type); } -static bool failover_unplug_primary(VirtIONet *n) +static bool failover_unplug_primary(VirtIONet *n, DeviceState *dev) { HotplugHandler *hotplug_ctrl; PCIDevice *pci_dev; Error *err = NULL; - hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); + hotplug_ctrl = qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { - pci_dev = PCI_DEVICE(n->primary_dev); + pci_dev = PCI_DEVICE(dev); pci_dev->partially_hotplugged = true; - hotplug_handler_unplug_request(hotplug_ctrl, n->primary_dev, &err); + hotplug_handler_unplug_request(hotplug_ctrl, dev, &err); if (err) { error_report_err(err); return false; @@ -3116,41 +3105,31 @@ static bool failover_unplug_primary(VirtIONet *n) return true; } -static bool failover_replug_primary(VirtIONet *n, Error **errp) +static bool failover_replug_primary(VirtIONet *n, DeviceState *dev, + Error **errp) { Error *err = NULL; HotplugHandler *hotplug_ctrl; - PCIDevice *pdev = PCI_DEVICE(n->primary_dev); + PCIDevice *pdev = PCI_DEVICE(dev); + BusState *primary_bus; if (!pdev->partially_hotplugged) { return true; } - if (!n->primary_device_opts) { - n->primary_device_opts = qemu_opts_from_qdict( - qemu_find_opts("device"), - n->primary_device_dict, errp); - if (!n->primary_device_opts) { - return false; - } - } - n->primary_bus = n->primary_dev->parent_bus; - if (!n->primary_bus) { + primary_bus = dev->parent_bus; + if (!primary_bus) { error_setg(errp, "virtio_net: couldn't find primary bus"); return false; } - qdev_set_parent_bus(n->primary_dev, n->primary_bus, &error_abort); - n->primary_should_be_hidden = false; - if (!qemu_opt_set_bool(n->primary_device_opts, - "partially_hotplugged", true, errp)) { - return false; - } - hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); + qdev_set_parent_bus(dev, primary_bus, &error_abort); + qatomic_set(&n->failover_primary_hidden, false); + hotplug_ctrl = qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { - hotplug_handler_pre_plug(hotplug_ctrl, n->primary_dev, &err); + hotplug_handler_pre_plug(hotplug_ctrl, dev, &err); if (err) { goto out; } - hotplug_handler_plug(hotplug_ctrl, n->primary_dev, &err); + hotplug_handler_plug(hotplug_ctrl, dev, &err); } out: @@ -3158,34 +3137,29 @@ out: return !err; } -static void virtio_net_handle_migration_primary(VirtIONet *n, - MigrationState *s) +static void virtio_net_handle_migration_primary(VirtIONet *n, MigrationState *s) { bool should_be_hidden; Error *err = NULL; + DeviceState *dev = failover_find_primary_device(n); - should_be_hidden = qatomic_read(&n->primary_should_be_hidden); - - if (!n->primary_dev) { - n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); - if (!n->primary_dev) { - return; - } + if (!dev) { + return; } + should_be_hidden = qatomic_read(&n->failover_primary_hidden); + if (migration_in_setup(s) && !should_be_hidden) { - if (failover_unplug_primary(n)) { - vmstate_unregister(VMSTATE_IF(n->primary_dev), - qdev_get_vmsd(n->primary_dev), - n->primary_dev); - qapi_event_send_unplug_primary(n->primary_device_id); - qatomic_set(&n->primary_should_be_hidden, true); + if (failover_unplug_primary(n, dev)) { + vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); + qapi_event_send_unplug_primary(dev->id); + qatomic_set(&n->failover_primary_hidden, true); } else { warn_report("couldn't unplug primary device"); } } else if (migration_has_failed(s)) { /* We already unplugged the device let's plug it back */ - if (!failover_replug_primary(n, &err)) { + if (!failover_replug_primary(n, dev, &err)) { if (err) { error_report_err(err); } @@ -3200,55 +3174,22 @@ static void virtio_net_migration_state_notifier(Notifier *notifier, void *data) virtio_net_handle_migration_primary(n, s); } -static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - QemuOpts *device_opts) +static bool failover_hide_primary_device(DeviceListener *listener, + QemuOpts *device_opts) { VirtIONet *n = container_of(listener, VirtIONet, primary_listener); - bool match_found = false; - bool hide = false; + const char *standby_id; if (!device_opts) { - return -1; - } - n->primary_device_dict = qemu_opts_to_qdict(device_opts, - n->primary_device_dict); - if (n->primary_device_dict) { - g_free(n->standby_id); - n->standby_id = g_strdup(qdict_get_try_str(n->primary_device_dict, - "failover_pair_id")); - } - if (g_strcmp0(n->standby_id, n->netclient_name) == 0) { - match_found = true; - } else { - match_found = false; - hide = false; - g_free(n->standby_id); - n->primary_device_dict = NULL; - goto out; + return false; } - - n->primary_device_opts = device_opts; - - /* primary_should_be_hidden is set during feature negotiation */ - hide = qatomic_read(&n->primary_should_be_hidden); - - if (n->primary_device_dict) { - g_free(n->primary_device_id); - n->primary_device_id = g_strdup(qdict_get_try_str( - n->primary_device_dict, "id")); - if (!n->primary_device_id) { - warn_report("primary_device_id not set"); - } + standby_id = qemu_opt_get(device_opts, "failover_pair_id"); + if (g_strcmp0(standby_id, n->netclient_name) != 0) { + return false; } -out: - if (match_found && hide) { - return 1; - } else if (match_found && !hide) { - return 0; - } else { - return -1; - } + /* failover_primary_hidden is set during feature negotiation */ + return qatomic_read(&n->failover_primary_hidden); } static void virtio_net_device_realize(DeviceState *dev, Error **errp) @@ -3285,9 +3226,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) } if (n->failover) { - n->primary_listener.should_be_hidden = - virtio_net_primary_should_be_hidden; - qatomic_set(&n->primary_should_be_hidden, true); + n->primary_listener.hide_device = failover_hide_primary_device; + qatomic_set(&n->failover_primary_hidden, true); device_listener_register(&n->primary_listener); n->migration_state.notify = virtio_net_migration_state_notifier; add_migration_state_change_notifier(&n->migration_state); @@ -3426,10 +3366,6 @@ static void virtio_net_device_unrealize(DeviceState *dev) if (n->failover) { device_listener_unregister(&n->primary_listener); - g_free(n->primary_device_id); - g_free(n->standby_id); - qobject_unref(n->primary_device_dict); - n->primary_device_dict = NULL; } max_queues = n->multiqueue ? n->max_queues : 1; @@ -3475,13 +3411,15 @@ static int virtio_net_pre_save(void *opaque) static bool primary_unplug_pending(void *opaque) { DeviceState *dev = opaque; + DeviceState *primary; VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIONet *n = VIRTIO_NET(vdev); if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_STANDBY)) { return false; } - return n->primary_dev ? n->primary_dev->pending_deleted_event : false; + primary = failover_find_primary_device(n); + return primary ? primary->pending_deleted_event : false; } static bool dev_unplug_pending(void *opaque) |