:p
atchew
Login
The following changes since commit 0fc0142828b5bc965790a1c5c6e241897d3387cb: Merge remote-tracking branch 'remotes/kraxel/tags/input-20200921-pull-request' into staging (2020-09-22 21:11:10 +0100) are available in the Git repository at: https://github.com/stefanha/qemu.git tags/block-pull-request for you to fetch changes up to d73415a315471ac0b127ed3fad45c8ec5d711de1: qemu/atomic.h: rename atomic_ to qatomic_ (2020-09-23 16:07:44 +0100) ---------------------------------------------------------------- Pull request This includes the atomic_ -> qatomic_ rename that touches many files and is prone to conflicts. ---------------------------------------------------------------- Halil Pasic (1): virtio: add vhost-user-fs-ccw device Marc Hartmayer (1): libvhost-user: handle endianness as mandated by the spec Stefan Hajnoczi (11): MAINTAINERS: add Stefan Hajnoczi as block/nvme.c maintainer util/iov: add iov_discard_undo() virtio-blk: undo destructive iov_discard_*() operations virtio-crypto: don't modify elem->in/out_sg docs/system: clarify deprecation schedule gitmodules: switch to qemu.org qboot mirror gitmodules: switch to qemu.org meson mirror gitmodules: add qemu.org vbootrom submodule fdmon-poll: reset npfd when upgrading to fdmon-epoll tests: add test-fdmon-epoll qemu/atomic.h: rename atomic_ to qatomic_ MAINTAINERS | 5 +- include/qemu/atomic.h | 248 +++++++++--------- docs/devel/lockcnt.txt | 8 +- docs/devel/rcu.txt | 34 +-- accel/tcg/atomic_template.h | 20 +- include/block/aio-wait.h | 4 +- include/block/aio.h | 8 +- include/exec/cpu_ldst.h | 2 +- include/exec/exec-all.h | 6 +- include/exec/log.h | 6 +- include/exec/memory.h | 2 +- include/exec/ram_addr.h | 26 +- include/exec/ramlist.h | 2 +- include/exec/tb-lookup.h | 4 +- include/hw/core/cpu.h | 2 +- include/hw/virtio/virtio-blk.h | 2 + include/qemu/atomic128.h | 6 +- include/qemu/bitops.h | 2 +- include/qemu/coroutine.h | 2 +- include/qemu/iov.h | 23 ++ include/qemu/log.h | 6 +- include/qemu/queue.h | 7 +- include/qemu/rcu.h | 10 +- include/qemu/rcu_queue.h | 100 +++---- include/qemu/seqlock.h | 8 +- include/qemu/stats64.h | 28 +- include/qemu/thread.h | 24 +- .../infiniband/hw/vmw_pvrdma/pvrdma_ring.h | 14 +- linux-user/qemu.h | 2 +- tcg/i386/tcg-target.h | 2 +- tcg/s390/tcg-target.h | 2 +- tcg/tci/tcg-target.h | 2 +- accel/kvm/kvm-all.c | 12 +- accel/tcg/cpu-exec.c | 15 +- accel/tcg/cputlb.c | 24 +- accel/tcg/tcg-all.c | 2 +- accel/tcg/translate-all.c | 55 ++-- audio/jackaudio.c | 18 +- block.c | 4 +- block/block-backend.c | 15 +- block/io.c | 48 ++-- block/nfs.c | 2 +- block/sheepdog.c | 2 +- block/throttle-groups.c | 12 +- block/throttle.c | 4 +- blockdev.c | 2 +- blockjob.c | 2 +- contrib/libvhost-user/libvhost-user.c | 79 +++--- cpus-common.c | 26 +- dump/dump.c | 8 +- exec.c | 49 ++-- hw/block/virtio-blk.c | 11 +- hw/core/cpu.c | 6 +- hw/display/qxl.c | 4 +- hw/hyperv/hyperv.c | 10 +- hw/hyperv/vmbus.c | 2 +- hw/i386/xen/xen-hvm.c | 2 +- hw/intc/rx_icu.c | 12 +- hw/intc/sifive_plic.c | 4 +- hw/misc/edu.c | 16 +- hw/net/virtio-net.c | 10 +- hw/rdma/rdma_backend.c | 18 +- hw/rdma/rdma_rm.c | 2 +- hw/rdma/vmw/pvrdma_dev_ring.c | 4 +- hw/s390x/s390-pci-bus.c | 2 +- hw/s390x/vhost-user-fs-ccw.c | 75 ++++++ hw/s390x/virtio-ccw.c | 2 +- hw/virtio/vhost.c | 2 +- hw/virtio/virtio-crypto.c | 17 +- hw/virtio/virtio-mmio.c | 6 +- hw/virtio/virtio-pci.c | 6 +- hw/virtio/virtio.c | 16 +- hw/xtensa/pic_cpu.c | 4 +- iothread.c | 6 +- linux-user/hppa/cpu_loop.c | 11 +- linux-user/signal.c | 8 +- migration/colo-failover.c | 4 +- migration/migration.c | 8 +- migration/multifd.c | 18 +- migration/postcopy-ram.c | 34 +-- migration/rdma.c | 34 +-- monitor/hmp.c | 6 +- monitor/misc.c | 2 +- monitor/monitor.c | 6 +- qemu-nbd.c | 2 +- qga/commands.c | 12 +- qom/object.c | 20 +- scsi/qemu-pr-helper.c | 4 +- softmmu/cpu-throttle.c | 10 +- softmmu/cpus.c | 42 +-- softmmu/memory.c | 6 +- softmmu/vl.c | 2 +- target/arm/mte_helper.c | 6 +- target/hppa/op_helper.c | 2 +- target/i386/mem_helper.c | 2 +- target/i386/whpx-all.c | 6 +- target/riscv/cpu_helper.c | 2 +- target/s390x/mem_helper.c | 4 +- target/xtensa/exc_helper.c | 4 +- target/xtensa/op_helper.c | 2 +- tcg/tcg.c | 58 ++-- tcg/tci.c | 2 +- tests/atomic64-bench.c | 14 +- tests/atomic_add-bench.c | 14 +- tests/iothread.c | 2 +- tests/qht-bench.c | 12 +- tests/rcutorture.c | 24 +- tests/test-aio-multithread.c | 52 ++-- tests/test-fdmon-epoll.c | 73 ++++++ tests/test-iov.c | 165 ++++++++++++ tests/test-logging.c | 4 +- tests/test-rcu-list.c | 38 +-- tests/test-thread-pool.c | 10 +- util/aio-posix.c | 14 +- util/aio-wait.c | 2 +- util/aio-win32.c | 5 +- util/async.c | 28 +- util/atomic64.c | 10 +- util/bitmap.c | 14 +- util/cacheinfo.c | 2 +- util/fdmon-epoll.c | 4 +- util/fdmon-io_uring.c | 12 +- util/fdmon-poll.c | 1 + util/iov.c | 50 +++- util/lockcnt.c | 52 ++-- util/log.c | 10 +- util/qemu-coroutine-lock.c | 18 +- util/qemu-coroutine-sleep.c | 4 +- util/qemu-coroutine.c | 6 +- util/qemu-sockets.c | 4 +- util/qemu-thread-posix.c | 12 +- util/qemu-thread-win32.c | 12 +- util/qemu-timer.c | 12 +- util/qht.c | 57 ++-- util/qsp.c | 50 ++-- util/rcu.c | 36 +-- util/stats64.c | 34 +-- .gitmodules | 6 +- docs/devel/atomics.rst | 134 +++++----- docs/system/deprecated.rst | 9 +- hw/s390x/meson.build | 1 + scripts/kernel-doc | 2 +- tcg/aarch64/tcg-target.c.inc | 2 +- tcg/mips/tcg-target.c.inc | 2 +- tcg/ppc/tcg-target.c.inc | 6 +- tcg/sparc/tcg-target.c.inc | 5 +- tests/meson.build | 3 + 147 files changed, 1508 insertions(+), 1069 deletions(-) create mode 100644 hw/s390x/vhost-user-fs-ccw.c create mode 100644 tests/test-fdmon-epoll.c -- 2.26.2
Development of the userspace NVMe block driver picked up again recently. After talking with Fam I am stepping up as block/nvme.c maintainer. Patches will be merged through my 'block' tree. Cc: Kevin Wolf <kwolf@redhat.com> Cc: Klaus Jensen <k.jensen@samsung.com> Cc: Fam Zheng <fam@euphon.net> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Acked-by: Kevin Wolf <kwolf@redhat.com> Acked-by: Klaus Jensen <k.jensen@samsung.com> Acked-by: Fam Zheng <fam@euphon.net> Message-id: 20200907111632.90499-1-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ S: Supported F: block/null.c NVMe Block Driver -M: Fam Zheng <fam@euphon.net> +M: Stefan Hajnoczi <stefanha@redhat.com> +R: Fam Zheng <fam@euphon.net> L: qemu-block@nongnu.org S: Supported F: block/nvme* +T: git https://github.com/stefanha/qemu.git block Bootdevice M: Gonglei <arei.gonglei@huawei.com> -- 2.26.2
From: Marc Hartmayer <mhartmay@linux.ibm.com> Since virtio existed even before it got standardized, the virtio standard defines the following types of virtio devices: + legacy device (pre-virtio 1.0) + non-legacy or VIRTIO 1.0 device + transitional device (which can act both as legacy and non-legacy) Virtio 1.0 defines the fields of the virtqueues as little endian, while legacy uses guest's native endian [1]. Currently libvhost-user does not handle virtio endianness at all, i.e. it works only if the native endianness matches with whatever is actually needed. That means things break spectacularly on big-endian targets. Let us handle virtio endianness for non-legacy as required by the virtio specification [1] and fence legacy virtio, as there is no safe way to figure out the needed endianness conversions for all cases. The fencing of legacy virtio devices is done in `vu_set_features_exec`. [1] https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-210003 Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com> Message-id: 20200901150019.29229-3-mhartmay@linux.ibm.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- contrib/libvhost-user/libvhost-user.c | 77 +++++++++++++++------------ 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index XXXXXXX..XXXXXXX 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -XXX,XX +XXX,XX @@ #include "qemu/atomic.h" #include "qemu/osdep.h" +#include "qemu/bswap.h" #include "qemu/memfd.h" #include "libvhost-user.h" @@ -XXX,XX +XXX,XX @@ vu_set_features_exec(VuDev *dev, VhostUserMsg *vmsg) DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); dev->features = vmsg->payload.u64; + if (!vu_has_feature(dev, VIRTIO_F_VERSION_1)) { + /* + * We only support devices conforming to VIRTIO 1.0 or + * later + */ + vu_panic(dev, "virtio legacy devices aren't supported by libvhost-user"); + return false; + } if (!(dev->features & VHOST_USER_F_PROTOCOL_FEATURES)) { vu_set_enable_all_rings(dev, true); @@ -XXX,XX +XXX,XX @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg) return false; } - vq->used_idx = vq->vring.used->idx; + vq->used_idx = lduw_le_p(&vq->vring.used->idx); if (vq->last_avail_idx != vq->used_idx) { bool resume = dev->iface->queue_is_processed_in_order && @@ -XXX,XX +XXX,XX @@ vu_check_queue_inflights(VuDev *dev, VuVirtq *vq) return 0; } - vq->used_idx = vq->vring.used->idx; + vq->used_idx = lduw_le_p(&vq->vring.used->idx); vq->resubmit_num = 0; vq->resubmit_list = NULL; vq->counter = 0; @@ -XXX,XX +XXX,XX @@ vu_queue_started(const VuDev *dev, const VuVirtq *vq) static inline uint16_t vring_avail_flags(VuVirtq *vq) { - return vq->vring.avail->flags; + return lduw_le_p(&vq->vring.avail->flags); } static inline uint16_t vring_avail_idx(VuVirtq *vq) { - vq->shadow_avail_idx = vq->vring.avail->idx; + vq->shadow_avail_idx = lduw_le_p(&vq->vring.avail->idx); return vq->shadow_avail_idx; } @@ -XXX,XX +XXX,XX @@ vring_avail_idx(VuVirtq *vq) static inline uint16_t vring_avail_ring(VuVirtq *vq, int i) { - return vq->vring.avail->ring[i]; + return lduw_le_p(&vq->vring.avail->ring[i]); } static inline uint16_t @@ -XXX,XX +XXX,XX @@ virtqueue_read_next_desc(VuDev *dev, struct vring_desc *desc, int i, unsigned int max, unsigned int *next) { /* If this descriptor says it doesn't chain, we're done. */ - if (!(desc[i].flags & VRING_DESC_F_NEXT)) { + if (!(lduw_le_p(&desc[i].flags) & VRING_DESC_F_NEXT)) { return VIRTQUEUE_READ_DESC_DONE; } /* Check they're not leading us off end of descriptors. */ - *next = desc[i].next; + *next = lduw_le_p(&desc[i].next); /* Make sure compiler knows to grab that: we don't want it changing! */ smp_wmb(); @@ -XXX,XX +XXX,XX @@ vu_queue_get_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int *in_bytes, } desc = vq->vring.desc; - if (desc[i].flags & VRING_DESC_F_INDIRECT) { - if (desc[i].len % sizeof(struct vring_desc)) { + if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_INDIRECT) { + if (ldl_le_p(&desc[i].len) % sizeof(struct vring_desc)) { vu_panic(dev, "Invalid size for indirect buffer table"); goto err; } @@ -XXX,XX +XXX,XX @@ vu_queue_get_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int *in_bytes, /* loop over the indirect descriptor table */ indirect = 1; - desc_addr = desc[i].addr; - desc_len = desc[i].len; + desc_addr = ldq_le_p(&desc[i].addr); + desc_len = ldl_le_p(&desc[i].len); max = desc_len / sizeof(struct vring_desc); read_len = desc_len; desc = vu_gpa_to_va(dev, &read_len, desc_addr); @@ -XXX,XX +XXX,XX @@ vu_queue_get_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int *in_bytes, goto err; } - if (desc[i].flags & VRING_DESC_F_WRITE) { - in_total += desc[i].len; + if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_WRITE) { + in_total += ldl_le_p(&desc[i].len); } else { - out_total += desc[i].len; + out_total += ldl_le_p(&desc[i].len); } if (in_total >= max_in_bytes && out_total >= max_out_bytes) { goto done; @@ -XXX,XX +XXX,XX @@ vring_used_flags_set_bit(VuVirtq *vq, int mask) flags = (uint16_t *)((char*)vq->vring.used + offsetof(struct vring_used, flags)); - *flags |= mask; + stw_le_p(flags, lduw_le_p(flags) | mask); } static inline void @@ -XXX,XX +XXX,XX @@ vring_used_flags_unset_bit(VuVirtq *vq, int mask) flags = (uint16_t *)((char*)vq->vring.used + offsetof(struct vring_used, flags)); - *flags &= ~mask; + stw_le_p(flags, lduw_le_p(flags) & ~mask); } static inline void @@ -XXX,XX +XXX,XX @@ vring_set_avail_event(VuVirtq *vq, uint16_t val) return; } - *((uint16_t *) &vq->vring.used->ring[vq->vring.num]) = val; + stw_le_p(&vq->vring.used->ring[vq->vring.num], val); } void @@ -XXX,XX +XXX,XX @@ vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz) struct vring_desc desc_buf[VIRTQUEUE_MAX_SIZE]; int rc; - if (desc[i].flags & VRING_DESC_F_INDIRECT) { - if (desc[i].len % sizeof(struct vring_desc)) { + if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_INDIRECT) { + if (ldl_le_p(&desc[i].len) % sizeof(struct vring_desc)) { vu_panic(dev, "Invalid size for indirect buffer table"); } /* loop over the indirect descriptor table */ - desc_addr = desc[i].addr; - desc_len = desc[i].len; + desc_addr = ldq_le_p(&desc[i].addr); + desc_len = ldl_le_p(&desc[i].len); max = desc_len / sizeof(struct vring_desc); read_len = desc_len; desc = vu_gpa_to_va(dev, &read_len, desc_addr); @@ -XXX,XX +XXX,XX @@ vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz) /* Collect all the descriptors */ do { - if (desc[i].flags & VRING_DESC_F_WRITE) { + if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_WRITE) { virtqueue_map_desc(dev, &in_num, iov + out_num, VIRTQUEUE_MAX_SIZE - out_num, true, - desc[i].addr, desc[i].len); + ldq_le_p(&desc[i].addr), ldl_le_p(&desc[i].len)); } else { if (in_num) { vu_panic(dev, "Incorrect order for descriptors"); @@ -XXX,XX +XXX,XX @@ vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz) } virtqueue_map_desc(dev, &out_num, iov, VIRTQUEUE_MAX_SIZE, false, - desc[i].addr, desc[i].len); + ldq_le_p(&desc[i].addr), ldl_le_p(&desc[i].len)); } /* If we've got too many, that implies a descriptor loop. */ @@ -XXX,XX +XXX,XX @@ vu_log_queue_fill(VuDev *dev, VuVirtq *vq, max = vq->vring.num; i = elem->index; - if (desc[i].flags & VRING_DESC_F_INDIRECT) { - if (desc[i].len % sizeof(struct vring_desc)) { + if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_INDIRECT) { + if (ldl_le_p(&desc[i].len) % sizeof(struct vring_desc)) { vu_panic(dev, "Invalid size for indirect buffer table"); } /* loop over the indirect descriptor table */ - desc_addr = desc[i].addr; - desc_len = desc[i].len; + desc_addr = ldq_le_p(&desc[i].addr); + desc_len = ldl_le_p(&desc[i].len); max = desc_len / sizeof(struct vring_desc); read_len = desc_len; desc = vu_gpa_to_va(dev, &read_len, desc_addr); @@ -XXX,XX +XXX,XX @@ vu_log_queue_fill(VuDev *dev, VuVirtq *vq, return; } - if (desc[i].flags & VRING_DESC_F_WRITE) { - min = MIN(desc[i].len, len); - vu_log_write(dev, desc[i].addr, min); + if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_WRITE) { + min = MIN(ldl_le_p(&desc[i].len), len); + vu_log_write(dev, ldq_le_p(&desc[i].addr), min); len -= min; } @@ -XXX,XX +XXX,XX @@ vu_queue_fill(VuDev *dev, VuVirtq *vq, idx = (idx + vq->used_idx) % vq->vring.num; - uelem.id = elem->index; - uelem.len = len; + stl_le_p(&uelem.id, elem->index); + stl_le_p(&uelem.len, len); vring_used_write(dev, vq, &uelem, idx); } static inline void vring_used_idx_set(VuDev *dev, VuVirtq *vq, uint16_t val) { - vq->vring.used->idx = val; + stw_le_p(&vq->vring.used->idx, val); vu_log_write(dev, vq->vring.log_guest_addr + offsetof(struct vring_used, idx), sizeof(vq->vring.used->idx)); -- 2.26.2
From: Halil Pasic <pasic@linux.ibm.com> Wire up the CCW device for vhost-user-fs. Reviewed-by: Cornelia Huck <cohuck@redhat.com> Signed-off-by: Halil Pasic <pasic@linux.ibm.com> Message-id: 20200901150019.29229-2-mhartmay@linux.ibm.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- hw/s390x/vhost-user-fs-ccw.c | 75 ++++++++++++++++++++++++++++++++++++ hw/s390x/meson.build | 1 + 2 files changed, 76 insertions(+) create mode 100644 hw/s390x/vhost-user-fs-ccw.c diff --git a/hw/s390x/vhost-user-fs-ccw.c b/hw/s390x/vhost-user-fs-ccw.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/s390x/vhost-user-fs-ccw.c @@ -XXX,XX +XXX,XX @@ +/* + * virtio ccw vhost-user-fs implementation + * + * Copyright 2020 IBM Corp. + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ +#include "qemu/osdep.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" +#include "hw/virtio/vhost-user-fs.h" +#include "virtio-ccw.h" + +typedef struct VHostUserFSCcw { + VirtioCcwDevice parent_obj; + VHostUserFS vdev; +} VHostUserFSCcw; + +#define TYPE_VHOST_USER_FS_CCW "vhost-user-fs-ccw" +#define VHOST_USER_FS_CCW(obj) \ + OBJECT_CHECK(VHostUserFSCcw, (obj), TYPE_VHOST_USER_FS_CCW) + + +static Property vhost_user_fs_ccw_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, + VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, + VIRTIO_CCW_MAX_REV), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vhost_user_fs_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp) +{ + VHostUserFSCcw *dev = VHOST_USER_FS_CCW(ccw_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_realize(vdev, BUS(&ccw_dev->bus), errp); +} + +static void vhost_user_fs_ccw_instance_init(Object *obj) +{ + VHostUserFSCcw *dev = VHOST_USER_FS_CCW(obj); + VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj); + + ccw_dev->force_revision_1 = true; + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_FS); +} + +static void vhost_user_fs_ccw_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->realize = vhost_user_fs_ccw_realize; + device_class_set_props(dc, vhost_user_fs_ccw_properties); + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); +} + +static const TypeInfo vhost_user_fs_ccw = { + .name = TYPE_VHOST_USER_FS_CCW, + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VHostUserFSCcw), + .instance_init = vhost_user_fs_ccw_instance_init, + .class_init = vhost_user_fs_ccw_class_init, +}; + +static void vhost_user_fs_ccw_register(void) +{ + type_register_static(&vhost_user_fs_ccw); +} + +type_init(vhost_user_fs_ccw_register) diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/meson.build +++ b/hw/s390x/meson.build @@ -XXX,XX +XXX,XX @@ virtio_ss.add(when: 'CONFIG_VIRTIO_SCSI', if_true: files('virtio-ccw-scsi.c')) virtio_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-ccw-serial.c')) virtio_ss.add(when: ['CONFIG_VIRTIO_9P', 'CONFIG_VIRTFS'], if_true: files('virtio-ccw-blk.c')) virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-ccw.c')) +virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-ccw.c')) s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss) hw_arch += {'s390x': s390x_ss} -- 2.26.2
The iov_discard_front/back() operations are useful for parsing iovecs but they modify the array elements. If the original array is needed after parsing finishes there is currently no way to restore it. Although g_memdup() can be used before performing destructive iov_discard_front/back() operations, this is inefficient. Introduce iov_discard_undo() to restore the array to the state prior to an iov_discard_front/back() operation. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Li Qiang <liq3ea@gmail.com> Message-Id: <20200917094455.822379-2-stefanha@redhat.com> --- include/qemu/iov.h | 23 +++++++ tests/test-iov.c | 165 +++++++++++++++++++++++++++++++++++++++++++++ util/iov.c | 50 ++++++++++++-- 3 files changed, 234 insertions(+), 4 deletions(-) diff --git a/include/qemu/iov.h b/include/qemu/iov.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/iov.h +++ b/include/qemu/iov.h @@ -XXX,XX +XXX,XX @@ size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, size_t bytes); +/* Information needed to undo an iov_discard_*() operation */ +typedef struct { + struct iovec *modified_iov; + struct iovec orig; +} IOVDiscardUndo; + +/* + * Undo an iov_discard_front_undoable() or iov_discard_back_undoable() + * operation. If multiple operations are made then each one needs a separate + * IOVDiscardUndo and iov_discard_undo() must be called in the reverse order + * that the operations were made. + */ +void iov_discard_undo(IOVDiscardUndo *undo); + +/* + * Undoable versions of iov_discard_front() and iov_discard_back(). Use + * iov_discard_undo() to reset to the state before the discard operations. + */ +size_t iov_discard_front_undoable(struct iovec **iov, unsigned int *iov_cnt, + size_t bytes, IOVDiscardUndo *undo); +size_t iov_discard_back_undoable(struct iovec *iov, unsigned int *iov_cnt, + size_t bytes, IOVDiscardUndo *undo); + typedef struct QEMUIOVector { struct iovec *iov; int niov; diff --git a/tests/test-iov.c b/tests/test-iov.c index XXXXXXX..XXXXXXX 100644 --- a/tests/test-iov.c +++ b/tests/test-iov.c @@ -XXX,XX +XXX,XX @@ static void iov_free(struct iovec *iov, unsigned niov) g_free(iov); } +static bool iov_equals(const struct iovec *a, const struct iovec *b, + unsigned niov) +{ + return memcmp(a, b, sizeof(a[0]) * niov) == 0; +} + static void test_iov_bytes(struct iovec *iov, unsigned niov, size_t offset, size_t bytes) { @@ -XXX,XX +XXX,XX @@ static void test_discard_front(void) iov_free(iov, iov_cnt); } +static void test_discard_front_undo(void) +{ + IOVDiscardUndo undo; + struct iovec *iov; + struct iovec *iov_tmp; + struct iovec *iov_orig; + unsigned int iov_cnt; + unsigned int iov_cnt_tmp; + size_t size; + + /* Discard zero bytes */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, 0, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard more bytes than vector size */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + size = iov_size(iov, iov_cnt); + iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size + 1, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard entire vector */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + size = iov_size(iov, iov_cnt); + iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard within first element */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + size = g_test_rand_int_range(1, iov->iov_len); + iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard entire first element */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, iov->iov_len, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard within second element */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len); + iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); +} + static void test_discard_back(void) { struct iovec *iov; @@ -XXX,XX +XXX,XX @@ static void test_discard_back(void) iov_free(iov, iov_cnt); } +static void test_discard_back_undo(void) +{ + IOVDiscardUndo undo; + struct iovec *iov; + struct iovec *iov_orig; + unsigned int iov_cnt; + unsigned int iov_cnt_tmp; + size_t size; + + /* Discard zero bytes */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_cnt_tmp = iov_cnt; + iov_discard_back_undoable(iov, &iov_cnt_tmp, 0, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard more bytes than vector size */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_cnt_tmp = iov_cnt; + size = iov_size(iov, iov_cnt); + iov_discard_back_undoable(iov, &iov_cnt_tmp, size + 1, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard entire vector */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_cnt_tmp = iov_cnt; + size = iov_size(iov, iov_cnt); + iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard within last element */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_cnt_tmp = iov_cnt; + size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len); + iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard entire last element */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_cnt_tmp = iov_cnt; + size = iov[iov_cnt - 1].iov_len; + iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); + + /* Discard within second-to-last element */ + iov_random(&iov, &iov_cnt); + iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt); + iov_cnt_tmp = iov_cnt; + size = iov[iov_cnt - 1].iov_len + + g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len); + iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo); + iov_discard_undo(&undo); + assert(iov_equals(iov, iov_orig, iov_cnt)); + g_free(iov_orig); + iov_free(iov, iov_cnt); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) g_test_add_func("/basic/iov/io", test_io); g_test_add_func("/basic/iov/discard-front", test_discard_front); g_test_add_func("/basic/iov/discard-back", test_discard_back); + g_test_add_func("/basic/iov/discard-front-undo", test_discard_front_undo); + g_test_add_func("/basic/iov/discard-back-undo", test_discard_back_undo); return g_test_run(); } diff --git a/util/iov.c b/util/iov.c index XXXXXXX..XXXXXXX 100644 --- a/util/iov.c +++ b/util/iov.c @@ -XXX,XX +XXX,XX @@ void qemu_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, void *buf) } } -size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, - size_t bytes) +void iov_discard_undo(IOVDiscardUndo *undo) +{ + /* Restore original iovec if it was modified */ + if (undo->modified_iov) { + *undo->modified_iov = undo->orig; + } +} + +size_t iov_discard_front_undoable(struct iovec **iov, + unsigned int *iov_cnt, + size_t bytes, + IOVDiscardUndo *undo) { size_t total = 0; struct iovec *cur; + if (undo) { + undo->modified_iov = NULL; + } + for (cur = *iov; *iov_cnt > 0; cur++) { if (cur->iov_len > bytes) { + if (undo) { + undo->modified_iov = cur; + undo->orig = *cur; + } + cur->iov_base += bytes; cur->iov_len -= bytes; total += bytes; @@ -XXX,XX +XXX,XX @@ size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, return total; } -size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, - size_t bytes) +size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, + size_t bytes) +{ + return iov_discard_front_undoable(iov, iov_cnt, bytes, NULL); +} + +size_t iov_discard_back_undoable(struct iovec *iov, + unsigned int *iov_cnt, + size_t bytes, + IOVDiscardUndo *undo) { size_t total = 0; struct iovec *cur; + if (undo) { + undo->modified_iov = NULL; + } + if (*iov_cnt == 0) { return 0; } @@ -XXX,XX +XXX,XX @@ size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, while (*iov_cnt > 0) { if (cur->iov_len > bytes) { + if (undo) { + undo->modified_iov = cur; + undo->orig = *cur; + } + cur->iov_len -= bytes; total += bytes; break; @@ -XXX,XX +XXX,XX @@ size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, return total; } +size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, + size_t bytes) +{ + return iov_discard_back_undoable(iov, iov_cnt, bytes, NULL); +} + void qemu_iovec_discard_back(QEMUIOVector *qiov, size_t bytes) { size_t total; -- 2.26.2
Fuzzing discovered that virtqueue_unmap_sg() is being called on modified req->in/out_sg iovecs. This means dma_memory_map() and dma_memory_unmap() calls do not have matching memory addresses. Fuzzing discovered that non-RAM addresses trigger a bug: void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len, bool is_write, hwaddr access_len) { if (buffer != bounce.buffer) { ^^^^^^^^^^^^^^^^^^^^^^^ A modified iov->iov_base is no longer recognized as a bounce buffer and the wrong branch is taken. There are more potential bugs: dirty memory is not tracked correctly and MemoryRegion refcounts can be leaked. Use the new iov_discard_undo() API to restore elem->in/out_sg before virtqueue_push() is called. Fixes: 827805a2492c1bbf1c0712ed18ee069b4ebf3dd6 ("virtio-blk: Convert VirtIOBlockReq.out to structrue") Reported-by: Alexander Bulekov <alxndr@bu.edu> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Li Qiang <liq3ea@gmail.com> Buglink: https://bugs.launchpad.net/qemu/+bug/1890360 Message-Id: <20200917094455.822379-3-stefanha@redhat.com> --- include/hw/virtio/virtio-blk.h | 2 ++ hw/block/virtio-blk.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -XXX,XX +XXX,XX @@ typedef struct VirtIOBlockReq { int64_t sector_num; VirtIOBlock *dev; VirtQueue *vq; + IOVDiscardUndo inhdr_undo; + IOVDiscardUndo outhdr_undo; struct virtio_blk_inhdr *in; struct virtio_blk_outhdr out; QEMUIOVector qiov; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index XXXXXXX..XXXXXXX 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -XXX,XX +XXX,XX @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) trace_virtio_blk_req_complete(vdev, req, status); stb_p(&req->in->status, status); + iov_discard_undo(&req->inhdr_undo); + iov_discard_undo(&req->outhdr_undo); virtqueue_push(req->vq, &req->elem, req->in_len); if (s->dataplane_started && !s->dataplane_disabled) { virtio_blk_data_plane_notify(s->dataplane, req->vq); @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) return -1; } - iov_discard_front(&out_iov, &out_num, sizeof(req->out)); + iov_discard_front_undoable(&out_iov, &out_num, sizeof(req->out), + &req->outhdr_undo); if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) { virtio_error(vdev, "virtio-blk request inhdr too short"); + iov_discard_undo(&req->outhdr_undo); return -1; } @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) req->in = (void *)in_iov[in_num - 1].iov_base + in_iov[in_num - 1].iov_len - sizeof(struct virtio_blk_inhdr); - iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr)); + iov_discard_back_undoable(in_iov, &in_num, sizeof(struct virtio_blk_inhdr), + &req->inhdr_undo); type = virtio_ldl_p(vdev, &req->out.type); @@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) if (unlikely(iov_to_buf(out_iov, out_num, 0, &dwz_hdr, sizeof(dwz_hdr)) != sizeof(dwz_hdr))) { + iov_discard_undo(&req->inhdr_undo); + iov_discard_undo(&req->outhdr_undo); virtio_error(vdev, "virtio-blk discard/write_zeroes header" " too short"); return -1; -- 2.26.2
A number of iov_discard_front/back() operations are made by virtio-crypto. The elem->in/out_sg iovec arrays are modified by these operations, resulting virtqueue_unmap_sg() calls on different addresses than were originally mapped. This is problematic because dirty memory may not be logged correctly, MemoryRegion refcounts may be leaked, and the non-RAM bounce buffer can be leaked. Take a copy of the elem->in/out_sg arrays so that the originals are preserved. The iov_discard_undo() API could be used instead (with better performance) but requires careful auditing of the code, so do the simple thing instead. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Li Qiang <liq3ea@gmail.com> Message-Id: <20200917094455.822379-4-stefanha@redhat.com> --- hw/virtio/virtio-crypto.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index XXXXXXX..XXXXXXX 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -XXX,XX +XXX,XX @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) size_t s; for (;;) { + g_autofree struct iovec *out_iov_copy = NULL; + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); if (!elem) { break; @@ -XXX,XX +XXX,XX @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } out_num = elem->out_num; - out_iov = elem->out_sg; + out_iov_copy = g_memdup(elem->out_sg, sizeof(out_iov[0]) * out_num); + out_iov = out_iov_copy; + in_num = elem->in_num; in_iov = elem->in_sg; + if (unlikely(iov_to_buf(out_iov, out_num, 0, &ctrl, sizeof(ctrl)) != sizeof(ctrl))) { virtio_error(vdev, "virtio-crypto request ctrl_hdr too short"); @@ -XXX,XX +XXX,XX @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) int queue_index = virtio_crypto_vq2q(virtio_get_queue_index(request->vq)); struct virtio_crypto_op_data_req req; int ret; + g_autofree struct iovec *in_iov_copy = NULL; + g_autofree struct iovec *out_iov_copy = NULL; struct iovec *in_iov; struct iovec *out_iov; unsigned in_num; @@ -XXX,XX +XXX,XX @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) } out_num = elem->out_num; - out_iov = elem->out_sg; + out_iov_copy = g_memdup(elem->out_sg, sizeof(out_iov[0]) * out_num); + out_iov = out_iov_copy; + in_num = elem->in_num; - in_iov = elem->in_sg; + in_iov_copy = g_memdup(elem->in_sg, sizeof(in_iov[0]) * in_num); + in_iov = in_iov_copy; + if (unlikely(iov_to_buf(out_iov, out_num, 0, &req, sizeof(req)) != sizeof(req))) { virtio_error(vdev, "virtio-crypto request outhdr too short"); -- 2.26.2
The sentence explaining the deprecation schedule is ambiguous. Make it clear that a feature deprecated in the Nth release is guaranteed to remain available in the N+1th release. Removal can occur in the N+2nd release or later. As an example of this in action, see commit 25956af3fe5dd0385ad8017bc768a6afe41e2a74 ("block: Finish deprecation of 'qemu-img convert -n -o'"). The feature was deprecated in QEMU 4.2.0. It was present in the 5.0.0 release and removed in the 5.1.0 release. Suggested-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Message-Id: <20200915150734.711426-1-stefanha@redhat.com> --- docs/system/deprecated.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -XXX,XX +XXX,XX @@ Deprecated features In general features are intended to be supported indefinitely once introduced into QEMU. In the event that a feature needs to be removed, -it will be listed in this section. The feature will remain functional -for 2 releases prior to actual removal. Deprecated features may also -generate warnings on the console when QEMU starts up, or if activated -via a monitor command, however, this is not a mandatory requirement. +it will be listed in this section. The feature will remain functional for the +release in which it was deprecated and one further release. After these two +releases, the feature is liable to be removed. Deprecated features may also +generate warnings on the console when QEMU starts up, or if activated via a +monitor command, however, this is not a mandatory requirement. Prior to the 2.10.0 release there was no official policy on how long features would be deprecated prior to their removal, nor -- 2.26.2
QEMU now hosts a mirror of qboot.git. QEMU mirrors third-party code to ensure that users can always build QEMU even if the dependency goes offline and so QEMU meets its responsibilities to provide full source code under software licenses. Suggested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20200915130834.706758-2-stefanha@redhat.com> --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index XXXXXXX..XXXXXXX 100644 --- a/.gitmodules +++ b/.gitmodules @@ -XXX,XX +XXX,XX @@ url = https://git.qemu.org/git/opensbi.git [submodule "roms/qboot"] path = roms/qboot - url = https://github.com/bonzini/qboot + url = https://git.qemu.org/git/qboot.git [submodule "meson"] path = meson url = https://github.com/mesonbuild/meson/ -- 2.26.2
QEMU now hosts a mirror of meson.git. QEMU mirrors third-party code to ensure that users can always build QEMU even if the dependency goes offline and so QEMU meets its responsibilities to provide full source code under software licenses. Suggested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Cc: Marc-André Lureau <marcandre.lureau@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20200915130834.706758-3-stefanha@redhat.com> --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index XXXXXXX..XXXXXXX 100644 --- a/.gitmodules +++ b/.gitmodules @@ -XXX,XX +XXX,XX @@ url = https://git.qemu.org/git/qboot.git [submodule "meson"] path = meson - url = https://github.com/mesonbuild/meson/ + url = https://git.qemu.org/git/meson.git [submodule "roms/vbootrom"] path = roms/vbootrom url = https://github.com/google/vbootrom.git -- 2.26.2
The vbootrom module is needed for the new NPCM7xx ARM SoCs. The vbootrom.git repo is now mirrored on qemu.org. QEMU mirrors third-party code to ensure that users can always build QEMU even if the dependency goes offline and so QEMU meets its responsibilities to provide full source code under software licenses. Suggested-by: Peter Maydell <peter.maydell@linaro.org> Cc: Havard Skinnemoen <hskinnemoen@google.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20200915130834.706758-4-stefanha@redhat.com> --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index XXXXXXX..XXXXXXX 100644 --- a/.gitmodules +++ b/.gitmodules @@ -XXX,XX +XXX,XX @@ url = https://git.qemu.org/git/meson.git [submodule "roms/vbootrom"] path = roms/vbootrom - url = https://github.com/google/vbootrom.git + url = https://git.qemu.org/git/vbootrom.git -- 2.26.2
npfd keeps track of how many pollfds are currently being monitored. It must be reset to 0 when fdmon_poll_wait() returns. When npfd reaches a treshold we switch to fdmon-epoll because it scales better. This patch resets npfd in the case where we switch to fdmon-epoll. Forgetting to do so results in the following assertion failure: util/fdmon-poll.c:65: fdmon_poll_wait: Assertion `npfd == 0' failed. Fixes: 1f050a4690f62a1e7dabc4f44141e9f762c3769f ("aio-posix: extract ppoll(2) and epoll(7) fd monitoring") Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1869952 Message-Id: <20200915120339.702938-2-stefanha@redhat.com> --- util/fdmon-poll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/util/fdmon-poll.c b/util/fdmon-poll.c index XXXXXXX..XXXXXXX 100644 --- a/util/fdmon-poll.c +++ b/util/fdmon-poll.c @@ -XXX,XX +XXX,XX @@ static int fdmon_poll_wait(AioContext *ctx, AioHandlerList *ready_list, /* epoll(7) is faster above a certain number of fds */ if (fdmon_epoll_try_upgrade(ctx, npfd)) { + npfd = 0; /* we won't need pollfds[], reset npfd */ return ctx->fdmon_ops->wait(ctx, ready_list, timeout); } -- 2.26.2
Test aio_disable_external(), which switches from fdmon-epoll back to fdmon-poll. This resulted in an assertion failure that was fixed in the previous patch. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20200915120339.702938-3-stefanha@redhat.com> --- MAINTAINERS | 1 + tests/test-fdmon-epoll.c | 73 ++++++++++++++++++++++++++++++++++++++++ tests/meson.build | 3 ++ 3 files changed, 77 insertions(+) create mode 100644 tests/test-fdmon-epoll.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: migration/block* F: include/block/aio.h F: include/block/aio-wait.h F: scripts/qemugdb/aio.py +F: tests/test-fdmon-epoll.c T: git https://github.com/stefanha/qemu.git block Block SCSI subsystem diff --git a/tests/test-fdmon-epoll.c b/tests/test-fdmon-epoll.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/test-fdmon-epoll.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * fdmon-epoll tests + * + * Copyright (c) 2020 Red Hat, Inc. + */ + +#include "qemu/osdep.h" +#include "block/aio.h" +#include "qapi/error.h" +#include "qemu/main-loop.h" + +static AioContext *ctx; + +static void dummy_fd_handler(EventNotifier *notifier) +{ + event_notifier_test_and_clear(notifier); +} + +static void add_event_notifiers(EventNotifier *notifiers, size_t n) +{ + for (size_t i = 0; i < n; i++) { + event_notifier_init(¬ifiers[i], false); + aio_set_event_notifier(ctx, ¬ifiers[i], false, + dummy_fd_handler, NULL); + } +} + +static void remove_event_notifiers(EventNotifier *notifiers, size_t n) +{ + for (size_t i = 0; i < n; i++) { + aio_set_event_notifier(ctx, ¬ifiers[i], false, NULL, NULL); + event_notifier_cleanup(¬ifiers[i]); + } +} + +/* Check that fd handlers work when external clients are disabled */ +static void test_external_disabled(void) +{ + EventNotifier notifiers[100]; + + /* fdmon-epoll is only enabled when many fd handlers are registered */ + add_event_notifiers(notifiers, G_N_ELEMENTS(notifiers)); + + event_notifier_set(¬ifiers[0]); + assert(aio_poll(ctx, true)); + + aio_disable_external(ctx); + event_notifier_set(¬ifiers[0]); + assert(aio_poll(ctx, true)); + aio_enable_external(ctx); + + remove_event_notifiers(notifiers, G_N_ELEMENTS(notifiers)); +} + +int main(int argc, char **argv) +{ + /* + * This code relies on the fact that fdmon-io_uring disables itself when + * the glib main loop is in use. The main loop uses fdmon-poll and upgrades + * to fdmon-epoll when the number of fds exceeds a threshold. + */ + qemu_init_main_loop(&error_fatal); + ctx = qemu_get_aio_context(); + + while (g_main_context_iteration(NULL, false)) { + /* Do nothing */ + } + + g_test_init(&argc, &argv, NULL); + g_test_add_func("/fdmon-epoll/external-disabled", test_external_disabled); + return g_test_run(); +} diff --git a/tests/meson.build b/tests/meson.build index XXXXXXX..XXXXXXX 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -XXX,XX +XXX,XX @@ if have_block if 'CONFIG_NETTLE' in config_host or 'CONFIG_GCRYPT' in config_host tests += {'test-crypto-pbkdf': [io]} endif + if 'CONFIG_EPOLL_CREATE1' in config_host + tests += {'test-fdmon-epoll': [testblock]} + endif benchs += { 'benchmark-crypto-hash': [crypto], 'benchmark-crypto-hmac': [crypto], -- 2.26.2
clang's C11 atomic_fetch_*() functions only take a C11 atomic type pointer argument. QEMU uses direct types (int, etc) and this causes a compiler error when a QEMU code calls these functions in a source file that also included <stdatomic.h> via a system header file: $ CC=clang CXX=clang++ ./configure ... && make ../util/async.c:79:17: error: address argument to atomic operation must be a pointer to _Atomic type ('unsigned int *' invalid) Avoid using atomic_*() names in QEMU's atomic.h since that namespace is used by <stdatomic.h>. Prefix QEMU's APIs with 'q' so that atomic.h and <stdatomic.h> can co-exist. I checked /usr/include on my machine and searched GitHub for existing "qatomic_" users but there seem to be none. This patch was generated using: $ git grep -h -o '\<atomic\(64\)\?_[a-z0-9_]\+' include/qemu/atomic.h | \ sort -u >/tmp/changed_identifiers $ for identifier in $(</tmp/changed_identifiers); do sed -i "s%\<$identifier\>%q$identifier%g" \ $(git grep -I -l "\<$identifier\>") done I manually fixed line-wrap issues and misaligned rST tables. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Acked-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20200923105646.47864-1-stefanha@redhat.com> --- include/qemu/atomic.h | 248 +++++++++--------- docs/devel/lockcnt.txt | 8 +- docs/devel/rcu.txt | 34 +-- accel/tcg/atomic_template.h | 20 +- include/block/aio-wait.h | 4 +- include/block/aio.h | 8 +- include/exec/cpu_ldst.h | 2 +- include/exec/exec-all.h | 6 +- include/exec/log.h | 6 +- include/exec/memory.h | 2 +- include/exec/ram_addr.h | 26 +- include/exec/ramlist.h | 2 +- include/exec/tb-lookup.h | 4 +- include/hw/core/cpu.h | 2 +- include/qemu/atomic128.h | 6 +- include/qemu/bitops.h | 2 +- include/qemu/coroutine.h | 2 +- include/qemu/log.h | 6 +- include/qemu/queue.h | 7 +- include/qemu/rcu.h | 10 +- include/qemu/rcu_queue.h | 100 +++---- include/qemu/seqlock.h | 8 +- include/qemu/stats64.h | 28 +- include/qemu/thread.h | 24 +- .../infiniband/hw/vmw_pvrdma/pvrdma_ring.h | 14 +- linux-user/qemu.h | 2 +- tcg/i386/tcg-target.h | 2 +- tcg/s390/tcg-target.h | 2 +- tcg/tci/tcg-target.h | 2 +- accel/kvm/kvm-all.c | 12 +- accel/tcg/cpu-exec.c | 15 +- accel/tcg/cputlb.c | 24 +- accel/tcg/tcg-all.c | 2 +- accel/tcg/translate-all.c | 55 ++-- audio/jackaudio.c | 18 +- block.c | 4 +- block/block-backend.c | 15 +- block/io.c | 48 ++-- block/nfs.c | 2 +- block/sheepdog.c | 2 +- block/throttle-groups.c | 12 +- block/throttle.c | 4 +- blockdev.c | 2 +- blockjob.c | 2 +- contrib/libvhost-user/libvhost-user.c | 2 +- cpus-common.c | 26 +- dump/dump.c | 8 +- exec.c | 49 ++-- hw/core/cpu.c | 6 +- hw/display/qxl.c | 4 +- hw/hyperv/hyperv.c | 10 +- hw/hyperv/vmbus.c | 2 +- hw/i386/xen/xen-hvm.c | 2 +- hw/intc/rx_icu.c | 12 +- hw/intc/sifive_plic.c | 4 +- hw/misc/edu.c | 16 +- hw/net/virtio-net.c | 10 +- hw/rdma/rdma_backend.c | 18 +- hw/rdma/rdma_rm.c | 2 +- hw/rdma/vmw/pvrdma_dev_ring.c | 4 +- hw/s390x/s390-pci-bus.c | 2 +- hw/s390x/virtio-ccw.c | 2 +- hw/virtio/vhost.c | 2 +- hw/virtio/virtio-mmio.c | 6 +- hw/virtio/virtio-pci.c | 6 +- hw/virtio/virtio.c | 16 +- hw/xtensa/pic_cpu.c | 4 +- iothread.c | 6 +- linux-user/hppa/cpu_loop.c | 11 +- linux-user/signal.c | 8 +- migration/colo-failover.c | 4 +- migration/migration.c | 8 +- migration/multifd.c | 18 +- migration/postcopy-ram.c | 34 +-- migration/rdma.c | 34 +-- monitor/hmp.c | 6 +- monitor/misc.c | 2 +- monitor/monitor.c | 6 +- qemu-nbd.c | 2 +- qga/commands.c | 12 +- qom/object.c | 20 +- scsi/qemu-pr-helper.c | 4 +- softmmu/cpu-throttle.c | 10 +- softmmu/cpus.c | 42 +-- softmmu/memory.c | 6 +- softmmu/vl.c | 2 +- target/arm/mte_helper.c | 6 +- target/hppa/op_helper.c | 2 +- target/i386/mem_helper.c | 2 +- target/i386/whpx-all.c | 6 +- target/riscv/cpu_helper.c | 2 +- target/s390x/mem_helper.c | 4 +- target/xtensa/exc_helper.c | 4 +- target/xtensa/op_helper.c | 2 +- tcg/tcg.c | 58 ++-- tcg/tci.c | 2 +- tests/atomic64-bench.c | 14 +- tests/atomic_add-bench.c | 14 +- tests/iothread.c | 2 +- tests/qht-bench.c | 12 +- tests/rcutorture.c | 24 +- tests/test-aio-multithread.c | 52 ++-- tests/test-logging.c | 4 +- tests/test-rcu-list.c | 38 +-- tests/test-thread-pool.c | 10 +- util/aio-posix.c | 14 +- util/aio-wait.c | 2 +- util/aio-win32.c | 5 +- util/async.c | 28 +- util/atomic64.c | 10 +- util/bitmap.c | 14 +- util/cacheinfo.c | 2 +- util/fdmon-epoll.c | 4 +- util/fdmon-io_uring.c | 12 +- util/lockcnt.c | 52 ++-- util/log.c | 10 +- util/qemu-coroutine-lock.c | 18 +- util/qemu-coroutine-sleep.c | 4 +- util/qemu-coroutine.c | 6 +- util/qemu-sockets.c | 4 +- util/qemu-thread-posix.c | 12 +- util/qemu-thread-win32.c | 12 +- util/qemu-timer.c | 12 +- util/qht.c | 57 ++-- util/qsp.c | 50 ++-- util/rcu.c | 36 +-- util/stats64.c | 34 +-- docs/devel/atomics.rst | 134 +++++----- scripts/kernel-doc | 2 +- tcg/aarch64/tcg-target.c.inc | 2 +- tcg/mips/tcg-target.c.inc | 2 +- tcg/ppc/tcg-target.c.inc | 6 +- tcg/sparc/tcg-target.c.inc | 5 +- 133 files changed, 1041 insertions(+), 1018 deletions(-) diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -XXX,XX +XXX,XX @@ * no effect on the generated code but not using the atomic primitives * will get flagged by sanitizers as a violation. */ -#define atomic_read__nocheck(ptr) \ +#define qatomic_read__nocheck(ptr) \ __atomic_load_n(ptr, __ATOMIC_RELAXED) -#define atomic_read(ptr) \ - ({ \ +#define qatomic_read(ptr) \ + ({ \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ - atomic_read__nocheck(ptr); \ + qatomic_read__nocheck(ptr); \ }) -#define atomic_set__nocheck(ptr, i) \ +#define qatomic_set__nocheck(ptr, i) \ __atomic_store_n(ptr, i, __ATOMIC_RELAXED) -#define atomic_set(ptr, i) do { \ +#define qatomic_set(ptr, i) do { \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ - atomic_set__nocheck(ptr, i); \ + qatomic_set__nocheck(ptr, i); \ } while(0) /* See above: most compilers currently treat consume and acquire the - * same, but this slows down atomic_rcu_read unnecessarily. + * same, but this slows down qatomic_rcu_read unnecessarily. */ #ifdef __SANITIZE_THREAD__ -#define atomic_rcu_read__nocheck(ptr, valptr) \ +#define qatomic_rcu_read__nocheck(ptr, valptr) \ __atomic_load(ptr, valptr, __ATOMIC_CONSUME); #else -#define atomic_rcu_read__nocheck(ptr, valptr) \ - __atomic_load(ptr, valptr, __ATOMIC_RELAXED); \ +#define qatomic_rcu_read__nocheck(ptr, valptr) \ + __atomic_load(ptr, valptr, __ATOMIC_RELAXED); \ smp_read_barrier_depends(); #endif -#define atomic_rcu_read(ptr) \ - ({ \ +#define qatomic_rcu_read(ptr) \ + ({ \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ - typeof_strip_qual(*ptr) _val; \ - atomic_rcu_read__nocheck(ptr, &_val); \ - _val; \ + typeof_strip_qual(*ptr) _val; \ + qatomic_rcu_read__nocheck(ptr, &_val); \ + _val; \ }) -#define atomic_rcu_set(ptr, i) do { \ +#define qatomic_rcu_set(ptr, i) do { \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ - __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \ + __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \ } while(0) -#define atomic_load_acquire(ptr) \ +#define qatomic_load_acquire(ptr) \ ({ \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ typeof_strip_qual(*ptr) _val; \ @@ -XXX,XX +XXX,XX @@ _val; \ }) -#define atomic_store_release(ptr, i) do { \ +#define qatomic_store_release(ptr, i) do { \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ __atomic_store_n(ptr, i, __ATOMIC_RELEASE); \ } while(0) @@ -XXX,XX +XXX,XX @@ /* All the remaining operations are fully sequentially consistent */ -#define atomic_xchg__nocheck(ptr, i) ({ \ +#define qatomic_xchg__nocheck(ptr, i) ({ \ __atomic_exchange_n(ptr, (i), __ATOMIC_SEQ_CST); \ }) -#define atomic_xchg(ptr, i) ({ \ +#define qatomic_xchg(ptr, i) ({ \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ - atomic_xchg__nocheck(ptr, i); \ + qatomic_xchg__nocheck(ptr, i); \ }) /* Returns the eventual value, failed or not */ -#define atomic_cmpxchg__nocheck(ptr, old, new) ({ \ +#define qatomic_cmpxchg__nocheck(ptr, old, new) ({ \ typeof_strip_qual(*ptr) _old = (old); \ (void)__atomic_compare_exchange_n(ptr, &_old, new, false, \ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); \ _old; \ }) -#define atomic_cmpxchg(ptr, old, new) ({ \ +#define qatomic_cmpxchg(ptr, old, new) ({ \ QEMU_BUILD_BUG_ON(sizeof(*ptr) > ATOMIC_REG_SIZE); \ - atomic_cmpxchg__nocheck(ptr, old, new); \ + qatomic_cmpxchg__nocheck(ptr, old, new); \ }) /* Provide shorter names for GCC atomic builtins, return old value */ -#define atomic_fetch_inc(ptr) __atomic_fetch_add(ptr, 1, __ATOMIC_SEQ_CST) -#define atomic_fetch_dec(ptr) __atomic_fetch_sub(ptr, 1, __ATOMIC_SEQ_CST) +#define qatomic_fetch_inc(ptr) __atomic_fetch_add(ptr, 1, __ATOMIC_SEQ_CST) +#define qatomic_fetch_dec(ptr) __atomic_fetch_sub(ptr, 1, __ATOMIC_SEQ_CST) -#ifndef atomic_fetch_add -#define atomic_fetch_add(ptr, n) __atomic_fetch_add(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_fetch_sub(ptr, n) __atomic_fetch_sub(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_fetch_and(ptr, n) __atomic_fetch_and(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_fetch_or(ptr, n) __atomic_fetch_or(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_fetch_xor(ptr, n) __atomic_fetch_xor(ptr, n, __ATOMIC_SEQ_CST) -#endif +#define qatomic_fetch_add(ptr, n) __atomic_fetch_add(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_fetch_sub(ptr, n) __atomic_fetch_sub(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_fetch_and(ptr, n) __atomic_fetch_and(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_fetch_or(ptr, n) __atomic_fetch_or(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_fetch_xor(ptr, n) __atomic_fetch_xor(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_inc_fetch(ptr) __atomic_add_fetch(ptr, 1, __ATOMIC_SEQ_CST) -#define atomic_dec_fetch(ptr) __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST) -#define atomic_add_fetch(ptr, n) __atomic_add_fetch(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_sub_fetch(ptr, n) __atomic_sub_fetch(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_and_fetch(ptr, n) __atomic_and_fetch(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_or_fetch(ptr, n) __atomic_or_fetch(ptr, n, __ATOMIC_SEQ_CST) -#define atomic_xor_fetch(ptr, n) __atomic_xor_fetch(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_inc_fetch(ptr) __atomic_add_fetch(ptr, 1, __ATOMIC_SEQ_CST) +#define qatomic_dec_fetch(ptr) __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST) +#define qatomic_add_fetch(ptr, n) __atomic_add_fetch(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_sub_fetch(ptr, n) __atomic_sub_fetch(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_and_fetch(ptr, n) __atomic_and_fetch(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_or_fetch(ptr, n) __atomic_or_fetch(ptr, n, __ATOMIC_SEQ_CST) +#define qatomic_xor_fetch(ptr, n) __atomic_xor_fetch(ptr, n, __ATOMIC_SEQ_CST) /* And even shorter names that return void. */ -#define atomic_inc(ptr) ((void) __atomic_fetch_add(ptr, 1, __ATOMIC_SEQ_CST)) -#define atomic_dec(ptr) ((void) __atomic_fetch_sub(ptr, 1, __ATOMIC_SEQ_CST)) -#define atomic_add(ptr, n) ((void) __atomic_fetch_add(ptr, n, __ATOMIC_SEQ_CST)) -#define atomic_sub(ptr, n) ((void) __atomic_fetch_sub(ptr, n, __ATOMIC_SEQ_CST)) -#define atomic_and(ptr, n) ((void) __atomic_fetch_and(ptr, n, __ATOMIC_SEQ_CST)) -#define atomic_or(ptr, n) ((void) __atomic_fetch_or(ptr, n, __ATOMIC_SEQ_CST)) -#define atomic_xor(ptr, n) ((void) __atomic_fetch_xor(ptr, n, __ATOMIC_SEQ_CST)) +#define qatomic_inc(ptr) \ + ((void) __atomic_fetch_add(ptr, 1, __ATOMIC_SEQ_CST)) +#define qatomic_dec(ptr) \ + ((void) __atomic_fetch_sub(ptr, 1, __ATOMIC_SEQ_CST)) +#define qatomic_add(ptr, n) \ + ((void) __atomic_fetch_add(ptr, n, __ATOMIC_SEQ_CST)) +#define qatomic_sub(ptr, n) \ + ((void) __atomic_fetch_sub(ptr, n, __ATOMIC_SEQ_CST)) +#define qatomic_and(ptr, n) \ + ((void) __atomic_fetch_and(ptr, n, __ATOMIC_SEQ_CST)) +#define qatomic_or(ptr, n) \ + ((void) __atomic_fetch_or(ptr, n, __ATOMIC_SEQ_CST)) +#define qatomic_xor(ptr, n) \ + ((void) __atomic_fetch_xor(ptr, n, __ATOMIC_SEQ_CST)) #else /* __ATOMIC_RELAXED */ @@ -XXX,XX +XXX,XX @@ * but it is a full barrier at the hardware level. Add a compiler barrier * to make it a full barrier also at the compiler level. */ -#define atomic_xchg(ptr, i) (barrier(), __sync_lock_test_and_set(ptr, i)) +#define qatomic_xchg(ptr, i) (barrier(), __sync_lock_test_and_set(ptr, i)) #elif defined(_ARCH_PPC) @@ -XXX,XX +XXX,XX @@ /* These will only be atomic if the processor does the fetch or store * in a single issue memory operation */ -#define atomic_read__nocheck(p) (*(__typeof__(*(p)) volatile*) (p)) -#define atomic_set__nocheck(p, i) ((*(__typeof__(*(p)) volatile*) (p)) = (i)) +#define qatomic_read__nocheck(p) (*(__typeof__(*(p)) volatile*) (p)) +#define qatomic_set__nocheck(p, i) ((*(__typeof__(*(p)) volatile*) (p)) = (i)) -#define atomic_read(ptr) atomic_read__nocheck(ptr) -#define atomic_set(ptr, i) atomic_set__nocheck(ptr,i) +#define qatomic_read(ptr) qatomic_read__nocheck(ptr) +#define qatomic_set(ptr, i) qatomic_set__nocheck(ptr,i) /** - * atomic_rcu_read - reads a RCU-protected pointer to a local variable + * qatomic_rcu_read - reads a RCU-protected pointer to a local variable * into a RCU read-side critical section. The pointer can later be safely * dereferenced within the critical section. * @@ -XXX,XX +XXX,XX @@ * Inserts memory barriers on architectures that require them (currently only * Alpha) and documents which pointers are protected by RCU. * - * atomic_rcu_read also includes a compiler barrier to ensure that + * qatomic_rcu_read also includes a compiler barrier to ensure that * value-speculative optimizations (e.g. VSS: Value Speculation * Scheduling) does not perform the data read before the pointer read * by speculating the value of the pointer. * - * Should match atomic_rcu_set(), atomic_xchg(), atomic_cmpxchg(). + * Should match qatomic_rcu_set(), qatomic_xchg(), qatomic_cmpxchg(). */ -#define atomic_rcu_read(ptr) ({ \ - typeof(*ptr) _val = atomic_read(ptr); \ +#define qatomic_rcu_read(ptr) ({ \ + typeof(*ptr) _val = qatomic_read(ptr); \ smp_read_barrier_depends(); \ _val; \ }) /** - * atomic_rcu_set - assigns (publicizes) a pointer to a new data structure + * qatomic_rcu_set - assigns (publicizes) a pointer to a new data structure * meant to be read by RCU read-side critical sections. * * Documents which pointers will be dereferenced by RCU read-side critical @@ -XXX,XX +XXX,XX @@ * them. It also makes sure the compiler does not reorder code initializing the * data structure before its publication. * - * Should match atomic_rcu_read(). + * Should match qatomic_rcu_read(). */ -#define atomic_rcu_set(ptr, i) do { \ +#define qatomic_rcu_set(ptr, i) do { \ smp_wmb(); \ - atomic_set(ptr, i); \ + qatomic_set(ptr, i); \ } while (0) -#define atomic_load_acquire(ptr) ({ \ - typeof(*ptr) _val = atomic_read(ptr); \ +#define qatomic_load_acquire(ptr) ({ \ + typeof(*ptr) _val = qatomic_read(ptr); \ smp_mb_acquire(); \ _val; \ }) -#define atomic_store_release(ptr, i) do { \ +#define qatomic_store_release(ptr, i) do { \ smp_mb_release(); \ - atomic_set(ptr, i); \ + qatomic_set(ptr, i); \ } while (0) -#ifndef atomic_xchg +#ifndef qatomic_xchg #if defined(__clang__) -#define atomic_xchg(ptr, i) __sync_swap(ptr, i) +#define qatomic_xchg(ptr, i) __sync_swap(ptr, i) #else /* __sync_lock_test_and_set() is documented to be an acquire barrier only. */ -#define atomic_xchg(ptr, i) (smp_mb(), __sync_lock_test_and_set(ptr, i)) +#define qatomic_xchg(ptr, i) (smp_mb(), __sync_lock_test_and_set(ptr, i)) #endif #endif -#define atomic_xchg__nocheck atomic_xchg +#define qatomic_xchg__nocheck qatomic_xchg /* Provide shorter names for GCC atomic builtins. */ -#define atomic_fetch_inc(ptr) __sync_fetch_and_add(ptr, 1) -#define atomic_fetch_dec(ptr) __sync_fetch_and_add(ptr, -1) +#define qatomic_fetch_inc(ptr) __sync_fetch_and_add(ptr, 1) +#define qatomic_fetch_dec(ptr) __sync_fetch_and_add(ptr, -1) -#ifndef atomic_fetch_add -#define atomic_fetch_add(ptr, n) __sync_fetch_and_add(ptr, n) -#define atomic_fetch_sub(ptr, n) __sync_fetch_and_sub(ptr, n) -#define atomic_fetch_and(ptr, n) __sync_fetch_and_and(ptr, n) -#define atomic_fetch_or(ptr, n) __sync_fetch_and_or(ptr, n) -#define atomic_fetch_xor(ptr, n) __sync_fetch_and_xor(ptr, n) -#endif +#define qatomic_fetch_add(ptr, n) __sync_fetch_and_add(ptr, n) +#define qatomic_fetch_sub(ptr, n) __sync_fetch_and_sub(ptr, n) +#define qatomic_fetch_and(ptr, n) __sync_fetch_and_and(ptr, n) +#define qatomic_fetch_or(ptr, n) __sync_fetch_and_or(ptr, n) +#define qatomic_fetch_xor(ptr, n) __sync_fetch_and_xor(ptr, n) -#define atomic_inc_fetch(ptr) __sync_add_and_fetch(ptr, 1) -#define atomic_dec_fetch(ptr) __sync_add_and_fetch(ptr, -1) -#define atomic_add_fetch(ptr, n) __sync_add_and_fetch(ptr, n) -#define atomic_sub_fetch(ptr, n) __sync_sub_and_fetch(ptr, n) -#define atomic_and_fetch(ptr, n) __sync_and_and_fetch(ptr, n) -#define atomic_or_fetch(ptr, n) __sync_or_and_fetch(ptr, n) -#define atomic_xor_fetch(ptr, n) __sync_xor_and_fetch(ptr, n) +#define qatomic_inc_fetch(ptr) __sync_add_and_fetch(ptr, 1) +#define qatomic_dec_fetch(ptr) __sync_add_and_fetch(ptr, -1) +#define qatomic_add_fetch(ptr, n) __sync_add_and_fetch(ptr, n) +#define qatomic_sub_fetch(ptr, n) __sync_sub_and_fetch(ptr, n) +#define qatomic_and_fetch(ptr, n) __sync_and_and_fetch(ptr, n) +#define qatomic_or_fetch(ptr, n) __sync_or_and_fetch(ptr, n) +#define qatomic_xor_fetch(ptr, n) __sync_xor_and_fetch(ptr, n) -#define atomic_cmpxchg(ptr, old, new) __sync_val_compare_and_swap(ptr, old, new) -#define atomic_cmpxchg__nocheck(ptr, old, new) atomic_cmpxchg(ptr, old, new) +#define qatomic_cmpxchg(ptr, old, new) \ + __sync_val_compare_and_swap(ptr, old, new) +#define qatomic_cmpxchg__nocheck(ptr, old, new) qatomic_cmpxchg(ptr, old, new) /* And even shorter names that return void. */ -#define atomic_inc(ptr) ((void) __sync_fetch_and_add(ptr, 1)) -#define atomic_dec(ptr) ((void) __sync_fetch_and_add(ptr, -1)) -#define atomic_add(ptr, n) ((void) __sync_fetch_and_add(ptr, n)) -#define atomic_sub(ptr, n) ((void) __sync_fetch_and_sub(ptr, n)) -#define atomic_and(ptr, n) ((void) __sync_fetch_and_and(ptr, n)) -#define atomic_or(ptr, n) ((void) __sync_fetch_and_or(ptr, n)) -#define atomic_xor(ptr, n) ((void) __sync_fetch_and_xor(ptr, n)) +#define qatomic_inc(ptr) ((void) __sync_fetch_and_add(ptr, 1)) +#define qatomic_dec(ptr) ((void) __sync_fetch_and_add(ptr, -1)) +#define qatomic_add(ptr, n) ((void) __sync_fetch_and_add(ptr, n)) +#define qatomic_sub(ptr, n) ((void) __sync_fetch_and_sub(ptr, n)) +#define qatomic_and(ptr, n) ((void) __sync_fetch_and_and(ptr, n)) +#define qatomic_or(ptr, n) ((void) __sync_fetch_and_or(ptr, n)) +#define qatomic_xor(ptr, n) ((void) __sync_fetch_and_xor(ptr, n)) #endif /* __ATOMIC_RELAXED */ @@ -XXX,XX +XXX,XX @@ /* This is more efficient than a store plus a fence. */ #if !defined(__SANITIZE_THREAD__) #if defined(__i386__) || defined(__x86_64__) || defined(__s390x__) -#define atomic_mb_set(ptr, i) ((void)atomic_xchg(ptr, i)) +#define qatomic_mb_set(ptr, i) ((void)qatomic_xchg(ptr, i)) #endif #endif -/* atomic_mb_read/set semantics map Java volatile variables. They are +/* qatomic_mb_read/set semantics map Java volatile variables. They are * less expensive on some platforms (notably POWER) than fully * sequentially consistent operations. * @@ -XXX,XX +XXX,XX @@ * use. See docs/devel/atomics.txt for more discussion. */ -#ifndef atomic_mb_read -#define atomic_mb_read(ptr) \ - atomic_load_acquire(ptr) +#ifndef qatomic_mb_read +#define qatomic_mb_read(ptr) \ + qatomic_load_acquire(ptr) #endif -#ifndef atomic_mb_set -#define atomic_mb_set(ptr, i) do { \ - atomic_store_release(ptr, i); \ +#ifndef qatomic_mb_set +#define qatomic_mb_set(ptr, i) do { \ + qatomic_store_release(ptr, i); \ smp_mb(); \ } while(0) #endif -#define atomic_fetch_inc_nonzero(ptr) ({ \ - typeof_strip_qual(*ptr) _oldn = atomic_read(ptr); \ - while (_oldn && atomic_cmpxchg(ptr, _oldn, _oldn + 1) != _oldn) { \ - _oldn = atomic_read(ptr); \ +#define qatomic_fetch_inc_nonzero(ptr) ({ \ + typeof_strip_qual(*ptr) _oldn = qatomic_read(ptr); \ + while (_oldn && qatomic_cmpxchg(ptr, _oldn, _oldn + 1) != _oldn) { \ + _oldn = qatomic_read(ptr); \ } \ _oldn; \ }) /* Abstractions to access atomically (i.e. "once") i64/u64 variables */ #ifdef CONFIG_ATOMIC64 -static inline int64_t atomic_read_i64(const int64_t *ptr) +static inline int64_t qatomic_read_i64(const int64_t *ptr) { /* use __nocheck because sizeof(void *) might be < sizeof(u64) */ - return atomic_read__nocheck(ptr); + return qatomic_read__nocheck(ptr); } -static inline uint64_t atomic_read_u64(const uint64_t *ptr) +static inline uint64_t qatomic_read_u64(const uint64_t *ptr) { - return atomic_read__nocheck(ptr); + return qatomic_read__nocheck(ptr); } -static inline void atomic_set_i64(int64_t *ptr, int64_t val) +static inline void qatomic_set_i64(int64_t *ptr, int64_t val) { - atomic_set__nocheck(ptr, val); + qatomic_set__nocheck(ptr, val); } -static inline void atomic_set_u64(uint64_t *ptr, uint64_t val) +static inline void qatomic_set_u64(uint64_t *ptr, uint64_t val) { - atomic_set__nocheck(ptr, val); + qatomic_set__nocheck(ptr, val); } -static inline void atomic64_init(void) +static inline void qatomic64_init(void) { } #else /* !CONFIG_ATOMIC64 */ -int64_t atomic_read_i64(const int64_t *ptr); -uint64_t atomic_read_u64(const uint64_t *ptr); -void atomic_set_i64(int64_t *ptr, int64_t val); -void atomic_set_u64(uint64_t *ptr, uint64_t val); -void atomic64_init(void); +int64_t qatomic_read_i64(const int64_t *ptr); +uint64_t qatomic_read_u64(const uint64_t *ptr); +void qatomic_set_i64(int64_t *ptr, int64_t val); +void qatomic_set_u64(uint64_t *ptr, uint64_t val); +void qatomic64_init(void); #endif /* !CONFIG_ATOMIC64 */ #endif /* QEMU_ATOMIC_H */ diff --git a/docs/devel/lockcnt.txt b/docs/devel/lockcnt.txt index XXXXXXX..XXXXXXX 100644 --- a/docs/devel/lockcnt.txt +++ b/docs/devel/lockcnt.txt @@ -XXX,XX +XXX,XX @@ not just frees, though there could be cases where this is not necessary. Reads, instead, can be done without taking the mutex, as long as the readers and writers use the same macros that are used for RCU, for -example atomic_rcu_read, atomic_rcu_set, QLIST_FOREACH_RCU, etc. This is +example qatomic_rcu_read, qatomic_rcu_set, QLIST_FOREACH_RCU, etc. This is because the reads are done outside a lock and a set or QLIST_INSERT_HEAD can happen concurrently with the read. The RCU API ensures that the processor and the compiler see all required memory barriers. @@ -XXX,XX +XXX,XX @@ qemu_lockcnt_lock and qemu_lockcnt_unlock: if (!xyz) { new_xyz = g_new(XYZ, 1); ... - atomic_rcu_set(&xyz, new_xyz); + qatomic_rcu_set(&xyz, new_xyz); } qemu_lockcnt_unlock(&xyz_lockcnt); @@ -XXX,XX +XXX,XX @@ qemu_lockcnt_dec: qemu_lockcnt_inc(&xyz_lockcnt); if (xyz) { - XYZ *p = atomic_rcu_read(&xyz); + XYZ *p = qatomic_rcu_read(&xyz); ... /* Accesses can now be done through "p". */ } @@ -XXX,XX +XXX,XX @@ the decrement, the locking and the check on count as follows: qemu_lockcnt_inc(&xyz_lockcnt); if (xyz) { - XYZ *p = atomic_rcu_read(&xyz); + XYZ *p = qatomic_rcu_read(&xyz); ... /* Accesses can now be done through "p". */ } diff --git a/docs/devel/rcu.txt b/docs/devel/rcu.txt index XXXXXXX..XXXXXXX 100644 --- a/docs/devel/rcu.txt +++ b/docs/devel/rcu.txt @@ -XXX,XX +XXX,XX @@ The core RCU API is small: g_free_rcu(&foo, rcu); - typeof(*p) atomic_rcu_read(p); + typeof(*p) qatomic_rcu_read(p); - atomic_rcu_read() is similar to atomic_load_acquire(), but it makes + qatomic_rcu_read() is similar to qatomic_load_acquire(), but it makes some assumptions on the code that calls it. This allows a more optimized implementation. - atomic_rcu_read assumes that whenever a single RCU critical + qatomic_rcu_read assumes that whenever a single RCU critical section reads multiple shared data, these reads are either data-dependent or need no ordering. This is almost always the case when using RCU, because read-side critical sections typically @@ -XXX,XX +XXX,XX @@ The core RCU API is small: every update) until reaching a data structure of interest, and then read from there. - RCU read-side critical sections must use atomic_rcu_read() to + RCU read-side critical sections must use qatomic_rcu_read() to read data, unless concurrent writes are prevented by another synchronization mechanism. @@ -XXX,XX +XXX,XX @@ The core RCU API is small: data structure in a single direction, opposite to the direction in which the updater initializes it. - void atomic_rcu_set(p, typeof(*p) v); + void qatomic_rcu_set(p, typeof(*p) v); - atomic_rcu_set() is similar to atomic_store_release(), though it also + qatomic_rcu_set() is similar to qatomic_store_release(), though it also makes assumptions on the code that calls it in order to allow a more optimized implementation. - In particular, atomic_rcu_set() suffices for synchronization + In particular, qatomic_rcu_set() suffices for synchronization with readers, if the updater never mutates a field within a data item that is already accessible to readers. This is the case when initializing a new copy of the RCU-protected data structure; just ensure that initialization of *p is carried out - before atomic_rcu_set() makes the data item visible to readers. + before qatomic_rcu_set() makes the data item visible to readers. If this rule is observed, writes will happen in the opposite order as reads in the RCU read-side critical sections (or if there is just one update), and there will be no need for other @@ -XXX,XX +XXX,XX @@ DIFFERENCES WITH LINUX programming; not allowing this would prevent upgrading an RCU read-side critical section to become an updater. -- atomic_rcu_read and atomic_rcu_set replace rcu_dereference and +- qatomic_rcu_read and qatomic_rcu_set replace rcu_dereference and rcu_assign_pointer. They take a _pointer_ to the variable being accessed. - call_rcu is a macro that has an extra argument (the name of the first @@ -XXX,XX +XXX,XX @@ may be used as a restricted reference-counting mechanism. For example, consider the following code fragment: rcu_read_lock(); - p = atomic_rcu_read(&foo); + p = qatomic_rcu_read(&foo); /* do something with p. */ rcu_read_unlock(); @@ -XXX,XX +XXX,XX @@ The write side looks simply like this (with appropriate locking): qemu_mutex_lock(&foo_mutex); old = foo; - atomic_rcu_set(&foo, new); + qatomic_rcu_set(&foo, new); qemu_mutex_unlock(&foo_mutex); synchronize_rcu(); free(old); @@ -XXX,XX +XXX,XX @@ If the processing cannot be done purely within the critical section, it is possible to combine this idiom with a "real" reference count: rcu_read_lock(); - p = atomic_rcu_read(&foo); + p = qatomic_rcu_read(&foo); foo_ref(p); rcu_read_unlock(); /* do something with p. */ @@ -XXX,XX +XXX,XX @@ The write side can be like this: qemu_mutex_lock(&foo_mutex); old = foo; - atomic_rcu_set(&foo, new); + qatomic_rcu_set(&foo, new); qemu_mutex_unlock(&foo_mutex); synchronize_rcu(); foo_unref(old); @@ -XXX,XX +XXX,XX @@ or with call_rcu: qemu_mutex_lock(&foo_mutex); old = foo; - atomic_rcu_set(&foo, new); + qatomic_rcu_set(&foo, new); qemu_mutex_unlock(&foo_mutex); call_rcu(foo_unref, old, rcu); @@ -XXX,XX +XXX,XX @@ last reference may be dropped on the read side. Hence you can use call_rcu() instead: foo_unref(struct foo *p) { - if (atomic_fetch_dec(&p->refcount) == 1) { + if (qatomic_fetch_dec(&p->refcount) == 1) { call_rcu(foo_destroy, p, rcu); } } @@ -XXX,XX +XXX,XX @@ Instead, we store the size of the array with the array itself: read side: rcu_read_lock(); - struct arr *array = atomic_rcu_read(&global_array); + struct arr *array = qatomic_rcu_read(&global_array); x = i < array->size ? array->data[i] : -1; rcu_read_unlock(); return x; @@ -XXX,XX +XXX,XX @@ Instead, we store the size of the array with the array itself: /* Removal phase. */ old_array = global_array; - atomic_rcu_set(&new_array->data, new_array); + qatomic_rcu_set(&new_array->data, new_array); synchronize_rcu(); /* Reclamation phase. */ diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index XXXXXXX..XXXXXXX 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -XXX,XX +XXX,XX @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, #if DATA_SIZE == 16 ret = atomic16_cmpxchg(haddr, cmpv, newv); #else - ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv); + ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv); #endif ATOMIC_MMU_CLEANUP; atomic_trace_rmw_post(env, addr, info); @@ -XXX,XX +XXX,XX @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ATOMIC_MMU_IDX); atomic_trace_rmw_pre(env, addr, info); - ret = atomic_xchg__nocheck(haddr, val); + ret = qatomic_xchg__nocheck(haddr, val); ATOMIC_MMU_CLEANUP; atomic_trace_rmw_post(env, addr, info); return ret; @@ -XXX,XX +XXX,XX @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ ATOMIC_MMU_IDX); \ atomic_trace_rmw_pre(env, addr, info); \ - ret = atomic_##X(haddr, val); \ + ret = qatomic_##X(haddr, val); \ ATOMIC_MMU_CLEANUP; \ atomic_trace_rmw_post(env, addr, info); \ return ret; \ @@ -XXX,XX +XXX,XX @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ATOMIC_MMU_IDX); \ atomic_trace_rmw_pre(env, addr, info); \ smp_mb(); \ - cmp = atomic_read__nocheck(haddr); \ + cmp = qatomic_read__nocheck(haddr); \ do { \ old = cmp; new = FN(old, val); \ - cmp = atomic_cmpxchg__nocheck(haddr, old, new); \ + cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \ } while (cmp != old); \ ATOMIC_MMU_CLEANUP; \ atomic_trace_rmw_post(env, addr, info); \ @@ -XXX,XX +XXX,XX @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, #if DATA_SIZE == 16 ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); #else - ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); + ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); #endif ATOMIC_MMU_CLEANUP; atomic_trace_rmw_post(env, addr, info); @@ -XXX,XX +XXX,XX @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ATOMIC_MMU_IDX); atomic_trace_rmw_pre(env, addr, info); - ret = atomic_xchg__nocheck(haddr, BSWAP(val)); + ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); ATOMIC_MMU_CLEANUP; atomic_trace_rmw_post(env, addr, info); return BSWAP(ret); @@ -XXX,XX +XXX,XX @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ false, ATOMIC_MMU_IDX); \ atomic_trace_rmw_pre(env, addr, info); \ - ret = atomic_##X(haddr, BSWAP(val)); \ + ret = qatomic_##X(haddr, BSWAP(val)); \ ATOMIC_MMU_CLEANUP; \ atomic_trace_rmw_post(env, addr, info); \ return BSWAP(ret); \ @@ -XXX,XX +XXX,XX @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ false, ATOMIC_MMU_IDX); \ atomic_trace_rmw_pre(env, addr, info); \ smp_mb(); \ - ldn = atomic_read__nocheck(haddr); \ + ldn = qatomic_read__nocheck(haddr); \ do { \ ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \ - ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ + ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ } while (ldo != ldn); \ ATOMIC_MMU_CLEANUP; \ atomic_trace_rmw_post(env, addr, info); \ diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h index XXXXXXX..XXXXXXX 100644 --- a/include/block/aio-wait.h +++ b/include/block/aio-wait.h @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; AioWait *wait_ = &global_aio_wait; \ AioContext *ctx_ = (ctx); \ /* Increment wait_->num_waiters before evaluating cond. */ \ - atomic_inc(&wait_->num_waiters); \ + qatomic_inc(&wait_->num_waiters); \ if (ctx_ && in_aio_context_home_thread(ctx_)) { \ while ((cond)) { \ aio_poll(ctx_, true); \ @@ -XXX,XX +XXX,XX @@ extern AioWait global_aio_wait; waited_ = true; \ } \ } \ - atomic_dec(&wait_->num_waiters); \ + qatomic_dec(&wait_->num_waiters); \ waited_; }) /** diff --git a/include/block/aio.h b/include/block/aio.h index XXXXXXX..XXXXXXX 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -XXX,XX +XXX,XX @@ int64_t aio_compute_timeout(AioContext *ctx); */ static inline void aio_disable_external(AioContext *ctx) { - atomic_inc(&ctx->external_disable_cnt); + qatomic_inc(&ctx->external_disable_cnt); } /** @@ -XXX,XX +XXX,XX @@ static inline void aio_enable_external(AioContext *ctx) { int old; - old = atomic_fetch_dec(&ctx->external_disable_cnt); + old = qatomic_fetch_dec(&ctx->external_disable_cnt); assert(old > 0); if (old == 1) { /* Kick event loop so it re-arms file descriptors */ @@ -XXX,XX +XXX,XX @@ static inline void aio_enable_external(AioContext *ctx) */ static inline bool aio_external_disabled(AioContext *ctx) { - return atomic_read(&ctx->external_disable_cnt); + return qatomic_read(&ctx->external_disable_cnt); } /** @@ -XXX,XX +XXX,XX @@ static inline bool aio_external_disabled(AioContext *ctx) */ static inline bool aio_node_check(AioContext *ctx, bool is_external) { - return !is_external || !atomic_read(&ctx->external_disable_cnt); + return !is_external || !qatomic_read(&ctx->external_disable_cnt); } /** diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -XXX,XX +XXX,XX @@ static inline target_ulong tlb_addr_write(const CPUTLBEntry *entry) #if TCG_OVERSIZED_GUEST return entry->addr_write; #else - return atomic_read(&entry->addr_write); + return qatomic_read(&entry->addr_write); #endif } diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -XXX,XX +XXX,XX @@ void QEMU_NORETURN cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); */ static inline bool cpu_loop_exit_requested(CPUState *cpu) { - return (int32_t)atomic_read(&cpu_neg(cpu)->icount_decr.u32) < 0; + return (int32_t)qatomic_read(&cpu_neg(cpu)->icount_decr.u32) < 0; } #if !defined(CONFIG_USER_ONLY) @@ -XXX,XX +XXX,XX @@ struct TranslationBlock { extern bool parallel_cpus; -/* Hide the atomic_read to make code a little easier on the eyes */ +/* Hide the qatomic_read to make code a little easier on the eyes */ static inline uint32_t tb_cflags(const TranslationBlock *tb) { - return atomic_read(&tb->cflags); + return qatomic_read(&tb->cflags); } /* current cflags for hashing/comparison */ diff --git a/include/exec/log.h b/include/exec/log.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/log.h +++ b/include/exec/log.h @@ -XXX,XX +XXX,XX @@ static inline void log_cpu_state(CPUState *cpu, int flags) if (qemu_log_enabled()) { rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile) { cpu_dump_state(cpu, logfile->fd, flags); } @@ -XXX,XX +XXX,XX @@ static inline void log_target_disas(CPUState *cpu, target_ulong start, { QemuLogFile *logfile; rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile) { target_disas(logfile->fd, cpu, start, len); } @@ -XXX,XX +XXX,XX @@ static inline void log_disas(void *code, unsigned long size, const char *note) { QemuLogFile *logfile; rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile) { disas(logfile->fd, code, size, note); } diff --git a/include/exec/memory.h b/include/exec/memory.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -XXX,XX +XXX,XX @@ struct FlatView { static inline FlatView *address_space_to_flatview(AddressSpace *as) { - return atomic_rcu_read(&as->current_map); + return qatomic_rcu_read(&as->current_map); } diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -XXX,XX +XXX,XX @@ static inline bool cpu_physical_memory_get_dirty(ram_addr_t start, page = start >> TARGET_PAGE_BITS; WITH_RCU_READ_LOCK_GUARD() { - blocks = atomic_rcu_read(&ram_list.dirty_memory[client]); + blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]); idx = page / DIRTY_MEMORY_BLOCK_SIZE; offset = page % DIRTY_MEMORY_BLOCK_SIZE; @@ -XXX,XX +XXX,XX @@ static inline bool cpu_physical_memory_all_dirty(ram_addr_t start, RCU_READ_LOCK_GUARD(); - blocks = atomic_rcu_read(&ram_list.dirty_memory[client]); + blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]); idx = page / DIRTY_MEMORY_BLOCK_SIZE; offset = page % DIRTY_MEMORY_BLOCK_SIZE; @@ -XXX,XX +XXX,XX @@ static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr, RCU_READ_LOCK_GUARD(); - blocks = atomic_rcu_read(&ram_list.dirty_memory[client]); + blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]); set_bit_atomic(offset, blocks->blocks[idx]); } @@ -XXX,XX +XXX,XX @@ static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start, WITH_RCU_READ_LOCK_GUARD() { for (i = 0; i < DIRTY_MEMORY_NUM; i++) { - blocks[i] = atomic_rcu_read(&ram_list.dirty_memory[i]); + blocks[i] = qatomic_rcu_read(&ram_list.dirty_memory[i]); } idx = page / DIRTY_MEMORY_BLOCK_SIZE; @@ -XXX,XX +XXX,XX @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, WITH_RCU_READ_LOCK_GUARD() { for (i = 0; i < DIRTY_MEMORY_NUM; i++) { - blocks[i] = atomic_rcu_read(&ram_list.dirty_memory[i])->blocks; + blocks[i] = + qatomic_rcu_read(&ram_list.dirty_memory[i])->blocks; } for (k = 0; k < nr; k++) { if (bitmap[k]) { unsigned long temp = leul_to_cpu(bitmap[k]); - atomic_or(&blocks[DIRTY_MEMORY_VGA][idx][offset], temp); + qatomic_or(&blocks[DIRTY_MEMORY_VGA][idx][offset], temp); if (global_dirty_log) { - atomic_or(&blocks[DIRTY_MEMORY_MIGRATION][idx][offset], - temp); + qatomic_or( + &blocks[DIRTY_MEMORY_MIGRATION][idx][offset], + temp); } if (tcg_enabled()) { - atomic_or(&blocks[DIRTY_MEMORY_CODE][idx][offset], - temp); + qatomic_or(&blocks[DIRTY_MEMORY_CODE][idx][offset], + temp); } } @@ -XXX,XX +XXX,XX @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, DIRTY_MEMORY_BLOCK_SIZE); unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS); - src = atomic_rcu_read( + src = qatomic_rcu_read( &ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION])->blocks; for (k = page; k < page + nr; k++) { if (src[idx][offset]) { - unsigned long bits = atomic_xchg(&src[idx][offset], 0); + unsigned long bits = qatomic_xchg(&src[idx][offset], 0); unsigned long new_dirty; new_dirty = ~dest[k]; dest[k] |= bits; diff --git a/include/exec/ramlist.h b/include/exec/ramlist.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/ramlist.h +++ b/include/exec/ramlist.h @@ -XXX,XX +XXX,XX @@ typedef struct RAMBlockNotifier RAMBlockNotifier; * rcu_read_lock(); * * DirtyMemoryBlocks *blocks = - * atomic_rcu_read(&ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]); + * qatomic_rcu_read(&ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]); * * ram_addr_t idx = (addr >> TARGET_PAGE_BITS) / DIRTY_MEMORY_BLOCK_SIZE; * unsigned long *block = blocks.blocks[idx]; diff --git a/include/exec/tb-lookup.h b/include/exec/tb-lookup.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/tb-lookup.h +++ b/include/exec/tb-lookup.h @@ -XXX,XX +XXX,XX @@ tb_lookup__cpu_state(CPUState *cpu, target_ulong *pc, target_ulong *cs_base, cpu_get_tb_cpu_state(env, pc, cs_base, flags); hash = tb_jmp_cache_hash_func(*pc); - tb = atomic_rcu_read(&cpu->tb_jmp_cache[hash]); + tb = qatomic_rcu_read(&cpu->tb_jmp_cache[hash]); cf_mask &= ~CF_CLUSTER_MASK; cf_mask |= cpu->cluster_index << CF_CLUSTER_SHIFT; @@ -XXX,XX +XXX,XX @@ tb_lookup__cpu_state(CPUState *cpu, target_ulong *pc, target_ulong *cs_base, if (tb == NULL) { return NULL; } - atomic_set(&cpu->tb_jmp_cache[hash], tb); + qatomic_set(&cpu->tb_jmp_cache[hash], tb); return tb; } diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -XXX,XX +XXX,XX @@ static inline void cpu_tb_jmp_cache_clear(CPUState *cpu) unsigned int i; for (i = 0; i < TB_JMP_CACHE_SIZE; i++) { - atomic_set(&cpu->tb_jmp_cache[i], NULL); + qatomic_set(&cpu->tb_jmp_cache[i], NULL); } } diff --git a/include/qemu/atomic128.h b/include/qemu/atomic128.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/atomic128.h +++ b/include/qemu/atomic128.h @@ -XXX,XX +XXX,XX @@ #if defined(CONFIG_ATOMIC128) static inline Int128 atomic16_cmpxchg(Int128 *ptr, Int128 cmp, Int128 new) { - return atomic_cmpxchg__nocheck(ptr, cmp, new); + return qatomic_cmpxchg__nocheck(ptr, cmp, new); } # define HAVE_CMPXCHG128 1 #elif defined(CONFIG_CMPXCHG128) @@ -XXX,XX +XXX,XX @@ Int128 QEMU_ERROR("unsupported atomic") #if defined(CONFIG_ATOMIC128) static inline Int128 atomic16_read(Int128 *ptr) { - return atomic_read__nocheck(ptr); + return qatomic_read__nocheck(ptr); } static inline void atomic16_set(Int128 *ptr, Int128 val) { - atomic_set__nocheck(ptr, val); + qatomic_set__nocheck(ptr, val); } # define HAVE_ATOMIC128 1 diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -XXX,XX +XXX,XX @@ static inline void set_bit_atomic(long nr, unsigned long *addr) unsigned long mask = BIT_MASK(nr); unsigned long *p = addr + BIT_WORD(nr); - atomic_or(p, mask); + qatomic_or(p, mask); } /** diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -XXX,XX +XXX,XX @@ static inline coroutine_fn void qemu_co_mutex_assert_locked(CoMutex *mutex) * because the condition will be false no matter whether we read NULL or * the pointer for any other coroutine. */ - assert(atomic_read(&mutex->locked) && + assert(qatomic_read(&mutex->locked) && mutex->holder == qemu_coroutine_self()); } diff --git a/include/qemu/log.h b/include/qemu/log.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -XXX,XX +XXX,XX @@ static inline bool qemu_log_separate(void) bool res = false; rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile && logfile->fd != stderr) { res = true; } @@ -XXX,XX +XXX,XX @@ static inline FILE *qemu_log_lock(void) { QemuLogFile *logfile; rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile) { qemu_flockfile(logfile->fd); return logfile->fd; @@ -XXX,XX +XXX,XX @@ qemu_log_vprintf(const char *fmt, va_list va) QemuLogFile *logfile; rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile) { vfprintf(logfile->fd, fmt, va); } diff --git a/include/qemu/queue.h b/include/qemu/queue.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/queue.h +++ b/include/qemu/queue.h @@ -XXX,XX +XXX,XX @@ struct { \ typeof(elm) save_sle_next; \ do { \ save_sle_next = (elm)->field.sle_next = (head)->slh_first; \ - } while (atomic_cmpxchg(&(head)->slh_first, save_sle_next, (elm)) != \ + } while (qatomic_cmpxchg(&(head)->slh_first, save_sle_next, (elm)) !=\ save_sle_next); \ } while (/*CONSTCOND*/0) #define QSLIST_MOVE_ATOMIC(dest, src) do { \ - (dest)->slh_first = atomic_xchg(&(src)->slh_first, NULL); \ + (dest)->slh_first = qatomic_xchg(&(src)->slh_first, NULL); \ } while (/*CONSTCOND*/0) #define QSLIST_REMOVE_HEAD(head, field) do { \ @@ -XXX,XX +XXX,XX @@ struct { \ /* * Simple queue access methods. */ -#define QSIMPLEQ_EMPTY_ATOMIC(head) (atomic_read(&((head)->sqh_first)) == NULL) +#define QSIMPLEQ_EMPTY_ATOMIC(head) \ + (qatomic_read(&((head)->sqh_first)) == NULL) #define QSIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) #define QSIMPLEQ_FIRST(head) ((head)->sqh_first) #define QSIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -XXX,XX +XXX,XX @@ static inline void rcu_read_lock(void) return; } - ctr = atomic_read(&rcu_gp_ctr); - atomic_set(&p_rcu_reader->ctr, ctr); + ctr = qatomic_read(&rcu_gp_ctr); + qatomic_set(&p_rcu_reader->ctr, ctr); /* Write p_rcu_reader->ctr before reading RCU-protected pointers. */ smp_mb_placeholder(); @@ -XXX,XX +XXX,XX @@ static inline void rcu_read_unlock(void) * smp_mb_placeholder(), this ensures writes to p_rcu_reader->ctr * are sequentially consistent. */ - atomic_store_release(&p_rcu_reader->ctr, 0); + qatomic_store_release(&p_rcu_reader->ctr, 0); /* Write p_rcu_reader->ctr before reading p_rcu_reader->waiting. */ smp_mb_placeholder(); - if (unlikely(atomic_read(&p_rcu_reader->waiting))) { - atomic_set(&p_rcu_reader->waiting, false); + if (unlikely(qatomic_read(&p_rcu_reader->waiting))) { + qatomic_set(&p_rcu_reader->waiting, false); qemu_event_set(&rcu_gp_event); } } diff --git a/include/qemu/rcu_queue.h b/include/qemu/rcu_queue.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/rcu_queue.h +++ b/include/qemu/rcu_queue.h @@ -XXX,XX +XXX,XX @@ extern "C" { /* * List access methods. */ -#define QLIST_EMPTY_RCU(head) (atomic_read(&(head)->lh_first) == NULL) -#define QLIST_FIRST_RCU(head) (atomic_rcu_read(&(head)->lh_first)) -#define QLIST_NEXT_RCU(elm, field) (atomic_rcu_read(&(elm)->field.le_next)) +#define QLIST_EMPTY_RCU(head) (qatomic_read(&(head)->lh_first) == NULL) +#define QLIST_FIRST_RCU(head) (qatomic_rcu_read(&(head)->lh_first)) +#define QLIST_NEXT_RCU(elm, field) (qatomic_rcu_read(&(elm)->field.le_next)) /* * List functions. @@ -XXX,XX +XXX,XX @@ extern "C" { /* - * The difference between atomic_read/set and atomic_rcu_read/set + * The difference between qatomic_read/set and qatomic_rcu_read/set * is in the including of a read/write memory barrier to the volatile * access. atomic_rcu_* macros include the memory barrier, the * plain atomic macros do not. Therefore, it should be correct to @@ -XXX,XX +XXX,XX @@ extern "C" { #define QLIST_INSERT_AFTER_RCU(listelm, elm, field) do { \ (elm)->field.le_next = (listelm)->field.le_next; \ (elm)->field.le_prev = &(listelm)->field.le_next; \ - atomic_rcu_set(&(listelm)->field.le_next, (elm)); \ + qatomic_rcu_set(&(listelm)->field.le_next, (elm)); \ if ((elm)->field.le_next != NULL) { \ (elm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ @@ -XXX,XX +XXX,XX @@ extern "C" { #define QLIST_INSERT_BEFORE_RCU(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ - atomic_rcu_set((listelm)->field.le_prev, (elm)); \ + qatomic_rcu_set((listelm)->field.le_prev, (elm)); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (/*CONSTCOND*/0) @@ -XXX,XX +XXX,XX @@ extern "C" { #define QLIST_INSERT_HEAD_RCU(head, elm, field) do { \ (elm)->field.le_prev = &(head)->lh_first; \ (elm)->field.le_next = (head)->lh_first; \ - atomic_rcu_set((&(head)->lh_first), (elm)); \ + qatomic_rcu_set((&(head)->lh_first), (elm)); \ if ((elm)->field.le_next != NULL) { \ (elm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ @@ -XXX,XX +XXX,XX @@ extern "C" { (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ } \ - atomic_set((elm)->field.le_prev, (elm)->field.le_next); \ + qatomic_set((elm)->field.le_prev, (elm)->field.le_next); \ } while (/*CONSTCOND*/0) /* List traversal must occur within an RCU critical section. */ #define QLIST_FOREACH_RCU(var, head, field) \ - for ((var) = atomic_rcu_read(&(head)->lh_first); \ + for ((var) = qatomic_rcu_read(&(head)->lh_first); \ (var); \ - (var) = atomic_rcu_read(&(var)->field.le_next)) + (var) = qatomic_rcu_read(&(var)->field.le_next)) /* List traversal must occur within an RCU critical section. */ #define QLIST_FOREACH_SAFE_RCU(var, head, field, next_var) \ - for ((var) = (atomic_rcu_read(&(head)->lh_first)); \ + for ((var) = (qatomic_rcu_read(&(head)->lh_first)); \ (var) && \ - ((next_var) = atomic_rcu_read(&(var)->field.le_next), 1); \ + ((next_var) = qatomic_rcu_read(&(var)->field.le_next), 1); \ (var) = (next_var)) /* @@ -XXX,XX +XXX,XX @@ extern "C" { */ /* Simple queue access methods */ -#define QSIMPLEQ_EMPTY_RCU(head) (atomic_read(&(head)->sqh_first) == NULL) -#define QSIMPLEQ_FIRST_RCU(head) atomic_rcu_read(&(head)->sqh_first) -#define QSIMPLEQ_NEXT_RCU(elm, field) atomic_rcu_read(&(elm)->field.sqe_next) +#define QSIMPLEQ_EMPTY_RCU(head) \ + (qatomic_read(&(head)->sqh_first) == NULL) +#define QSIMPLEQ_FIRST_RCU(head) qatomic_rcu_read(&(head)->sqh_first) +#define QSIMPLEQ_NEXT_RCU(elm, field) qatomic_rcu_read(&(elm)->field.sqe_next) /* Simple queue functions */ #define QSIMPLEQ_INSERT_HEAD_RCU(head, elm, field) do { \ @@ -XXX,XX +XXX,XX @@ extern "C" { if ((elm)->field.sqe_next == NULL) { \ (head)->sqh_last = &(elm)->field.sqe_next; \ } \ - atomic_rcu_set(&(head)->sqh_first, (elm)); \ + qatomic_rcu_set(&(head)->sqh_first, (elm)); \ } while (/*CONSTCOND*/0) #define QSIMPLEQ_INSERT_TAIL_RCU(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ - atomic_rcu_set((head)->sqh_last, (elm)); \ + qatomic_rcu_set((head)->sqh_last, (elm)); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (/*CONSTCOND*/0) @@ -XXX,XX +XXX,XX @@ extern "C" { if ((elm)->field.sqe_next == NULL) { \ (head)->sqh_last = &(elm)->field.sqe_next; \ } \ - atomic_rcu_set(&(listelm)->field.sqe_next, (elm)); \ + qatomic_rcu_set(&(listelm)->field.sqe_next, (elm)); \ } while (/*CONSTCOND*/0) #define QSIMPLEQ_REMOVE_HEAD_RCU(head, field) do { \ - atomic_set(&(head)->sqh_first, (head)->sqh_first->field.sqe_next); \ + qatomic_set(&(head)->sqh_first, (head)->sqh_first->field.sqe_next);\ if ((head)->sqh_first == NULL) { \ (head)->sqh_last = &(head)->sqh_first; \ } \ @@ -XXX,XX +XXX,XX @@ extern "C" { while (curr->field.sqe_next != (elm)) { \ curr = curr->field.sqe_next; \ } \ - atomic_set(&curr->field.sqe_next, \ + qatomic_set(&curr->field.sqe_next, \ curr->field.sqe_next->field.sqe_next); \ if (curr->field.sqe_next == NULL) { \ (head)->sqh_last = &(curr)->field.sqe_next; \ @@ -XXX,XX +XXX,XX @@ extern "C" { } while (/*CONSTCOND*/0) #define QSIMPLEQ_FOREACH_RCU(var, head, field) \ - for ((var) = atomic_rcu_read(&(head)->sqh_first); \ + for ((var) = qatomic_rcu_read(&(head)->sqh_first); \ (var); \ - (var) = atomic_rcu_read(&(var)->field.sqe_next)) + (var) = qatomic_rcu_read(&(var)->field.sqe_next)) #define QSIMPLEQ_FOREACH_SAFE_RCU(var, head, field, next) \ - for ((var) = atomic_rcu_read(&(head)->sqh_first); \ - (var) && ((next) = atomic_rcu_read(&(var)->field.sqe_next), 1); \ + for ((var) = qatomic_rcu_read(&(head)->sqh_first); \ + (var) && ((next) = qatomic_rcu_read(&(var)->field.sqe_next), 1);\ (var) = (next)) /* @@ -XXX,XX +XXX,XX @@ extern "C" { */ /* Tail queue access methods */ -#define QTAILQ_EMPTY_RCU(head) (atomic_read(&(head)->tqh_first) == NULL) -#define QTAILQ_FIRST_RCU(head) atomic_rcu_read(&(head)->tqh_first) -#define QTAILQ_NEXT_RCU(elm, field) atomic_rcu_read(&(elm)->field.tqe_next) +#define QTAILQ_EMPTY_RCU(head) (qatomic_read(&(head)->tqh_first) == NULL) +#define QTAILQ_FIRST_RCU(head) qatomic_rcu_read(&(head)->tqh_first) +#define QTAILQ_NEXT_RCU(elm, field) qatomic_rcu_read(&(elm)->field.tqe_next) /* Tail queue functions */ #define QTAILQ_INSERT_HEAD_RCU(head, elm, field) do { \ @@ -XXX,XX +XXX,XX @@ extern "C" { } else { \ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \ } \ - atomic_rcu_set(&(head)->tqh_first, (elm)); \ + qatomic_rcu_set(&(head)->tqh_first, (elm)); \ (elm)->field.tqe_circ.tql_prev = &(head)->tqh_circ; \ } while (/*CONSTCOND*/0) #define QTAILQ_INSERT_TAIL_RCU(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_circ.tql_prev = (head)->tqh_circ.tql_prev; \ - atomic_rcu_set(&(head)->tqh_circ.tql_prev->tql_next, (elm)); \ + qatomic_rcu_set(&(head)->tqh_circ.tql_prev->tql_next, (elm)); \ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \ } while (/*CONSTCOND*/0) @@ -XXX,XX +XXX,XX @@ extern "C" { } else { \ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \ } \ - atomic_rcu_set(&(listelm)->field.tqe_next, (elm)); \ + qatomic_rcu_set(&(listelm)->field.tqe_next, (elm)); \ (elm)->field.tqe_circ.tql_prev = &(listelm)->field.tqe_circ; \ } while (/*CONSTCOND*/0) #define QTAILQ_INSERT_BEFORE_RCU(listelm, elm, field) do { \ (elm)->field.tqe_circ.tql_prev = (listelm)->field.tqe_circ.tql_prev; \ (elm)->field.tqe_next = (listelm); \ - atomic_rcu_set(&(listelm)->field.tqe_circ.tql_prev->tql_next, (elm)); \ + qatomic_rcu_set(&(listelm)->field.tqe_circ.tql_prev->tql_next, (elm));\ (listelm)->field.tqe_circ.tql_prev = &(elm)->field.tqe_circ; \ } while (/*CONSTCOND*/0) @@ -XXX,XX +XXX,XX @@ extern "C" { } else { \ (head)->tqh_circ.tql_prev = (elm)->field.tqe_circ.tql_prev; \ } \ - atomic_set(&(elm)->field.tqe_circ.tql_prev->tql_next, (elm)->field.tqe_next); \ + qatomic_set(&(elm)->field.tqe_circ.tql_prev->tql_next, \ + (elm)->field.tqe_next); \ (elm)->field.tqe_circ.tql_prev = NULL; \ } while (/*CONSTCOND*/0) #define QTAILQ_FOREACH_RCU(var, head, field) \ - for ((var) = atomic_rcu_read(&(head)->tqh_first); \ + for ((var) = qatomic_rcu_read(&(head)->tqh_first); \ (var); \ - (var) = atomic_rcu_read(&(var)->field.tqe_next)) + (var) = qatomic_rcu_read(&(var)->field.tqe_next)) #define QTAILQ_FOREACH_SAFE_RCU(var, head, field, next) \ - for ((var) = atomic_rcu_read(&(head)->tqh_first); \ - (var) && ((next) = atomic_rcu_read(&(var)->field.tqe_next), 1); \ + for ((var) = qatomic_rcu_read(&(head)->tqh_first); \ + (var) && ((next) = qatomic_rcu_read(&(var)->field.tqe_next), 1);\ (var) = (next)) /* @@ -XXX,XX +XXX,XX @@ extern "C" { */ /* Singly-linked list access methods */ -#define QSLIST_EMPTY_RCU(head) (atomic_read(&(head)->slh_first) == NULL) -#define QSLIST_FIRST_RCU(head) atomic_rcu_read(&(head)->slh_first) -#define QSLIST_NEXT_RCU(elm, field) atomic_rcu_read(&(elm)->field.sle_next) +#define QSLIST_EMPTY_RCU(head) (qatomic_read(&(head)->slh_first) == NULL) +#define QSLIST_FIRST_RCU(head) qatomic_rcu_read(&(head)->slh_first) +#define QSLIST_NEXT_RCU(elm, field) qatomic_rcu_read(&(elm)->field.sle_next) /* Singly-linked list functions */ #define QSLIST_INSERT_HEAD_RCU(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ - atomic_rcu_set(&(head)->slh_first, (elm)); \ + qatomic_rcu_set(&(head)->slh_first, (elm)); \ } while (/*CONSTCOND*/0) #define QSLIST_INSERT_AFTER_RCU(head, listelm, elm, field) do { \ (elm)->field.sle_next = (listelm)->field.sle_next; \ - atomic_rcu_set(&(listelm)->field.sle_next, (elm)); \ + qatomic_rcu_set(&(listelm)->field.sle_next, (elm)); \ } while (/*CONSTCOND*/0) #define QSLIST_REMOVE_HEAD_RCU(head, field) do { \ - atomic_set(&(head)->slh_first, (head)->slh_first->field.sle_next); \ + qatomic_set(&(head)->slh_first, (head)->slh_first->field.sle_next);\ } while (/*CONSTCOND*/0) #define QSLIST_REMOVE_RCU(head, elm, type, field) do { \ @@ -XXX,XX +XXX,XX @@ extern "C" { while (curr->field.sle_next != (elm)) { \ curr = curr->field.sle_next; \ } \ - atomic_set(&curr->field.sle_next, \ + qatomic_set(&curr->field.sle_next, \ curr->field.sle_next->field.sle_next); \ } \ } while (/*CONSTCOND*/0) #define QSLIST_FOREACH_RCU(var, head, field) \ - for ((var) = atomic_rcu_read(&(head)->slh_first); \ - (var); \ - (var) = atomic_rcu_read(&(var)->field.sle_next)) + for ((var) = qatomic_rcu_read(&(head)->slh_first); \ + (var); \ + (var) = qatomic_rcu_read(&(var)->field.sle_next)) -#define QSLIST_FOREACH_SAFE_RCU(var, head, field, next) \ - for ((var) = atomic_rcu_read(&(head)->slh_first); \ - (var) && ((next) = atomic_rcu_read(&(var)->field.sle_next), 1); \ +#define QSLIST_FOREACH_SAFE_RCU(var, head, field, next) \ + for ((var) = qatomic_rcu_read(&(head)->slh_first); \ + (var) && ((next) = qatomic_rcu_read(&(var)->field.sle_next), 1); \ (var) = (next)) #ifdef __cplusplus diff --git a/include/qemu/seqlock.h b/include/qemu/seqlock.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/seqlock.h +++ b/include/qemu/seqlock.h @@ -XXX,XX +XXX,XX @@ static inline void seqlock_init(QemuSeqLock *sl) /* Lock out other writers and update the count. */ static inline void seqlock_write_begin(QemuSeqLock *sl) { - atomic_set(&sl->sequence, sl->sequence + 1); + qatomic_set(&sl->sequence, sl->sequence + 1); /* Write sequence before updating other fields. */ smp_wmb(); @@ -XXX,XX +XXX,XX @@ static inline void seqlock_write_end(QemuSeqLock *sl) /* Write other fields before finalizing sequence. */ smp_wmb(); - atomic_set(&sl->sequence, sl->sequence + 1); + qatomic_set(&sl->sequence, sl->sequence + 1); } /* Lock out other writers and update the count. */ @@ -XXX,XX +XXX,XX @@ static inline void seqlock_write_unlock_impl(QemuSeqLock *sl, QemuLockable *lock static inline unsigned seqlock_read_begin(const QemuSeqLock *sl) { /* Always fail if a write is in progress. */ - unsigned ret = atomic_read(&sl->sequence); + unsigned ret = qatomic_read(&sl->sequence); /* Read sequence before reading other fields. */ smp_rmb(); @@ -XXX,XX +XXX,XX @@ static inline int seqlock_read_retry(const QemuSeqLock *sl, unsigned start) { /* Read other fields before reading final sequence. */ smp_rmb(); - return unlikely(atomic_read(&sl->sequence) != start); + return unlikely(qatomic_read(&sl->sequence) != start); } #endif diff --git a/include/qemu/stats64.h b/include/qemu/stats64.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/stats64.h +++ b/include/qemu/stats64.h @@ -XXX,XX +XXX,XX @@ static inline void stat64_init(Stat64 *s, uint64_t value) static inline uint64_t stat64_get(const Stat64 *s) { - return atomic_read__nocheck(&s->value); + return qatomic_read__nocheck(&s->value); } static inline void stat64_add(Stat64 *s, uint64_t value) { - atomic_add(&s->value, value); + qatomic_add(&s->value, value); } static inline void stat64_min(Stat64 *s, uint64_t value) { - uint64_t orig = atomic_read__nocheck(&s->value); + uint64_t orig = qatomic_read__nocheck(&s->value); while (orig > value) { - orig = atomic_cmpxchg__nocheck(&s->value, orig, value); + orig = qatomic_cmpxchg__nocheck(&s->value, orig, value); } } static inline void stat64_max(Stat64 *s, uint64_t value) { - uint64_t orig = atomic_read__nocheck(&s->value); + uint64_t orig = qatomic_read__nocheck(&s->value); while (orig < value) { - orig = atomic_cmpxchg__nocheck(&s->value, orig, value); + orig = qatomic_cmpxchg__nocheck(&s->value, orig, value); } } #else @@ -XXX,XX +XXX,XX @@ static inline void stat64_add(Stat64 *s, uint64_t value) low = (uint32_t) value; if (!low) { if (high) { - atomic_add(&s->high, high); + qatomic_add(&s->high, high); } return; } @@ -XXX,XX +XXX,XX @@ static inline void stat64_add(Stat64 *s, uint64_t value) * the high 32 bits, so it can race just fine with stat64_add32_carry * and even stat64_get! */ - old = atomic_cmpxchg(&s->low, orig, result); + old = qatomic_cmpxchg(&s->low, orig, result); if (orig == old) { return; } @@ -XXX,XX +XXX,XX @@ static inline void stat64_min(Stat64 *s, uint64_t value) high = value >> 32; low = (uint32_t) value; do { - orig_high = atomic_read(&s->high); + orig_high = qatomic_read(&s->high); if (orig_high < high) { return; } @@ -XXX,XX +XXX,XX @@ static inline void stat64_min(Stat64 *s, uint64_t value) * the write barrier in stat64_min_slow. */ smp_rmb(); - orig_low = atomic_read(&s->low); + orig_low = qatomic_read(&s->low); if (orig_low <= low) { return; } @@ -XXX,XX +XXX,XX @@ static inline void stat64_min(Stat64 *s, uint64_t value) * we may miss being lucky. */ smp_rmb(); - orig_high = atomic_read(&s->high); + orig_high = qatomic_read(&s->high); if (orig_high < high) { return; } @@ -XXX,XX +XXX,XX @@ static inline void stat64_max(Stat64 *s, uint64_t value) high = value >> 32; low = (uint32_t) value; do { - orig_high = atomic_read(&s->high); + orig_high = qatomic_read(&s->high); if (orig_high > high) { return; } @@ -XXX,XX +XXX,XX @@ static inline void stat64_max(Stat64 *s, uint64_t value) * the write barrier in stat64_max_slow. */ smp_rmb(); - orig_low = atomic_read(&s->low); + orig_low = qatomic_read(&s->low); if (orig_low >= low) { return; } @@ -XXX,XX +XXX,XX @@ static inline void stat64_max(Stat64 *s, uint64_t value) * we may miss being lucky. */ smp_rmb(); - orig_high = atomic_read(&s->high); + orig_high = qatomic_read(&s->high); if (orig_high > high) { return; } diff --git a/include/qemu/thread.h b/include/qemu/thread.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -XXX,XX +XXX,XX @@ extern QemuCondTimedWaitFunc qemu_cond_timedwait_func; qemu_cond_timedwait_impl(c, m, ms, __FILE__, __LINE__) #else #define qemu_mutex_lock(m) ({ \ - QemuMutexLockFunc _f = atomic_read(&qemu_mutex_lock_func); \ + QemuMutexLockFunc _f = qatomic_read(&qemu_mutex_lock_func); \ _f(m, __FILE__, __LINE__); \ }) -#define qemu_mutex_trylock(m) ({ \ - QemuMutexTrylockFunc _f = atomic_read(&qemu_mutex_trylock_func); \ - _f(m, __FILE__, __LINE__); \ +#define qemu_mutex_trylock(m) ({ \ + QemuMutexTrylockFunc _f = qatomic_read(&qemu_mutex_trylock_func); \ + _f(m, __FILE__, __LINE__); \ }) -#define qemu_rec_mutex_lock(m) ({ \ - QemuRecMutexLockFunc _f = atomic_read(&qemu_rec_mutex_lock_func); \ - _f(m, __FILE__, __LINE__); \ +#define qemu_rec_mutex_lock(m) ({ \ + QemuRecMutexLockFunc _f = qatomic_read(&qemu_rec_mutex_lock_func);\ + _f(m, __FILE__, __LINE__); \ }) #define qemu_rec_mutex_trylock(m) ({ \ QemuRecMutexTrylockFunc _f; \ - _f = atomic_read(&qemu_rec_mutex_trylock_func); \ + _f = qatomic_read(&qemu_rec_mutex_trylock_func); \ _f(m, __FILE__, __LINE__); \ }) #define qemu_cond_wait(c, m) ({ \ - QemuCondWaitFunc _f = atomic_read(&qemu_cond_wait_func); \ + QemuCondWaitFunc _f = qatomic_read(&qemu_cond_wait_func); \ _f(c, m, __FILE__, __LINE__); \ }) #define qemu_cond_timedwait(c, m, ms) ({ \ - QemuCondTimedWaitFunc _f = atomic_read(&qemu_cond_timedwait_func); \ + QemuCondTimedWaitFunc _f = qatomic_read(&qemu_cond_timedwait_func);\ _f(c, m, ms, __FILE__, __LINE__); \ }) #endif @@ -XXX,XX +XXX,XX @@ static inline void qemu_spin_lock(QemuSpin *spin) __tsan_mutex_pre_lock(spin, 0); #endif while (unlikely(__sync_lock_test_and_set(&spin->value, true))) { - while (atomic_read(&spin->value)) { + while (qatomic_read(&spin->value)) { cpu_relax(); } } @@ -XXX,XX +XXX,XX @@ static inline bool qemu_spin_trylock(QemuSpin *spin) static inline bool qemu_spin_locked(QemuSpin *spin) { - return atomic_read(&spin->value); + return qatomic_read(&spin->value); } static inline void qemu_spin_unlock(QemuSpin *spin) diff --git a/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h b/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h index XXXXXXX..XXXXXXX 100644 --- a/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h +++ b/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h @@ -XXX,XX +XXX,XX @@ static inline int pvrdma_idx_valid(uint32_t idx, uint32_t max_elems) static inline int32_t pvrdma_idx(int *var, uint32_t max_elems) { - const unsigned int idx = atomic_read(var); + const unsigned int idx = qatomic_read(var); if (pvrdma_idx_valid(idx, max_elems)) return idx & (max_elems - 1); @@ -XXX,XX +XXX,XX @@ static inline int32_t pvrdma_idx(int *var, uint32_t max_elems) static inline void pvrdma_idx_ring_inc(int *var, uint32_t max_elems) { - uint32_t idx = atomic_read(var) + 1; /* Increment. */ + uint32_t idx = qatomic_read(var) + 1; /* Increment. */ idx &= (max_elems << 1) - 1; /* Modulo size, flip gen. */ - atomic_set(var, idx); + qatomic_set(var, idx); } static inline int32_t pvrdma_idx_ring_has_space(const struct pvrdma_ring *r, uint32_t max_elems, uint32_t *out_tail) { - const uint32_t tail = atomic_read(&r->prod_tail); - const uint32_t head = atomic_read(&r->cons_head); + const uint32_t tail = qatomic_read(&r->prod_tail); + const uint32_t head = qatomic_read(&r->cons_head); if (pvrdma_idx_valid(tail, max_elems) && pvrdma_idx_valid(head, max_elems)) { @@ -XXX,XX +XXX,XX @@ static inline int32_t pvrdma_idx_ring_has_space(const struct pvrdma_ring *r, static inline int32_t pvrdma_idx_ring_has_data(const struct pvrdma_ring *r, uint32_t max_elems, uint32_t *out_head) { - const uint32_t tail = atomic_read(&r->prod_tail); - const uint32_t head = atomic_read(&r->cons_head); + const uint32_t tail = qatomic_read(&r->prod_tail); + const uint32_t head = qatomic_read(&r->cons_head); if (pvrdma_idx_valid(tail, max_elems) && pvrdma_idx_valid(head, max_elems)) { diff --git a/linux-user/qemu.h b/linux-user/qemu.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -XXX,XX +XXX,XX @@ typedef struct TaskState { /* Nonzero if process_pending_signals() needs to do something (either * handle a pending signal or unblock signals). * This flag is written from a signal handler so should be accessed via - * the atomic_read() and atomic_set() functions. (It is not accessed + * the qatomic_read() and qatomic_set() functions. (It is not accessed * from multiple threads.) */ int signal_pending; diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index XXXXXXX..XXXXXXX 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr, uintptr_t addr) { /* patch the branch destination */ - atomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4)); + qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4)); /* no need to flush icache explicitly */ } diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index XXXXXXX..XXXXXXX 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, { /* patch the branch destination */ intptr_t disp = addr - (jmp_addr - 2); - atomic_set((int32_t *)jmp_addr, disp / 2); + qatomic_set((int32_t *)jmp_addr, disp / 2); /* no need to flush icache explicitly */ } diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index XXXXXXX..XXXXXXX 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -XXX,XX +XXX,XX @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr, uintptr_t addr) { /* patch the branch destination */ - atomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4)); + qatomic_set((int32_t *)jmp_addr, addr - (jmp_addr + 4)); /* no need to flush icache explicitly */ } diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index XXXXXXX..XXXXXXX 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -XXX,XX +XXX,XX @@ static __thread bool have_sigbus_pending; static void kvm_cpu_kick(CPUState *cpu) { - atomic_set(&cpu->kvm_run->immediate_exit, 1); + qatomic_set(&cpu->kvm_run->immediate_exit, 1); } static void kvm_cpu_kick_self(void) @@ -XXX,XX +XXX,XX @@ static void kvm_eat_signals(CPUState *cpu) int r; if (kvm_immediate_exit) { - atomic_set(&cpu->kvm_run->immediate_exit, 0); + qatomic_set(&cpu->kvm_run->immediate_exit, 0); /* Write kvm_run->immediate_exit before the cpu->exit_request * write in kvm_cpu_exec. */ @@ -XXX,XX +XXX,XX @@ int kvm_cpu_exec(CPUState *cpu) DPRINTF("kvm_cpu_exec()\n"); if (kvm_arch_process_async_events(cpu)) { - atomic_set(&cpu->exit_request, 0); + qatomic_set(&cpu->exit_request, 0); return EXCP_HLT; } @@ -XXX,XX +XXX,XX @@ int kvm_cpu_exec(CPUState *cpu) } kvm_arch_pre_run(cpu, run); - if (atomic_read(&cpu->exit_request)) { + if (qatomic_read(&cpu->exit_request)) { DPRINTF("interrupt exit requested\n"); /* * KVM requires us to reenter the kernel after IO exits to complete @@ -XXX,XX +XXX,XX @@ int kvm_cpu_exec(CPUState *cpu) vm_stop(RUN_STATE_INTERNAL_ERROR); } - atomic_set(&cpu->exit_request, 0); + qatomic_set(&cpu->exit_request, 0); return ret; } @@ -XXX,XX +XXX,XX @@ int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) have_sigbus_pending = true; pending_sigbus_addr = addr; pending_sigbus_code = code; - atomic_set(&cpu->exit_request, 1); + qatomic_set(&cpu->exit_request, 1); return 0; #else return 1; diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index XXXXXXX..XXXXXXX 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -XXX,XX +XXX,XX @@ static inline void tb_add_jump(TranslationBlock *tb, int n, goto out_unlock_next; } /* Atomically claim the jump destination slot only if it was NULL */ - old = atomic_cmpxchg(&tb->jmp_dest[n], (uintptr_t)NULL, (uintptr_t)tb_next); + old = qatomic_cmpxchg(&tb->jmp_dest[n], (uintptr_t)NULL, + (uintptr_t)tb_next); if (old) { goto out_unlock_next; } @@ -XXX,XX +XXX,XX @@ static inline TranslationBlock *tb_find(CPUState *cpu, tb = tb_gen_code(cpu, pc, cs_base, flags, cf_mask); mmap_unlock(); /* We add the TB in the virtual pc hash table for the fast lookup */ - atomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb); + qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb); } #ifndef CONFIG_USER_ONLY /* We don't take care of direct jumps when address mapping changes in @@ -XXX,XX +XXX,XX @@ static inline bool cpu_handle_interrupt(CPUState *cpu, * Ensure zeroing happens before reading cpu->exit_request or * cpu->interrupt_request (see also smp_wmb in cpu_exit()) */ - atomic_mb_set(&cpu_neg(cpu)->icount_decr.u16.high, 0); + qatomic_mb_set(&cpu_neg(cpu)->icount_decr.u16.high, 0); - if (unlikely(atomic_read(&cpu->interrupt_request))) { + if (unlikely(qatomic_read(&cpu->interrupt_request))) { int interrupt_request; qemu_mutex_lock_iothread(); interrupt_request = cpu->interrupt_request; @@ -XXX,XX +XXX,XX @@ static inline bool cpu_handle_interrupt(CPUState *cpu, } /* Finally, check if we need to exit to the main loop. */ - if (unlikely(atomic_read(&cpu->exit_request)) + if (unlikely(qatomic_read(&cpu->exit_request)) || (use_icount && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0)) { - atomic_set(&cpu->exit_request, 0); + qatomic_set(&cpu->exit_request, 0); if (cpu->exception_index == -1) { cpu->exception_index = EXCP_INTERRUPT; } @@ -XXX,XX +XXX,XX @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, } *last_tb = NULL; - insns_left = atomic_read(&cpu_neg(cpu)->icount_decr.u32); + insns_left = qatomic_read(&cpu_neg(cpu)->icount_decr.u32); if (insns_left < 0) { /* Something asked us to stop executing chained TBs; just * continue round the main loop. Whatever requested the exit diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index XXXXXXX..XXXXXXX 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -XXX,XX +XXX,XX @@ void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) CPU_FOREACH(cpu) { CPUArchState *env = cpu->env_ptr; - full += atomic_read(&env_tlb(env)->c.full_flush_count); - part += atomic_read(&env_tlb(env)->c.part_flush_count); - elide += atomic_read(&env_tlb(env)->c.elide_flush_count); + full += qatomic_read(&env_tlb(env)->c.full_flush_count); + part += qatomic_read(&env_tlb(env)->c.part_flush_count); + elide += qatomic_read(&env_tlb(env)->c.elide_flush_count); } *pfull = full; *ppart = part; @@ -XXX,XX +XXX,XX @@ static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) cpu_tb_jmp_cache_clear(cpu); if (to_clean == ALL_MMUIDX_BITS) { - atomic_set(&env_tlb(env)->c.full_flush_count, + qatomic_set(&env_tlb(env)->c.full_flush_count, env_tlb(env)->c.full_flush_count + 1); } else { - atomic_set(&env_tlb(env)->c.part_flush_count, + qatomic_set(&env_tlb(env)->c.part_flush_count, env_tlb(env)->c.part_flush_count + ctpop16(to_clean)); if (to_clean != asked) { - atomic_set(&env_tlb(env)->c.elide_flush_count, + qatomic_set(&env_tlb(env)->c.elide_flush_count, env_tlb(env)->c.elide_flush_count + ctpop16(asked & ~to_clean)); } @@ -XXX,XX +XXX,XX @@ void tlb_unprotect_code(ram_addr_t ram_addr) * generated code. * * Other vCPUs might be reading their TLBs during guest execution, so we update - * te->addr_write with atomic_set. We don't need to worry about this for + * te->addr_write with qatomic_set. We don't need to worry about this for * oversized guests as MTTCG is disabled for them. * * Called with tlb_c.lock held. @@ -XXX,XX +XXX,XX @@ static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry, #if TCG_OVERSIZED_GUEST tlb_entry->addr_write |= TLB_NOTDIRTY; #else - atomic_set(&tlb_entry->addr_write, + qatomic_set(&tlb_entry->addr_write, tlb_entry->addr_write | TLB_NOTDIRTY); #endif } @@ -XXX,XX +XXX,XX @@ static inline target_ulong tlb_read_ofs(CPUTLBEntry *entry, size_t ofs) #if TCG_OVERSIZED_GUEST return *(target_ulong *)((uintptr_t)entry + ofs); #else - /* ofs might correspond to .addr_write, so use atomic_read */ - return atomic_read((target_ulong *)((uintptr_t)entry + ofs)); + /* ofs might correspond to .addr_write, so use qatomic_read */ + return qatomic_read((target_ulong *)((uintptr_t)entry + ofs)); #endif } @@ -XXX,XX +XXX,XX @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, CPUTLBEntry *vtlb = &env_tlb(env)->d[mmu_idx].vtable[vidx]; target_ulong cmp; - /* elt_ofs might correspond to .addr_write, so use atomic_read */ + /* elt_ofs might correspond to .addr_write, so use qatomic_read */ #if TCG_OVERSIZED_GUEST cmp = *(target_ulong *)((uintptr_t)vtlb + elt_ofs); #else - cmp = atomic_read((target_ulong *)((uintptr_t)vtlb + elt_ofs)); + cmp = qatomic_read((target_ulong *)((uintptr_t)vtlb + elt_ofs)); #endif if (cmp == page) { diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index XXXXXXX..XXXXXXX 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -XXX,XX +XXX,XX @@ static void tcg_handle_interrupt(CPUState *cpu, int mask) if (!qemu_cpu_is_self(cpu)) { qemu_cpu_kick(cpu); } else { - atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); + qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); if (use_icount && !cpu->can_do_io && (mask & ~old_mask) != 0) { diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index XXXXXXX..XXXXXXX 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -XXX,XX +XXX,XX @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, restore_state_to_opc(env, tb, data); #ifdef CONFIG_PROFILER - atomic_set(&prof->restore_time, + qatomic_set(&prof->restore_time, prof->restore_time + profile_getclock() - ti); - atomic_set(&prof->restore_count, prof->restore_count + 1); + qatomic_set(&prof->restore_count, prof->restore_count + 1); #endif return 0; } @@ -XXX,XX +XXX,XX @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) /* Level 2..N-1. */ for (i = v_l2_levels; i > 0; i--) { - void **p = atomic_rcu_read(lp); + void **p = qatomic_rcu_read(lp); if (p == NULL) { void *existing; @@ -XXX,XX +XXX,XX @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) return NULL; } p = g_new0(void *, V_L2_SIZE); - existing = atomic_cmpxchg(lp, NULL, p); + existing = qatomic_cmpxchg(lp, NULL, p); if (unlikely(existing)) { g_free(p); p = existing; @@ -XXX,XX +XXX,XX @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) lp = p + ((index >> (i * V_L2_BITS)) & (V_L2_SIZE - 1)); } - pd = atomic_rcu_read(lp); + pd = qatomic_rcu_read(lp); if (pd == NULL) { void *existing; @@ -XXX,XX +XXX,XX @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc) } } #endif - existing = atomic_cmpxchg(lp, NULL, pd); + existing = qatomic_cmpxchg(lp, NULL, pd); if (unlikely(existing)) { #ifndef CONFIG_USER_ONLY { @@ -XXX,XX +XXX,XX @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) tcg_region_reset_all(); /* XXX: flush processor icache at this point if cache flush is expensive */ - atomic_mb_set(&tb_ctx.tb_flush_count, tb_ctx.tb_flush_count + 1); + qatomic_mb_set(&tb_ctx.tb_flush_count, tb_ctx.tb_flush_count + 1); done: mmap_unlock(); @@ -XXX,XX +XXX,XX @@ done: void tb_flush(CPUState *cpu) { if (tcg_enabled()) { - unsigned tb_flush_count = atomic_mb_read(&tb_ctx.tb_flush_count); + unsigned tb_flush_count = qatomic_mb_read(&tb_ctx.tb_flush_count); if (cpu_in_exclusive_context(cpu)) { do_tb_flush(cpu, RUN_ON_CPU_HOST_INT(tb_flush_count)); @@ -XXX,XX +XXX,XX @@ static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig) int n; /* mark the LSB of jmp_dest[] so that no further jumps can be inserted */ - ptr = atomic_or_fetch(&orig->jmp_dest[n_orig], 1); + ptr = qatomic_or_fetch(&orig->jmp_dest[n_orig], 1); dest = (TranslationBlock *)(ptr & ~1); if (dest == NULL) { return; @@ -XXX,XX +XXX,XX @@ static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig) * While acquiring the lock, the jump might have been removed if the * destination TB was invalidated; check again. */ - ptr_locked = atomic_read(&orig->jmp_dest[n_orig]); + ptr_locked = qatomic_read(&orig->jmp_dest[n_orig]); if (ptr_locked != ptr) { qemu_spin_unlock(&dest->jmp_lock); /* @@ -XXX,XX +XXX,XX @@ static inline void tb_jmp_unlink(TranslationBlock *dest) TB_FOR_EACH_JMP(dest, tb, n) { tb_reset_jump(tb, n); - atomic_and(&tb->jmp_dest[n], (uintptr_t)NULL | 1); + qatomic_and(&tb->jmp_dest[n], (uintptr_t)NULL | 1); /* No need to clear the list entry; setting the dest ptr is enough */ } dest->jmp_list_head = (uintptr_t)NULL; @@ -XXX,XX +XXX,XX @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) /* make sure no further incoming jumps will be chained to this TB */ qemu_spin_lock(&tb->jmp_lock); - atomic_set(&tb->cflags, tb->cflags | CF_INVALID); + qatomic_set(&tb->cflags, tb->cflags | CF_INVALID); qemu_spin_unlock(&tb->jmp_lock); /* remove the TB from the hash list */ @@ -XXX,XX +XXX,XX @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) /* remove the TB from the hash list */ h = tb_jmp_cache_hash_func(tb->pc); CPU_FOREACH(cpu) { - if (atomic_read(&cpu->tb_jmp_cache[h]) == tb) { - atomic_set(&cpu->tb_jmp_cache[h], NULL); + if (qatomic_read(&cpu->tb_jmp_cache[h]) == tb) { + qatomic_set(&cpu->tb_jmp_cache[h], NULL); } } @@ -XXX,XX +XXX,XX @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list) /* suppress any remaining jumps to this TB */ tb_jmp_unlink(tb); - atomic_set(&tcg_ctx->tb_phys_invalidate_count, + qatomic_set(&tcg_ctx->tb_phys_invalidate_count, tcg_ctx->tb_phys_invalidate_count + 1); } @@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_gen_code(CPUState *cpu, #ifdef CONFIG_PROFILER /* includes aborted translations because of exceptions */ - atomic_set(&prof->tb_count1, prof->tb_count1 + 1); + qatomic_set(&prof->tb_count1, prof->tb_count1 + 1); ti = profile_getclock(); #endif @@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_gen_code(CPUState *cpu, } #ifdef CONFIG_PROFILER - atomic_set(&prof->tb_count, prof->tb_count + 1); - atomic_set(&prof->interm_time, prof->interm_time + profile_getclock() - ti); + qatomic_set(&prof->tb_count, prof->tb_count + 1); + qatomic_set(&prof->interm_time, + prof->interm_time + profile_getclock() - ti); ti = profile_getclock(); #endif @@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_gen_code(CPUState *cpu, tb->tc.size = gen_code_size; #ifdef CONFIG_PROFILER - atomic_set(&prof->code_time, prof->code_time + profile_getclock() - ti); - atomic_set(&prof->code_in_len, prof->code_in_len + tb->size); - atomic_set(&prof->code_out_len, prof->code_out_len + gen_code_size); - atomic_set(&prof->search_out_len, prof->search_out_len + search_size); + qatomic_set(&prof->code_time, prof->code_time + profile_getclock() - ti); + qatomic_set(&prof->code_in_len, prof->code_in_len + tb->size); + qatomic_set(&prof->code_out_len, prof->code_out_len + gen_code_size); + qatomic_set(&prof->search_out_len, prof->search_out_len + search_size); #endif #ifdef DEBUG_DISAS @@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_gen_code(CPUState *cpu, } #endif - atomic_set(&tcg_ctx->code_gen_ptr, (void *) + qatomic_set(&tcg_ctx->code_gen_ptr, (void *) ROUND_UP((uintptr_t)gen_code_buf + gen_code_size + search_size, CODE_GEN_ALIGN)); @@ -XXX,XX +XXX,XX @@ TranslationBlock *tb_gen_code(CPUState *cpu, uintptr_t orig_aligned = (uintptr_t)gen_code_buf; orig_aligned -= ROUND_UP(sizeof(*tb), qemu_icache_linesize); - atomic_set(&tcg_ctx->code_gen_ptr, (void *)orig_aligned); + qatomic_set(&tcg_ctx->code_gen_ptr, (void *)orig_aligned); tb_destroy(tb); return existing_tb; } @@ -XXX,XX +XXX,XX @@ static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr) unsigned int i, i0 = tb_jmp_cache_hash_page(page_addr); for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { - atomic_set(&cpu->tb_jmp_cache[i0 + i], NULL); + qatomic_set(&cpu->tb_jmp_cache[i0 + i], NULL); } } @@ -XXX,XX +XXX,XX @@ void dump_exec_info(void) qemu_printf("\nStatistics:\n"); qemu_printf("TB flush count %u\n", - atomic_read(&tb_ctx.tb_flush_count)); + qatomic_read(&tb_ctx.tb_flush_count)); qemu_printf("TB invalidate count %zu\n", tcg_tb_phys_invalidate_count()); @@ -XXX,XX +XXX,XX @@ void cpu_interrupt(CPUState *cpu, int mask) { g_assert(qemu_mutex_iothread_locked()); cpu->interrupt_request |= mask; - atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); + qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); } /* diff --git a/audio/jackaudio.c b/audio/jackaudio.c index XXXXXXX..XXXXXXX 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -XXX,XX +XXX,XX @@ static void qjack_buffer_create(QJackBuffer *buffer, int channels, int frames) static void qjack_buffer_clear(QJackBuffer *buffer) { assert(buffer->data); - atomic_store_release(&buffer->used, 0); + qatomic_store_release(&buffer->used, 0); buffer->rptr = 0; buffer->wptr = 0; } @@ -XXX,XX +XXX,XX @@ static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size) assert(buffer->data); const int samples = size / sizeof(float); int frames = samples / buffer->channels; - const int avail = buffer->frames - atomic_load_acquire(&buffer->used); + const int avail = buffer->frames - qatomic_load_acquire(&buffer->used); if (frames > avail) { frames = avail; @@ -XXX,XX +XXX,XX @@ static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size) buffer->wptr = wptr; - atomic_add(&buffer->used, frames); + qatomic_add(&buffer->used, frames); return frames * buffer->channels * sizeof(float); }; @@ -XXX,XX +XXX,XX @@ static int qjack_buffer_write(QJackBuffer *buffer, float *data, int size) static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames) { assert(buffer->data); - const int avail = buffer->frames - atomic_load_acquire(&buffer->used); + const int avail = buffer->frames - qatomic_load_acquire(&buffer->used); int wptr = buffer->wptr; if (frames > avail) { @@ -XXX,XX +XXX,XX @@ static int qjack_buffer_write_l(QJackBuffer *buffer, float **dest, int frames) } buffer->wptr = wptr; - atomic_add(&buffer->used, frames); + qatomic_add(&buffer->used, frames); return frames; } @@ -XXX,XX +XXX,XX @@ static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size) assert(buffer->data); const int samples = size / sizeof(float); int frames = samples / buffer->channels; - const int avail = atomic_load_acquire(&buffer->used); + const int avail = qatomic_load_acquire(&buffer->used); if (frames > avail) { frames = avail; @@ -XXX,XX +XXX,XX @@ static int qjack_buffer_read(QJackBuffer *buffer, float *dest, int size) buffer->rptr = rptr; - atomic_sub(&buffer->used, frames); + qatomic_sub(&buffer->used, frames); return frames * buffer->channels * sizeof(float); } @@ -XXX,XX +XXX,XX @@ static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames) { assert(buffer->data); int copy = frames; - const int used = atomic_load_acquire(&buffer->used); + const int used = qatomic_load_acquire(&buffer->used); int rptr = buffer->rptr; if (copy > used) { @@ -XXX,XX +XXX,XX @@ static int qjack_buffer_read_l(QJackBuffer *buffer, float **dest, int frames) } buffer->rptr = rptr; - atomic_sub(&buffer->used, copy); + qatomic_sub(&buffer->used, copy); return copy; } diff --git a/block.c b/block.c index XXXXXXX..XXXXXXX 100644 --- a/block.c +++ b/block.c @@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, } /* bdrv_new() and bdrv_close() make it so */ - assert(atomic_read(&bs->copy_on_read) == 0); + assert(qatomic_read(&bs->copy_on_read) == 0); if (bs->open_flags & BDRV_O_COPY_ON_READ) { if (!bs->read_only) { @@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs) bs->file = NULL; g_free(bs->opaque); bs->opaque = NULL; - atomic_set(&bs->copy_on_read, 0); + qatomic_set(&bs->copy_on_read, 0); bs->backing_file[0] = '\0'; bs->backing_format[0] = '\0'; bs->total_sectors = 0; diff --git a/block/block-backend.c b/block/block-backend.c index XXXXXXX..XXXXXXX 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -XXX,XX +XXX,XX @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) void blk_inc_in_flight(BlockBackend *blk) { - atomic_inc(&blk->in_flight); + qatomic_inc(&blk->in_flight); } void blk_dec_in_flight(BlockBackend *blk) { - atomic_dec(&blk->in_flight); + qatomic_dec(&blk->in_flight); aio_wait_kick(); } @@ -XXX,XX +XXX,XX @@ void blk_drain(BlockBackend *blk) /* We may have -ENOMEDIUM completions in flight */ AIO_WAIT_WHILE(blk_get_aio_context(blk), - atomic_mb_read(&blk->in_flight) > 0); + qatomic_mb_read(&blk->in_flight) > 0); if (bs) { bdrv_drained_end(bs); @@ -XXX,XX +XXX,XX @@ void blk_drain_all(void) aio_context_acquire(ctx); /* We may have -ENOMEDIUM completions in flight */ - AIO_WAIT_WHILE(ctx, atomic_mb_read(&blk->in_flight) > 0); + AIO_WAIT_WHILE(ctx, qatomic_mb_read(&blk->in_flight) > 0); aio_context_release(ctx); } @@ -XXX,XX +XXX,XX @@ void blk_io_limits_update_group(BlockBackend *blk, const char *group) static void blk_root_drained_begin(BdrvChild *child) { BlockBackend *blk = child->opaque; + ThrottleGroupMember *tgm = &blk->public.throttle_group_member; if (++blk->quiesce_counter == 1) { if (blk->dev_ops && blk->dev_ops->drained_begin) { @@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child) /* Note that blk->root may not be accessible here yet if we are just * attaching to a BlockDriverState that is drained. Use child instead. */ - if (atomic_fetch_inc(&blk->public.throttle_group_member.io_limits_disabled) == 0) { - throttle_group_restart_tgm(&blk->public.throttle_group_member); + if (qatomic_fetch_inc(&tgm->io_limits_disabled) == 0) { + throttle_group_restart_tgm(tgm); } } @@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter) assert(blk->quiesce_counter); assert(blk->public.throttle_group_member.io_limits_disabled); - atomic_dec(&blk->public.throttle_group_member.io_limits_disabled); + qatomic_dec(&blk->public.throttle_group_member.io_limits_disabled); if (--blk->quiesce_counter == 0) { if (blk->dev_ops && blk->dev_ops->drained_end) { diff --git a/block/io.c b/block/io.c index XXXXXXX..XXXXXXX 100644 --- a/block/io.c +++ b/block/io.c @@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end_single(BdrvChild *c) { int drained_end_counter = 0; bdrv_parent_drained_end_single_no_poll(c, &drained_end_counter); - BDRV_POLL_WHILE(c->bs, atomic_read(&drained_end_counter) > 0); + BDRV_POLL_WHILE(c->bs, qatomic_read(&drained_end_counter) > 0); } static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore, @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) */ void bdrv_enable_copy_on_read(BlockDriverState *bs) { - atomic_inc(&bs->copy_on_read); + qatomic_inc(&bs->copy_on_read); } void bdrv_disable_copy_on_read(BlockDriverState *bs) { - int old = atomic_fetch_dec(&bs->copy_on_read); + int old = qatomic_fetch_dec(&bs->copy_on_read); assert(old >= 1); } @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) } /* Set data->done and decrement drained_end_counter before bdrv_wakeup() */ - atomic_mb_set(&data->done, true); + qatomic_mb_set(&data->done, true); if (!data->begin) { - atomic_dec(data->drained_end_counter); + qatomic_dec(data->drained_end_counter); } bdrv_dec_in_flight(bs); @@ -XXX,XX +XXX,XX @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, }; if (!begin) { - atomic_inc(drained_end_counter); + qatomic_inc(drained_end_counter); } /* Make sure the driver callback completes during the polling phase for @@ -XXX,XX +XXX,XX @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, return true; } - if (atomic_read(&bs->in_flight)) { + if (qatomic_read(&bs->in_flight)) { return true; } @@ -XXX,XX +XXX,XX @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, assert(!qemu_in_coroutine()); /* Stop things in parent-to-child order */ - if (atomic_fetch_inc(&bs->quiesce_counter) == 0) { + if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) { aio_disable_external(bdrv_get_aio_context(bs)); } @@ -XXX,XX +XXX,XX @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, bdrv_parent_drained_end(bs, parent, ignore_bds_parents, drained_end_counter); - old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter); + old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter); if (old_quiesce_counter == 1) { aio_enable_external(bdrv_get_aio_context(bs)); } @@ -XXX,XX +XXX,XX @@ void bdrv_drained_end(BlockDriverState *bs) { int drained_end_counter = 0; bdrv_do_drained_end(bs, false, NULL, false, &drained_end_counter); - BDRV_POLL_WHILE(bs, atomic_read(&drained_end_counter) > 0); + BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0); } void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter) @@ -XXX,XX +XXX,XX @@ void bdrv_subtree_drained_end(BlockDriverState *bs) { int drained_end_counter = 0; bdrv_do_drained_end(bs, true, NULL, false, &drained_end_counter); - BDRV_POLL_WHILE(bs, atomic_read(&drained_end_counter) > 0); + BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0); } void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) @@ -XXX,XX +XXX,XX @@ void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) &drained_end_counter); } - BDRV_POLL_WHILE(child->bs, atomic_read(&drained_end_counter) > 0); + BDRV_POLL_WHILE(child->bs, qatomic_read(&drained_end_counter) > 0); } /* @@ -XXX,XX +XXX,XX @@ static void bdrv_drain_assert_idle(BlockDriverState *bs) { BdrvChild *child, *next; - assert(atomic_read(&bs->in_flight) == 0); + assert(qatomic_read(&bs->in_flight) == 0); QLIST_FOREACH_SAFE(child, &bs->children, next, next) { bdrv_drain_assert_idle(child->bs); } @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all_end(void) } assert(qemu_get_current_aio_context() == qemu_get_aio_context()); - AIO_WAIT_WHILE(NULL, atomic_read(&drained_end_counter) > 0); + AIO_WAIT_WHILE(NULL, qatomic_read(&drained_end_counter) > 0); assert(bdrv_drain_all_count > 0); bdrv_drain_all_count--; @@ -XXX,XX +XXX,XX @@ void bdrv_drain_all(void) static void tracked_request_end(BdrvTrackedRequest *req) { if (req->serialising) { - atomic_dec(&req->bs->serialising_in_flight); + qatomic_dec(&req->bs->serialising_in_flight); } qemu_co_mutex_lock(&req->bs->reqs_lock); @@ -XXX,XX +XXX,XX @@ bool bdrv_mark_request_serialising(BdrvTrackedRequest *req, uint64_t align) qemu_co_mutex_lock(&bs->reqs_lock); if (!req->serialising) { - atomic_inc(&req->bs->serialising_in_flight); + qatomic_inc(&req->bs->serialising_in_flight); req->serialising = true; } @@ -XXX,XX +XXX,XX @@ static int bdrv_get_cluster_size(BlockDriverState *bs) void bdrv_inc_in_flight(BlockDriverState *bs) { - atomic_inc(&bs->in_flight); + qatomic_inc(&bs->in_flight); } void bdrv_wakeup(BlockDriverState *bs) @@ -XXX,XX +XXX,XX @@ void bdrv_wakeup(BlockDriverState *bs) void bdrv_dec_in_flight(BlockDriverState *bs) { - atomic_dec(&bs->in_flight); + qatomic_dec(&bs->in_flight); bdrv_wakeup(bs); } @@ -XXX,XX +XXX,XX @@ static bool coroutine_fn bdrv_wait_serialising_requests(BdrvTrackedRequest *self BlockDriverState *bs = self->bs; bool waited = false; - if (!atomic_read(&bs->serialising_in_flight)) { + if (!qatomic_read(&bs->serialising_in_flight)) { return false; } @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, bdrv_inc_in_flight(bs); /* Don't do copy-on-read if we read data before write operation */ - if (atomic_read(&bs->copy_on_read)) { + if (qatomic_read(&bs->copy_on_read)) { flags |= BDRV_REQ_COPY_ON_READ; } @@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes, int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE); BlockDriverState *bs = child->bs; - atomic_inc(&bs->write_gen); + qatomic_inc(&bs->write_gen); /* * Discard cannot extend the image, but in error handling cases, such as @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) } qemu_co_mutex_lock(&bs->reqs_lock); - current_gen = atomic_read(&bs->write_gen); + current_gen = qatomic_read(&bs->write_gen); /* Wait until any previous flushes are completed */ while (bs->active_flush_req) { @@ -XXX,XX +XXX,XX @@ void bdrv_io_plug(BlockDriverState *bs) bdrv_io_plug(child->bs); } - if (atomic_fetch_inc(&bs->io_plugged) == 0) { + if (qatomic_fetch_inc(&bs->io_plugged) == 0) { BlockDriver *drv = bs->drv; if (drv && drv->bdrv_io_plug) { drv->bdrv_io_plug(bs); @@ -XXX,XX +XXX,XX @@ void bdrv_io_unplug(BlockDriverState *bs) BdrvChild *child; assert(bs->io_plugged); - if (atomic_fetch_dec(&bs->io_plugged) == 1) { + if (qatomic_fetch_dec(&bs->io_plugged) == 1) { BlockDriver *drv = bs->drv; if (drv && drv->bdrv_io_unplug) { drv->bdrv_io_unplug(bs); diff --git a/block/nfs.c b/block/nfs.c index XXXXXXX..XXXXXXX 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -XXX,XX +XXX,XX @@ nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data, } /* Set task->complete before reading bs->wakeup. */ - atomic_mb_set(&task->complete, 1); + qatomic_mb_set(&task->complete, 1); bdrv_wakeup(task->bs); } diff --git a/block/sheepdog.c b/block/sheepdog.c index XXXXXXX..XXXXXXX 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -XXX,XX +XXX,XX @@ out: srco->co = NULL; srco->ret = ret; /* Set srco->finished before reading bs->wakeup. */ - atomic_mb_set(&srco->finished, true); + qatomic_mb_set(&srco->finished, true); if (srco->bs) { bdrv_wakeup(srco->bs); } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index XXXXXXX..XXXXXXX 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -XXX,XX +XXX,XX @@ static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm, * immediately if it has pending requests. Otherwise we could be * forcing it to wait for other member's throttled requests. */ if (tgm_has_pending_reqs(tgm, is_write) && - atomic_read(&tgm->io_limits_disabled)) { + qatomic_read(&tgm->io_limits_disabled)) { return tgm; } @@ -XXX,XX +XXX,XX @@ static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm, ThrottleTimers *tt = &tgm->throttle_timers; bool must_wait; - if (atomic_read(&tgm->io_limits_disabled)) { + if (qatomic_read(&tgm->io_limits_disabled)) { return false; } @@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_group_restart_queue_entry(void *opaque) g_free(data); - atomic_dec(&tgm->restart_pending); + qatomic_dec(&tgm->restart_pending); aio_wait_kick(); } @@ -XXX,XX +XXX,XX @@ static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write * be no timer pending on this tgm at this point */ assert(!timer_pending(tgm->throttle_timers.timers[is_write])); - atomic_inc(&tgm->restart_pending); + qatomic_inc(&tgm->restart_pending); co = qemu_coroutine_create(throttle_group_restart_queue_entry, rd); aio_co_enter(tgm->aio_context, co); @@ -XXX,XX +XXX,XX @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm, tgm->throttle_state = ts; tgm->aio_context = ctx; - atomic_set(&tgm->restart_pending, 0); + qatomic_set(&tgm->restart_pending, 0); qemu_mutex_lock(&tg->lock); /* If the ThrottleGroup is new set this ThrottleGroupMember as the token */ @@ -XXX,XX +XXX,XX @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm) } /* Wait for throttle_group_restart_queue_entry() coroutines to finish */ - AIO_WAIT_WHILE(tgm->aio_context, atomic_read(&tgm->restart_pending) > 0); + AIO_WAIT_WHILE(tgm->aio_context, qatomic_read(&tgm->restart_pending) > 0); qemu_mutex_lock(&tg->lock); for (i = 0; i < 2; i++) { diff --git a/block/throttle.c b/block/throttle.c index XXXXXXX..XXXXXXX 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -XXX,XX +XXX,XX @@ static void throttle_reopen_abort(BDRVReopenState *reopen_state) static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs) { ThrottleGroupMember *tgm = bs->opaque; - if (atomic_fetch_inc(&tgm->io_limits_disabled) == 0) { + if (qatomic_fetch_inc(&tgm->io_limits_disabled) == 0) { throttle_group_restart_tgm(tgm); } } @@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs) { ThrottleGroupMember *tgm = bs->opaque; assert(tgm->io_limits_disabled); - atomic_dec(&tgm->io_limits_disabled); + qatomic_dec(&tgm->io_limits_disabled); } static const char *const throttle_strong_runtime_opts[] = { diff --git a/blockdev.c b/blockdev.c index XXXXXXX..XXXXXXX 100644 --- a/blockdev.c +++ b/blockdev.c @@ -XXX,XX +XXX,XX @@ static void external_snapshot_commit(BlkActionState *common) /* We don't need (or want) to use the transactional * bdrv_reopen_multiple() across all the entries at once, because we * don't want to abort all of them if one of them fails the reopen */ - if (!atomic_read(&state->old_bs->copy_on_read)) { + if (!qatomic_read(&state->old_bs->copy_on_read)) { bdrv_reopen_set_read_only(state->old_bs, true, NULL); } diff --git a/blockjob.c b/blockjob.c index XXXXXXX..XXXXXXX 100644 --- a/blockjob.c +++ b/blockjob.c @@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp) info = g_new0(BlockJobInfo, 1); info->type = g_strdup(job_type_str(&job->job)); info->device = g_strdup(job->job.id); - info->busy = atomic_read(&job->job.busy); + info->busy = qatomic_read(&job->job.busy); info->paused = job->job.pause_count > 0; info->offset = job->job.progress.current; info->len = job->job.progress.total; diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index XXXXXXX..XXXXXXX 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -XXX,XX +XXX,XX @@ static void vu_log_page(uint8_t *log_table, uint64_t page) { DPRINT("Logged dirty guest page: %"PRId64"\n", page); - atomic_or(&log_table[page / 8], 1 << (page % 8)); + qatomic_or(&log_table[page / 8], 1 << (page % 8)); } static void diff --git a/cpus-common.c b/cpus-common.c index XXXXXXX..XXXXXXX 100644 --- a/cpus-common.c +++ b/cpus-common.c @@ -XXX,XX +XXX,XX @@ void do_run_on_cpu(CPUState *cpu, run_on_cpu_func func, run_on_cpu_data data, wi.exclusive = false; queue_work_on_cpu(cpu, &wi); - while (!atomic_mb_read(&wi.done)) { + while (!qatomic_mb_read(&wi.done)) { CPUState *self_cpu = current_cpu; qemu_cond_wait(&qemu_work_cond, mutex); @@ -XXX,XX +XXX,XX @@ void start_exclusive(void) exclusive_idle(); /* Make all other cpus stop executing. */ - atomic_set(&pending_cpus, 1); + qatomic_set(&pending_cpus, 1); /* Write pending_cpus before reading other_cpu->running. */ smp_mb(); running_cpus = 0; CPU_FOREACH(other_cpu) { - if (atomic_read(&other_cpu->running)) { + if (qatomic_read(&other_cpu->running)) { other_cpu->has_waiter = true; running_cpus++; qemu_cpu_kick(other_cpu); } } - atomic_set(&pending_cpus, running_cpus + 1); + qatomic_set(&pending_cpus, running_cpus + 1); while (pending_cpus > 1) { qemu_cond_wait(&exclusive_cond, &qemu_cpu_list_lock); } @@ -XXX,XX +XXX,XX @@ void end_exclusive(void) current_cpu->in_exclusive_context = false; qemu_mutex_lock(&qemu_cpu_list_lock); - atomic_set(&pending_cpus, 0); + qatomic_set(&pending_cpus, 0); qemu_cond_broadcast(&exclusive_resume); qemu_mutex_unlock(&qemu_cpu_list_lock); } @@ -XXX,XX +XXX,XX @@ void end_exclusive(void) /* Wait for exclusive ops to finish, and begin cpu execution. */ void cpu_exec_start(CPUState *cpu) { - atomic_set(&cpu->running, true); + qatomic_set(&cpu->running, true); /* Write cpu->running before reading pending_cpus. */ smp_mb(); @@ -XXX,XX +XXX,XX @@ void cpu_exec_start(CPUState *cpu) * 3. pending_cpus == 0. Then start_exclusive is definitely going to * see cpu->running == true, and it will kick the CPU. */ - if (unlikely(atomic_read(&pending_cpus))) { + if (unlikely(qatomic_read(&pending_cpus))) { QEMU_LOCK_GUARD(&qemu_cpu_list_lock); if (!cpu->has_waiter) { /* Not counted in pending_cpus, let the exclusive item * run. Since we have the lock, just set cpu->running to true * while holding it; no need to check pending_cpus again. */ - atomic_set(&cpu->running, false); + qatomic_set(&cpu->running, false); exclusive_idle(); /* Now pending_cpus is zero. */ - atomic_set(&cpu->running, true); + qatomic_set(&cpu->running, true); } else { /* Counted in pending_cpus, go ahead and release the * waiter at cpu_exec_end. @@ -XXX,XX +XXX,XX @@ void cpu_exec_start(CPUState *cpu) /* Mark cpu as not executing, and release pending exclusive ops. */ void cpu_exec_end(CPUState *cpu) { - atomic_set(&cpu->running, false); + qatomic_set(&cpu->running, false); /* Write cpu->running before reading pending_cpus. */ smp_mb(); @@ -XXX,XX +XXX,XX @@ void cpu_exec_end(CPUState *cpu) * see cpu->running == false, and it can ignore this CPU until the * next cpu_exec_start. */ - if (unlikely(atomic_read(&pending_cpus))) { + if (unlikely(qatomic_read(&pending_cpus))) { QEMU_LOCK_GUARD(&qemu_cpu_list_lock); if (cpu->has_waiter) { cpu->has_waiter = false; - atomic_set(&pending_cpus, pending_cpus - 1); + qatomic_set(&pending_cpus, pending_cpus - 1); if (pending_cpus == 1) { qemu_cond_signal(&exclusive_cond); } @@ -XXX,XX +XXX,XX @@ void process_queued_cpu_work(CPUState *cpu) if (wi->free) { g_free(wi); } else { - atomic_mb_set(&wi->done, true); + qatomic_mb_set(&wi->done, true); } } qemu_mutex_unlock(&cpu->work_mutex); diff --git a/dump/dump.c b/dump/dump.c index XXXXXXX..XXXXXXX 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -XXX,XX +XXX,XX @@ static void dump_state_prepare(DumpState *s) bool dump_in_progress(void) { DumpState *state = &dump_state_global; - return (atomic_read(&state->status) == DUMP_STATUS_ACTIVE); + return (qatomic_read(&state->status) == DUMP_STATUS_ACTIVE); } /* calculate total size of memory to be dumped (taking filter into @@ -XXX,XX +XXX,XX @@ static void dump_process(DumpState *s, Error **errp) /* make sure status is written after written_size updates */ smp_wmb(); - atomic_set(&s->status, + qatomic_set(&s->status, (local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED)); /* send DUMP_COMPLETED message (unconditionally) */ @@ -XXX,XX +XXX,XX @@ DumpQueryResult *qmp_query_dump(Error **errp) { DumpQueryResult *result = g_new(DumpQueryResult, 1); DumpState *state = &dump_state_global; - result->status = atomic_read(&state->status); + result->status = qatomic_read(&state->status); /* make sure we are reading status and written_size in order */ smp_rmb(); result->completed = state->written_size; @@ -XXX,XX +XXX,XX @@ void qmp_dump_guest_memory(bool paging, const char *file, begin, length, &local_err); if (local_err) { error_propagate(errp, local_err); - atomic_set(&s->status, DUMP_STATUS_FAILED); + qatomic_set(&s->status, DUMP_STATUS_FAILED); return; } diff --git a/exec.c b/exec.c index XXXXXXX..XXXXXXX 100644 --- a/exec.c +++ b/exec.c @@ -XXX,XX +XXX,XX @@ static MemoryRegionSection *address_space_lookup_region(AddressSpaceDispatch *d, hwaddr addr, bool resolve_subpage) { - MemoryRegionSection *section = atomic_read(&d->mru_section); + MemoryRegionSection *section = qatomic_read(&d->mru_section); subpage_t *subpage; if (!section || section == &d->map.sections[PHYS_SECTION_UNASSIGNED] || !section_covers_addr(section, addr)) { section = phys_page_find(d, addr); - atomic_set(&d->mru_section, section); + qatomic_set(&d->mru_section, section); } if (resolve_subpage && section->mr->subpage) { subpage = container_of(section->mr, subpage_t, iomem); @@ -XXX,XX +XXX,XX @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, IOMMUMemoryRegionClass *imrc; IOMMUTLBEntry iotlb; int iommu_idx; - AddressSpaceDispatch *d = atomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch); + AddressSpaceDispatch *d = + qatomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch); for (;;) { section = address_space_translate_internal(d, addr, &addr, plen, false); @@ -XXX,XX +XXX,XX @@ static RAMBlock *qemu_get_ram_block(ram_addr_t addr) { RAMBlock *block; - block = atomic_rcu_read(&ram_list.mru_block); + block = qatomic_rcu_read(&ram_list.mru_block); if (block && addr - block->offset < block->max_length) { return block; } @@ -XXX,XX +XXX,XX @@ found: * call_rcu(reclaim_ramblock, xxx); * rcu_read_unlock() * - * atomic_rcu_set is not needed here. The block was already published + * qatomic_rcu_set is not needed here. The block was already published * when it was placed into the list. Here we're just making an extra * copy of the pointer. */ @@ -XXX,XX +XXX,XX @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start, page = start_page; WITH_RCU_READ_LOCK_GUARD() { - blocks = atomic_rcu_read(&ram_list.dirty_memory[client]); + blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]); ramblock = qemu_get_ram_block(start); /* Range sanity check on the ramblock */ assert(start >= ramblock->offset && @@ -XXX,XX +XXX,XX @@ DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty dest = 0; WITH_RCU_READ_LOCK_GUARD() { - blocks = atomic_rcu_read(&ram_list.dirty_memory[client]); + blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]); while (page < end) { unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE; @@ -XXX,XX +XXX,XX @@ static void dirty_memory_extend(ram_addr_t old_ram_size, DirtyMemoryBlocks *new_blocks; int j; - old_blocks = atomic_rcu_read(&ram_list.dirty_memory[i]); + old_blocks = qatomic_rcu_read(&ram_list.dirty_memory[i]); new_blocks = g_malloc(sizeof(*new_blocks) + sizeof(new_blocks->blocks[0]) * new_num_blocks); @@ -XXX,XX +XXX,XX @@ static void dirty_memory_extend(ram_addr_t old_ram_size, new_blocks->blocks[j] = bitmap_new(DIRTY_MEMORY_BLOCK_SIZE); } - atomic_rcu_set(&ram_list.dirty_memory[i], new_blocks); + qatomic_rcu_set(&ram_list.dirty_memory[i], new_blocks); if (old_blocks) { g_free_rcu(old_blocks, rcu); @@ -XXX,XX +XXX,XX @@ RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset, } RCU_READ_LOCK_GUARD(); - block = atomic_rcu_read(&ram_list.mru_block); + block = qatomic_rcu_read(&ram_list.mru_block); if (block && block->host && host - block->host < block->max_length) { goto found; } @@ -XXX,XX +XXX,XX @@ MemoryRegionSection *iotlb_to_section(CPUState *cpu, { int asidx = cpu_asidx_from_attrs(cpu, attrs); CPUAddressSpace *cpuas = &cpu->cpu_ases[asidx]; - AddressSpaceDispatch *d = atomic_rcu_read(&cpuas->memory_dispatch); + AddressSpaceDispatch *d = qatomic_rcu_read(&cpuas->memory_dispatch); MemoryRegionSection *sections = d->map.sections; return §ions[index & ~TARGET_PAGE_MASK]; @@ -XXX,XX +XXX,XX @@ static void tcg_commit(MemoryListener *listener) * may have split the RCU critical section. */ d = address_space_to_dispatch(cpuas->as); - atomic_rcu_set(&cpuas->memory_dispatch, d); + qatomic_rcu_set(&cpuas->memory_dispatch, d); tlb_flush(cpuas->cpu); } @@ -XXX,XX +XXX,XX @@ void cpu_register_map_client(QEMUBH *bh) qemu_mutex_lock(&map_client_list_lock); client->bh = bh; QLIST_INSERT_HEAD(&map_client_list, client, link); - if (!atomic_read(&bounce.in_use)) { + if (!qatomic_read(&bounce.in_use)) { cpu_notify_map_clients_locked(); } qemu_mutex_unlock(&map_client_list_lock); @@ -XXX,XX +XXX,XX @@ void *address_space_map(AddressSpace *as, mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs); if (!memory_access_is_direct(mr, is_write)) { - if (atomic_xchg(&bounce.in_use, true)) { + if (qatomic_xchg(&bounce.in_use, true)) { *plen = 0; return NULL; } @@ -XXX,XX +XXX,XX @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len, qemu_vfree(bounce.buffer); bounce.buffer = NULL; memory_region_unref(bounce.mr); - atomic_mb_set(&bounce.in_use, false); + qatomic_mb_set(&bounce.in_use, false); cpu_notify_map_clients(); } @@ -XXX,XX +XXX,XX @@ int ram_block_discard_disable(bool state) int old; if (!state) { - atomic_dec(&ram_block_discard_disabled); + qatomic_dec(&ram_block_discard_disabled); return 0; } do { - old = atomic_read(&ram_block_discard_disabled); + old = qatomic_read(&ram_block_discard_disabled); if (old < 0) { return -EBUSY; } - } while (atomic_cmpxchg(&ram_block_discard_disabled, old, old + 1) != old); + } while (qatomic_cmpxchg(&ram_block_discard_disabled, + old, old + 1) != old); return 0; } @@ -XXX,XX +XXX,XX @@ int ram_block_discard_require(bool state) int old; if (!state) { - atomic_inc(&ram_block_discard_disabled); + qatomic_inc(&ram_block_discard_disabled); return 0; } do { - old = atomic_read(&ram_block_discard_disabled); + old = qatomic_read(&ram_block_discard_disabled); if (old > 0) { return -EBUSY; } - } while (atomic_cmpxchg(&ram_block_discard_disabled, old, old - 1) != old); + } while (qatomic_cmpxchg(&ram_block_discard_disabled, + old, old - 1) != old); return 0; } bool ram_block_discard_is_disabled(void) { - return atomic_read(&ram_block_discard_disabled) > 0; + return qatomic_read(&ram_block_discard_disabled) > 0; } bool ram_block_discard_is_required(void) { - return atomic_read(&ram_block_discard_disabled) < 0; + return qatomic_read(&ram_block_discard_disabled) < 0; } #endif diff --git a/hw/core/cpu.c b/hw/core/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -XXX,XX +XXX,XX @@ void cpu_reset_interrupt(CPUState *cpu, int mask) void cpu_exit(CPUState *cpu) { - atomic_set(&cpu->exit_request, 1); + qatomic_set(&cpu->exit_request, 1); /* Ensure cpu_exec will see the exit request after TCG has exited. */ smp_wmb(); - atomic_set(&cpu->icount_decr_ptr->u16.high, -1); + qatomic_set(&cpu->icount_decr_ptr->u16.high, -1); } int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, @@ -XXX,XX +XXX,XX @@ static void cpu_common_reset(DeviceState *dev) cpu->halted = cpu->start_powered_off; cpu->mem_io_pc = 0; cpu->icount_extra = 0; - atomic_set(&cpu->icount_decr_ptr->u32, 0); + qatomic_set(&cpu->icount_decr_ptr->u32, 0); cpu->can_do_io = 1; cpu->exception_index = -1; cpu->crash_occurred = false; diff --git a/hw/display/qxl.c b/hw/display/qxl.c index XXXXXXX..XXXXXXX 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -XXX,XX +XXX,XX @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) /* * Older versions of Spice forgot to define the QXLRam struct * with the '__aligned__(4)' attribute. clang 7 and newer will - * thus warn that atomic_fetch_or(&d->ram->int_pending, ...) + * thus warn that qatomic_fetch_or(&d->ram->int_pending, ...) * might be a misaligned atomic access, and will generate an * out-of-line call for it, which results in a link error since * we don't currently link against libatomic. @@ -XXX,XX +XXX,XX @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) #define ALIGNED_UINT32_PTR(P) ((uint32_t *)P) #endif - old_pending = atomic_fetch_or(ALIGNED_UINT32_PTR(&d->ram->int_pending), + old_pending = qatomic_fetch_or(ALIGNED_UINT32_PTR(&d->ram->int_pending), le_events); if ((old_pending & le_events) == le_events) { return; diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index XXXXXXX..XXXXXXX 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -XXX,XX +XXX,XX @@ static void sint_msg_bh(void *opaque) HvSintRoute *sint_route = opaque; HvSintStagedMessage *staged_msg = sint_route->staged_msg; - if (atomic_read(&staged_msg->state) != HV_STAGED_MSG_POSTED) { + if (qatomic_read(&staged_msg->state) != HV_STAGED_MSG_POSTED) { /* status nor ready yet (spurious ack from guest?), ignore */ return; } @@ -XXX,XX +XXX,XX @@ static void sint_msg_bh(void *opaque) staged_msg->status = 0; /* staged message processing finished, ready to start over */ - atomic_set(&staged_msg->state, HV_STAGED_MSG_FREE); + qatomic_set(&staged_msg->state, HV_STAGED_MSG_FREE); /* drop the reference taken in hyperv_post_msg */ hyperv_sint_route_unref(sint_route); } @@ -XXX,XX +XXX,XX @@ static void cpu_post_msg(CPUState *cs, run_on_cpu_data data) memory_region_set_dirty(&synic->msg_page_mr, 0, sizeof(*synic->msg_page)); posted: - atomic_set(&staged_msg->state, HV_STAGED_MSG_POSTED); + qatomic_set(&staged_msg->state, HV_STAGED_MSG_POSTED); /* * Notify the msg originator of the progress made; if the slot was busy we * set msg_pending flag in it so it will be the guest who will do EOM and @@ -XXX,XX +XXX,XX @@ int hyperv_post_msg(HvSintRoute *sint_route, struct hyperv_message *src_msg) assert(staged_msg); /* grab the staging area */ - if (atomic_cmpxchg(&staged_msg->state, HV_STAGED_MSG_FREE, + if (qatomic_cmpxchg(&staged_msg->state, HV_STAGED_MSG_FREE, HV_STAGED_MSG_BUSY) != HV_STAGED_MSG_FREE) { return -EAGAIN; } @@ -XXX,XX +XXX,XX @@ int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno) set_mask = BIT_MASK(eventno); flags = synic->event_page->slot[sint_route->sint].flags; - if ((atomic_fetch_or(&flags[set_idx], set_mask) & set_mask) != set_mask) { + if ((qatomic_fetch_or(&flags[set_idx], set_mask) & set_mask) != set_mask) { memory_region_set_dirty(&synic->event_page_mr, 0, sizeof(*synic->event_page)); ret = hyperv_sint_route_set_sint(sint_route); diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -XXX,XX +XXX,XX @@ static int vmbus_channel_notify_guest(VMBusChannel *chan) idx = BIT_WORD(chan->id); mask = BIT_MASK(chan->id); - if ((atomic_fetch_or(&int_map[idx], mask) & mask) != mask) { + if ((qatomic_fetch_or(&int_map[idx], mask) & mask) != mask) { res = hyperv_sint_route_set_sint(chan->notify_route); dirty = len; } diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -XXX,XX +XXX,XX @@ static int handle_buffered_iopage(XenIOState *state) assert(req.dir == IOREQ_WRITE); assert(!req.data_is_ptr); - atomic_add(&buf_page->read_pointer, qw + 1); + qatomic_add(&buf_page->read_pointer, qw + 1); } return req.count; diff --git a/hw/intc/rx_icu.c b/hw/intc/rx_icu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/rx_icu.c +++ b/hw/intc/rx_icu.c @@ -XXX,XX +XXX,XX @@ static void rxicu_request(RXICUState *icu, int n_IRQ) int enable; enable = icu->ier[n_IRQ / 8] & (1 << (n_IRQ & 7)); - if (n_IRQ > 0 && enable != 0 && atomic_read(&icu->req_irq) < 0) { - atomic_set(&icu->req_irq, n_IRQ); + if (n_IRQ > 0 && enable != 0 && qatomic_read(&icu->req_irq) < 0) { + qatomic_set(&icu->req_irq, n_IRQ); set_irq(icu, n_IRQ, rxicu_level(icu, n_IRQ)); } } @@ -XXX,XX +XXX,XX @@ static void rxicu_set_irq(void *opaque, int n_IRQ, int level) } if (issue == 0 && src->sense == TRG_LEVEL) { icu->ir[n_IRQ] = 0; - if (atomic_read(&icu->req_irq) == n_IRQ) { + if (qatomic_read(&icu->req_irq) == n_IRQ) { /* clear request */ set_irq(icu, n_IRQ, 0); - atomic_set(&icu->req_irq, -1); + qatomic_set(&icu->req_irq, -1); } return; } @@ -XXX,XX +XXX,XX @@ static void rxicu_ack_irq(void *opaque, int no, int level) int n_IRQ; int max_pri; - n_IRQ = atomic_read(&icu->req_irq); + n_IRQ = qatomic_read(&icu->req_irq); if (n_IRQ < 0) { return; } - atomic_set(&icu->req_irq, -1); + qatomic_set(&icu->req_irq, -1); if (icu->src[n_IRQ].sense != TRG_LEVEL) { icu->ir[n_IRQ] = 0; } diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -XXX,XX +XXX,XX @@ static void sifive_plic_print_state(SiFivePLICState *plic) static uint32_t atomic_set_masked(uint32_t *a, uint32_t mask, uint32_t value) { - uint32_t old, new, cmp = atomic_read(a); + uint32_t old, new, cmp = qatomic_read(a); do { old = cmp; new = (old & ~mask) | (value & mask); - cmp = atomic_cmpxchg(a, old, new); + cmp = qatomic_cmpxchg(a, old, new); } while (old != cmp); return old; diff --git a/hw/misc/edu.c b/hw/misc/edu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -XXX,XX +XXX,XX @@ static uint64_t edu_mmio_read(void *opaque, hwaddr addr, unsigned size) qemu_mutex_unlock(&edu->thr_mutex); break; case 0x20: - val = atomic_read(&edu->status); + val = qatomic_read(&edu->status); break; case 0x24: val = edu->irq_status; @@ -XXX,XX +XXX,XX @@ static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val, edu->addr4 = ~val; break; case 0x08: - if (atomic_read(&edu->status) & EDU_STATUS_COMPUTING) { + if (qatomic_read(&edu->status) & EDU_STATUS_COMPUTING) { break; } /* EDU_STATUS_COMPUTING cannot go 0->1 concurrently, because it is only @@ -XXX,XX +XXX,XX @@ static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val, */ qemu_mutex_lock(&edu->thr_mutex); edu->fact = val; - atomic_or(&edu->status, EDU_STATUS_COMPUTING); + qatomic_or(&edu->status, EDU_STATUS_COMPUTING); qemu_cond_signal(&edu->thr_cond); qemu_mutex_unlock(&edu->thr_mutex); break; case 0x20: if (val & EDU_STATUS_IRQFACT) { - atomic_or(&edu->status, EDU_STATUS_IRQFACT); + qatomic_or(&edu->status, EDU_STATUS_IRQFACT); } else { - atomic_and(&edu->status, ~EDU_STATUS_IRQFACT); + qatomic_and(&edu->status, ~EDU_STATUS_IRQFACT); } break; case 0x60: @@ -XXX,XX +XXX,XX @@ static void *edu_fact_thread(void *opaque) uint32_t val, ret = 1; qemu_mutex_lock(&edu->thr_mutex); - while ((atomic_read(&edu->status) & EDU_STATUS_COMPUTING) == 0 && + while ((qatomic_read(&edu->status) & EDU_STATUS_COMPUTING) == 0 && !edu->stopping) { qemu_cond_wait(&edu->thr_cond, &edu->thr_mutex); } @@ -XXX,XX +XXX,XX @@ static void *edu_fact_thread(void *opaque) qemu_mutex_lock(&edu->thr_mutex); edu->fact = ret; qemu_mutex_unlock(&edu->thr_mutex); - atomic_and(&edu->status, ~EDU_STATUS_COMPUTING); + qatomic_and(&edu->status, ~EDU_STATUS_COMPUTING); - if (atomic_read(&edu->status) & EDU_STATUS_IRQFACT) { + if (qatomic_read(&edu->status) & EDU_STATUS_IRQFACT) { qemu_mutex_lock_iothread(); edu_raise_irq(edu, FACT_IRQ); qemu_mutex_unlock_iothread(); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index XXXXXXX..XXXXXXX 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -XXX,XX +XXX,XX @@ 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); - atomic_set(&n->primary_should_be_hidden, false); + qatomic_set(&n->primary_should_be_hidden, false); failover_add_primary(n, &err); if (err) { n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); @@ -XXX,XX +XXX,XX @@ static void virtio_net_handle_migration_primary(VirtIONet *n, bool should_be_hidden; Error *err = NULL; - should_be_hidden = atomic_read(&n->primary_should_be_hidden); + 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); @@ -XXX,XX +XXX,XX @@ static void virtio_net_handle_migration_primary(VirtIONet *n, qdev_get_vmsd(n->primary_dev), n->primary_dev); qapi_event_send_unplug_primary(n->primary_device_id); - atomic_set(&n->primary_should_be_hidden, true); + qatomic_set(&n->primary_should_be_hidden, true); } else { warn_report("couldn't unplug primary device"); } @@ -XXX,XX +XXX,XX @@ static int virtio_net_primary_should_be_hidden(DeviceListener *listener, n->primary_device_opts = device_opts; /* primary_should_be_hidden is set during feature negotiation */ - hide = atomic_read(&n->primary_should_be_hidden); + hide = qatomic_read(&n->primary_should_be_hidden); if (n->primary_device_dict) { g_free(n->primary_device_id); @@ -XXX,XX +XXX,XX @@ 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; - atomic_set(&n->primary_should_be_hidden, true); + qatomic_set(&n->primary_should_be_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); diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c index XXXXXXX..XXXXXXX 100644 --- a/hw/rdma/rdma_backend.c +++ b/hw/rdma/rdma_backend.c @@ -XXX,XX +XXX,XX @@ static void free_cqe_ctx(gpointer data, gpointer user_data) bctx = rdma_rm_get_cqe_ctx(rdma_dev_res, cqe_ctx_id); if (bctx) { rdma_rm_dealloc_cqe_ctx(rdma_dev_res, cqe_ctx_id); - atomic_dec(&rdma_dev_res->stats.missing_cqe); + qatomic_dec(&rdma_dev_res->stats.missing_cqe); } g_free(bctx); } @@ -XXX,XX +XXX,XX @@ static void clean_recv_mads(RdmaBackendDev *backend_dev) cqe_ctx_id = rdma_protected_qlist_pop_int64(&backend_dev-> recv_mads_list); if (cqe_ctx_id != -ENOENT) { - atomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); + qatomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); free_cqe_ctx(GINT_TO_POINTER(cqe_ctx_id), backend_dev->rdma_dev_res); } @@ -XXX,XX +XXX,XX @@ static int rdma_poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq) } total_ne += ne; } while (ne > 0); - atomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne); + qatomic_sub(&rdma_dev_res->stats.missing_cqe, total_ne); } if (ne < 0) { @@ -XXX,XX +XXX,XX @@ static void *comp_handler_thread(void *arg) static inline void disable_rdmacm_mux_async(RdmaBackendDev *backend_dev) { - atomic_set(&backend_dev->rdmacm_mux.can_receive, 0); + qatomic_set(&backend_dev->rdmacm_mux.can_receive, 0); } static inline void enable_rdmacm_mux_async(RdmaBackendDev *backend_dev) { - atomic_set(&backend_dev->rdmacm_mux.can_receive, sizeof(RdmaCmMuxMsg)); + qatomic_set(&backend_dev->rdmacm_mux.can_receive, sizeof(RdmaCmMuxMsg)); } static inline int rdmacm_mux_can_process_async(RdmaBackendDev *backend_dev) { - return atomic_read(&backend_dev->rdmacm_mux.can_receive); + return qatomic_read(&backend_dev->rdmacm_mux.can_receive); } static int rdmacm_mux_check_op_status(CharBackend *mad_chr_be) @@ -XXX,XX +XXX,XX @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev, goto err_dealloc_cqe_ctx; } - atomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); + qatomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); backend_dev->rdma_dev_res->stats.tx++; return; @@ -XXX,XX +XXX,XX @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev, goto err_dealloc_cqe_ctx; } - atomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); + qatomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); backend_dev->rdma_dev_res->stats.rx_bufs++; return; @@ -XXX,XX +XXX,XX @@ void rdma_backend_post_srq_recv(RdmaBackendDev *backend_dev, goto err_dealloc_cqe_ctx; } - atomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); + qatomic_inc(&backend_dev->rdma_dev_res->stats.missing_cqe); backend_dev->rdma_dev_res->stats.rx_bufs++; backend_dev->rdma_dev_res->stats.rx_srq++; diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c index XXXXXXX..XXXXXXX 100644 --- a/hw/rdma/rdma_rm.c +++ b/hw/rdma/rdma_rm.c @@ -XXX,XX +XXX,XX @@ int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr) qemu_mutex_init(&dev_res->lock); memset(&dev_res->stats, 0, sizeof(dev_res->stats)); - atomic_set(&dev_res->stats.missing_cqe, 0); + qatomic_set(&dev_res->stats.missing_cqe, 0); return 0; } diff --git a/hw/rdma/vmw/pvrdma_dev_ring.c b/hw/rdma/vmw/pvrdma_dev_ring.c index XXXXXXX..XXXXXXX 100644 --- a/hw/rdma/vmw/pvrdma_dev_ring.c +++ b/hw/rdma/vmw/pvrdma_dev_ring.c @@ -XXX,XX +XXX,XX @@ int pvrdma_ring_init(PvrdmaRing *ring, const char *name, PCIDevice *dev, ring->max_elems = max_elems; ring->elem_sz = elem_sz; /* TODO: Give a moment to think if we want to redo driver settings - atomic_set(&ring->ring_state->prod_tail, 0); - atomic_set(&ring->ring_state->cons_head, 0); + qatomic_set(&ring->ring_state->prod_tail, 0); + qatomic_set(&ring->ring_state->cons_head, 0); */ ring->npages = npages; ring->pages = g_malloc(npages * sizeof(void *)); diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) actual = *ind_addr; do { expected = actual; - actual = atomic_cmpxchg(ind_addr, expected, expected | to_be_set); + actual = qatomic_cmpxchg(ind_addr, expected, expected | to_be_set); } while (actual != expected); cpu_physical_memory_unmap((void *)ind_addr, len, 1, len); diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -XXX,XX +XXX,XX @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, actual = *ind_addr; do { expected = actual; - actual = atomic_cmpxchg(ind_addr, expected, expected | to_be_set); + actual = qatomic_cmpxchg(ind_addr, expected, expected | to_be_set); } while (actual != expected); trace_virtio_ccw_set_ind(ind_loc, actual, actual | to_be_set); cpu_physical_memory_unmap((void *)ind_addr, len, 1, len); diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index XXXXXXX..XXXXXXX 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -XXX,XX +XXX,XX @@ static void vhost_dev_sync_region(struct vhost_dev *dev, } /* Data must be read atomically. We don't really need barrier semantics * but it's easier to use atomic_* than roll our own. */ - log = atomic_xchg(from, 0); + log = qatomic_xchg(from, 0); while (log) { int bit = ctzl(log); hwaddr page_addr; diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index XXXXXXX..XXXXXXX 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -XXX,XX +XXX,XX @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size) } return proxy->vqs[vdev->queue_sel].enabled; case VIRTIO_MMIO_INTERRUPT_STATUS: - return atomic_read(&vdev->isr); + return qatomic_read(&vdev->isr); case VIRTIO_MMIO_STATUS: return vdev->status; case VIRTIO_MMIO_CONFIG_GENERATION: @@ -XXX,XX +XXX,XX @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, } break; case VIRTIO_MMIO_INTERRUPT_ACK: - atomic_and(&vdev->isr, ~value); + qatomic_and(&vdev->isr, ~value); virtio_update_irq(vdev); break; case VIRTIO_MMIO_STATUS: @@ -XXX,XX +XXX,XX @@ static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector) if (!vdev) { return; } - level = (atomic_read(&vdev->isr) != 0); + level = (qatomic_read(&vdev->isr) != 0); trace_virtio_mmio_setting_irq(level); qemu_set_irq(proxy->irq, level); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index XXXXXXX..XXXXXXX 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -XXX,XX +XXX,XX @@ static void virtio_pci_notify(DeviceState *d, uint16_t vector) msix_notify(&proxy->pci_dev, vector); else { VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - pci_set_irq(&proxy->pci_dev, atomic_read(&vdev->isr) & 1); + pci_set_irq(&proxy->pci_dev, qatomic_read(&vdev->isr) & 1); } } @@ -XXX,XX +XXX,XX @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr) break; case VIRTIO_PCI_ISR: /* reading from the ISR also clears it. */ - ret = atomic_xchg(&vdev->isr, 0); + ret = qatomic_xchg(&vdev->isr, 0); pci_irq_deassert(&proxy->pci_dev); break; case VIRTIO_MSI_CONFIG_VECTOR: @@ -XXX,XX +XXX,XX @@ static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr, { VirtIOPCIProxy *proxy = opaque; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - uint64_t val = atomic_xchg(&vdev->isr, 0); + uint64_t val = qatomic_xchg(&vdev->isr, 0); pci_irq_deassert(&proxy->pci_dev); return val; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index XXXXXXX..XXXXXXX 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -XXX,XX +XXX,XX @@ static void virtio_virtqueue_reset_region_cache(struct VirtQueue *vq) { VRingMemoryRegionCaches *caches; - caches = atomic_read(&vq->vring.caches); - atomic_rcu_set(&vq->vring.caches, NULL); + caches = qatomic_read(&vq->vring.caches); + qatomic_rcu_set(&vq->vring.caches, NULL); if (caches) { call_rcu(caches, virtio_free_region_cache, rcu); } @@ -XXX,XX +XXX,XX @@ static void virtio_init_region_cache(VirtIODevice *vdev, int n) goto err_avail; } - atomic_rcu_set(&vq->vring.caches, new); + qatomic_rcu_set(&vq->vring.caches, new); if (old) { call_rcu(old, virtio_free_region_cache, rcu); } @@ -XXX,XX +XXX,XX @@ static void vring_packed_flags_write(VirtIODevice *vdev, /* Called within rcu_read_lock(). */ static VRingMemoryRegionCaches *vring_get_region_caches(struct VirtQueue *vq) { - return atomic_rcu_read(&vq->vring.caches); + return qatomic_rcu_read(&vq->vring.caches); } /* Called within rcu_read_lock(). */ @@ -XXX,XX +XXX,XX @@ void virtio_reset(void *opaque) vdev->queue_sel = 0; vdev->status = 0; vdev->disabled = false; - atomic_set(&vdev->isr, 0); + qatomic_set(&vdev->isr, 0); vdev->config_vector = VIRTIO_NO_VECTOR; virtio_notify_vector(vdev, vdev->config_vector); @@ -XXX,XX +XXX,XX @@ void virtio_del_queue(VirtIODevice *vdev, int n) static void virtio_set_isr(VirtIODevice *vdev, int value) { - uint8_t old = atomic_read(&vdev->isr); + uint8_t old = qatomic_read(&vdev->isr); /* Do not write ISR if it does not change, so that its cacheline remains * shared in the common case where the guest does not read it. */ if ((old & value) != value) { - atomic_or(&vdev->isr, value); + qatomic_or(&vdev->isr, value); } } @@ -XXX,XX +XXX,XX @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->started = false; vdev->device_id = device_id; vdev->status = 0; - atomic_set(&vdev->isr, 0); + qatomic_set(&vdev->isr, 0); vdev->queue_sel = 0; vdev->config_vector = VIRTIO_NO_VECTOR; vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_QUEUE_MAX); diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index XXXXXXX..XXXXXXX 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -XXX,XX +XXX,XX @@ static void xtensa_set_irq(void *opaque, int irq, int active) uint32_t irq_bit = 1 << irq; if (active) { - atomic_or(&env->sregs[INTSET], irq_bit); + qatomic_or(&env->sregs[INTSET], irq_bit); } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) { - atomic_and(&env->sregs[INTSET], ~irq_bit); + qatomic_and(&env->sregs[INTSET], ~irq_bit); } check_interrupts(env); diff --git a/iothread.c b/iothread.c index XXXXXXX..XXXXXXX 100644 --- a/iothread.c +++ b/iothread.c @@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque) * We must check the running state again in case it was * changed in previous aio_poll() */ - if (iothread->running && atomic_read(&iothread->run_gcontext)) { + if (iothread->running && qatomic_read(&iothread->run_gcontext)) { g_main_loop_run(iothread->main_loop); } } @@ -XXX,XX +XXX,XX @@ static void iothread_instance_init(Object *obj) iothread->thread_id = -1; qemu_sem_init(&iothread->init_done_sem, 0); /* By default, we don't run gcontext */ - atomic_set(&iothread->run_gcontext, 0); + qatomic_set(&iothread->run_gcontext, 0); } static void iothread_instance_finalize(Object *obj) @@ -XXX,XX +XXX,XX @@ IOThreadInfoList *qmp_query_iothreads(Error **errp) GMainContext *iothread_get_g_main_context(IOThread *iothread) { - atomic_set(&iothread->run_gcontext, 1); + qatomic_set(&iothread->run_gcontext, 1); aio_notify(iothread->ctx); return iothread->worker_context; } diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -XXX,XX +XXX,XX @@ static abi_ulong hppa_lws(CPUHPPAState *env) } old = tswap32(old); new = tswap32(new); - ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new); + ret = qatomic_cmpxchg((uint32_t *)g2h(addr), old, new); ret = tswap32(ret); break; @@ -XXX,XX +XXX,XX @@ static abi_ulong hppa_lws(CPUHPPAState *env) case 0: old = *(uint8_t *)g2h(old); new = *(uint8_t *)g2h(new); - ret = atomic_cmpxchg((uint8_t *)g2h(addr), old, new); + ret = qatomic_cmpxchg((uint8_t *)g2h(addr), old, new); ret = ret != old; break; case 1: old = *(uint16_t *)g2h(old); new = *(uint16_t *)g2h(new); - ret = atomic_cmpxchg((uint16_t *)g2h(addr), old, new); + ret = qatomic_cmpxchg((uint16_t *)g2h(addr), old, new); ret = ret != old; break; case 2: old = *(uint32_t *)g2h(old); new = *(uint32_t *)g2h(new); - ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new); + ret = qatomic_cmpxchg((uint32_t *)g2h(addr), old, new); ret = ret != old; break; case 3: @@ -XXX,XX +XXX,XX @@ static abi_ulong hppa_lws(CPUHPPAState *env) o64 = *(uint64_t *)g2h(old); n64 = *(uint64_t *)g2h(new); #ifdef CONFIG_ATOMIC64 - r64 = atomic_cmpxchg__nocheck((uint64_t *)g2h(addr), o64, n64); + r64 = qatomic_cmpxchg__nocheck((uint64_t *)g2h(addr), + o64, n64); ret = r64 != o64; #else start_exclusive(); diff --git a/linux-user/signal.c b/linux-user/signal.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -XXX,XX +XXX,XX @@ int block_signals(void) sigfillset(&set); sigprocmask(SIG_SETMASK, &set, 0); - return atomic_xchg(&ts->signal_pending, 1); + return qatomic_xchg(&ts->signal_pending, 1); } /* Wrapper for sigprocmask function @@ -XXX,XX +XXX,XX @@ int queue_signal(CPUArchState *env, int sig, int si_type, ts->sync_signal.info = *info; ts->sync_signal.pending = sig; /* signal that a new signal is pending */ - atomic_set(&ts->signal_pending, 1); + qatomic_set(&ts->signal_pending, 1); return 1; /* indicates that the signal was queued */ } @@ -XXX,XX +XXX,XX @@ void process_pending_signals(CPUArchState *cpu_env) sigset_t set; sigset_t *blocked_set; - while (atomic_read(&ts->signal_pending)) { + while (qatomic_read(&ts->signal_pending)) { /* FIXME: This is not threadsafe. */ sigfillset(&set); sigprocmask(SIG_SETMASK, &set, 0); @@ -XXX,XX +XXX,XX @@ void process_pending_signals(CPUArchState *cpu_env) * of unblocking might cause us to take another host signal which * will set signal_pending again). */ - atomic_set(&ts->signal_pending, 0); + qatomic_set(&ts->signal_pending, 0); ts->in_sigsuspend = 0; set = ts->signal_mask; sigdelset(&set, SIGSEGV); diff --git a/migration/colo-failover.c b/migration/colo-failover.c index XXXXXXX..XXXXXXX 100644 --- a/migration/colo-failover.c +++ b/migration/colo-failover.c @@ -XXX,XX +XXX,XX @@ FailoverStatus failover_set_state(FailoverStatus old_state, { FailoverStatus old; - old = atomic_cmpxchg(&failover_state, old_state, new_state); + old = qatomic_cmpxchg(&failover_state, old_state, new_state); if (old == old_state) { trace_colo_failover_set_state(FailoverStatus_str(new_state)); } @@ -XXX,XX +XXX,XX @@ FailoverStatus failover_set_state(FailoverStatus old_state, FailoverStatus failover_get_state(void) { - return atomic_read(&failover_state); + return qatomic_read(&failover_state); } void qmp_x_colo_lost_heartbeat(Error **errp) diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ void qmp_migrate_start_postcopy(Error **errp) * we don't error if migration has finished since that would be racy * with issuing this command. */ - atomic_set(&s->start_postcopy, true); + qatomic_set(&s->start_postcopy, true); } /* shared migration helpers */ @@ -XXX,XX +XXX,XX @@ void qmp_migrate_start_postcopy(Error **errp) void migrate_set_state(int *state, int old_state, int new_state) { assert(new_state < MIGRATION_STATUS__MAX); - if (atomic_cmpxchg(state, old_state, new_state) == old_state) { + if (qatomic_cmpxchg(state, old_state, new_state) == old_state) { trace_migrate_set_state(MigrationStatus_str(new_state)); migrate_generate_event(new_state); } @@ -XXX,XX +XXX,XX @@ void qmp_migrate_recover(const char *uri, Error **errp) return; } - if (atomic_cmpxchg(&mis->postcopy_recover_triggered, + if (qatomic_cmpxchg(&mis->postcopy_recover_triggered, false, true) == true) { error_setg(errp, "Migrate recovery is triggered already"); return; @@ -XXX,XX +XXX,XX @@ static MigIterateState migration_iteration_run(MigrationState *s) if (pending_size && pending_size >= s->threshold_size) { /* Still a significant amount to transfer */ if (!in_postcopy && pend_pre <= s->threshold_size && - atomic_read(&s->start_postcopy)) { + qatomic_read(&s->start_postcopy)) { if (postcopy_start(s)) { error_report("%s: postcopy failed to start", __func__); } diff --git a/migration/multifd.c b/migration/multifd.c index XXXXXXX..XXXXXXX 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -XXX,XX +XXX,XX @@ static int multifd_send_pages(QEMUFile *f) MultiFDPages_t *pages = multifd_send_state->pages; uint64_t transferred; - if (atomic_read(&multifd_send_state->exiting)) { + if (qatomic_read(&multifd_send_state->exiting)) { return -1; } @@ -XXX,XX +XXX,XX @@ static void multifd_send_terminate_threads(Error *err) * threads at the same time, we can end calling this function * twice. */ - if (atomic_xchg(&multifd_send_state->exiting, 1)) { + if (qatomic_xchg(&multifd_send_state->exiting, 1)) { return; } @@ -XXX,XX +XXX,XX @@ static void *multifd_send_thread(void *opaque) while (true) { qemu_sem_wait(&p->sem); - if (atomic_read(&multifd_send_state->exiting)) { + if (qatomic_read(&multifd_send_state->exiting)) { break; } qemu_mutex_lock(&p->mutex); @@ -XXX,XX +XXX,XX @@ int multifd_save_setup(Error **errp) multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); multifd_send_state->pages = multifd_pages_init(page_count); qemu_sem_init(&multifd_send_state->channels_ready, 0); - atomic_set(&multifd_send_state->exiting, 0); + qatomic_set(&multifd_send_state->exiting, 0); multifd_send_state->ops = multifd_ops[migrate_multifd_compression()]; for (i = 0; i < thread_count; i++) { @@ -XXX,XX +XXX,XX @@ int multifd_load_setup(Error **errp) thread_count = migrate_multifd_channels(); multifd_recv_state = g_malloc0(sizeof(*multifd_recv_state)); multifd_recv_state->params = g_new0(MultiFDRecvParams, thread_count); - atomic_set(&multifd_recv_state->count, 0); + qatomic_set(&multifd_recv_state->count, 0); qemu_sem_init(&multifd_recv_state->sem_sync, 0); multifd_recv_state->ops = multifd_ops[migrate_multifd_compression()]; @@ -XXX,XX +XXX,XX @@ bool multifd_recv_all_channels_created(void) return true; } - return thread_count == atomic_read(&multifd_recv_state->count); + return thread_count == qatomic_read(&multifd_recv_state->count); } /* @@ -XXX,XX +XXX,XX @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) error_propagate_prepend(errp, local_err, "failed to receive packet" " via multifd channel %d: ", - atomic_read(&multifd_recv_state->count)); + qatomic_read(&multifd_recv_state->count)); return false; } trace_multifd_recv_new_channel(id); @@ -XXX,XX +XXX,XX @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) p->running = true; qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p, QEMU_THREAD_JOINABLE); - atomic_inc(&multifd_recv_state->count); - return atomic_read(&multifd_recv_state->count) == + qatomic_inc(&multifd_recv_state->count); + return qatomic_read(&multifd_recv_state->count) == migrate_multifd_channels(); } diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index XXXXXXX..XXXXXXX 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -XXX,XX +XXX,XX @@ int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis) Error *local_err = NULL; /* Let the fault thread quit */ - atomic_set(&mis->fault_thread_quit, 1); + qatomic_set(&mis->fault_thread_quit, 1); postcopy_fault_thread_notify(mis); trace_postcopy_ram_incoming_cleanup_join(); qemu_thread_join(&mis->fault_thread); @@ -XXX,XX +XXX,XX @@ static void mark_postcopy_blocktime_begin(uintptr_t addr, uint32_t ptid, low_time_offset = get_low_time_offset(dc); if (dc->vcpu_addr[cpu] == 0) { - atomic_inc(&dc->smp_cpus_down); + qatomic_inc(&dc->smp_cpus_down); } - atomic_xchg(&dc->last_begin, low_time_offset); - atomic_xchg(&dc->page_fault_vcpu_time[cpu], low_time_offset); - atomic_xchg(&dc->vcpu_addr[cpu], addr); + qatomic_xchg(&dc->last_begin, low_time_offset); + qatomic_xchg(&dc->page_fault_vcpu_time[cpu], low_time_offset); + qatomic_xchg(&dc->vcpu_addr[cpu], addr); /* * check it here, not at the beginning of the function, @@ -XXX,XX +XXX,XX @@ static void mark_postcopy_blocktime_begin(uintptr_t addr, uint32_t ptid, */ already_received = ramblock_recv_bitmap_test(rb, (void *)addr); if (already_received) { - atomic_xchg(&dc->vcpu_addr[cpu], 0); - atomic_xchg(&dc->page_fault_vcpu_time[cpu], 0); - atomic_dec(&dc->smp_cpus_down); + qatomic_xchg(&dc->vcpu_addr[cpu], 0); + qatomic_xchg(&dc->page_fault_vcpu_time[cpu], 0); + qatomic_dec(&dc->smp_cpus_down); } trace_mark_postcopy_blocktime_begin(addr, dc, dc->page_fault_vcpu_time[cpu], cpu, already_received); @@ -XXX,XX +XXX,XX @@ static void mark_postcopy_blocktime_end(uintptr_t addr) for (i = 0; i < smp_cpus; i++) { uint32_t vcpu_blocktime = 0; - read_vcpu_time = atomic_fetch_add(&dc->page_fault_vcpu_time[i], 0); - if (atomic_fetch_add(&dc->vcpu_addr[i], 0) != addr || + read_vcpu_time = qatomic_fetch_add(&dc->page_fault_vcpu_time[i], 0); + if (qatomic_fetch_add(&dc->vcpu_addr[i], 0) != addr || read_vcpu_time == 0) { continue; } - atomic_xchg(&dc->vcpu_addr[i], 0); + qatomic_xchg(&dc->vcpu_addr[i], 0); vcpu_blocktime = low_time_offset - read_vcpu_time; affected_cpu += 1; /* we need to know is that mark_postcopy_end was due to * faulted page, another possible case it's prefetched * page and in that case we shouldn't be here */ if (!vcpu_total_blocktime && - atomic_fetch_add(&dc->smp_cpus_down, 0) == smp_cpus) { + qatomic_fetch_add(&dc->smp_cpus_down, 0) == smp_cpus) { vcpu_total_blocktime = true; } /* continue cycle, due to one page could affect several vCPUs */ dc->vcpu_blocktime[i] += vcpu_blocktime; } - atomic_sub(&dc->smp_cpus_down, affected_cpu); + qatomic_sub(&dc->smp_cpus_down, affected_cpu); if (vcpu_total_blocktime) { - dc->total_blocktime += low_time_offset - atomic_fetch_add( + dc->total_blocktime += low_time_offset - qatomic_fetch_add( &dc->last_begin, 0); } trace_mark_postcopy_blocktime_end(addr, dc, dc->total_blocktime, @@ -XXX,XX +XXX,XX @@ static void *postcopy_ram_fault_thread(void *opaque) error_report("%s: read() failed", __func__); } - if (atomic_read(&mis->fault_thread_quit)) { + if (qatomic_read(&mis->fault_thread_quit)) { trace_postcopy_ram_fault_thread_quit(); break; } @@ -XXX,XX +XXX,XX @@ static PostcopyState incoming_postcopy_state; PostcopyState postcopy_state_get(void) { - return atomic_mb_read(&incoming_postcopy_state); + return qatomic_mb_read(&incoming_postcopy_state); } /* Set the state and return the old state */ PostcopyState postcopy_state_set(PostcopyState new_state) { - return atomic_xchg(&incoming_postcopy_state, new_state); + return qatomic_xchg(&incoming_postcopy_state, new_state); } /* Register a handler for external shared memory postcopy diff --git a/migration/rdma.c b/migration/rdma.c index XXXXXXX..XXXXXXX 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -XXX,XX +XXX,XX @@ static ssize_t qio_channel_rdma_writev(QIOChannel *ioc, size_t len = 0; RCU_READ_LOCK_GUARD(); - rdma = atomic_rcu_read(&rioc->rdmaout); + rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { return -EIO; @@ -XXX,XX +XXX,XX @@ static ssize_t qio_channel_rdma_readv(QIOChannel *ioc, size_t done = 0; RCU_READ_LOCK_GUARD(); - rdma = atomic_rcu_read(&rioc->rdmain); + rdma = qatomic_rcu_read(&rioc->rdmain); if (!rdma) { return -EIO; @@ -XXX,XX +XXX,XX @@ qio_channel_rdma_source_prepare(GSource *source, RCU_READ_LOCK_GUARD(); if (rsource->condition == G_IO_IN) { - rdma = atomic_rcu_read(&rsource->rioc->rdmain); + rdma = qatomic_rcu_read(&rsource->rioc->rdmain); } else { - rdma = atomic_rcu_read(&rsource->rioc->rdmaout); + rdma = qatomic_rcu_read(&rsource->rioc->rdmaout); } if (!rdma) { @@ -XXX,XX +XXX,XX @@ qio_channel_rdma_source_check(GSource *source) RCU_READ_LOCK_GUARD(); if (rsource->condition == G_IO_IN) { - rdma = atomic_rcu_read(&rsource->rioc->rdmain); + rdma = qatomic_rcu_read(&rsource->rioc->rdmain); } else { - rdma = atomic_rcu_read(&rsource->rioc->rdmaout); + rdma = qatomic_rcu_read(&rsource->rioc->rdmaout); } if (!rdma) { @@ -XXX,XX +XXX,XX @@ qio_channel_rdma_source_dispatch(GSource *source, RCU_READ_LOCK_GUARD(); if (rsource->condition == G_IO_IN) { - rdma = atomic_rcu_read(&rsource->rioc->rdmain); + rdma = qatomic_rcu_read(&rsource->rioc->rdmain); } else { - rdma = atomic_rcu_read(&rsource->rioc->rdmaout); + rdma = qatomic_rcu_read(&rsource->rioc->rdmaout); } if (!rdma) { @@ -XXX,XX +XXX,XX @@ static int qio_channel_rdma_close(QIOChannel *ioc, rdmain = rioc->rdmain; if (rdmain) { - atomic_rcu_set(&rioc->rdmain, NULL); + qatomic_rcu_set(&rioc->rdmain, NULL); } rdmaout = rioc->rdmaout; if (rdmaout) { - atomic_rcu_set(&rioc->rdmaout, NULL); + qatomic_rcu_set(&rioc->rdmaout, NULL); } rcu->rdmain = rdmain; @@ -XXX,XX +XXX,XX @@ qio_channel_rdma_shutdown(QIOChannel *ioc, RCU_READ_LOCK_GUARD(); - rdmain = atomic_rcu_read(&rioc->rdmain); - rdmaout = atomic_rcu_read(&rioc->rdmain); + rdmain = qatomic_rcu_read(&rioc->rdmain); + rdmaout = qatomic_rcu_read(&rioc->rdmain); switch (how) { case QIO_CHANNEL_SHUTDOWN_READ: @@ -XXX,XX +XXX,XX @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque, int ret; RCU_READ_LOCK_GUARD(); - rdma = atomic_rcu_read(&rioc->rdmaout); + rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { return -EIO; @@ -XXX,XX +XXX,XX @@ static int qemu_rdma_registration_handle(QEMUFile *f, void *opaque) int i = 0; RCU_READ_LOCK_GUARD(); - rdma = atomic_rcu_read(&rioc->rdmain); + rdma = qatomic_rcu_read(&rioc->rdmain); if (!rdma) { return -EIO; @@ -XXX,XX +XXX,XX @@ rdma_block_notification_handle(QIOChannelRDMA *rioc, const char *name) int found = -1; RCU_READ_LOCK_GUARD(); - rdma = atomic_rcu_read(&rioc->rdmain); + rdma = qatomic_rcu_read(&rioc->rdmain); if (!rdma) { return -EIO; @@ -XXX,XX +XXX,XX @@ static int qemu_rdma_registration_start(QEMUFile *f, void *opaque, RDMAContext *rdma; RCU_READ_LOCK_GUARD(); - rdma = atomic_rcu_read(&rioc->rdmaout); + rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { return -EIO; } @@ -XXX,XX +XXX,XX @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, int ret = 0; RCU_READ_LOCK_GUARD(); - rdma = atomic_rcu_read(&rioc->rdmaout); + rdma = qatomic_rcu_read(&rioc->rdmaout); if (!rdma) { return -EIO; } diff --git a/monitor/hmp.c b/monitor/hmp.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/hmp.c +++ b/monitor/hmp.c @@ -XXX,XX +XXX,XX @@ static void monitor_event(void *opaque, QEMUChrEvent event) monitor_resume(mon); monitor_flush(mon); } else { - atomic_mb_set(&mon->suspend_cnt, 0); + qatomic_mb_set(&mon->suspend_cnt, 0); } break; case CHR_EVENT_MUX_OUT: if (mon->reset_seen) { - if (atomic_mb_read(&mon->suspend_cnt) == 0) { + if (qatomic_mb_read(&mon->suspend_cnt) == 0) { monitor_printf(mon, "\n"); } monitor_flush(mon); monitor_suspend(mon); } else { - atomic_inc(&mon->suspend_cnt); + qatomic_inc(&mon->suspend_cnt); } qemu_mutex_lock(&mon->mon_lock); mon->mux_out = 1; diff --git a/monitor/misc.c b/monitor/misc.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -XXX,XX +XXX,XX @@ static uint64_t vtop(void *ptr, Error **errp) } /* Force copy-on-write if necessary. */ - atomic_add((uint8_t *)ptr, 0); + qatomic_add((uint8_t *)ptr, 0); if (pread(fd, &pinfo, sizeof(pinfo), offset) != sizeof(pinfo)) { error_setg_errno(errp, errno, "Cannot read pagemap"); diff --git a/monitor/monitor.c b/monitor/monitor.c index XXXXXXX..XXXXXXX 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -XXX,XX +XXX,XX @@ int monitor_suspend(Monitor *mon) return -ENOTTY; } - atomic_inc(&mon->suspend_cnt); + qatomic_inc(&mon->suspend_cnt); if (mon->use_io_thread) { /* @@ -XXX,XX +XXX,XX @@ void monitor_resume(Monitor *mon) return; } - if (atomic_dec_fetch(&mon->suspend_cnt) == 0) { + if (qatomic_dec_fetch(&mon->suspend_cnt) == 0) { AioContext *ctx; if (mon->use_io_thread) { @@ -XXX,XX +XXX,XX @@ int monitor_can_read(void *opaque) { Monitor *mon = opaque; - return !atomic_mb_read(&mon->suspend_cnt); + return !qatomic_mb_read(&mon->suspend_cnt); } void monitor_list_append(Monitor *mon) diff --git a/qemu-nbd.c b/qemu-nbd.c index XXXXXXX..XXXXXXX 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -XXX,XX +XXX,XX @@ QEMU_COPYRIGHT "\n" #if HAVE_NBD_DEVICE static void termsig_handler(int signum) { - atomic_cmpxchg(&state, RUNNING, TERMINATE); + qatomic_cmpxchg(&state, RUNNING, TERMINATE); qemu_notify_event(); } #endif /* HAVE_NBD_DEVICE */ diff --git a/qga/commands.c b/qga/commands.c index XXXXXXX..XXXXXXX 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -XXX,XX +XXX,XX @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp) ges = g_new0(GuestExecStatus, 1); - bool finished = atomic_mb_read(&gei->finished); + bool finished = qatomic_mb_read(&gei->finished); /* need to wait till output channels are closed * to be sure we captured all output at this point */ if (gei->has_output) { - finished = finished && atomic_mb_read(&gei->out.closed); - finished = finished && atomic_mb_read(&gei->err.closed); + finished = finished && qatomic_mb_read(&gei->out.closed); + finished = finished && qatomic_mb_read(&gei->err.closed); } ges->exited = finished; @@ -XXX,XX +XXX,XX @@ static void guest_exec_child_watch(GPid pid, gint status, gpointer data) (int32_t)gpid_to_int64(pid), (uint32_t)status); gei->status = status; - atomic_mb_set(&gei->finished, true); + qatomic_mb_set(&gei->finished, true); g_spawn_close_pid(pid); } @@ -XXX,XX +XXX,XX @@ static gboolean guest_exec_input_watch(GIOChannel *ch, done: g_io_channel_shutdown(ch, true, NULL); g_io_channel_unref(ch); - atomic_mb_set(&p->closed, true); + qatomic_mb_set(&p->closed, true); g_free(p->data); return false; @@ -XXX,XX +XXX,XX @@ static gboolean guest_exec_output_watch(GIOChannel *ch, close: g_io_channel_shutdown(ch, true, NULL); g_io_channel_unref(ch); - atomic_mb_set(&p->closed, true); + qatomic_mb_set(&p->closed, true); return false; } diff --git a/qom/object.c b/qom/object.c index XXXXXXX..XXXXXXX 100644 --- a/qom/object.c +++ b/qom/object.c @@ -XXX,XX +XXX,XX @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename, Object *inst; for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) { - if (atomic_read(&obj->class->object_cast_cache[i]) == typename) { + if (qatomic_read(&obj->class->object_cast_cache[i]) == typename) { goto out; } } @@ -XXX,XX +XXX,XX @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename, if (obj && obj == inst) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { - atomic_set(&obj->class->object_cast_cache[i - 1], - atomic_read(&obj->class->object_cast_cache[i])); + qatomic_set(&obj->class->object_cast_cache[i - 1], + qatomic_read(&obj->class->object_cast_cache[i])); } - atomic_set(&obj->class->object_cast_cache[i - 1], typename); + qatomic_set(&obj->class->object_cast_cache[i - 1], typename); } out: @@ -XXX,XX +XXX,XX @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, int i; for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) { - if (atomic_read(&class->class_cast_cache[i]) == typename) { + if (qatomic_read(&class->class_cast_cache[i]) == typename) { ret = class; goto out; } @@ -XXX,XX +XXX,XX @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class, #ifdef CONFIG_QOM_CAST_DEBUG if (class && ret == class) { for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) { - atomic_set(&class->class_cast_cache[i - 1], - atomic_read(&class->class_cast_cache[i])); + qatomic_set(&class->class_cast_cache[i - 1], + qatomic_read(&class->class_cast_cache[i])); } - atomic_set(&class->class_cast_cache[i - 1], typename); + qatomic_set(&class->class_cast_cache[i - 1], typename); } out: #endif @@ -XXX,XX +XXX,XX @@ Object *object_ref(void *objptr) if (!obj) { return NULL; } - atomic_inc(&obj->ref); + qatomic_inc(&obj->ref); return obj; } @@ -XXX,XX +XXX,XX @@ void object_unref(void *objptr) g_assert(obj->ref > 0); /* parent always holds a reference to its children */ - if (atomic_fetch_dec(&obj->ref) == 1) { + if (qatomic_fetch_dec(&obj->ref) == 1) { object_finalize(obj); } } diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index XXXXXXX..XXXXXXX 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -XXX,XX +XXX,XX @@ static void coroutine_fn prh_co_entry(void *opaque) goto out; } - while (atomic_read(&state) == RUNNING) { + while (qatomic_read(&state) == RUNNING) { PRHelperRequest req; PRHelperResponse resp; int sz; @@ -XXX,XX +XXX,XX @@ static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaqu static void termsig_handler(int signum) { - atomic_cmpxchg(&state, RUNNING, TERMINATE); + qatomic_cmpxchg(&state, RUNNING, TERMINATE); qemu_notify_event(); } diff --git a/softmmu/cpu-throttle.c b/softmmu/cpu-throttle.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/cpu-throttle.c +++ b/softmmu/cpu-throttle.c @@ -XXX,XX +XXX,XX @@ static void cpu_throttle_thread(CPUState *cpu, run_on_cpu_data opaque) } sleeptime_ns = endtime_ns - qemu_clock_get_ns(QEMU_CLOCK_REALTIME); } - atomic_set(&cpu->throttle_thread_scheduled, 0); + qatomic_set(&cpu->throttle_thread_scheduled, 0); } static void cpu_throttle_timer_tick(void *opaque) @@ -XXX,XX +XXX,XX @@ static void cpu_throttle_timer_tick(void *opaque) return; } CPU_FOREACH(cpu) { - if (!atomic_xchg(&cpu->throttle_thread_scheduled, 1)) { + if (!qatomic_xchg(&cpu->throttle_thread_scheduled, 1)) { async_run_on_cpu(cpu, cpu_throttle_thread, RUN_ON_CPU_NULL); } @@ -XXX,XX +XXX,XX @@ void cpu_throttle_set(int new_throttle_pct) new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX); new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN); - atomic_set(&throttle_percentage, new_throttle_pct); + qatomic_set(&throttle_percentage, new_throttle_pct); timer_mod(throttle_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + CPU_THROTTLE_TIMESLICE_NS); @@ -XXX,XX +XXX,XX @@ void cpu_throttle_set(int new_throttle_pct) void cpu_throttle_stop(void) { - atomic_set(&throttle_percentage, 0); + qatomic_set(&throttle_percentage, 0); } bool cpu_throttle_active(void) @@ -XXX,XX +XXX,XX @@ bool cpu_throttle_active(void) int cpu_throttle_get_percentage(void) { - return atomic_read(&throttle_percentage); + return qatomic_read(&throttle_percentage); } void cpu_throttle_init(void) diff --git a/softmmu/cpus.c b/softmmu/cpus.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -XXX,XX +XXX,XX @@ static void cpu_update_icount_locked(CPUState *cpu) int64_t executed = cpu_get_icount_executed(cpu); cpu->icount_budget -= executed; - atomic_set_i64(&timers_state.qemu_icount, + qatomic_set_i64(&timers_state.qemu_icount, timers_state.qemu_icount + executed); } @@ -XXX,XX +XXX,XX @@ static int64_t cpu_get_icount_raw_locked(void) cpu_update_icount_locked(cpu); } /* The read is protected by the seqlock, but needs atomic64 to avoid UB */ - return atomic_read_i64(&timers_state.qemu_icount); + return qatomic_read_i64(&timers_state.qemu_icount); } static int64_t cpu_get_icount_locked(void) { int64_t icount = cpu_get_icount_raw_locked(); - return atomic_read_i64(&timers_state.qemu_icount_bias) + + return qatomic_read_i64(&timers_state.qemu_icount_bias) + cpu_icount_to_ns(icount); } @@ -XXX,XX +XXX,XX @@ int64_t cpu_get_icount(void) int64_t cpu_icount_to_ns(int64_t icount) { - return icount << atomic_read(&timers_state.icount_time_shift); + return icount << qatomic_read(&timers_state.icount_time_shift); } static int64_t cpu_get_ticks_locked(void) @@ -XXX,XX +XXX,XX @@ static void icount_adjust(void) && last_delta + ICOUNT_WOBBLE < delta * 2 && timers_state.icount_time_shift > 0) { /* The guest is getting too far ahead. Slow time down. */ - atomic_set(&timers_state.icount_time_shift, + qatomic_set(&timers_state.icount_time_shift, timers_state.icount_time_shift - 1); } if (delta < 0 && last_delta - ICOUNT_WOBBLE > delta * 2 && timers_state.icount_time_shift < MAX_ICOUNT_SHIFT) { /* The guest is getting too far behind. Speed time up. */ - atomic_set(&timers_state.icount_time_shift, + qatomic_set(&timers_state.icount_time_shift, timers_state.icount_time_shift + 1); } last_delta = delta; - atomic_set_i64(&timers_state.qemu_icount_bias, + qatomic_set_i64(&timers_state.qemu_icount_bias, cur_icount - (timers_state.qemu_icount << timers_state.icount_time_shift)); seqlock_write_unlock(&timers_state.vm_clock_seqlock, @@ -XXX,XX +XXX,XX @@ static void icount_adjust_vm(void *opaque) static int64_t qemu_icount_round(int64_t count) { - int shift = atomic_read(&timers_state.icount_time_shift); + int shift = qatomic_read(&timers_state.icount_time_shift); return (count + (1 << shift) - 1) >> shift; } @@ -XXX,XX +XXX,XX @@ static void icount_warp_rt(void) int64_t delta = clock - cur_icount; warp_delta = MIN(warp_delta, delta); } - atomic_set_i64(&timers_state.qemu_icount_bias, + qatomic_set_i64(&timers_state.qemu_icount_bias, timers_state.qemu_icount_bias + warp_delta); } timers_state.vm_clock_warp_start = -1; @@ -XXX,XX +XXX,XX @@ void qtest_clock_warp(int64_t dest) seqlock_write_lock(&timers_state.vm_clock_seqlock, &timers_state.vm_clock_lock); - atomic_set_i64(&timers_state.qemu_icount_bias, + qatomic_set_i64(&timers_state.qemu_icount_bias, timers_state.qemu_icount_bias + warp); seqlock_write_unlock(&timers_state.vm_clock_seqlock, &timers_state.vm_clock_lock); @@ -XXX,XX +XXX,XX @@ void qemu_start_warp_timer(void) */ seqlock_write_lock(&timers_state.vm_clock_seqlock, &timers_state.vm_clock_lock); - atomic_set_i64(&timers_state.qemu_icount_bias, + qatomic_set_i64(&timers_state.qemu_icount_bias, timers_state.qemu_icount_bias + deadline); seqlock_write_unlock(&timers_state.vm_clock_seqlock, &timers_state.vm_clock_lock); @@ -XXX,XX +XXX,XX @@ static void qemu_cpu_kick_rr_next_cpu(void) { CPUState *cpu; do { - cpu = atomic_mb_read(&tcg_current_rr_cpu); + cpu = qatomic_mb_read(&tcg_current_rr_cpu); if (cpu) { cpu_exit(cpu); } - } while (cpu != atomic_mb_read(&tcg_current_rr_cpu)); + } while (cpu != qatomic_mb_read(&tcg_current_rr_cpu)); } /* Kick all RR vCPUs */ @@ -XXX,XX +XXX,XX @@ static void qemu_cpu_stop(CPUState *cpu, bool exit) static void qemu_wait_io_event_common(CPUState *cpu) { - atomic_mb_set(&cpu->thread_kicked, false); + qatomic_mb_set(&cpu->thread_kicked, false); if (cpu->stop) { qemu_cpu_stop(cpu, false); } @@ -XXX,XX +XXX,XX @@ static int tcg_cpu_exec(CPUState *cpu) ret = cpu_exec(cpu); cpu_exec_end(cpu); #ifdef CONFIG_PROFILER - atomic_set(&tcg_ctx->prof.cpu_exec_time, + qatomic_set(&tcg_ctx->prof.cpu_exec_time, tcg_ctx->prof.cpu_exec_time + profile_getclock() - ti); #endif return ret; @@ -XXX,XX +XXX,XX @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) while (cpu && cpu_work_list_empty(cpu) && !cpu->exit_request) { - atomic_mb_set(&tcg_current_rr_cpu, cpu); + qatomic_mb_set(&tcg_current_rr_cpu, cpu); current_cpu = cpu; qemu_clock_enable(QEMU_CLOCK_VIRTUAL, @@ -XXX,XX +XXX,XX @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) cpu = CPU_NEXT(cpu); } /* while (cpu && !cpu->exit_request).. */ - /* Does not need atomic_mb_set because a spurious wakeup is okay. */ - atomic_set(&tcg_current_rr_cpu, NULL); + /* Does not need qatomic_mb_set because a spurious wakeup is okay. */ + qatomic_set(&tcg_current_rr_cpu, NULL); if (cpu && cpu->exit_request) { - atomic_mb_set(&cpu->exit_request, 0); + qatomic_mb_set(&cpu->exit_request, 0); } if (use_icount && all_cpu_threads_idle()) { @@ -XXX,XX +XXX,XX @@ static void *qemu_tcg_cpu_thread_fn(void *arg) } } - atomic_mb_set(&cpu->exit_request, 0); + qatomic_mb_set(&cpu->exit_request, 0); qemu_wait_io_event(cpu); } while (!cpu->unplug || cpu_can_run(cpu)); @@ -XXX,XX +XXX,XX @@ bool qemu_mutex_iothread_locked(void) */ void qemu_mutex_lock_iothread_impl(const char *file, int line) { - QemuMutexLockFunc bql_lock = atomic_read(&qemu_bql_mutex_lock_func); + QemuMutexLockFunc bql_lock = qatomic_read(&qemu_bql_mutex_lock_func); g_assert(!qemu_mutex_iothread_locked()); bql_lock(&qemu_global_mutex, file, line); diff --git a/softmmu/memory.c b/softmmu/memory.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -XXX,XX +XXX,XX @@ static void flatview_destroy(FlatView *view) static bool flatview_ref(FlatView *view) { - return atomic_fetch_inc_nonzero(&view->ref) > 0; + return qatomic_fetch_inc_nonzero(&view->ref) > 0; } void flatview_unref(FlatView *view) { - if (atomic_fetch_dec(&view->ref) == 1) { + if (qatomic_fetch_dec(&view->ref) == 1) { trace_flatview_destroy_rcu(view, view->root); assert(view->root); call_rcu(view, flatview_destroy, rcu); @@ -XXX,XX +XXX,XX @@ static void address_space_set_flatview(AddressSpace *as) } /* Writes are protected by the BQL. */ - atomic_rcu_set(&as->current_map, new_view); + qatomic_rcu_set(&as->current_map, new_view); if (old_view) { flatview_unref(old_view); } diff --git a/softmmu/vl.c b/softmmu/vl.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -XXX,XX +XXX,XX @@ ShutdownCause qemu_reset_requested_get(void) static int qemu_shutdown_requested(void) { - return atomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE); + return qatomic_xchg(&shutdown_requested, SHUTDOWN_CAUSE_NONE); } static void qemu_kill_report(void) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -XXX,XX +XXX,XX @@ static void store_tag1(uint64_t ptr, uint8_t *mem, int tag) static void store_tag1_parallel(uint64_t ptr, uint8_t *mem, int tag) { int ofs = extract32(ptr, LOG2_TAG_GRANULE, 1) * 4; - uint8_t old = atomic_read(mem); + uint8_t old = qatomic_read(mem); while (1) { uint8_t new = deposit32(old, ofs, 4, tag); - uint8_t cmp = atomic_cmpxchg(mem, old, new); + uint8_t cmp = qatomic_cmpxchg(mem, old, new); if (likely(cmp == old)) { return; } @@ -XXX,XX +XXX,XX @@ static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt, 2 * TAG_GRANULE, MMU_DATA_STORE, 1, ra); if (mem1) { tag |= tag << 4; - atomic_set(mem1, tag); + qatomic_set(mem1, tag); } } } diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -XXX,XX +XXX,XX @@ static void atomic_store_3(CPUHPPAState *env, target_ulong addr, uint32_t val, old = *haddr; while (1) { new = (old & ~mask) | (val & mask); - cmp = atomic_cmpxchg(haddr, old, new); + cmp = qatomic_cmpxchg(haddr, old, new); if (cmp == old) { return; } diff --git a/target/i386/mem_helper.c b/target/i386/mem_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/mem_helper.c +++ b/target/i386/mem_helper.c @@ -XXX,XX +XXX,XX @@ void helper_cmpxchg8b(CPUX86State *env, target_ulong a0) uint64_t *haddr = g2h(a0); cmpv = cpu_to_le64(cmpv); newv = cpu_to_le64(newv); - oldv = atomic_cmpxchg__nocheck(haddr, cmpv, newv); + oldv = qatomic_cmpxchg__nocheck(haddr, cmpv, newv); oldv = le64_to_cpu(oldv); } #else diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c index XXXXXXX..XXXXXXX 100644 --- a/target/i386/whpx-all.c +++ b/target/i386/whpx-all.c @@ -XXX,XX +XXX,XX @@ static int whpx_vcpu_run(CPUState *cpu) whpx_vcpu_process_async_events(cpu); if (cpu->halted) { cpu->exception_index = EXCP_HLT; - atomic_set(&cpu->exit_request, false); + qatomic_set(&cpu->exit_request, false); return 0; } @@ -XXX,XX +XXX,XX @@ static int whpx_vcpu_run(CPUState *cpu) whpx_vcpu_pre_run(cpu); - if (atomic_read(&cpu->exit_request)) { + if (qatomic_read(&cpu->exit_request)) { whpx_vcpu_kick(cpu); } @@ -XXX,XX +XXX,XX @@ static int whpx_vcpu_run(CPUState *cpu) qemu_mutex_lock_iothread(); current_cpu = cpu; - atomic_set(&cpu->exit_request, false); + qatomic_set(&cpu->exit_request, false); return ret < 0; } diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -XXX,XX +XXX,XX @@ restart: *pte_pa = pte = updated_pte; #else target_ulong old_pte = - atomic_cmpxchg(pte_pa, pte, updated_pte); + qatomic_cmpxchg(pte_pa, pte, updated_pte); if (old_pte != pte) { goto restart; } else { diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -XXX,XX +XXX,XX @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, if (parallel) { #ifdef CONFIG_USER_ONLY uint32_t *haddr = g2h(a1); - ov = atomic_cmpxchg__nocheck(haddr, cv, nv); + ov = qatomic_cmpxchg__nocheck(haddr, cv, nv); #else TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx); ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra); @@ -XXX,XX +XXX,XX @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, #ifdef CONFIG_ATOMIC64 # ifdef CONFIG_USER_ONLY uint64_t *haddr = g2h(a1); - ov = atomic_cmpxchg__nocheck(haddr, cv, nv); + ov = qatomic_cmpxchg__nocheck(haddr, cv, nv); # else TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx); ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra); diff --git a/target/xtensa/exc_helper.c b/target/xtensa/exc_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/xtensa/exc_helper.c +++ b/target/xtensa/exc_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(check_interrupts)(CPUXtensaState *env) void HELPER(intset)(CPUXtensaState *env, uint32_t v) { - atomic_or(&env->sregs[INTSET], + qatomic_or(&env->sregs[INTSET], v & env->config->inttype_mask[INTTYPE_SOFTWARE]); } static void intclear(CPUXtensaState *env, uint32_t v) { - atomic_and(&env->sregs[INTSET], ~v); + qatomic_and(&env->sregs[INTSET], ~v); } void HELPER(intclear)(CPUXtensaState *env, uint32_t v) diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) { uint64_t dcc; - atomic_and(&env->sregs[INTSET], + qatomic_and(&env->sregs[INTSET], ~(1u << env->config->timerint[i])); HELPER(update_ccount)(env); dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1; diff --git a/tcg/tcg.c b/tcg/tcg.c index XXXXXXX..XXXXXXX 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -XXX,XX +XXX,XX @@ static inline bool tcg_region_initial_alloc__locked(TCGContext *s) /* Call from a safe-work context */ void tcg_region_reset_all(void) { - unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); + unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); unsigned int i; qemu_mutex_lock(®ion.lock); @@ -XXX,XX +XXX,XX @@ void tcg_region_reset_all(void) region.agg_size_full = 0; for (i = 0; i < n_ctxs; i++) { - TCGContext *s = atomic_read(&tcg_ctxs[i]); + TCGContext *s = qatomic_read(&tcg_ctxs[i]); bool err = tcg_region_initial_alloc__locked(s); g_assert(!err); @@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void) } /* Claim an entry in tcg_ctxs */ - n = atomic_fetch_inc(&n_tcg_ctxs); + n = qatomic_fetch_inc(&n_tcg_ctxs); g_assert(n < ms->smp.max_cpus); - atomic_set(&tcg_ctxs[n], s); + qatomic_set(&tcg_ctxs[n], s); if (n > 0) { alloc_tcg_plugin_context(s); @@ -XXX,XX +XXX,XX @@ void tcg_register_thread(void) */ size_t tcg_code_size(void) { - unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); + unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); unsigned int i; size_t total; qemu_mutex_lock(®ion.lock); total = region.agg_size_full; for (i = 0; i < n_ctxs; i++) { - const TCGContext *s = atomic_read(&tcg_ctxs[i]); + const TCGContext *s = qatomic_read(&tcg_ctxs[i]); size_t size; - size = atomic_read(&s->code_gen_ptr) - s->code_gen_buffer; + size = qatomic_read(&s->code_gen_ptr) - s->code_gen_buffer; g_assert(size <= s->code_gen_buffer_size); total += size; } @@ -XXX,XX +XXX,XX @@ size_t tcg_code_capacity(void) size_t tcg_tb_phys_invalidate_count(void) { - unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); + unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); unsigned int i; size_t total = 0; for (i = 0; i < n_ctxs; i++) { - const TCGContext *s = atomic_read(&tcg_ctxs[i]); + const TCGContext *s = qatomic_read(&tcg_ctxs[i]); - total += atomic_read(&s->tb_phys_invalidate_count); + total += qatomic_read(&s->tb_phys_invalidate_count); } return total; } @@ -XXX,XX +XXX,XX @@ TranslationBlock *tcg_tb_alloc(TCGContext *s) } goto retry; } - atomic_set(&s->code_gen_ptr, next); + qatomic_set(&s->code_gen_ptr, next); s->data_gen_ptr = NULL; return tb; } @@ -XXX,XX +XXX,XX @@ static void tcg_dump_ops(TCGContext *s, bool have_prefs) QemuLogFile *logfile; rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile) { for (; col < 40; ++col) { putc(' ', logfile->fd); @@ -XXX,XX +XXX,XX @@ void tcg_op_remove(TCGContext *s, TCGOp *op) s->nb_ops--; #ifdef CONFIG_PROFILER - atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); + qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); #endif } @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) /* avoid copy/paste errors */ #define PROF_ADD(to, from, field) \ do { \ - (to)->field += atomic_read(&((from)->field)); \ + (to)->field += qatomic_read(&((from)->field)); \ } while (0) #define PROF_MAX(to, from, field) \ do { \ - typeof((from)->field) val__ = atomic_read(&((from)->field)); \ + typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ if (val__ > (to)->field) { \ (to)->field = val__; \ } \ @@ -XXX,XX +XXX,XX @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) static inline void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) { - unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); + unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); unsigned int i; for (i = 0; i < n_ctxs; i++) { - TCGContext *s = atomic_read(&tcg_ctxs[i]); + TCGContext *s = qatomic_read(&tcg_ctxs[i]); const TCGProfile *orig = &s->prof; if (counters) { @@ -XXX,XX +XXX,XX @@ void tcg_dump_op_count(void) int64_t tcg_cpu_exec_time(void) { - unsigned int n_ctxs = atomic_read(&n_tcg_ctxs); + unsigned int n_ctxs = qatomic_read(&n_tcg_ctxs); unsigned int i; int64_t ret = 0; for (i = 0; i < n_ctxs; i++) { - const TCGContext *s = atomic_read(&tcg_ctxs[i]); + const TCGContext *s = qatomic_read(&tcg_ctxs[i]); const TCGProfile *prof = &s->prof; - ret += atomic_read(&prof->cpu_exec_time); + ret += qatomic_read(&prof->cpu_exec_time); } return ret; } @@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) QTAILQ_FOREACH(op, &s->ops, link) { n++; } - atomic_set(&prof->op_count, prof->op_count + n); + qatomic_set(&prof->op_count, prof->op_count + n); if (n > prof->op_count_max) { - atomic_set(&prof->op_count_max, n); + qatomic_set(&prof->op_count_max, n); } n = s->nb_temps; - atomic_set(&prof->temp_count, prof->temp_count + n); + qatomic_set(&prof->temp_count, prof->temp_count + n); if (n > prof->temp_count_max) { - atomic_set(&prof->temp_count_max, n); + qatomic_set(&prof->temp_count_max, n); } } #endif @@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) #endif #ifdef CONFIG_PROFILER - atomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); + qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); #endif #ifdef USE_TCG_OPTIMIZATIONS @@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) #endif #ifdef CONFIG_PROFILER - atomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); - atomic_set(&prof->la_time, prof->la_time - profile_getclock()); + qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); + qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); #endif reachable_code_pass(s); @@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) } #ifdef CONFIG_PROFILER - atomic_set(&prof->la_time, prof->la_time + profile_getclock()); + qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); #endif #ifdef DEBUG_DISAS @@ -XXX,XX +XXX,XX @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) TCGOpcode opc = op->opc; #ifdef CONFIG_PROFILER - atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); + qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); #endif switch (opc) { diff --git a/tcg/tci.c b/tcg/tci.c index XXXXXXX..XXXXXXX 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -XXX,XX +XXX,XX @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) case INDEX_op_goto_tb: /* Jump address is aligned */ tb_ptr = QEMU_ALIGN_PTR_UP(tb_ptr, 4); - t0 = atomic_read((int32_t *)tb_ptr); + t0 = qatomic_read((int32_t *)tb_ptr); tb_ptr += sizeof(int32_t); tci_assert(tb_ptr == old_code_ptr + op_size); tb_ptr += (int32_t)t0; diff --git a/tests/atomic64-bench.c b/tests/atomic64-bench.c index XXXXXXX..XXXXXXX 100644 --- a/tests/atomic64-bench.c +++ b/tests/atomic64-bench.c @@ -XXX,XX +XXX,XX @@ static void *thread_func(void *arg) { struct thread_info *info = arg; - atomic_inc(&n_ready_threads); - while (!atomic_read(&test_start)) { + qatomic_inc(&n_ready_threads); + while (!qatomic_read(&test_start)) { cpu_relax(); } - while (!atomic_read(&test_stop)) { + while (!qatomic_read(&test_stop)) { unsigned int index; info->r = xorshift64star(info->r); index = info->r & (range - 1); - atomic_read_i64(&counts[index].i64); + qatomic_read_i64(&counts[index].i64); info->accesses++; } return NULL; @@ -XXX,XX +XXX,XX @@ static void run_test(void) { unsigned int i; - while (atomic_read(&n_ready_threads) != n_threads) { + while (qatomic_read(&n_ready_threads) != n_threads) { cpu_relax(); } - atomic_set(&test_start, true); + qatomic_set(&test_start, true); g_usleep(duration * G_USEC_PER_SEC); - atomic_set(&test_stop, true); + qatomic_set(&test_stop, true); for (i = 0; i < n_threads; i++) { qemu_thread_join(&threads[i]); diff --git a/tests/atomic_add-bench.c b/tests/atomic_add-bench.c index XXXXXXX..XXXXXXX 100644 --- a/tests/atomic_add-bench.c +++ b/tests/atomic_add-bench.c @@ -XXX,XX +XXX,XX @@ static void *thread_func(void *arg) { struct thread_info *info = arg; - atomic_inc(&n_ready_threads); - while (!atomic_read(&test_start)) { + qatomic_inc(&n_ready_threads); + while (!qatomic_read(&test_start)) { cpu_relax(); } - while (!atomic_read(&test_stop)) { + while (!qatomic_read(&test_stop)) { unsigned int index; info->r = xorshift64star(info->r); @@ -XXX,XX +XXX,XX @@ static void *thread_func(void *arg) counts[index].val += 1; qemu_mutex_unlock(&counts[index].lock); } else { - atomic_inc(&counts[index].val); + qatomic_inc(&counts[index].val); } } return NULL; @@ -XXX,XX +XXX,XX @@ static void run_test(void) { unsigned int i; - while (atomic_read(&n_ready_threads) != n_threads) { + while (qatomic_read(&n_ready_threads) != n_threads) { cpu_relax(); } - atomic_set(&test_start, true); + qatomic_set(&test_start, true); g_usleep(duration * G_USEC_PER_SEC); - atomic_set(&test_stop, true); + qatomic_set(&test_stop, true); for (i = 0; i < n_threads; i++) { qemu_thread_join(&threads[i]); diff --git a/tests/iothread.c b/tests/iothread.c index XXXXXXX..XXXXXXX 100644 --- a/tests/iothread.c +++ b/tests/iothread.c @@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque) qemu_cond_signal(&iothread->init_done_cond); qemu_mutex_unlock(&iothread->init_done_lock); - while (!atomic_read(&iothread->stopping)) { + while (!qatomic_read(&iothread->stopping)) { aio_poll(iothread->ctx, true); } diff --git a/tests/qht-bench.c b/tests/qht-bench.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qht-bench.c +++ b/tests/qht-bench.c @@ -XXX,XX +XXX,XX @@ static void *thread_func(void *p) rcu_register_thread(); - atomic_inc(&n_ready_threads); - while (!atomic_read(&test_start)) { + qatomic_inc(&n_ready_threads); + while (!qatomic_read(&test_start)) { cpu_relax(); } rcu_read_lock(); - while (!atomic_read(&test_stop)) { + while (!qatomic_read(&test_stop)) { info->seed = xorshift64star(info->seed); info->func(info); } @@ -XXX,XX +XXX,XX @@ static void run_test(void) { int i; - while (atomic_read(&n_ready_threads) != n_rw_threads + n_rz_threads) { + while (qatomic_read(&n_ready_threads) != n_rw_threads + n_rz_threads) { cpu_relax(); } - atomic_set(&test_start, true); + qatomic_set(&test_start, true); g_usleep(duration * G_USEC_PER_SEC); - atomic_set(&test_stop, true); + qatomic_set(&test_stop, true); for (i = 0; i < n_rw_threads; i++) { qemu_thread_join(&rw_threads[i]); diff --git a/tests/rcutorture.c b/tests/rcutorture.c index XXXXXXX..XXXXXXX 100644 --- a/tests/rcutorture.c +++ b/tests/rcutorture.c @@ -XXX,XX +XXX,XX @@ static void *rcu_read_perf_test(void *arg) rcu_register_thread(); *(struct rcu_reader_data **)arg = &rcu_reader; - atomic_inc(&nthreadsrunning); + qatomic_inc(&nthreadsrunning); while (goflag == GOFLAG_INIT) { g_usleep(1000); } @@ -XXX,XX +XXX,XX @@ static void *rcu_update_perf_test(void *arg) rcu_register_thread(); *(struct rcu_reader_data **)arg = &rcu_reader; - atomic_inc(&nthreadsrunning); + qatomic_inc(&nthreadsrunning); while (goflag == GOFLAG_INIT) { g_usleep(1000); } @@ -XXX,XX +XXX,XX @@ static void perftestinit(void) static void perftestrun(int nthreads, int duration, int nreaders, int nupdaters) { - while (atomic_read(&nthreadsrunning) < nthreads) { + while (qatomic_read(&nthreadsrunning) < nthreads) { g_usleep(1000); } goflag = GOFLAG_RUN; @@ -XXX,XX +XXX,XX @@ static void *rcu_read_stress_test(void *arg) } while (goflag == GOFLAG_RUN) { rcu_read_lock(); - p = atomic_rcu_read(&rcu_stress_current); - if (atomic_read(&p->mbtest) == 0) { + p = qatomic_rcu_read(&rcu_stress_current); + if (qatomic_read(&p->mbtest) == 0) { n_mberror++; } rcu_read_lock(); @@ -XXX,XX +XXX,XX @@ static void *rcu_read_stress_test(void *arg) garbage++; } rcu_read_unlock(); - pc = atomic_read(&p->age); + pc = qatomic_read(&p->age); rcu_read_unlock(); if ((pc > RCU_STRESS_PIPE_LEN) || (pc < 0)) { pc = RCU_STRESS_PIPE_LEN; @@ -XXX,XX +XXX,XX @@ static void *rcu_read_stress_test(void *arg) static void *rcu_update_stress_test(void *arg) { int i, rcu_stress_idx = 0; - struct rcu_stress *cp = atomic_read(&rcu_stress_current); + struct rcu_stress *cp = qatomic_read(&rcu_stress_current); rcu_register_thread(); *(struct rcu_reader_data **)arg = &rcu_reader; @@ -XXX,XX +XXX,XX @@ static void *rcu_update_stress_test(void *arg) p = &rcu_stress_array[rcu_stress_idx]; /* catching up with ourselves would be a bug */ assert(p != cp); - atomic_set(&p->mbtest, 0); + qatomic_set(&p->mbtest, 0); smp_mb(); - atomic_set(&p->age, 0); - atomic_set(&p->mbtest, 1); - atomic_rcu_set(&rcu_stress_current, p); + qatomic_set(&p->age, 0); + qatomic_set(&p->mbtest, 1); + qatomic_rcu_set(&rcu_stress_current, p); cp = p; /* * New RCU structure is now live, update pipe counts on old @@ -XXX,XX +XXX,XX @@ static void *rcu_update_stress_test(void *arg) */ for (i = 0; i < RCU_STRESS_PIPE_LEN; i++) { if (i != rcu_stress_idx) { - atomic_set(&rcu_stress_array[i].age, + qatomic_set(&rcu_stress_array[i].age, rcu_stress_array[i].age + 1); } } diff --git a/tests/test-aio-multithread.c b/tests/test-aio-multithread.c index XXXXXXX..XXXXXXX 100644 --- a/tests/test-aio-multithread.c +++ b/tests/test-aio-multithread.c @@ -XXX,XX +XXX,XX @@ static bool schedule_next(int n) { Coroutine *co; - co = atomic_xchg(&to_schedule[n], NULL); + co = qatomic_xchg(&to_schedule[n], NULL); if (!co) { - atomic_inc(&count_retry); + qatomic_inc(&count_retry); return false; } if (n == id) { - atomic_inc(&count_here); + qatomic_inc(&count_here); } else { - atomic_inc(&count_other); + qatomic_inc(&count_other); } aio_co_schedule(ctx[n], co); @@ -XXX,XX +XXX,XX @@ static coroutine_fn void test_multi_co_schedule_entry(void *opaque) { g_assert(to_schedule[id] == NULL); - while (!atomic_mb_read(&now_stopping)) { + while (!qatomic_mb_read(&now_stopping)) { int n; n = g_test_rand_int_range(0, NUM_CONTEXTS); schedule_next(n); - atomic_mb_set(&to_schedule[id], qemu_coroutine_self()); + qatomic_mb_set(&to_schedule[id], qemu_coroutine_self()); qemu_coroutine_yield(); g_assert(to_schedule[id] == NULL); } @@ -XXX,XX +XXX,XX @@ static void test_multi_co_schedule(int seconds) g_usleep(seconds * 1000000); - atomic_mb_set(&now_stopping, true); + qatomic_mb_set(&now_stopping, true); for (i = 0; i < NUM_CONTEXTS; i++) { ctx_run(i, finish_cb, NULL); to_schedule[i] = NULL; @@ -XXX,XX +XXX,XX @@ static CoMutex comutex; static void coroutine_fn test_multi_co_mutex_entry(void *opaque) { - while (!atomic_mb_read(&now_stopping)) { + while (!qatomic_mb_read(&now_stopping)) { qemu_co_mutex_lock(&comutex); counter++; qemu_co_mutex_unlock(&comutex); @@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_multi_co_mutex_entry(void *opaque) * exits before the coroutine is woken up, causing a spurious * assertion failure. */ - atomic_inc(&atomic_counter); + qatomic_inc(&atomic_counter); } - atomic_dec(&running); + qatomic_dec(&running); } static void test_multi_co_mutex(int threads, int seconds) @@ -XXX,XX +XXX,XX @@ static void test_multi_co_mutex(int threads, int seconds) g_usleep(seconds * 1000000); - atomic_mb_set(&now_stopping, true); + qatomic_mb_set(&now_stopping, true); while (running > 0) { g_usleep(100000); } @@ -XXX,XX +XXX,XX @@ static void mcs_mutex_lock(void) nodes[id].next = -1; nodes[id].locked = 1; - prev = atomic_xchg(&mutex_head, id); + prev = qatomic_xchg(&mutex_head, id); if (prev != -1) { - atomic_set(&nodes[prev].next, id); + qatomic_set(&nodes[prev].next, id); qemu_futex_wait(&nodes[id].locked, 1); } } @@ -XXX,XX +XXX,XX @@ static void mcs_mutex_lock(void) static void mcs_mutex_unlock(void) { int next; - if (atomic_read(&nodes[id].next) == -1) { - if (atomic_read(&mutex_head) == id && - atomic_cmpxchg(&mutex_head, id, -1) == id) { + if (qatomic_read(&nodes[id].next) == -1) { + if (qatomic_read(&mutex_head) == id && + qatomic_cmpxchg(&mutex_head, id, -1) == id) { /* Last item in the list, exit. */ return; } - while (atomic_read(&nodes[id].next) == -1) { + while (qatomic_read(&nodes[id].next) == -1) { /* mcs_mutex_lock did the xchg, but has not updated * nodes[prev].next yet. */ @@ -XXX,XX +XXX,XX @@ static void mcs_mutex_unlock(void) } /* Wake up the next in line. */ - next = atomic_read(&nodes[id].next); + next = qatomic_read(&nodes[id].next); nodes[next].locked = 0; qemu_futex_wake(&nodes[next].locked, 1); } static void test_multi_fair_mutex_entry(void *opaque) { - while (!atomic_mb_read(&now_stopping)) { + while (!qatomic_mb_read(&now_stopping)) { mcs_mutex_lock(); counter++; mcs_mutex_unlock(); - atomic_inc(&atomic_counter); + qatomic_inc(&atomic_counter); } - atomic_dec(&running); + qatomic_dec(&running); } static void test_multi_fair_mutex(int threads, int seconds) @@ -XXX,XX +XXX,XX @@ static void test_multi_fair_mutex(int threads, int seconds) g_usleep(seconds * 1000000); - atomic_mb_set(&now_stopping, true); + qatomic_mb_set(&now_stopping, true); while (running > 0) { g_usleep(100000); } @@ -XXX,XX +XXX,XX @@ static QemuMutex mutex; static void test_multi_mutex_entry(void *opaque) { - while (!atomic_mb_read(&now_stopping)) { + while (!qatomic_mb_read(&now_stopping)) { qemu_mutex_lock(&mutex); counter++; qemu_mutex_unlock(&mutex); - atomic_inc(&atomic_counter); + qatomic_inc(&atomic_counter); } - atomic_dec(&running); + qatomic_dec(&running); } static void test_multi_mutex(int threads, int seconds) @@ -XXX,XX +XXX,XX @@ static void test_multi_mutex(int threads, int seconds) g_usleep(seconds * 1000000); - atomic_mb_set(&now_stopping, true); + qatomic_mb_set(&now_stopping, true); while (running > 0) { g_usleep(100000); } diff --git a/tests/test-logging.c b/tests/test-logging.c index XXXXXXX..XXXXXXX 100644 --- a/tests/test-logging.c +++ b/tests/test-logging.c @@ -XXX,XX +XXX,XX @@ static void test_logfile_write(gconstpointer data) */ qemu_set_log_filename(file_path, &error_abort); rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); orig_fd = logfile->fd; g_assert(logfile && logfile->fd); fprintf(logfile->fd, "%s 1st write to file\n", __func__); @@ -XXX,XX +XXX,XX @@ static void test_logfile_write(gconstpointer data) /* Change the logfile and ensure that the handle is still valid. */ qemu_set_log_filename(file_path1, &error_abort); - logfile2 = atomic_rcu_read(&qemu_logfile); + logfile2 = qatomic_rcu_read(&qemu_logfile); g_assert(logfile->fd == orig_fd); g_assert(logfile2->fd != logfile->fd); fprintf(logfile->fd, "%s 2nd write to file\n", __func__); diff --git a/tests/test-rcu-list.c b/tests/test-rcu-list.c index XXXXXXX..XXXXXXX 100644 --- a/tests/test-rcu-list.c +++ b/tests/test-rcu-list.c @@ -XXX,XX +XXX,XX @@ static void reclaim_list_el(struct rcu_head *prcu) struct list_element *el = container_of(prcu, struct list_element, rcu); g_free(el); /* Accessed only from call_rcu thread. */ - atomic_set_i64(&n_reclaims, n_reclaims + 1); + qatomic_set_i64(&n_reclaims, n_reclaims + 1); } #if TEST_LIST_TYPE == 1 @@ -XXX,XX +XXX,XX @@ static void *rcu_q_reader(void *arg) rcu_register_thread(); *(struct rcu_reader_data **)arg = &rcu_reader; - atomic_inc(&nthreadsrunning); - while (atomic_read(&goflag) == GOFLAG_INIT) { + qatomic_inc(&nthreadsrunning); + while (qatomic_read(&goflag) == GOFLAG_INIT) { g_usleep(1000); } - while (atomic_read(&goflag) == GOFLAG_RUN) { + while (qatomic_read(&goflag) == GOFLAG_RUN) { rcu_read_lock(); TEST_LIST_FOREACH_RCU(el, &Q_list_head, entry) { n_reads_local++; - if (atomic_read(&goflag) == GOFLAG_STOP) { + if (qatomic_read(&goflag) == GOFLAG_STOP) { break; } } @@ -XXX,XX +XXX,XX @@ static void *rcu_q_updater(void *arg) struct list_element *el, *prev_el; *(struct rcu_reader_data **)arg = &rcu_reader; - atomic_inc(&nthreadsrunning); - while (atomic_read(&goflag) == GOFLAG_INIT) { + qatomic_inc(&nthreadsrunning); + while (qatomic_read(&goflag) == GOFLAG_INIT) { g_usleep(1000); } - while (atomic_read(&goflag) == GOFLAG_RUN) { + while (qatomic_read(&goflag) == GOFLAG_RUN) { target_el = select_random_el(RCU_Q_LEN); j = 0; /* FOREACH_RCU could work here but let's use both macros */ @@ -XXX,XX +XXX,XX @@ static void *rcu_q_updater(void *arg) break; } } - if (atomic_read(&goflag) == GOFLAG_STOP) { + if (qatomic_read(&goflag) == GOFLAG_STOP) { break; } target_el = select_random_el(RCU_Q_LEN); @@ -XXX,XX +XXX,XX @@ static void *rcu_q_updater(void *arg) qemu_mutex_lock(&counts_mutex); n_nodes += n_nodes_local; n_updates += n_updates_local; - atomic_set_i64(&n_nodes_removed, n_nodes_removed + n_removed_local); + qatomic_set_i64(&n_nodes_removed, n_nodes_removed + n_removed_local); qemu_mutex_unlock(&counts_mutex); return NULL; } @@ -XXX,XX +XXX,XX @@ static void rcu_qtest_init(void) static void rcu_qtest_run(int duration, int nreaders) { int nthreads = nreaders + 1; - while (atomic_read(&nthreadsrunning) < nthreads) { + while (qatomic_read(&nthreadsrunning) < nthreads) { g_usleep(1000); } - atomic_set(&goflag, GOFLAG_RUN); + qatomic_set(&goflag, GOFLAG_RUN); sleep(duration); - atomic_set(&goflag, GOFLAG_STOP); + qatomic_set(&goflag, GOFLAG_STOP); wait_all_threads(); } @@ -XXX,XX +XXX,XX @@ static void rcu_qtest(const char *test, int duration, int nreaders) n_removed_local++; } qemu_mutex_lock(&counts_mutex); - atomic_set_i64(&n_nodes_removed, n_nodes_removed + n_removed_local); + qatomic_set_i64(&n_nodes_removed, n_nodes_removed + n_removed_local); qemu_mutex_unlock(&counts_mutex); synchronize_rcu(); - while (atomic_read_i64(&n_nodes_removed) > atomic_read_i64(&n_reclaims)) { + while (qatomic_read_i64(&n_nodes_removed) > + qatomic_read_i64(&n_reclaims)) { g_usleep(100); synchronize_rcu(); } if (g_test_in_charge) { - g_assert_cmpint(atomic_read_i64(&n_nodes_removed), ==, - atomic_read_i64(&n_reclaims)); + g_assert_cmpint(qatomic_read_i64(&n_nodes_removed), ==, + qatomic_read_i64(&n_reclaims)); } else { printf("%s: %d readers; 1 updater; nodes read: " \ "%lld, nodes removed: %"PRIi64"; nodes reclaimed: %"PRIi64"\n", test, nthreadsrunning - 1, n_reads, - atomic_read_i64(&n_nodes_removed), atomic_read_i64(&n_reclaims)); + qatomic_read_i64(&n_nodes_removed), + qatomic_read_i64(&n_reclaims)); exit(0); } } diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c index XXXXXXX..XXXXXXX 100644 --- a/tests/test-thread-pool.c +++ b/tests/test-thread-pool.c @@ -XXX,XX +XXX,XX @@ typedef struct { static int worker_cb(void *opaque) { WorkerTestData *data = opaque; - return atomic_fetch_inc(&data->n); + return qatomic_fetch_inc(&data->n); } static int long_cb(void *opaque) { WorkerTestData *data = opaque; - if (atomic_cmpxchg(&data->n, 0, 1) == 0) { + if (qatomic_cmpxchg(&data->n, 0, 1) == 0) { g_usleep(2000000); - atomic_or(&data->n, 2); + qatomic_or(&data->n, 2); } return 0; } @@ -XXX,XX +XXX,XX @@ static void do_test_cancel(bool sync) /* Cancel the jobs that haven't been started yet. */ num_canceled = 0; for (i = 0; i < 100; i++) { - if (atomic_cmpxchg(&data[i].n, 0, 4) == 0) { + if (qatomic_cmpxchg(&data[i].n, 0, 4) == 0) { data[i].ret = -ECANCELED; if (sync) { bdrv_aio_cancel(data[i].aiocb); @@ -XXX,XX +XXX,XX @@ static void do_test_cancel(bool sync) g_assert_cmpint(num_canceled, <, 100); for (i = 0; i < 100; i++) { - if (data[i].aiocb && atomic_read(&data[i].n) < 4) { + if (data[i].aiocb && qatomic_read(&data[i].n) < 4) { if (sync) { /* Canceling the others will be a blocking operation. */ bdrv_aio_cancel(data[i].aiocb); diff --git a/util/aio-posix.c b/util/aio-posix.c index XXXXXXX..XXXXXXX 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -XXX,XX +XXX,XX @@ bool aio_poll_disabled(AioContext *ctx) { - return atomic_read(&ctx->poll_disable_cnt); + return qatomic_read(&ctx->poll_disable_cnt); } void aio_add_ready_handler(AioHandlerList *ready_list, @@ -XXX,XX +XXX,XX @@ void aio_set_fd_handler(AioContext *ctx, * Changing handlers is a rare event, and a little wasted polling until * the aio_notify below is not an issue. */ - atomic_set(&ctx->poll_disable_cnt, - atomic_read(&ctx->poll_disable_cnt) + poll_disable_change); + qatomic_set(&ctx->poll_disable_cnt, + qatomic_read(&ctx->poll_disable_cnt) + poll_disable_change); ctx->fdmon_ops->update(ctx, node, new_node); if (node) { @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) */ use_notify_me = timeout != 0; if (use_notify_me) { - atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) + 2); + qatomic_set(&ctx->notify_me, qatomic_read(&ctx->notify_me) + 2); /* * Write ctx->notify_me before reading ctx->notified. Pairs with * smp_mb in aio_notify(). @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) smp_mb(); /* Don't block if aio_notify() was called */ - if (atomic_read(&ctx->notified)) { + if (qatomic_read(&ctx->notified)) { timeout = 0; } } @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) if (use_notify_me) { /* Finish the poll before clearing the flag. */ - atomic_store_release(&ctx->notify_me, - atomic_read(&ctx->notify_me) - 2); + qatomic_store_release(&ctx->notify_me, + qatomic_read(&ctx->notify_me) - 2); } aio_notify_accept(ctx); diff --git a/util/aio-wait.c b/util/aio-wait.c index XXXXXXX..XXXXXXX 100644 --- a/util/aio-wait.c +++ b/util/aio-wait.c @@ -XXX,XX +XXX,XX @@ static void dummy_bh_cb(void *opaque) void aio_wait_kick(void) { /* The barrier (or an atomic op) is in the caller. */ - if (atomic_read(&global_aio_wait.num_waiters)) { + if (qatomic_read(&global_aio_wait.num_waiters)) { aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL); } } diff --git a/util/aio-win32.c b/util/aio-win32.c index XXXXXXX..XXXXXXX 100644 --- a/util/aio-win32.c +++ b/util/aio-win32.c @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) * so disable the optimization now. */ if (blocking) { - atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) + 2); + qatomic_set(&ctx->notify_me, qatomic_read(&ctx->notify_me) + 2); /* * Write ctx->notify_me before computing the timeout * (reading bottom half flags, etc.). Pairs with @@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking) ret = WaitForMultipleObjects(count, events, FALSE, timeout); if (blocking) { assert(first); - atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) - 2); + qatomic_store_release(&ctx->notify_me, + qatomic_read(&ctx->notify_me) - 2); aio_notify_accept(ctx); } diff --git a/util/async.c b/util/async.c index XXXXXXX..XXXXXXX 100644 --- a/util/async.c +++ b/util/async.c @@ -XXX,XX +XXX,XX @@ static void aio_bh_enqueue(QEMUBH *bh, unsigned new_flags) unsigned old_flags; /* - * The memory barrier implicit in atomic_fetch_or makes sure that: + * The memory barrier implicit in qatomic_fetch_or makes sure that: * 1. idle & any writes needed by the callback are done before the * locations are read in the aio_bh_poll. * 2. ctx is loaded before the callback has a chance to execute and bh * could be freed. */ - old_flags = atomic_fetch_or(&bh->flags, BH_PENDING | new_flags); + old_flags = qatomic_fetch_or(&bh->flags, BH_PENDING | new_flags); if (!(old_flags & BH_PENDING)) { QSLIST_INSERT_HEAD_ATOMIC(&ctx->bh_list, bh, next); } @@ -XXX,XX +XXX,XX @@ static QEMUBH *aio_bh_dequeue(BHList *head, unsigned *flags) QSLIST_REMOVE_HEAD(head, next); /* - * The atomic_and is paired with aio_bh_enqueue(). The implicit memory + * The qatomic_and is paired with aio_bh_enqueue(). The implicit memory * barrier ensures that the callback sees all writes done by the scheduling * thread. It also ensures that the scheduling thread sees the cleared * flag before bh->cb has run, and thus will call aio_notify again if * necessary. */ - *flags = atomic_fetch_and(&bh->flags, + *flags = qatomic_fetch_and(&bh->flags, ~(BH_PENDING | BH_SCHEDULED | BH_IDLE)); return bh; } @@ -XXX,XX +XXX,XX @@ void qemu_bh_schedule(QEMUBH *bh) */ void qemu_bh_cancel(QEMUBH *bh) { - atomic_and(&bh->flags, ~BH_SCHEDULED); + qatomic_and(&bh->flags, ~BH_SCHEDULED); } /* This func is async.The bottom half will do the delete action at the finial @@ -XXX,XX +XXX,XX @@ aio_ctx_prepare(GSource *source, gint *timeout) { AioContext *ctx = (AioContext *) source; - atomic_set(&ctx->notify_me, atomic_read(&ctx->notify_me) | 1); + qatomic_set(&ctx->notify_me, qatomic_read(&ctx->notify_me) | 1); /* * Write ctx->notify_me before computing the timeout @@ -XXX,XX +XXX,XX @@ aio_ctx_check(GSource *source) BHListSlice *s; /* Finish computing the timeout before clearing the flag. */ - atomic_store_release(&ctx->notify_me, atomic_read(&ctx->notify_me) & ~1); + qatomic_store_release(&ctx->notify_me, qatomic_read(&ctx->notify_me) & ~1); aio_notify_accept(ctx); QSLIST_FOREACH_RCU(bh, &ctx->bh_list, next) { @@ -XXX,XX +XXX,XX @@ void aio_notify(AioContext *ctx) * aio_notify_accept. */ smp_wmb(); - atomic_set(&ctx->notified, true); + qatomic_set(&ctx->notified, true); /* * Write ctx->notified before reading ctx->notify_me. Pairs * with smp_mb in aio_ctx_prepare or aio_poll. */ smp_mb(); - if (atomic_read(&ctx->notify_me)) { + if (qatomic_read(&ctx->notify_me)) { event_notifier_set(&ctx->notifier); } } void aio_notify_accept(AioContext *ctx) { - atomic_set(&ctx->notified, false); + qatomic_set(&ctx->notified, false); /* * Write ctx->notified before reading e.g. bh->flags. Pairs with smp_wmb @@ -XXX,XX +XXX,XX @@ static bool aio_context_notifier_poll(void *opaque) EventNotifier *e = opaque; AioContext *ctx = container_of(e, AioContext, notifier); - return atomic_read(&ctx->notified); + return qatomic_read(&ctx->notified); } static void co_schedule_bh_cb(void *opaque) @@ -XXX,XX +XXX,XX @@ static void co_schedule_bh_cb(void *opaque) aio_context_acquire(ctx); /* Protected by write barrier in qemu_aio_coroutine_enter */ - atomic_set(&co->scheduled, NULL); + qatomic_set(&co->scheduled, NULL); qemu_aio_coroutine_enter(ctx, co); aio_context_release(ctx); } @@ -XXX,XX +XXX,XX @@ fail: void aio_co_schedule(AioContext *ctx, Coroutine *co) { trace_aio_co_schedule(ctx, co); - const char *scheduled = atomic_cmpxchg(&co->scheduled, NULL, + const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL, __func__); if (scheduled) { @@ -XXX,XX +XXX,XX @@ void aio_co_wake(struct Coroutine *co) * qemu_coroutine_enter. */ smp_read_barrier_depends(); - ctx = atomic_read(&co->ctx); + ctx = qatomic_read(&co->ctx); aio_co_enter(ctx, co); } diff --git a/util/atomic64.c b/util/atomic64.c index XXXXXXX..XXXXXXX 100644 --- a/util/atomic64.c +++ b/util/atomic64.c @@ -XXX,XX +XXX,XX @@ static QemuSpin *addr_to_lock(const void *addr) return ret; \ } -GEN_READ(atomic_read_i64, int64_t) -GEN_READ(atomic_read_u64, uint64_t) +GEN_READ(qatomic_read_i64, int64_t) +GEN_READ(qatomic_read_u64, uint64_t) #undef GEN_READ #define GEN_SET(name, type) \ @@ -XXX,XX +XXX,XX @@ GEN_READ(atomic_read_u64, uint64_t) qemu_spin_unlock(lock); \ } -GEN_SET(atomic_set_i64, int64_t) -GEN_SET(atomic_set_u64, uint64_t) +GEN_SET(qatomic_set_i64, int64_t) +GEN_SET(qatomic_set_u64, uint64_t) #undef GEN_SET -void atomic64_init(void) +void qatomic64_init(void) { int i; diff --git a/util/bitmap.c b/util/bitmap.c index XXXXXXX..XXXXXXX 100644 --- a/util/bitmap.c +++ b/util/bitmap.c @@ -XXX,XX +XXX,XX @@ void bitmap_set_atomic(unsigned long *map, long start, long nr) /* First word */ if (nr - bits_to_set > 0) { - atomic_or(p, mask_to_set); + qatomic_or(p, mask_to_set); nr -= bits_to_set; bits_to_set = BITS_PER_LONG; mask_to_set = ~0UL; @@ -XXX,XX +XXX,XX @@ void bitmap_set_atomic(unsigned long *map, long start, long nr) /* Last word */ if (nr) { mask_to_set &= BITMAP_LAST_WORD_MASK(size); - atomic_or(p, mask_to_set); + qatomic_or(p, mask_to_set); } else { - /* If we avoided the full barrier in atomic_or(), issue a + /* If we avoided the full barrier in qatomic_or(), issue a * barrier to account for the assignments in the while loop. */ smp_mb(); @@ -XXX,XX +XXX,XX @@ bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr) /* First word */ if (nr - bits_to_clear > 0) { - old_bits = atomic_fetch_and(p, ~mask_to_clear); + old_bits = qatomic_fetch_and(p, ~mask_to_clear); dirty |= old_bits & mask_to_clear; nr -= bits_to_clear; bits_to_clear = BITS_PER_LONG; @@ -XXX,XX +XXX,XX @@ bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr) if (bits_to_clear == BITS_PER_LONG) { while (nr >= BITS_PER_LONG) { if (*p) { - old_bits = atomic_xchg(p, 0); + old_bits = qatomic_xchg(p, 0); dirty |= old_bits; } nr -= BITS_PER_LONG; @@ -XXX,XX +XXX,XX @@ bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr) /* Last word */ if (nr) { mask_to_clear &= BITMAP_LAST_WORD_MASK(size); - old_bits = atomic_fetch_and(p, ~mask_to_clear); + old_bits = qatomic_fetch_and(p, ~mask_to_clear); dirty |= old_bits & mask_to_clear; } else { if (!dirty) { @@ -XXX,XX +XXX,XX @@ void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src, long nr) { while (nr > 0) { - *dst = atomic_xchg(src, 0); + *dst = qatomic_xchg(src, 0); dst++; src++; nr -= BITS_PER_LONG; diff --git a/util/cacheinfo.c b/util/cacheinfo.c index XXXXXXX..XXXXXXX 100644 --- a/util/cacheinfo.c +++ b/util/cacheinfo.c @@ -XXX,XX +XXX,XX @@ static void __attribute__((constructor)) init_cache_info(void) qemu_dcache_linesize = dsize; qemu_dcache_linesize_log = ctz32(dsize); - atomic64_init(); + qatomic64_init(); } diff --git a/util/fdmon-epoll.c b/util/fdmon-epoll.c index XXXXXXX..XXXXXXX 100644 --- a/util/fdmon-epoll.c +++ b/util/fdmon-epoll.c @@ -XXX,XX +XXX,XX @@ static int fdmon_epoll_wait(AioContext *ctx, AioHandlerList *ready_list, struct epoll_event events[128]; /* Fall back while external clients are disabled */ - if (atomic_read(&ctx->external_disable_cnt)) { + if (qatomic_read(&ctx->external_disable_cnt)) { return fdmon_poll_ops.wait(ctx, ready_list, timeout); } @@ -XXX,XX +XXX,XX @@ bool fdmon_epoll_try_upgrade(AioContext *ctx, unsigned npfd) } /* Do not upgrade while external clients are disabled */ - if (atomic_read(&ctx->external_disable_cnt)) { + if (qatomic_read(&ctx->external_disable_cnt)) { return false; } diff --git a/util/fdmon-io_uring.c b/util/fdmon-io_uring.c index XXXXXXX..XXXXXXX 100644 --- a/util/fdmon-io_uring.c +++ b/util/fdmon-io_uring.c @@ -XXX,XX +XXX,XX @@ static void enqueue(AioHandlerSList *head, AioHandler *node, unsigned flags) { unsigned old_flags; - old_flags = atomic_fetch_or(&node->flags, FDMON_IO_URING_PENDING | flags); + old_flags = qatomic_fetch_or(&node->flags, FDMON_IO_URING_PENDING | flags); if (!(old_flags & FDMON_IO_URING_PENDING)) { QSLIST_INSERT_HEAD_ATOMIC(head, node, node_submitted); } @@ -XXX,XX +XXX,XX @@ static AioHandler *dequeue(AioHandlerSList *head, unsigned *flags) * telling process_cqe() to delete the AioHandler when its * IORING_OP_POLL_ADD completes. */ - *flags = atomic_fetch_and(&node->flags, ~(FDMON_IO_URING_PENDING | + *flags = qatomic_fetch_and(&node->flags, ~(FDMON_IO_URING_PENDING | FDMON_IO_URING_ADD)); return node; } @@ -XXX,XX +XXX,XX @@ static bool process_cqe(AioContext *ctx, * with enqueue() here then we can safely clear the FDMON_IO_URING_REMOVE * bit before IORING_OP_POLL_REMOVE is submitted. */ - flags = atomic_fetch_and(&node->flags, ~FDMON_IO_URING_REMOVE); + flags = qatomic_fetch_and(&node->flags, ~FDMON_IO_URING_REMOVE); if (flags & FDMON_IO_URING_REMOVE) { QLIST_INSERT_HEAD_RCU(&ctx->deleted_aio_handlers, node, node_deleted); return false; @@ -XXX,XX +XXX,XX @@ static int fdmon_io_uring_wait(AioContext *ctx, AioHandlerList *ready_list, int ret; /* Fall back while external clients are disabled */ - if (atomic_read(&ctx->external_disable_cnt)) { + if (qatomic_read(&ctx->external_disable_cnt)) { return fdmon_poll_ops.wait(ctx, ready_list, timeout); } @@ -XXX,XX +XXX,XX @@ static bool fdmon_io_uring_need_wait(AioContext *ctx) } /* Are we falling back to fdmon-poll? */ - return atomic_read(&ctx->external_disable_cnt); + return qatomic_read(&ctx->external_disable_cnt); } static const FDMonOps fdmon_io_uring_ops = { @@ -XXX,XX +XXX,XX @@ void fdmon_io_uring_destroy(AioContext *ctx) /* Move handlers due to be removed onto the deleted list */ while ((node = QSLIST_FIRST_RCU(&ctx->submit_list))) { - unsigned flags = atomic_fetch_and(&node->flags, + unsigned flags = qatomic_fetch_and(&node->flags, ~(FDMON_IO_URING_PENDING | FDMON_IO_URING_ADD | FDMON_IO_URING_REMOVE)); diff --git a/util/lockcnt.c b/util/lockcnt.c index XXXXXXX..XXXXXXX 100644 --- a/util/lockcnt.c +++ b/util/lockcnt.c @@ -XXX,XX +XXX,XX @@ static bool qemu_lockcnt_cmpxchg_or_wait(QemuLockCnt *lockcnt, int *val, int expected = *val; trace_lockcnt_fast_path_attempt(lockcnt, expected, new_if_free); - *val = atomic_cmpxchg(&lockcnt->count, expected, new_if_free); + *val = qatomic_cmpxchg(&lockcnt->count, expected, new_if_free); if (*val == expected) { trace_lockcnt_fast_path_success(lockcnt, expected, new_if_free); *val = new_if_free; @@ -XXX,XX +XXX,XX @@ static bool qemu_lockcnt_cmpxchg_or_wait(QemuLockCnt *lockcnt, int *val, int new = expected - QEMU_LOCKCNT_STATE_LOCKED + QEMU_LOCKCNT_STATE_WAITING; trace_lockcnt_futex_wait_prepare(lockcnt, expected, new); - *val = atomic_cmpxchg(&lockcnt->count, expected, new); + *val = qatomic_cmpxchg(&lockcnt->count, expected, new); if (*val == expected) { *val = new; } @@ -XXX,XX +XXX,XX @@ static bool qemu_lockcnt_cmpxchg_or_wait(QemuLockCnt *lockcnt, int *val, *waited = true; trace_lockcnt_futex_wait(lockcnt, *val); qemu_futex_wait(&lockcnt->count, *val); - *val = atomic_read(&lockcnt->count); + *val = qatomic_read(&lockcnt->count); trace_lockcnt_futex_wait_resume(lockcnt, *val); continue; } @@ -XXX,XX +XXX,XX @@ static void lockcnt_wake(QemuLockCnt *lockcnt) void qemu_lockcnt_inc(QemuLockCnt *lockcnt) { - int val = atomic_read(&lockcnt->count); + int val = qatomic_read(&lockcnt->count); bool waited = false; for (;;) { if (val >= QEMU_LOCKCNT_COUNT_STEP) { int expected = val; - val = atomic_cmpxchg(&lockcnt->count, val, val + QEMU_LOCKCNT_COUNT_STEP); + val = qatomic_cmpxchg(&lockcnt->count, val, + val + QEMU_LOCKCNT_COUNT_STEP); if (val == expected) { break; } @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_inc(QemuLockCnt *lockcnt) void qemu_lockcnt_dec(QemuLockCnt *lockcnt) { - atomic_sub(&lockcnt->count, QEMU_LOCKCNT_COUNT_STEP); + qatomic_sub(&lockcnt->count, QEMU_LOCKCNT_COUNT_STEP); } /* Decrement a counter, and return locked if it is decremented to zero. @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_dec(QemuLockCnt *lockcnt) */ bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt) { - int val = atomic_read(&lockcnt->count); + int val = qatomic_read(&lockcnt->count); int locked_state = QEMU_LOCKCNT_STATE_LOCKED; bool waited = false; for (;;) { if (val >= 2 * QEMU_LOCKCNT_COUNT_STEP) { int expected = val; - val = atomic_cmpxchg(&lockcnt->count, val, val - QEMU_LOCKCNT_COUNT_STEP); + val = qatomic_cmpxchg(&lockcnt->count, val, + val - QEMU_LOCKCNT_COUNT_STEP); if (val == expected) { break; } @@ -XXX,XX +XXX,XX @@ bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt) */ bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt) { - int val = atomic_read(&lockcnt->count); + int val = qatomic_read(&lockcnt->count); int locked_state = QEMU_LOCKCNT_STATE_LOCKED; bool waited = false; @@ -XXX,XX +XXX,XX @@ bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt) void qemu_lockcnt_lock(QemuLockCnt *lockcnt) { - int val = atomic_read(&lockcnt->count); + int val = qatomic_read(&lockcnt->count); int step = QEMU_LOCKCNT_STATE_LOCKED; bool waited = false; @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt) { int expected, new, val; - val = atomic_read(&lockcnt->count); + val = qatomic_read(&lockcnt->count); do { expected = val; new = (val + QEMU_LOCKCNT_COUNT_STEP) & ~QEMU_LOCKCNT_STATE_MASK; trace_lockcnt_unlock_attempt(lockcnt, val, new); - val = atomic_cmpxchg(&lockcnt->count, val, new); + val = qatomic_cmpxchg(&lockcnt->count, val, new); } while (val != expected); trace_lockcnt_unlock_success(lockcnt, val, new); @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_unlock(QemuLockCnt *lockcnt) { int expected, new, val; - val = atomic_read(&lockcnt->count); + val = qatomic_read(&lockcnt->count); do { expected = val; new = val & ~QEMU_LOCKCNT_STATE_MASK; trace_lockcnt_unlock_attempt(lockcnt, val, new); - val = atomic_cmpxchg(&lockcnt->count, val, new); + val = qatomic_cmpxchg(&lockcnt->count, val, new); } while (val != expected); trace_lockcnt_unlock_success(lockcnt, val, new); @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_unlock(QemuLockCnt *lockcnt) unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt) { - return atomic_read(&lockcnt->count) >> QEMU_LOCKCNT_COUNT_SHIFT; + return qatomic_read(&lockcnt->count) >> QEMU_LOCKCNT_COUNT_SHIFT; } #else void qemu_lockcnt_init(QemuLockCnt *lockcnt) @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_inc(QemuLockCnt *lockcnt) { int old; for (;;) { - old = atomic_read(&lockcnt->count); + old = qatomic_read(&lockcnt->count); if (old == 0) { qemu_lockcnt_lock(lockcnt); qemu_lockcnt_inc_and_unlock(lockcnt); return; } else { - if (atomic_cmpxchg(&lockcnt->count, old, old + 1) == old) { + if (qatomic_cmpxchg(&lockcnt->count, old, old + 1) == old) { return; } } @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_inc(QemuLockCnt *lockcnt) void qemu_lockcnt_dec(QemuLockCnt *lockcnt) { - atomic_dec(&lockcnt->count); + qatomic_dec(&lockcnt->count); } /* Decrement a counter, and return locked if it is decremented to zero. @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_dec(QemuLockCnt *lockcnt) */ bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt) { - int val = atomic_read(&lockcnt->count); + int val = qatomic_read(&lockcnt->count); while (val > 1) { - int old = atomic_cmpxchg(&lockcnt->count, val, val - 1); + int old = qatomic_cmpxchg(&lockcnt->count, val, val - 1); if (old != val) { val = old; continue; @@ -XXX,XX +XXX,XX @@ bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt) } qemu_lockcnt_lock(lockcnt); - if (atomic_fetch_dec(&lockcnt->count) == 1) { + if (qatomic_fetch_dec(&lockcnt->count) == 1) { return true; } @@ -XXX,XX +XXX,XX @@ bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt) bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt) { /* No need for acquire semantics if we return false. */ - int val = atomic_read(&lockcnt->count); + int val = qatomic_read(&lockcnt->count); if (val > 1) { return false; } qemu_lockcnt_lock(lockcnt); - if (atomic_fetch_dec(&lockcnt->count) == 1) { + if (qatomic_fetch_dec(&lockcnt->count) == 1) { return true; } @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_lock(QemuLockCnt *lockcnt) void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt) { - atomic_inc(&lockcnt->count); + qatomic_inc(&lockcnt->count); qemu_mutex_unlock(&lockcnt->mutex); } @@ -XXX,XX +XXX,XX @@ void qemu_lockcnt_unlock(QemuLockCnt *lockcnt) unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt) { - return atomic_read(&lockcnt->count); + return qatomic_read(&lockcnt->count); } #endif diff --git a/util/log.c b/util/log.c index XXXXXXX..XXXXXXX 100644 --- a/util/log.c +++ b/util/log.c @@ -XXX,XX +XXX,XX @@ int qemu_log(const char *fmt, ...) QemuLogFile *logfile; rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile) { va_list ap; va_start(ap, fmt); @@ -XXX,XX +XXX,XX @@ void qemu_set_log(int log_flags) QEMU_LOCK_GUARD(&qemu_logfile_mutex); if (qemu_logfile && !need_to_open_file) { logfile = qemu_logfile; - atomic_rcu_set(&qemu_logfile, NULL); + qatomic_rcu_set(&qemu_logfile, NULL); call_rcu(logfile, qemu_logfile_free, rcu); } else if (!qemu_logfile && need_to_open_file) { logfile = g_new0(QemuLogFile, 1); @@ -XXX,XX +XXX,XX @@ void qemu_set_log(int log_flags) #endif log_append = 1; } - atomic_rcu_set(&qemu_logfile, logfile); + qatomic_rcu_set(&qemu_logfile, logfile); } } @@ -XXX,XX +XXX,XX @@ void qemu_log_flush(void) QemuLogFile *logfile; rcu_read_lock(); - logfile = atomic_rcu_read(&qemu_logfile); + logfile = qatomic_rcu_read(&qemu_logfile); if (logfile) { fflush(logfile->fd); } @@ -XXX,XX +XXX,XX @@ void qemu_log_close(void) logfile = qemu_logfile; if (logfile) { - atomic_rcu_set(&qemu_logfile, NULL); + qatomic_rcu_set(&qemu_logfile, NULL); call_rcu(logfile, qemu_logfile_free, rcu); } qemu_mutex_unlock(&qemu_logfile_mutex); diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-coroutine-lock.c +++ b/util/qemu-coroutine-lock.c @@ -XXX,XX +XXX,XX @@ static void coroutine_fn qemu_co_mutex_lock_slowpath(AioContext *ctx, /* This is the "Responsibility Hand-Off" protocol; a lock() picks from * a concurrent unlock() the responsibility of waking somebody up. */ - old_handoff = atomic_mb_read(&mutex->handoff); + old_handoff = qatomic_mb_read(&mutex->handoff); if (old_handoff && has_waiters(mutex) && - atomic_cmpxchg(&mutex->handoff, old_handoff, 0) == old_handoff) { + qatomic_cmpxchg(&mutex->handoff, old_handoff, 0) == old_handoff) { /* There can be no concurrent pops, because there can be only * one active handoff at a time. */ @@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex) */ i = 0; retry_fast_path: - waiters = atomic_cmpxchg(&mutex->locked, 0, 1); + waiters = qatomic_cmpxchg(&mutex->locked, 0, 1); if (waiters != 0) { while (waiters == 1 && ++i < 1000) { - if (atomic_read(&mutex->ctx) == ctx) { + if (qatomic_read(&mutex->ctx) == ctx) { break; } - if (atomic_read(&mutex->locked) == 0) { + if (qatomic_read(&mutex->locked) == 0) { goto retry_fast_path; } cpu_relax(); } - waiters = atomic_fetch_inc(&mutex->locked); + waiters = qatomic_fetch_inc(&mutex->locked); } if (waiters == 0) { @@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex) mutex->ctx = NULL; mutex->holder = NULL; self->locks_held--; - if (atomic_fetch_dec(&mutex->locked) == 1) { + if (qatomic_fetch_dec(&mutex->locked) == 1) { /* No waiting qemu_co_mutex_lock(). Pfew, that was easy! */ return; } @@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex) } our_handoff = mutex->sequence; - atomic_mb_set(&mutex->handoff, our_handoff); + qatomic_mb_set(&mutex->handoff, our_handoff); if (!has_waiters(mutex)) { /* The concurrent lock has not added itself yet, so it * will be able to pick our handoff. @@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex) /* Try to do the handoff protocol ourselves; if somebody else has * already taken it, however, we're done and they're responsible. */ - if (atomic_cmpxchg(&mutex->handoff, our_handoff, 0) != our_handoff) { + if (qatomic_cmpxchg(&mutex->handoff, our_handoff, 0) != our_handoff) { break; } } diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-coroutine-sleep.c +++ b/util/qemu-coroutine-sleep.c @@ -XXX,XX +XXX,XX @@ struct QemuCoSleepState { void qemu_co_sleep_wake(QemuCoSleepState *sleep_state) { /* Write of schedule protected by barrier write in aio_co_schedule */ - const char *scheduled = atomic_cmpxchg(&sleep_state->co->scheduled, + const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled, qemu_co_sleep_ns__scheduled, NULL); assert(scheduled == qemu_co_sleep_ns__scheduled); @@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns, .user_state_pointer = sleep_state, }; - const char *scheduled = atomic_cmpxchg(&state.co->scheduled, NULL, + const char *scheduled = qatomic_cmpxchg(&state.co->scheduled, NULL, qemu_co_sleep_ns__scheduled); if (scheduled) { fprintf(stderr, diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -XXX,XX +XXX,XX @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque) * release_pool_size and the actual size of release_pool. But * it is just a heuristic, it does not need to be perfect. */ - alloc_pool_size = atomic_xchg(&release_pool_size, 0); + alloc_pool_size = qatomic_xchg(&release_pool_size, 0); QSLIST_MOVE_ATOMIC(&alloc_pool, &release_pool); co = QSLIST_FIRST(&alloc_pool); } @@ -XXX,XX +XXX,XX @@ static void coroutine_delete(Coroutine *co) if (CONFIG_COROUTINE_POOL) { if (release_pool_size < POOL_BATCH_SIZE * 2) { QSLIST_INSERT_HEAD_ATOMIC(&release_pool, co, pool_next); - atomic_inc(&release_pool_size); + qatomic_inc(&release_pool_size); return; } if (alloc_pool_size < POOL_BATCH_SIZE) { @@ -XXX,XX +XXX,XX @@ void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co) /* Cannot rely on the read barrier for to in aio_co_wake(), as there are * callers outside of aio_co_wake() */ - const char *scheduled = atomic_mb_read(&to->scheduled); + const char *scheduled = qatomic_mb_read(&to->scheduled); QSIMPLEQ_REMOVE_HEAD(&pending, co_queue_next); diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -XXX,XX +XXX,XX @@ static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, memset(&ai, 0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; - if (atomic_read(&useV4Mapped)) { + if (qatomic_read(&useV4Mapped)) { ai.ai_flags |= AI_V4MAPPED; } ai.ai_family = inet_ai_family_from_address(saddr, &err); @@ -XXX,XX +XXX,XX @@ static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, */ if (rc == EAI_BADFLAGS && (ai.ai_flags & AI_V4MAPPED)) { - atomic_set(&useV4Mapped, 0); + qatomic_set(&useV4Mapped, 0); ai.ai_flags &= ~AI_V4MAPPED; rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); } diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -XXX,XX +XXX,XX @@ void qemu_event_set(QemuEvent *ev) */ assert(ev->initialized); smp_mb(); - if (atomic_read(&ev->value) != EV_SET) { - if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) { + if (qatomic_read(&ev->value) != EV_SET) { + if (qatomic_xchg(&ev->value, EV_SET) == EV_BUSY) { /* There were waiters, wake them up. */ qemu_futex_wake(ev, INT_MAX); } @@ -XXX,XX +XXX,XX @@ void qemu_event_reset(QemuEvent *ev) unsigned value; assert(ev->initialized); - value = atomic_read(&ev->value); + value = qatomic_read(&ev->value); smp_mb_acquire(); if (value == EV_SET) { /* * If there was a concurrent reset (or even reset+wait), * do nothing. Otherwise change EV_SET->EV_FREE. */ - atomic_or(&ev->value, EV_FREE); + qatomic_or(&ev->value, EV_FREE); } } @@ -XXX,XX +XXX,XX @@ void qemu_event_wait(QemuEvent *ev) unsigned value; assert(ev->initialized); - value = atomic_read(&ev->value); + value = qatomic_read(&ev->value); smp_mb_acquire(); if (value != EV_SET) { if (value == EV_FREE) { @@ -XXX,XX +XXX,XX @@ void qemu_event_wait(QemuEvent *ev) * a concurrent busy->free transition. After the CAS, the * event will be either set or busy. */ - if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { + if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { return; } } diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-thread-win32.c +++ b/util/qemu-thread-win32.c @@ -XXX,XX +XXX,XX @@ void qemu_event_set(QemuEvent *ev) * ev->value we need a full memory barrier here. */ smp_mb(); - if (atomic_read(&ev->value) != EV_SET) { - if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) { + if (qatomic_read(&ev->value) != EV_SET) { + if (qatomic_xchg(&ev->value, EV_SET) == EV_BUSY) { /* There were waiters, wake them up. */ SetEvent(ev->event); } @@ -XXX,XX +XXX,XX @@ void qemu_event_reset(QemuEvent *ev) unsigned value; assert(ev->initialized); - value = atomic_read(&ev->value); + value = qatomic_read(&ev->value); smp_mb_acquire(); if (value == EV_SET) { /* If there was a concurrent reset (or even reset+wait), * do nothing. Otherwise change EV_SET->EV_FREE. */ - atomic_or(&ev->value, EV_FREE); + qatomic_or(&ev->value, EV_FREE); } } @@ -XXX,XX +XXX,XX @@ void qemu_event_wait(QemuEvent *ev) unsigned value; assert(ev->initialized); - value = atomic_read(&ev->value); + value = qatomic_read(&ev->value); smp_mb_acquire(); if (value != EV_SET) { if (value == EV_FREE) { @@ -XXX,XX +XXX,XX @@ void qemu_event_wait(QemuEvent *ev) * because there cannot be a concurrent busy->free transition. * After the CAS, the event will be either set or busy. */ - if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { + if (qatomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { value = EV_SET; } else { value = EV_BUSY; diff --git a/util/qemu-timer.c b/util/qemu-timer.c index XXXXXXX..XXXXXXX 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -XXX,XX +XXX,XX @@ void qemu_clock_enable(QEMUClockType type, bool enabled) bool timerlist_has_timers(QEMUTimerList *timer_list) { - return !!atomic_read(&timer_list->active_timers); + return !!qatomic_read(&timer_list->active_timers); } bool qemu_clock_has_timers(QEMUClockType type) @@ -XXX,XX +XXX,XX @@ bool timerlist_expired(QEMUTimerList *timer_list) { int64_t expire_time; - if (!atomic_read(&timer_list->active_timers)) { + if (!qatomic_read(&timer_list->active_timers)) { return false; } @@ -XXX,XX +XXX,XX @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) int64_t delta; int64_t expire_time; - if (!atomic_read(&timer_list->active_timers)) { + if (!qatomic_read(&timer_list->active_timers)) { return -1; } @@ -XXX,XX +XXX,XX @@ static void timer_del_locked(QEMUTimerList *timer_list, QEMUTimer *ts) if (!t) break; if (t == ts) { - atomic_set(pt, t->next); + qatomic_set(pt, t->next); break; } pt = &t->next; @@ -XXX,XX +XXX,XX @@ static bool timer_mod_ns_locked(QEMUTimerList *timer_list, } ts->expire_time = MAX(expire_time, 0); ts->next = *pt; - atomic_set(pt, ts); + qatomic_set(pt, ts); return pt == &timer_list->active_timers; } @@ -XXX,XX +XXX,XX @@ bool timerlist_run_timers(QEMUTimerList *timer_list) QEMUTimerCB *cb; void *opaque; - if (!atomic_read(&timer_list->active_timers)) { + if (!qatomic_read(&timer_list->active_timers)) { return false; } diff --git a/util/qht.c b/util/qht.c index XXXXXXX..XXXXXXX 100644 --- a/util/qht.c +++ b/util/qht.c @@ -XXX,XX +XXX,XX @@ static inline void qht_unlock(struct qht *ht) /* * Note: reading partially-updated pointers in @pointers could lead to - * segfaults. We thus access them with atomic_read/set; this guarantees + * segfaults. We thus access them with qatomic_read/set; this guarantees * that the compiler makes all those accesses atomic. We also need the - * volatile-like behavior in atomic_read, since otherwise the compiler + * volatile-like behavior in qatomic_read, since otherwise the compiler * might refetch the pointer. - * atomic_read's are of course not necessary when the bucket lock is held. + * qatomic_read's are of course not necessary when the bucket lock is held. * * If both ht->lock and b->lock are grabbed, ht->lock should always * be grabbed first. @@ -XXX,XX +XXX,XX @@ void qht_map_lock_buckets__no_stale(struct qht *ht, struct qht_map **pmap) { struct qht_map *map; - map = atomic_rcu_read(&ht->map); + map = qatomic_rcu_read(&ht->map); qht_map_lock_buckets(map); if (likely(!qht_map_is_stale__locked(ht, map))) { *pmap = map; @@ -XXX,XX +XXX,XX @@ struct qht_bucket *qht_bucket_lock__no_stale(struct qht *ht, uint32_t hash, struct qht_bucket *b; struct qht_map *map; - map = atomic_rcu_read(&ht->map); + map = qatomic_rcu_read(&ht->map); b = qht_map_to_bucket(map, hash); qemu_spin_lock(&b->lock); @@ -XXX,XX +XXX,XX @@ struct qht_bucket *qht_bucket_lock__no_stale(struct qht *ht, uint32_t hash, static inline bool qht_map_needs_resize(const struct qht_map *map) { - return atomic_read(&map->n_added_buckets) > map->n_added_buckets_threshold; + return qatomic_read(&map->n_added_buckets) > + map->n_added_buckets_threshold; } static inline void qht_chain_destroy(const struct qht_bucket *head) @@ -XXX,XX +XXX,XX @@ void qht_init(struct qht *ht, qht_cmp_func_t cmp, size_t n_elems, ht->mode = mode; qemu_mutex_init(&ht->lock); map = qht_map_create(n_buckets); - atomic_rcu_set(&ht->map, map); + qatomic_rcu_set(&ht->map, map); } /* call only when there are no readers/writers left */ @@ -XXX,XX +XXX,XX @@ static void qht_bucket_reset__locked(struct qht_bucket *head) if (b->pointers[i] == NULL) { goto done; } - atomic_set(&b->hashes[i], 0); - atomic_set(&b->pointers[i], NULL); + qatomic_set(&b->hashes[i], 0); + qatomic_set(&b->pointers[i], NULL); } b = b->next; } while (b); @@ -XXX,XX +XXX,XX @@ void *qht_do_lookup(const struct qht_bucket *head, qht_lookup_func_t func, do { for (i = 0; i < QHT_BUCKET_ENTRIES; i++) { - if (atomic_read(&b->hashes[i]) == hash) { + if (qatomic_read(&b->hashes[i]) == hash) { /* The pointer is dereferenced before seqlock_read_retry, * so (unlike qht_insert__locked) we need to use - * atomic_rcu_read here. + * qatomic_rcu_read here. */ - void *p = atomic_rcu_read(&b->pointers[i]); + void *p = qatomic_rcu_read(&b->pointers[i]); if (likely(p) && likely(func(p, userp))) { return p; } } } - b = atomic_rcu_read(&b->next); + b = qatomic_rcu_read(&b->next); } while (b); return NULL; @@ -XXX,XX +XXX,XX @@ void *qht_lookup_custom(const struct qht *ht, const void *userp, uint32_t hash, unsigned int version; void *ret; - map = atomic_rcu_read(&ht->map); + map = qatomic_rcu_read(&ht->map); b = qht_map_to_bucket(map, hash); version = seqlock_read_begin(&b->sequence); @@ -XXX,XX +XXX,XX @@ static void *qht_insert__locked(const struct qht *ht, struct qht_map *map, memset(b, 0, sizeof(*b)); new = b; i = 0; - atomic_inc(&map->n_added_buckets); + qatomic_inc(&map->n_added_buckets); if (unlikely(qht_map_needs_resize(map)) && needs_resize) { *needs_resize = true; } @@ -XXX,XX +XXX,XX @@ static void *qht_insert__locked(const struct qht *ht, struct qht_map *map, /* found an empty key: acquire the seqlock and write */ seqlock_write_begin(&head->sequence); if (new) { - atomic_rcu_set(&prev->next, b); + qatomic_rcu_set(&prev->next, b); } /* smp_wmb() implicit in seqlock_write_begin. */ - atomic_set(&b->hashes[i], hash); - atomic_set(&b->pointers[i], p); + qatomic_set(&b->hashes[i], hash); + qatomic_set(&b->pointers[i], p); seqlock_write_end(&head->sequence); return NULL; } @@ -XXX,XX +XXX,XX @@ qht_entry_move(struct qht_bucket *to, int i, struct qht_bucket *from, int j) qht_debug_assert(to->pointers[i]); qht_debug_assert(from->pointers[j]); - atomic_set(&to->hashes[i], from->hashes[j]); - atomic_set(&to->pointers[i], from->pointers[j]); + qatomic_set(&to->hashes[i], from->hashes[j]); + qatomic_set(&to->pointers[i], from->pointers[j]); - atomic_set(&from->hashes[j], 0); - atomic_set(&from->pointers[j], NULL); + qatomic_set(&from->hashes[j], 0); + qatomic_set(&from->pointers[j], NULL); } /* @@ -XXX,XX +XXX,XX @@ static inline void qht_bucket_remove_entry(struct qht_bucket *orig, int pos) if (qht_entry_is_last(orig, pos)) { orig->hashes[pos] = 0; - atomic_set(&orig->pointers[pos], NULL); + qatomic_set(&orig->pointers[pos], NULL); return; } do { @@ -XXX,XX +XXX,XX @@ do_qht_iter(struct qht *ht, const struct qht_iter *iter, void *userp) { struct qht_map *map; - map = atomic_rcu_read(&ht->map); + map = qatomic_rcu_read(&ht->map); qht_map_lock_buckets(map); qht_map_iter__all_locked(map, iter, userp); qht_map_unlock_buckets(map); @@ -XXX,XX +XXX,XX @@ static void qht_do_resize_reset(struct qht *ht, struct qht_map *new, bool reset) qht_map_iter__all_locked(old, &iter, &data); qht_map_debug__all_locked(new); - atomic_rcu_set(&ht->map, new); + qatomic_rcu_set(&ht->map, new); qht_map_unlock_buckets(old); call_rcu(old, qht_map_destroy, rcu); } @@ -XXX,XX +XXX,XX @@ void qht_statistics_init(const struct qht *ht, struct qht_stats *stats) const struct qht_map *map; int i; - map = atomic_rcu_read(&ht->map); + map = qatomic_rcu_read(&ht->map); stats->used_head_buckets = 0; stats->entries = 0; @@ -XXX,XX +XXX,XX @@ void qht_statistics_init(const struct qht *ht, struct qht_stats *stats) b = head; do { for (j = 0; j < QHT_BUCKET_ENTRIES; j++) { - if (atomic_read(&b->pointers[j]) == NULL) { + if (qatomic_read(&b->pointers[j]) == NULL) { break; } entries++; } buckets++; - b = atomic_rcu_read(&b->next); + b = qatomic_rcu_read(&b->next); } while (b); } while (seqlock_read_retry(&head->sequence, version)); diff --git a/util/qsp.c b/util/qsp.c index XXXXXXX..XXXXXXX 100644 --- a/util/qsp.c +++ b/util/qsp.c @@ -XXX,XX +XXX,XX @@ static void qsp_do_init(void) static __attribute__((noinline)) void qsp_init__slowpath(void) { - if (atomic_cmpxchg(&qsp_initializing, false, true) == false) { + if (qatomic_cmpxchg(&qsp_initializing, false, true) == false) { qsp_do_init(); - atomic_set(&qsp_initialized, true); + qatomic_set(&qsp_initialized, true); } else { - while (!atomic_read(&qsp_initialized)) { + while (!qatomic_read(&qsp_initialized)) { cpu_relax(); } } @@ -XXX,XX +XXX,XX @@ static __attribute__((noinline)) void qsp_init__slowpath(void) /* qsp_init() must be called from _all_ exported functions */ static inline void qsp_init(void) { - if (likely(atomic_read(&qsp_initialized))) { + if (likely(qatomic_read(&qsp_initialized))) { return; } qsp_init__slowpath(); @@ -XXX,XX +XXX,XX @@ static QSPEntry *qsp_entry_get(const void *obj, const char *file, int line, */ static inline void do_qsp_entry_record(QSPEntry *e, int64_t delta, bool acq) { - atomic_set_u64(&e->ns, e->ns + delta); + qatomic_set_u64(&e->ns, e->ns + delta); if (acq) { - atomic_set_u64(&e->n_acqs, e->n_acqs + 1); + qatomic_set_u64(&e->n_acqs, e->n_acqs + 1); } } @@ -XXX,XX +XXX,XX @@ qsp_cond_timedwait(QemuCond *cond, QemuMutex *mutex, int ms, bool qsp_is_enabled(void) { - return atomic_read(&qemu_mutex_lock_func) == qsp_mutex_lock; + return qatomic_read(&qemu_mutex_lock_func) == qsp_mutex_lock; } void qsp_enable(void) { - atomic_set(&qemu_mutex_lock_func, qsp_mutex_lock); - atomic_set(&qemu_mutex_trylock_func, qsp_mutex_trylock); - atomic_set(&qemu_bql_mutex_lock_func, qsp_bql_mutex_lock); - atomic_set(&qemu_rec_mutex_lock_func, qsp_rec_mutex_lock); - atomic_set(&qemu_rec_mutex_trylock_func, qsp_rec_mutex_trylock); - atomic_set(&qemu_cond_wait_func, qsp_cond_wait); - atomic_set(&qemu_cond_timedwait_func, qsp_cond_timedwait); + qatomic_set(&qemu_mutex_lock_func, qsp_mutex_lock); + qatomic_set(&qemu_mutex_trylock_func, qsp_mutex_trylock); + qatomic_set(&qemu_bql_mutex_lock_func, qsp_bql_mutex_lock); + qatomic_set(&qemu_rec_mutex_lock_func, qsp_rec_mutex_lock); + qatomic_set(&qemu_rec_mutex_trylock_func, qsp_rec_mutex_trylock); + qatomic_set(&qemu_cond_wait_func, qsp_cond_wait); + qatomic_set(&qemu_cond_timedwait_func, qsp_cond_timedwait); } void qsp_disable(void) { - atomic_set(&qemu_mutex_lock_func, qemu_mutex_lock_impl); - atomic_set(&qemu_mutex_trylock_func, qemu_mutex_trylock_impl); - atomic_set(&qemu_bql_mutex_lock_func, qemu_mutex_lock_impl); - atomic_set(&qemu_rec_mutex_lock_func, qemu_rec_mutex_lock_impl); - atomic_set(&qemu_rec_mutex_trylock_func, qemu_rec_mutex_trylock_impl); - atomic_set(&qemu_cond_wait_func, qemu_cond_wait_impl); - atomic_set(&qemu_cond_timedwait_func, qemu_cond_timedwait_impl); + qatomic_set(&qemu_mutex_lock_func, qemu_mutex_lock_impl); + qatomic_set(&qemu_mutex_trylock_func, qemu_mutex_trylock_impl); + qatomic_set(&qemu_bql_mutex_lock_func, qemu_mutex_lock_impl); + qatomic_set(&qemu_rec_mutex_lock_func, qemu_rec_mutex_lock_impl); + qatomic_set(&qemu_rec_mutex_trylock_func, qemu_rec_mutex_trylock_impl); + qatomic_set(&qemu_cond_wait_func, qemu_cond_wait_impl); + qatomic_set(&qemu_cond_timedwait_func, qemu_cond_timedwait_impl); } static gint qsp_tree_cmp(gconstpointer ap, gconstpointer bp, gpointer up) @@ -XXX,XX +XXX,XX @@ static void qsp_aggregate(void *p, uint32_t h, void *up) * The entry is in the global hash table; read from it atomically (as in * "read once"). */ - agg->ns += atomic_read_u64(&e->ns); - agg->n_acqs += atomic_read_u64(&e->n_acqs); + agg->ns += qatomic_read_u64(&e->ns); + agg->n_acqs += qatomic_read_u64(&e->n_acqs); } static void qsp_iter_diff(void *p, uint32_t hash, void *htp) @@ -XXX,XX +XXX,XX @@ static void qsp_mktree(GTree *tree, bool callsite_coalesce) * with the snapshot. */ WITH_RCU_READ_LOCK_GUARD() { - QSPSnapshot *snap = atomic_rcu_read(&qsp_snapshot); + QSPSnapshot *snap = qatomic_rcu_read(&qsp_snapshot); /* Aggregate all results from the global hash table into a local one */ qht_init(&ht, qsp_entry_no_thread_cmp, QSP_INITIAL_SIZE, @@ -XXX,XX +XXX,XX @@ void qsp_reset(void) qht_iter(&qsp_ht, qsp_aggregate, &new->ht); /* replace the previous snapshot, if any */ - old = atomic_xchg(&qsp_snapshot, new); + old = qatomic_xchg(&qsp_snapshot, new); if (old) { call_rcu(old, qsp_snapshot_destroy, rcu); } diff --git a/util/rcu.c b/util/rcu.c index XXXXXXX..XXXXXXX 100644 --- a/util/rcu.c +++ b/util/rcu.c @@ -XXX,XX +XXX,XX @@ static inline int rcu_gp_ongoing(unsigned long *ctr) { unsigned long v; - v = atomic_read(ctr); + v = qatomic_read(ctr); return v && (v != rcu_gp_ctr); } @@ -XXX,XX +XXX,XX @@ static void wait_for_readers(void) */ qemu_event_reset(&rcu_gp_event); - /* Instead of using atomic_mb_set for index->waiting, and - * atomic_mb_read for index->ctr, memory barriers are placed + /* Instead of using qatomic_mb_set for index->waiting, and + * qatomic_mb_read for index->ctr, memory barriers are placed * manually since writes to different threads are independent. * qemu_event_reset has acquire semantics, so no memory barrier * is needed here. */ QLIST_FOREACH(index, ®istry, node) { - atomic_set(&index->waiting, true); + qatomic_set(&index->waiting, true); } /* Here, order the stores to index->waiting before the loads of @@ -XXX,XX +XXX,XX @@ static void wait_for_readers(void) /* No need for mb_set here, worst of all we * get some extra futex wakeups. */ - atomic_set(&index->waiting, false); + qatomic_set(&index->waiting, false); } } @@ -XXX,XX +XXX,XX @@ void synchronize_rcu(void) QEMU_LOCK_GUARD(&rcu_registry_lock); if (!QLIST_EMPTY(®istry)) { - /* In either case, the atomic_mb_set below blocks stores that free + /* In either case, the qatomic_mb_set below blocks stores that free * old RCU-protected pointers. */ if (sizeof(rcu_gp_ctr) < 8) { @@ -XXX,XX +XXX,XX @@ void synchronize_rcu(void) * * Switch parity: 0 -> 1, 1 -> 0. */ - atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); + qatomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); wait_for_readers(); - atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); + qatomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR); } else { /* Increment current grace period. */ - atomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr + RCU_GP_CTR); + qatomic_mb_set(&rcu_gp_ctr, rcu_gp_ctr + RCU_GP_CTR); } wait_for_readers(); @@ -XXX,XX +XXX,XX @@ static void enqueue(struct rcu_head *node) struct rcu_head **old_tail; node->next = NULL; - old_tail = atomic_xchg(&tail, &node->next); - atomic_mb_set(old_tail, node); + old_tail = qatomic_xchg(&tail, &node->next); + qatomic_mb_set(old_tail, node); } static struct rcu_head *try_dequeue(void) @@ -XXX,XX +XXX,XX @@ retry: * The tail, because it is the first step in the enqueuing. * It is only the next pointers that might be inconsistent. */ - if (head == &dummy && atomic_mb_read(&tail) == &dummy.next) { + if (head == &dummy && qatomic_mb_read(&tail) == &dummy.next) { abort(); } @@ -XXX,XX +XXX,XX @@ retry: * wrong and we need to wait until its enqueuer finishes the update. */ node = head; - next = atomic_mb_read(&head->next); + next = qatomic_mb_read(&head->next); if (!next) { return NULL; } @@ -XXX,XX +XXX,XX @@ static void *call_rcu_thread(void *opaque) for (;;) { int tries = 0; - int n = atomic_read(&rcu_call_count); + int n = qatomic_read(&rcu_call_count); /* Heuristically wait for a decent number of callbacks to pile up. * Fetch rcu_call_count now, we only must process elements that were @@ -XXX,XX +XXX,XX @@ static void *call_rcu_thread(void *opaque) g_usleep(10000); if (n == 0) { qemu_event_reset(&rcu_call_ready_event); - n = atomic_read(&rcu_call_count); + n = qatomic_read(&rcu_call_count); if (n == 0) { #if defined(CONFIG_MALLOC_TRIM) malloc_trim(4 * 1024 * 1024); @@ -XXX,XX +XXX,XX @@ static void *call_rcu_thread(void *opaque) qemu_event_wait(&rcu_call_ready_event); } } - n = atomic_read(&rcu_call_count); + n = qatomic_read(&rcu_call_count); } - atomic_sub(&rcu_call_count, n); + qatomic_sub(&rcu_call_count, n); synchronize_rcu(); qemu_mutex_lock_iothread(); while (n > 0) { @@ -XXX,XX +XXX,XX @@ void call_rcu1(struct rcu_head *node, void (*func)(struct rcu_head *node)) { node->func = func; enqueue(node); - atomic_inc(&rcu_call_count); + qatomic_inc(&rcu_call_count); qemu_event_set(&rcu_call_ready_event); } diff --git a/util/stats64.c b/util/stats64.c index XXXXXXX..XXXXXXX 100644 --- a/util/stats64.c +++ b/util/stats64.c @@ -XXX,XX +XXX,XX @@ static inline void stat64_rdlock(Stat64 *s) { /* Keep out incoming writers to avoid them starving us. */ - atomic_add(&s->lock, 2); + qatomic_add(&s->lock, 2); /* If there is a concurrent writer, wait for it. */ - while (atomic_read(&s->lock) & 1) { + while (qatomic_read(&s->lock) & 1) { cpu_relax(); } } static inline void stat64_rdunlock(Stat64 *s) { - atomic_sub(&s->lock, 2); + qatomic_sub(&s->lock, 2); } static inline bool stat64_wrtrylock(Stat64 *s) { - return atomic_cmpxchg(&s->lock, 0, 1) == 0; + return qatomic_cmpxchg(&s->lock, 0, 1) == 0; } static inline void stat64_wrunlock(Stat64 *s) { - atomic_dec(&s->lock); + qatomic_dec(&s->lock); } uint64_t stat64_get(const Stat64 *s) @@ -XXX,XX +XXX,XX @@ uint64_t stat64_get(const Stat64 *s) /* 64-bit writes always take the lock, so we can read in * any order. */ - high = atomic_read(&s->high); - low = atomic_read(&s->low); + high = qatomic_read(&s->high); + low = qatomic_read(&s->low); stat64_rdunlock((Stat64 *)s); return ((uint64_t)high << 32) | low; @@ -XXX,XX +XXX,XX @@ bool stat64_add32_carry(Stat64 *s, uint32_t low, uint32_t high) * order of our update. By updating s->low first, we can check * whether we have to carry into s->high. */ - old = atomic_fetch_add(&s->low, low); + old = qatomic_fetch_add(&s->low, low); high += (old + low) < old; - atomic_add(&s->high, high); + qatomic_add(&s->high, high); stat64_wrunlock(s); return true; } @@ -XXX,XX +XXX,XX @@ bool stat64_min_slow(Stat64 *s, uint64_t value) return false; } - high = atomic_read(&s->high); - low = atomic_read(&s->low); + high = qatomic_read(&s->high); + low = qatomic_read(&s->low); orig = ((uint64_t)high << 32) | low; if (value < orig) { @@ -XXX,XX +XXX,XX @@ bool stat64_min_slow(Stat64 *s, uint64_t value) * effect on stat64_min is that the slow path may be triggered * unnecessarily. */ - atomic_set(&s->low, (uint32_t)value); + qatomic_set(&s->low, (uint32_t)value); smp_wmb(); - atomic_set(&s->high, value >> 32); + qatomic_set(&s->high, value >> 32); } stat64_wrunlock(s); return true; @@ -XXX,XX +XXX,XX @@ bool stat64_max_slow(Stat64 *s, uint64_t value) return false; } - high = atomic_read(&s->high); - low = atomic_read(&s->low); + high = qatomic_read(&s->high); + low = qatomic_read(&s->low); orig = ((uint64_t)high << 32) | low; if (value > orig) { @@ -XXX,XX +XXX,XX @@ bool stat64_max_slow(Stat64 *s, uint64_t value) * effect on stat64_max is that the slow path may be triggered * unnecessarily. */ - atomic_set(&s->low, (uint32_t)value); + qatomic_set(&s->low, (uint32_t)value); smp_wmb(); - atomic_set(&s->high, value >> 32); + qatomic_set(&s->high, value >> 32); } stat64_wrunlock(s); return true; diff --git a/docs/devel/atomics.rst b/docs/devel/atomics.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/devel/atomics.rst +++ b/docs/devel/atomics.rst @@ -XXX,XX +XXX,XX @@ provides macros that fall in three camps: - compiler barriers: ``barrier()``; -- weak atomic access and manual memory barriers: ``atomic_read()``, - ``atomic_set()``, ``smp_rmb()``, ``smp_wmb()``, ``smp_mb()``, ``smp_mb_acquire()``, - ``smp_mb_release()``, ``smp_read_barrier_depends()``; +- weak atomic access and manual memory barriers: ``qatomic_read()``, + ``qatomic_set()``, ``smp_rmb()``, ``smp_wmb()``, ``smp_mb()``, + ``smp_mb_acquire()``, ``smp_mb_release()``, ``smp_read_barrier_depends()``; - sequentially consistent atomic access: everything else. @@ -XXX,XX +XXX,XX @@ in the order specified by its program". ``qemu/atomic.h`` provides the following set of atomic read-modify-write operations:: - void atomic_inc(ptr) - void atomic_dec(ptr) - void atomic_add(ptr, val) - void atomic_sub(ptr, val) - void atomic_and(ptr, val) - void atomic_or(ptr, val) + void qatomic_inc(ptr) + void qatomic_dec(ptr) + void qatomic_add(ptr, val) + void qatomic_sub(ptr, val) + void qatomic_and(ptr, val) + void qatomic_or(ptr, val) - typeof(*ptr) atomic_fetch_inc(ptr) - typeof(*ptr) atomic_fetch_dec(ptr) - typeof(*ptr) atomic_fetch_add(ptr, val) - typeof(*ptr) atomic_fetch_sub(ptr, val) - typeof(*ptr) atomic_fetch_and(ptr, val) - typeof(*ptr) atomic_fetch_or(ptr, val) - typeof(*ptr) atomic_fetch_xor(ptr, val) - typeof(*ptr) atomic_fetch_inc_nonzero(ptr) - typeof(*ptr) atomic_xchg(ptr, val) - typeof(*ptr) atomic_cmpxchg(ptr, old, new) + typeof(*ptr) qatomic_fetch_inc(ptr) + typeof(*ptr) qatomic_fetch_dec(ptr) + typeof(*ptr) qatomic_fetch_add(ptr, val) + typeof(*ptr) qatomic_fetch_sub(ptr, val) + typeof(*ptr) qatomic_fetch_and(ptr, val) + typeof(*ptr) qatomic_fetch_or(ptr, val) + typeof(*ptr) qatomic_fetch_xor(ptr, val) + typeof(*ptr) qatomic_fetch_inc_nonzero(ptr) + typeof(*ptr) qatomic_xchg(ptr, val) + typeof(*ptr) qatomic_cmpxchg(ptr, old, new) all of which return the old value of ``*ptr``. These operations are polymorphic; they operate on any type that is as wide as a pointer or @@ -XXX,XX +XXX,XX @@ smaller. Similar operations return the new value of ``*ptr``:: - typeof(*ptr) atomic_inc_fetch(ptr) - typeof(*ptr) atomic_dec_fetch(ptr) - typeof(*ptr) atomic_add_fetch(ptr, val) - typeof(*ptr) atomic_sub_fetch(ptr, val) - typeof(*ptr) atomic_and_fetch(ptr, val) - typeof(*ptr) atomic_or_fetch(ptr, val) - typeof(*ptr) atomic_xor_fetch(ptr, val) + typeof(*ptr) qatomic_inc_fetch(ptr) + typeof(*ptr) qatomic_dec_fetch(ptr) + typeof(*ptr) qatomic_add_fetch(ptr, val) + typeof(*ptr) qatomic_sub_fetch(ptr, val) + typeof(*ptr) qatomic_and_fetch(ptr, val) + typeof(*ptr) qatomic_or_fetch(ptr, val) + typeof(*ptr) qatomic_xor_fetch(ptr, val) ``qemu/atomic.h`` also provides loads and stores that cannot be reordered with each other:: - typeof(*ptr) atomic_mb_read(ptr) - void atomic_mb_set(ptr, val) + typeof(*ptr) qatomic_mb_read(ptr) + void qatomic_mb_set(ptr, val) However these do not provide sequential consistency and, in particular, they do not participate in the total ordering enforced by @@ -XXX,XX +XXX,XX @@ easiest to hardest): - lightweight synchronization primitives such as ``QemuEvent`` -- RCU operations (``atomic_rcu_read``, ``atomic_rcu_set``) when publishing +- RCU operations (``qatomic_rcu_read``, ``qatomic_rcu_set``) when publishing or accessing a new version of a data structure -- other atomic accesses: ``atomic_read`` and ``atomic_load_acquire`` for - loads, ``atomic_set`` and ``atomic_store_release`` for stores, ``smp_mb`` +- other atomic accesses: ``qatomic_read`` and ``qatomic_load_acquire`` for + loads, ``qatomic_set`` and ``qatomic_store_release`` for stores, ``smp_mb`` to forbid reordering subsequent loads before a store. @@ -XXX,XX +XXX,XX @@ The only guarantees that you can rely upon in this case are: When using this model, variables are accessed with: -- ``atomic_read()`` and ``atomic_set()``; these prevent the compiler from +- ``qatomic_read()`` and ``qatomic_set()``; these prevent the compiler from optimizing accesses out of existence and creating unsolicited accesses, but do not otherwise impose any ordering on loads and stores: both the compiler and the processor are free to reorder them. -- ``atomic_load_acquire()``, which guarantees the LOAD to appear to +- ``qatomic_load_acquire()``, which guarantees the LOAD to appear to happen, with respect to the other components of the system, before all the LOAD or STORE operations specified afterwards. - Operations coming before ``atomic_load_acquire()`` can still be + Operations coming before ``qatomic_load_acquire()`` can still be reordered after it. -- ``atomic_store_release()``, which guarantees the STORE to appear to +- ``qatomic_store_release()``, which guarantees the STORE to appear to happen, with respect to the other components of the system, after all the LOAD or STORE operations specified before. - Operations coming after ``atomic_store_release()`` can still be + Operations coming after ``qatomic_store_release()`` can still be reordered before it. Restrictions to the ordering of accesses can also be specified @@ -XXX,XX +XXX,XX @@ They come in six kinds: dependency and a full read barrier or better is required. -Memory barriers and ``atomic_load_acquire``/``atomic_store_release`` are +Memory barriers and ``qatomic_load_acquire``/``qatomic_store_release`` are mostly used when a data structure has one thread that is always a writer and one thread that is always a reader: @@ -XXX,XX +XXX,XX @@ and one thread that is always a reader: +==================================+==================================+ | :: | :: | | | | - | atomic_store_release(&a, x); | y = atomic_load_acquire(&b); | - | atomic_store_release(&b, y); | x = atomic_load_acquire(&a); | + | qatomic_store_release(&a, x); | y = qatomic_load_acquire(&b); | + | qatomic_store_release(&b, y); | x = qatomic_load_acquire(&a); | +----------------------------------+----------------------------------+ In this case, correctness is easy to check for using the "pairing" @@ -XXX,XX +XXX,XX @@ outside a loop. For example: | | | | n = 0; | n = 0; | | for (i = 0; i < 10; i++) | for (i = 0; i < 10; i++) | - | n += atomic_load_acquire(&a[i]); | n += atomic_read(&a[i]); | + | n += qatomic_load_acquire(&a[i]); | n += qatomic_read(&a[i]); | | | smp_mb_acquire(); | +------------------------------------------+----------------------------------+ | :: | :: | | | | | | smp_mb_release(); | | for (i = 0; i < 10; i++) | for (i = 0; i < 10; i++) | - | atomic_store_release(&a[i], false); | atomic_set(&a[i], false); | + | qatomic_store_release(&a[i], false); | qatomic_set(&a[i], false); | +------------------------------------------+----------------------------------+ Splitting a loop can also be useful to reduce the number of barriers: @@ -XXX,XX +XXX,XX @@ Splitting a loop can also be useful to reduce the number of barriers: | | | | n = 0; | smp_mb_release(); | | for (i = 0; i < 10; i++) { | for (i = 0; i < 10; i++) | - | atomic_store_release(&a[i], false); | atomic_set(&a[i], false); | + | qatomic_store_release(&a[i], false); | qatomic_set(&a[i], false); | | smp_mb(); | smb_mb(); | - | n += atomic_read(&b[i]); | n = 0; | + | n += qatomic_read(&b[i]); | n = 0; | | } | for (i = 0; i < 10; i++) | - | | n += atomic_read(&b[i]); | + | | n += qatomic_read(&b[i]); | +------------------------------------------+----------------------------------+ In this case, a ``smp_mb_release()`` is also replaced with a (possibly cheaper, and clearer @@ -XXX,XX +XXX,XX @@ as well) ``smp_wmb()``: | | | | | smp_mb_release(); | | for (i = 0; i < 10; i++) { | for (i = 0; i < 10; i++) | - | atomic_store_release(&a[i], false); | atomic_set(&a[i], false); | - | atomic_store_release(&b[i], false); | smb_wmb(); | + | qatomic_store_release(&a[i], false); | qatomic_set(&a[i], false); | + | qatomic_store_release(&b[i], false); | smb_wmb(); | | } | for (i = 0; i < 10; i++) | - | | atomic_set(&b[i], false); | + | | qatomic_set(&b[i], false); | +------------------------------------------+----------------------------------+ @@ -XXX,XX +XXX,XX @@ as well) ``smp_wmb()``: Acquire/release pairing and the *synchronizes-with* relation ------------------------------------------------------------ -Atomic operations other than ``atomic_set()`` and ``atomic_read()`` have +Atomic operations other than ``qatomic_set()`` and ``qatomic_read()`` have either *acquire* or *release* semantics [#rmw]_. This has two effects: .. [#rmw] Read-modify-write operations can have both---acquire applies to the @@ -XXX,XX +XXX,XX @@ thread 2 is relying on the *synchronizes-with* relation between ``pthread_exit`` Synchronization between threads basically descends from this pairing of a release operation and an acquire operation. Therefore, atomic operations -other than ``atomic_set()`` and ``atomic_read()`` will almost always be +other than ``qatomic_set()`` and ``qatomic_read()`` will almost always be paired with another operation of the opposite kind: an acquire operation will pair with a release operation and vice versa. This rule of thumb is extremely useful; in the case of QEMU, however, note that the other operation may actually be in a driver that runs in the guest! ``smp_read_barrier_depends()``, ``smp_rmb()``, ``smp_mb_acquire()``, -``atomic_load_acquire()`` and ``atomic_rcu_read()`` all count +``qatomic_load_acquire()`` and ``qatomic_rcu_read()`` all count as acquire operations. ``smp_wmb()``, ``smp_mb_release()``, -``atomic_store_release()`` and ``atomic_rcu_set()`` all count as release +``qatomic_store_release()`` and ``qatomic_rcu_set()`` all count as release operations. ``smp_mb()`` counts as both acquire and release, therefore it can pair with any other atomic operation. Here is an example: @@ -XXX,XX +XXX,XX @@ it can pair with any other atomic operation. Here is an example: +======================+==============================+ | :: | :: | | | | - | atomic_set(&a, 1); | | + | qatomic_set(&a, 1);| | | smp_wmb(); | | - | atomic_set(&b, 2); | x = atomic_read(&b); | + | qatomic_set(&b, 2);| x = qatomic_read(&b); | | | smp_rmb(); | - | | y = atomic_read(&a); | + | | y = qatomic_read(&a); | +----------------------+------------------------------+ Note that a load-store pair only counts if the two operations access the @@ -XXX,XX +XXX,XX @@ correct synchronization: +================================+================================+ | :: | :: | | | | - | atomic_set(&a, 1); | | - | atomic_store_release(&b, 2); | x = atomic_load_acquire(&b); | - | | y = atomic_read(&a); | + | qatomic_set(&a, 1); | | + | qatomic_store_release(&b, 2);| x = qatomic_load_acquire(&b);| + | | y = qatomic_read(&a); | +--------------------------------+--------------------------------+ Acquire and release semantics of higher-level primitives can also be @@ -XXX,XX +XXX,XX @@ cannot be a data race: | smp_wmb(); | | | x->i = 2; | | | smp_wmb(); | | - | atomic_set(&a, x); | x = atomic_read(&a); | + | qatomic_set(&a, x);| x = qatomic_read(&a); | | | smp_read_barrier_depends(); | | | y = x->i; | | | smp_read_barrier_depends(); | @@ -XXX,XX +XXX,XX @@ and memory barriers, and the equivalents in QEMU: at all. Linux 4.1 updated them to implement volatile semantics via ``ACCESS_ONCE`` (or the more recent ``READ``/``WRITE_ONCE``). - QEMU's ``atomic_read`` and ``atomic_set`` implement C11 atomic relaxed + QEMU's ``qatomic_read`` and ``qatomic_set`` implement C11 atomic relaxed semantics if the compiler supports it, and volatile semantics otherwise. Both semantics prevent the compiler from doing certain transformations; the difference is that atomic accesses are guaranteed to be atomic, @@ -XXX,XX +XXX,XX @@ and memory barriers, and the equivalents in QEMU: since we assume the variables passed are machine-word sized and properly aligned. - No barriers are implied by ``atomic_read`` and ``atomic_set`` in either Linux - or QEMU. + No barriers are implied by ``qatomic_read`` and ``qatomic_set`` in either + Linux or QEMU. - atomic read-modify-write operations in Linux are of three kinds: @@ -XXX,XX +XXX,XX @@ and memory barriers, and the equivalents in QEMU: a different set of memory barriers; in QEMU, all of them enforce sequential consistency. -- in QEMU, ``atomic_read()`` and ``atomic_set()`` do not participate in +- in QEMU, ``qatomic_read()`` and ``qatomic_set()`` do not participate in the total ordering enforced by sequentially-consistent operations. This is because QEMU uses the C11 memory model. The following example is correct in Linux but not in QEMU: @@ -XXX,XX +XXX,XX @@ and memory barriers, and the equivalents in QEMU: +==================================+================================+ | :: | :: | | | | - | a = atomic_fetch_add(&x, 2); | a = atomic_fetch_add(&x, 2); | - | b = READ_ONCE(&y); | b = atomic_read(&y); | + | a = atomic_fetch_add(&x, 2); | a = qatomic_fetch_add(&x, 2);| + | b = READ_ONCE(&y); | b = qatomic_read(&y); | +----------------------------------+--------------------------------+ because the read of ``y`` can be moved (by either the processor or the @@ -XXX,XX +XXX,XX @@ and memory barriers, and the equivalents in QEMU: +================================+ | :: | | | - | a = atomic_read(&x); | - | atomic_set(&x, a + 2); | + | a = qatomic_read(&x); | + | qatomic_set(&x, a + 2); | | smp_mb(); | - | b = atomic_read(&y); | + | b = qatomic_read(&y); | +--------------------------------+ Sources diff --git a/scripts/kernel-doc b/scripts/kernel-doc index XXXXXXX..XXXXXXX 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -XXX,XX +XXX,XX @@ sub dump_function($$) { # If you mess with these regexps, it's a good idea to check that # the following functions' documentation still comes out right: # - parport_register_device (function pointer parameters) - # - atomic_set (macro) + # - qatomic_set (macro) # - pci_match_device, __copy_to_user (long return type) if ($define && $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s+/) { diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index XXXXXXX..XXXXXXX 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr, i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd; } pair = (uint64_t)i2 << 32 | i1; - atomic_set((uint64_t *)jmp_addr, pair); + qatomic_set((uint64_t *)jmp_addr, pair); flush_icache_range(jmp_addr, jmp_addr + 8); } diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index XXXXXXX..XXXXXXX 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -XXX,XX +XXX,XX @@ static void tcg_target_init(TCGContext *s) void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr, uintptr_t addr) { - atomic_set((uint32_t *)jmp_addr, deposit32(OPC_J, 0, 26, addr >> 2)); + qatomic_set((uint32_t *)jmp_addr, deposit32(OPC_J, 0, 26, addr >> 2)); flush_icache_range(jmp_addr, jmp_addr + 4); } diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index XXXXXXX..XXXXXXX 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr, #endif /* As per the enclosing if, this is ppc64. Avoid the _Static_assert - within atomic_set that would fail to build a ppc32 host. */ - atomic_set__nocheck((uint64_t *)jmp_addr, pair); + within qatomic_set that would fail to build a ppc32 host. */ + qatomic_set__nocheck((uint64_t *)jmp_addr, pair); flush_icache_range(jmp_addr, jmp_addr + 8); } else { intptr_t diff = addr - jmp_addr; tcg_debug_assert(in_range_b(diff)); - atomic_set((uint32_t *)jmp_addr, B | (diff & 0x3fffffc)); + qatomic_set((uint32_t *)jmp_addr, B | (diff & 0x3fffffc)); flush_icache_range(jmp_addr, jmp_addr + 4); } } diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc index XXXXXXX..XXXXXXX 100644 --- a/tcg/sparc/tcg-target.c.inc +++ b/tcg/sparc/tcg-target.c.inc @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr, tcg_debug_assert(br_disp == (int32_t)br_disp); if (!USE_REG_TB) { - atomic_set((uint32_t *)jmp_addr, deposit32(CALL, 0, 30, br_disp >> 2)); + qatomic_set((uint32_t *)jmp_addr, + deposit32(CALL, 0, 30, br_disp >> 2)); flush_icache_range(jmp_addr, jmp_addr + 4); return; } @@ -XXX,XX +XXX,XX @@ void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr, | INSN_IMM13((tb_disp & 0x3ff) | -0x400)); } - atomic_set((uint64_t *)jmp_addr, deposit64(i2, 32, 32, i1)); + qatomic_set((uint64_t *)jmp_addr, deposit64(i2, 32, 32, i1)); flush_icache_range(jmp_addr, jmp_addr + 8); } -- 2.26.2
The following changes since commit 1214d55d1c41fbab3a9973a05085b8760647e411: Merge remote-tracking branch 'remotes/nvme/tags/nvme-next-pull-request' into staging (2021-02-09 13:24:37 +0000) are available in the Git repository at: https://gitlab.com/stefanha/qemu.git tags/block-pull-request for you to fetch changes up to eb847c42296497978942f738cd41dc29a35a49b2: docs: fix Parallels Image "dirty bitmap" section (2021-02-10 09:23:28 +0000) ---------------------------------------------------------------- Pull request v4: * Add PCI_EXPRESS Kconfig dependency to fix s390x in "multi-process: setup PCI host bridge for remote device" [Philippe and Thomas] ---------------------------------------------------------------- Denis V. Lunev (1): docs: fix Parallels Image "dirty bitmap" section Elena Ufimtseva (8): multi-process: add configure and usage information io: add qio_channel_writev_full_all helper io: add qio_channel_readv_full_all_eof & qio_channel_readv_full_all helpers multi-process: define MPQemuMsg format and transmission functions multi-process: introduce proxy object multi-process: add proxy communication functions multi-process: Forward PCI config space acceses to the remote process multi-process: perform device reset in the remote process Jagannathan Raman (11): memory: alloc RAM from file at offset multi-process: Add config option for multi-process QEMU multi-process: setup PCI host bridge for remote device multi-process: setup a machine object for remote device process multi-process: Initialize message handler in remote device multi-process: Associate fd of a PCIDevice with its object multi-process: setup memory manager for remote device multi-process: PCI BAR read/write handling for proxy & remote endpoints multi-process: Synchronize remote memory multi-process: create IOHUB object to handle irq multi-process: Retrieve PCI info from remote process John G Johnson (1): multi-process: add the concept description to docs/devel/qemu-multiprocess Stefan Hajnoczi (6): .github: point Repo Lockdown bot to GitLab repo gitmodules: use GitLab repos instead of qemu.org gitlab-ci: remove redundant GitLab repo URL command docs: update README to use GitLab repo URLs pc-bios: update mirror URLs to GitLab get_maintainer: update repo URL to GitLab MAINTAINERS | 24 + README.rst | 4 +- docs/devel/index.rst | 1 + docs/devel/multi-process.rst | 966 ++++++++++++++++++++++ docs/system/index.rst | 1 + docs/system/multi-process.rst | 64 ++ docs/interop/parallels.txt | 2 +- configure | 10 + meson.build | 5 +- hw/remote/trace.h | 1 + include/exec/memory.h | 2 + include/exec/ram_addr.h | 4 +- include/hw/pci-host/remote.h | 30 + include/hw/pci/pci_ids.h | 3 + include/hw/remote/iohub.h | 42 + include/hw/remote/machine.h | 38 + include/hw/remote/memory.h | 19 + include/hw/remote/mpqemu-link.h | 99 +++ include/hw/remote/proxy-memory-listener.h | 28 + include/hw/remote/proxy.h | 48 ++ include/io/channel.h | 78 ++ include/qemu/mmap-alloc.h | 4 +- include/sysemu/iothread.h | 6 + backends/hostmem-memfd.c | 2 +- hw/misc/ivshmem.c | 3 +- hw/pci-host/remote.c | 75 ++ hw/remote/iohub.c | 119 +++ hw/remote/machine.c | 80 ++ hw/remote/memory.c | 65 ++ hw/remote/message.c | 230 ++++++ hw/remote/mpqemu-link.c | 267 ++++++ hw/remote/proxy-memory-listener.c | 227 +++++ hw/remote/proxy.c | 379 +++++++++ hw/remote/remote-obj.c | 203 +++++ io/channel.c | 116 ++- iothread.c | 6 + softmmu/memory.c | 3 +- softmmu/physmem.c | 12 +- util/mmap-alloc.c | 8 +- util/oslib-posix.c | 2 +- .github/lockdown.yml | 8 +- .gitlab-ci.yml | 1 - .gitmodules | 44 +- Kconfig.host | 4 + hw/Kconfig | 1 + hw/meson.build | 1 + hw/pci-host/Kconfig | 3 + hw/pci-host/meson.build | 1 + hw/remote/Kconfig | 4 + hw/remote/meson.build | 13 + hw/remote/trace-events | 4 + pc-bios/README | 4 +- scripts/get_maintainer.pl | 2 +- 53 files changed, 3296 insertions(+), 70 deletions(-) create mode 100644 docs/devel/multi-process.rst create mode 100644 docs/system/multi-process.rst create mode 100644 hw/remote/trace.h create mode 100644 include/hw/pci-host/remote.h create mode 100644 include/hw/remote/iohub.h create mode 100644 include/hw/remote/machine.h create mode 100644 include/hw/remote/memory.h create mode 100644 include/hw/remote/mpqemu-link.h create mode 100644 include/hw/remote/proxy-memory-listener.h create mode 100644 include/hw/remote/proxy.h create mode 100644 hw/pci-host/remote.c create mode 100644 hw/remote/iohub.c create mode 100644 hw/remote/machine.c create mode 100644 hw/remote/memory.c create mode 100644 hw/remote/message.c create mode 100644 hw/remote/mpqemu-link.c create mode 100644 hw/remote/proxy-memory-listener.c create mode 100644 hw/remote/proxy.c create mode 100644 hw/remote/remote-obj.c create mode 100644 hw/remote/Kconfig create mode 100644 hw/remote/meson.build create mode 100644 hw/remote/trace-events -- 2.29.2
Use the GitLab repo URL as the main repo location in order to reduce load on qemu.org. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Message-id: 20210111115017.156802-2-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- .github/lockdown.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/lockdown.yml b/.github/lockdown.yml index XXXXXXX..XXXXXXX 100644 --- a/.github/lockdown.yml +++ b/.github/lockdown.yml @@ -XXX,XX +XXX,XX @@ issues: comment: | Thank you for your interest in the QEMU project. - This repository is a read-only mirror of the project's master - repostories hosted on https://git.qemu.org/git/qemu.git. + This repository is a read-only mirror of the project's repostories hosted + at https://gitlab.com/qemu-project/qemu.git. The project does not process issues filed on GitHub. The project issues are tracked on Launchpad: @@ -XXX,XX +XXX,XX @@ pulls: comment: | Thank you for your interest in the QEMU project. - This repository is a read-only mirror of the project's master - repostories hosted on https://git.qemu.org/git/qemu.git. + This repository is a read-only mirror of the project's repostories hosted + on https://gitlab.com/qemu-project/qemu.git. The project does not process merge requests filed on GitHub. QEMU welcomes contributions of code (either fixing bugs or adding new -- 2.29.2
qemu.org is running out of bandwidth and the QEMU project is moving towards a gating CI on GitLab. Use the GitLab repos instead of qemu.org (they will become mirrors). Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Message-id: 20210111115017.156802-3-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- .gitmodules | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.gitmodules b/.gitmodules index XXXXXXX..XXXXXXX 100644 --- a/.gitmodules +++ b/.gitmodules @@ -XXX,XX +XXX,XX @@ [submodule "roms/seabios"] path = roms/seabios - url = https://git.qemu.org/git/seabios.git/ + url = https://gitlab.com/qemu-project/seabios.git/ [submodule "roms/SLOF"] path = roms/SLOF - url = https://git.qemu.org/git/SLOF.git + url = https://gitlab.com/qemu-project/SLOF.git [submodule "roms/ipxe"] path = roms/ipxe - url = https://git.qemu.org/git/ipxe.git + url = https://gitlab.com/qemu-project/ipxe.git [submodule "roms/openbios"] path = roms/openbios - url = https://git.qemu.org/git/openbios.git + url = https://gitlab.com/qemu-project/openbios.git [submodule "roms/qemu-palcode"] path = roms/qemu-palcode - url = https://git.qemu.org/git/qemu-palcode.git + url = https://gitlab.com/qemu-project/qemu-palcode.git [submodule "roms/sgabios"] path = roms/sgabios - url = https://git.qemu.org/git/sgabios.git + url = https://gitlab.com/qemu-project/sgabios.git [submodule "dtc"] path = dtc - url = https://git.qemu.org/git/dtc.git + url = https://gitlab.com/qemu-project/dtc.git [submodule "roms/u-boot"] path = roms/u-boot - url = https://git.qemu.org/git/u-boot.git + url = https://gitlab.com/qemu-project/u-boot.git [submodule "roms/skiboot"] path = roms/skiboot - url = https://git.qemu.org/git/skiboot.git + url = https://gitlab.com/qemu-project/skiboot.git [submodule "roms/QemuMacDrivers"] path = roms/QemuMacDrivers - url = https://git.qemu.org/git/QemuMacDrivers.git + url = https://gitlab.com/qemu-project/QemuMacDrivers.git [submodule "ui/keycodemapdb"] path = ui/keycodemapdb - url = https://git.qemu.org/git/keycodemapdb.git + url = https://gitlab.com/qemu-project/keycodemapdb.git [submodule "capstone"] path = capstone - url = https://git.qemu.org/git/capstone.git + url = https://gitlab.com/qemu-project/capstone.git [submodule "roms/seabios-hppa"] path = roms/seabios-hppa - url = https://git.qemu.org/git/seabios-hppa.git + url = https://gitlab.com/qemu-project/seabios-hppa.git [submodule "roms/u-boot-sam460ex"] path = roms/u-boot-sam460ex - url = https://git.qemu.org/git/u-boot-sam460ex.git + url = https://gitlab.com/qemu-project/u-boot-sam460ex.git [submodule "tests/fp/berkeley-testfloat-3"] path = tests/fp/berkeley-testfloat-3 - url = https://git.qemu.org/git/berkeley-testfloat-3.git + url = https://gitlab.com/qemu-project/berkeley-testfloat-3.git [submodule "tests/fp/berkeley-softfloat-3"] path = tests/fp/berkeley-softfloat-3 - url = https://git.qemu.org/git/berkeley-softfloat-3.git + url = https://gitlab.com/qemu-project/berkeley-softfloat-3.git [submodule "roms/edk2"] path = roms/edk2 - url = https://git.qemu.org/git/edk2.git + url = https://gitlab.com/qemu-project/edk2.git [submodule "slirp"] path = slirp - url = https://git.qemu.org/git/libslirp.git + url = https://gitlab.com/qemu-project/libslirp.git [submodule "roms/opensbi"] path = roms/opensbi - url = https://git.qemu.org/git/opensbi.git + url = https://gitlab.com/qemu-project/opensbi.git [submodule "roms/qboot"] path = roms/qboot - url = https://git.qemu.org/git/qboot.git + url = https://gitlab.com/qemu-project/qboot.git [submodule "meson"] path = meson - url = https://git.qemu.org/git/meson.git + url = https://gitlab.com/qemu-project/meson.git [submodule "roms/vbootrom"] path = roms/vbootrom - url = https://git.qemu.org/git/vbootrom.git + url = https://gitlab.com/qemu-project/vbootrom.git -- 2.29.2
It is no longer necessary to point .gitmodules at GitLab repos when running in GitLab CI since they are now used all the time. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Message-id: 20210111115017.156802-4-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index XXXXXXX..XXXXXXX 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -XXX,XX +XXX,XX @@ include: image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest before_script: - JOBS=$(expr $(nproc) + 1) - - sed -i s,git.qemu.org/git,gitlab.com/qemu-project, .gitmodules script: - mkdir build - cd build -- 2.29.2
qemu.org is running out of bandwidth and the QEMU project is moving towards a gating CI on GitLab. Use the GitLab repos instead of qemu.org (they will become mirrors). Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Message-id: 20210111115017.156802-5-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index XXXXXXX..XXXXXXX 100644 --- a/README.rst +++ b/README.rst @@ -XXX,XX +XXX,XX @@ The QEMU source code is maintained under the GIT version control system. .. code-block:: shell - git clone https://git.qemu.org/git/qemu.git + git clone https://gitlab.com/qemu-project/qemu.git When submitting patches, one common approach is to use 'git format-patch' and/or 'git send-email' to format & send the mail to the @@ -XXX,XX +XXX,XX @@ The QEMU website is also maintained under source control. .. code-block:: shell - git clone https://git.qemu.org/git/qemu-web.git + git clone https://gitlab.com/qemu-project/qemu-web.git * `<https://www.qemu.org/2017/02/04/the-new-qemu-website-is-up/>`_ -- 2.29.2
qemu.org is running out of bandwidth and the QEMU project is moving towards a gating CI on GitLab. Use the GitLab repos instead of qemu.org (they will become mirrors). Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Message-id: 20210111115017.156802-6-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- pc-bios/README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index XXXXXXX..XXXXXXX 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -XXX,XX +XXX,XX @@ legacy x86 software to communicate with an attached serial console as if a video card were attached. The master sources reside in a subversion repository at http://sgabios.googlecode.com/svn/trunk. A git mirror is - available at https://git.qemu.org/git/sgabios.git. + available at https://gitlab.com/qemu-project/sgabios.git. - The PXE roms come from the iPXE project. Built with BANNER_TIME 0. Sources available at http://ipxe.org. Vendor:Device ID -> ROM mapping: @@ -XXX,XX +XXX,XX @@ - The u-boot binary for e500 comes from the upstream denx u-boot project where it was compiled using the qemu-ppce500 target. - A git mirror is available at: https://git.qemu.org/git/u-boot.git + A git mirror is available at: https://gitlab.com/qemu-project/u-boot.git The hash used to compile the current version is: 2072e72 - Skiboot (https://github.com/open-power/skiboot/) is an OPAL -- 2.29.2
qemu.org is running out of bandwidth and the QEMU project is moving towards a gating CI on GitLab. Use the GitLab repos instead of qemu.org (they will become mirrors). Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Wainer dos Santos Moschetta <wainersm@redhat.com> Reviewed-by: Thomas Huth <thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Message-id: 20210111115017.156802-7-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- scripts/get_maintainer.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index XXXXXXX..XXXXXXX 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -XXX,XX +XXX,XX @@ sub vcs_exists { warn("$P: No supported VCS found. Add --nogit to options?\n"); warn("Using a git repository produces better results.\n"); warn("Try latest git repository using:\n"); - warn("git clone https://git.qemu.org/git/qemu.git\n"); + warn("git clone https://gitlab.com/qemu-project/qemu.git\n"); $printed_novcs = 1; } return 0; -- 2.29.2
From: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 02a68adef99f5df6a380bf8fd7b90948777e411c.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 7 + docs/devel/index.rst | 1 + docs/devel/multi-process.rst | 966 +++++++++++++++++++++++++++++++++++ 3 files changed, 974 insertions(+) create mode 100644 docs/devel/multi-process.rst diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ S: Maintained F: hw/semihosting/ F: include/hw/semihosting/ +Multi-process QEMU +M: Elena Ufimtseva <elena.ufimtseva@oracle.com> +M: Jagannathan Raman <jag.raman@oracle.com> +M: John G Johnson <john.g.johnson@oracle.com> +S: Maintained +F: docs/devel/multi-process.rst + Build and test automation ------------------------- Build and test automation diff --git a/docs/devel/index.rst b/docs/devel/index.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/devel/index.rst +++ b/docs/devel/index.rst @@ -XXX,XX +XXX,XX @@ Contents: clocks qom block-coroutine-wrapper + multi-process diff --git a/docs/devel/multi-process.rst b/docs/devel/multi-process.rst new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/docs/devel/multi-process.rst @@ -XXX,XX +XXX,XX @@ +This is the design document for multi-process QEMU. It does not +necessarily reflect the status of the current implementation, which +may lack features or be considerably different from what is described +in this document. This document is still useful as a description of +the goals and general direction of this feature. + +Please refer to the following wiki for latest details: +https://wiki.qemu.org/Features/MultiProcessQEMU + +Multi-process QEMU +=================== + +QEMU is often used as the hypervisor for virtual machines running in the +Oracle cloud. Since one of the advantages of cloud computing is the +ability to run many VMs from different tenants in the same cloud +infrastructure, a guest that compromised its hypervisor could +potentially use the hypervisor's access privileges to access data it is +not authorized for. + +QEMU can be susceptible to security attacks because it is a large, +monolithic program that provides many features to the VMs it services. +Many of these features can be configured out of QEMU, but even a reduced +configuration QEMU has a large amount of code a guest can potentially +attack. Separating QEMU reduces the attack surface by aiding to +limit each component in the system to only access the resources that +it needs to perform its job. + +QEMU services +------------- + +QEMU can be broadly described as providing three main services. One is a +VM control point, where VMs can be created, migrated, re-configured, and +destroyed. A second is to emulate the CPU instructions within the VM, +often accelerated by HW virtualization features such as Intel's VT +extensions. Finally, it provides IO services to the VM by emulating HW +IO devices, such as disk and network devices. + +A multi-process QEMU +~~~~~~~~~~~~~~~~~~~~ + +A multi-process QEMU involves separating QEMU services into separate +host processes. Each of these processes can be given only the privileges +it needs to provide its service, e.g., a disk service could be given +access only to the disk images it provides, and not be allowed to +access other files, or any network devices. An attacker who compromised +this service would not be able to use this exploit to access files or +devices beyond what the disk service was given access to. + +A QEMU control process would remain, but in multi-process mode, will +have no direct interfaces to the VM. During VM execution, it would still +provide the user interface to hot-plug devices or live migrate the VM. + +A first step in creating a multi-process QEMU is to separate IO services +from the main QEMU program, which would continue to provide CPU +emulation. i.e., the control process would also be the CPU emulation +process. In a later phase, CPU emulation could be separated from the +control process. + +Separating IO services +---------------------- + +Separating IO services into individual host processes is a good place to +begin for a couple of reasons. One is the sheer number of IO devices QEMU +can emulate provides a large surface of interfaces which could potentially +be exploited, and, indeed, have been a source of exploits in the past. +Another is the modular nature of QEMU device emulation code provides +interface points where the QEMU functions that perform device emulation +can be separated from the QEMU functions that manage the emulation of +guest CPU instructions. The devices emulated in the separate process are +referred to as remote devices. + +QEMU device emulation +~~~~~~~~~~~~~~~~~~~~~ + +QEMU uses an object oriented SW architecture for device emulation code. +Configured objects are all compiled into the QEMU binary, then objects +are instantiated by name when used by the guest VM. For example, the +code to emulate a device named "foo" is always present in QEMU, but its +instantiation code is only run when the device is included in the target +VM. (e.g., via the QEMU command line as *-device foo*) + +The object model is hierarchical, so device emulation code names its +parent object (such as "pci-device" for a PCI device) and QEMU will +instantiate a parent object before calling the device's instantiation +code. + +Current separation models +~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to separate the device emulation code from the CPU emulation +code, the device object code must run in a different process. There are +a couple of existing QEMU features that can run emulation code +separately from the main QEMU process. These are examined below. + +vhost user model +^^^^^^^^^^^^^^^^ + +Virtio guest device drivers can be connected to vhost user applications +in order to perform their IO operations. This model uses special virtio +device drivers in the guest and vhost user device objects in QEMU, but +once the QEMU vhost user code has configured the vhost user application, +mission-mode IO is performed by the application. The vhost user +application is a daemon process that can be contacted via a known UNIX +domain socket. + +vhost socket +'''''''''''' + +As mentioned above, one of the tasks of the vhost device object within +QEMU is to contact the vhost application and send it configuration +information about this device instance. As part of the configuration +process, the application can also be sent other file descriptors over +the socket, which then can be used by the vhost user application in +various ways, some of which are described below. + +vhost MMIO store acceleration +''''''''''''''''''''''''''''' + +VMs are often run using HW virtualization features via the KVM kernel +driver. This driver allows QEMU to accelerate the emulation of guest CPU +instructions by running the guest in a virtual HW mode. When the guest +executes instructions that cannot be executed by virtual HW mode, +execution returns to the KVM driver so it can inform QEMU to emulate the +instructions in SW. + +One of the events that can cause a return to QEMU is when a guest device +driver accesses an IO location. QEMU then dispatches the memory +operation to the corresponding QEMU device object. In the case of a +vhost user device, the memory operation would need to be sent over a +socket to the vhost application. This path is accelerated by the QEMU +virtio code by setting up an eventfd file descriptor that the vhost +application can directly receive MMIO store notifications from the KVM +driver, instead of needing them to be sent to the QEMU process first. + +vhost interrupt acceleration +'''''''''''''''''''''''''''' + +Another optimization used by the vhost application is the ability to +directly inject interrupts into the VM via the KVM driver, again, +bypassing the need to send the interrupt back to the QEMU process first. +The QEMU virtio setup code configures the KVM driver with an eventfd +that triggers the device interrupt in the guest when the eventfd is +written. This irqfd file descriptor is then passed to the vhost user +application program. + +vhost access to guest memory +'''''''''''''''''''''''''''' + +The vhost application is also allowed to directly access guest memory, +instead of needing to send the data as messages to QEMU. This is also +done with file descriptors sent to the vhost user application by QEMU. +These descriptors can be passed to ``mmap()`` by the vhost application +to map the guest address space into the vhost application. + +IOMMUs introduce another level of complexity, since the address given to +the guest virtio device to DMA to or from is not a guest physical +address. This case is handled by having vhost code within QEMU register +as a listener for IOMMU mapping changes. The vhost application maintains +a cache of IOMMMU translations: sending translation requests back to +QEMU on cache misses, and in turn receiving flush requests from QEMU +when mappings are purged. + +applicability to device separation +'''''''''''''''''''''''''''''''''' + +Much of the vhost model can be re-used by separated device emulation. In +particular, the ideas of using a socket between QEMU and the device +emulation application, using a file descriptor to inject interrupts into +the VM via KVM, and allowing the application to ``mmap()`` the guest +should be re used. + +There are, however, some notable differences between how a vhost +application works and the needs of separated device emulation. The most +basic is that vhost uses custom virtio device drivers which always +trigger IO with MMIO stores. A separated device emulation model must +work with existing IO device models and guest device drivers. MMIO loads +break vhost store acceleration since they are synchronous - guest +progress cannot continue until the load has been emulated. By contrast, +stores are asynchronous, the guest can continue after the store event +has been sent to the vhost application. + +Another difference is that in the vhost user model, a single daemon can +support multiple QEMU instances. This is contrary to the security regime +desired, in which the emulation application should only be allowed to +access the files or devices the VM it's running on behalf of can access. +#### qemu-io model + +Qemu-io is a test harness used to test changes to the QEMU block backend +object code. (e.g., the code that implements disk images for disk driver +emulation) Qemu-io is not a device emulation application per se, but it +does compile the QEMU block objects into a separate binary from the main +QEMU one. This could be useful for disk device emulation, since its +emulation applications will need to include the QEMU block objects. + +New separation model based on proxy objects +------------------------------------------- + +A different model based on proxy objects in the QEMU program +communicating with remote emulation programs could provide separation +while minimizing the changes needed to the device emulation code. The +rest of this section is a discussion of how a proxy object model would +work. + +Remote emulation processes +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The remote emulation process will run the QEMU object hierarchy without +modification. The device emulation objects will be also be based on the +QEMU code, because for anything but the simplest device, it would not be +a tractable to re-implement both the object model and the many device +backends that QEMU has. + +The processes will communicate with the QEMU process over UNIX domain +sockets. The processes can be executed either as standalone processes, +or be executed by QEMU. In both cases, the host backends the emulation +processes will provide are specified on its command line, as they would +be for QEMU. For example: + +:: + + disk-proc -blockdev driver=file,node-name=file0,filename=disk-file0 \ + -blockdev driver=qcow2,node-name=drive0,file=file0 + +would indicate process *disk-proc* uses a qcow2 emulated disk named +*file0* as its backend. + +Emulation processes may emulate more than one guest controller. A common +configuration might be to put all controllers of the same device class +(e.g., disk, network, etc.) in a single process, so that all backends of +the same type can be managed by a single QMP monitor. + +communication with QEMU +^^^^^^^^^^^^^^^^^^^^^^^ + +The first argument to the remote emulation process will be a Unix domain +socket that connects with the Proxy object. This is a required argument. + +:: + + disk-proc <socket number> <backend list> + +remote process QMP monitor +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Remote emulation processes can be monitored via QMP, similar to QEMU +itself. The QMP monitor socket is specified the same as for a QEMU +process: + +:: + + disk-proc -qmp unix:/tmp/disk-mon,server + +can be monitored over the UNIX socket path */tmp/disk-mon*. + +QEMU command line +~~~~~~~~~~~~~~~~~ + +Each remote device emulated in a remote process on the host is +represented as a *-device* of type *pci-proxy-dev*. A socket +sub-option to this option specifies the Unix socket that connects +to the remote process. An *id* sub-option is required, and it should +be the same id as used in the remote process. + +:: + + qemu-system-x86_64 ... -device pci-proxy-dev,id=lsi0,socket=3 + +can be used to add a device emulated in a remote process + + +QEMU management of remote processes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +QEMU is not aware of the type of type of the remote PCI device. It is +a pass through device as far as QEMU is concerned. + +communication with emulation process +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +primary channel +''''''''''''''' + +The primary channel (referred to as com in the code) is used to bootstrap +the remote process. It is also used to pass on device-agnostic commands +like reset. + +per-device channels +''''''''''''''''''' + +Each remote device communicates with QEMU using a dedicated communication +channel. The proxy object sets up this channel using the primary +channel during its initialization. + +QEMU device proxy objects +~~~~~~~~~~~~~~~~~~~~~~~~~ + +QEMU has an object model based on sub-classes inherited from the +"object" super-class. The sub-classes that are of interest here are the +"device" and "bus" sub-classes whose child sub-classes make up the +device tree of a QEMU emulated system. + +The proxy object model will use device proxy objects to replace the +device emulation code within the QEMU process. These objects will live +in the same place in the object and bus hierarchies as the objects they +replace. i.e., the proxy object for an LSI SCSI controller will be a +sub-class of the "pci-device" class, and will have the same PCI bus +parent and the same SCSI bus child objects as the LSI controller object +it replaces. + +It is worth noting that the same proxy object is used to mediate with +all types of remote PCI devices. + +object initialization +^^^^^^^^^^^^^^^^^^^^^ + +The Proxy device objects are initialized in the exact same manner in +which any other QEMU device would be initialized. + +In addition, the Proxy objects perform the following two tasks: +- Parses the "socket" sub option and connects to the remote process +using this channel +- Uses the "id" sub-option to connect to the emulated device on the +separate process + +class\_init +''''''''''' + +The ``class_init()`` method of a proxy object will, in general behave +similarly to the object it replaces, including setting any static +properties and methods needed by the proxy. + +instance\_init / realize +'''''''''''''''''''''''' + +The ``instance_init()`` and ``realize()`` functions would only need to +perform tasks related to being a proxy, such are registering its own +MMIO handlers, or creating a child bus that other proxy devices can be +attached to later. + +Other tasks will be device-specific. For example, PCI device objects +will initialize the PCI config space in order to make a valid PCI device +tree within the QEMU process. + +address space registration +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Most devices are driven by guest device driver accesses to IO addresses +or ports. The QEMU device emulation code uses QEMU's memory region +function calls (such as ``memory_region_init_io()``) to add callback +functions that QEMU will invoke when the guest accesses the device's +areas of the IO address space. When a guest driver does access the +device, the VM will exit HW virtualization mode and return to QEMU, +which will then lookup and execute the corresponding callback function. + +A proxy object would need to mirror the memory region calls the actual +device emulator would perform in its initialization code, but with its +own callbacks. When invoked by QEMU as a result of a guest IO operation, +they will forward the operation to the device emulation process. + +PCI config space +^^^^^^^^^^^^^^^^ + +PCI devices also have a configuration space that can be accessed by the +guest driver. Guest accesses to this space is not handled by the device +emulation object, but by its PCI parent object. Much of this space is +read-only, but certain registers (especially BAR and MSI-related ones) +need to be propagated to the emulation process. + +PCI parent proxy +'''''''''''''''' + +One way to propagate guest PCI config accesses is to create a +"pci-device-proxy" class that can serve as the parent of a PCI device +proxy object. This class's parent would be "pci-device" and it would +override the PCI parent's ``config_read()`` and ``config_write()`` +methods with ones that forward these operations to the emulation +program. + +interrupt receipt +^^^^^^^^^^^^^^^^^ + +A proxy for a device that generates interrupts will need to create a +socket to receive interrupt indications from the emulation process. An +incoming interrupt indication would then be sent up to its bus parent to +be injected into the guest. For example, a PCI device object may use +``pci_set_irq()``. + +live migration +^^^^^^^^^^^^^^ + +The proxy will register to save and restore any *vmstate* it needs over +a live migration event. The device proxy does not need to manage the +remote device's *vmstate*; that will be handled by the remote process +proxy (see below). + +QEMU remote device operation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generic device operations, such as DMA, will be performed by the remote +process proxy by sending messages to the remote process. + +DMA operations +^^^^^^^^^^^^^^ + +DMA operations would be handled much like vhost applications do. One of +the initial messages sent to the emulation process is a guest memory +table. Each entry in this table consists of a file descriptor and size +that the emulation process can ``mmap()`` to directly access guest +memory, similar to ``vhost_user_set_mem_table()``. Note guest memory +must be backed by file descriptors, such as when QEMU is given the +*-mem-path* command line option. + +IOMMU operations +^^^^^^^^^^^^^^^^ + +When the emulated system includes an IOMMU, the remote process proxy in +QEMU will need to create a socket for IOMMU requests from the emulation +process. It will handle those requests with an +``address_space_get_iotlb_entry()`` call. In order to handle IOMMU +unmaps, the remote process proxy will also register as a listener on the +device's DMA address space. When an IOMMU memory region is created +within the DMA address space, an IOMMU notifier for unmaps will be added +to the memory region that will forward unmaps to the emulation process +over the IOMMU socket. + +device hot-plug via QMP +^^^^^^^^^^^^^^^^^^^^^^^ + +An QMP "device\_add" command can add a device emulated by a remote +process. It will also have "rid" option to the command, just as the +*-device* command line option does. The remote process may either be one +started at QEMU startup, or be one added by the "add-process" QMP +command described above. In either case, the remote process proxy will +forward the new device's JSON description to the corresponding emulation +process. + +live migration +^^^^^^^^^^^^^^ + +The remote process proxy will also register for live migration +notifications with ``vmstate_register()``. When called to save state, +the proxy will send the remote process a secondary socket file +descriptor to save the remote process's device *vmstate* over. The +incoming byte stream length and data will be saved as the proxy's +*vmstate*. When the proxy is resumed on its new host, this *vmstate* +will be extracted, and a secondary socket file descriptor will be sent +to the new remote process through which it receives the *vmstate* in +order to restore the devices there. + +device emulation in remote process +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The parts of QEMU that the emulation program will need include the +object model; the memory emulation objects; the device emulation objects +of the targeted device, and any dependent devices; and, the device's +backends. It will also need code to setup the machine environment, +handle requests from the QEMU process, and route machine-level requests +(such as interrupts or IOMMU mappings) back to the QEMU process. + +initialization +^^^^^^^^^^^^^^ + +The process initialization sequence will follow the same sequence +followed by QEMU. It will first initialize the backend objects, then +device emulation objects. The JSON descriptions sent by the QEMU process +will drive which objects need to be created. + +- address spaces + +Before the device objects are created, the initial address spaces and +memory regions must be configured with ``memory_map_init()``. This +creates a RAM memory region object (*system\_memory*) and an IO memory +region object (*system\_io*). + +- RAM + +RAM memory region creation will follow how ``pc_memory_init()`` creates +them, but must use ``memory_region_init_ram_from_fd()`` instead of +``memory_region_allocate_system_memory()``. The file descriptors needed +will be supplied by the guest memory table from above. Those RAM regions +would then be added to the *system\_memory* memory region with +``memory_region_add_subregion()``. + +- PCI + +IO initialization will be driven by the JSON descriptions sent from the +QEMU process. For a PCI device, a PCI bus will need to be created with +``pci_root_bus_new()``, and a PCI memory region will need to be created +and added to the *system\_memory* memory region with +``memory_region_add_subregion_overlap()``. The overlap version is +required for architectures where PCI memory overlaps with RAM memory. + +MMIO handling +^^^^^^^^^^^^^ + +The device emulation objects will use ``memory_region_init_io()`` to +install their MMIO handlers, and ``pci_register_bar()`` to associate +those handlers with a PCI BAR, as they do within QEMU currently. + +In order to use ``address_space_rw()`` in the emulation process to +handle MMIO requests from QEMU, the PCI physical addresses must be the +same in the QEMU process and the device emulation process. In order to +accomplish that, guest BAR programming must also be forwarded from QEMU +to the emulation process. + +interrupt injection +^^^^^^^^^^^^^^^^^^^ + +When device emulation wants to inject an interrupt into the VM, the +request climbs the device's bus object hierarchy until the point where a +bus object knows how to signal the interrupt to the guest. The details +depend on the type of interrupt being raised. + +- PCI pin interrupts + +On x86 systems, there is an emulated IOAPIC object attached to the root +PCI bus object, and the root PCI object forwards interrupt requests to +it. The IOAPIC object, in turn, calls the KVM driver to inject the +corresponding interrupt into the VM. The simplest way to handle this in +an emulation process would be to setup the root PCI bus driver (via +``pci_bus_irqs()``) to send a interrupt request back to the QEMU +process, and have the device proxy object reflect it up the PCI tree +there. + +- PCI MSI/X interrupts + +PCI MSI/X interrupts are implemented in HW as DMA writes to a +CPU-specific PCI address. In QEMU on x86, a KVM APIC object receives +these DMA writes, then calls into the KVM driver to inject the interrupt +into the VM. A simple emulation process implementation would be to send +the MSI DMA address from QEMU as a message at initialization, then +install an address space handler at that address which forwards the MSI +message back to QEMU. + +DMA operations +^^^^^^^^^^^^^^ + +When a emulation object wants to DMA into or out of guest memory, it +first must use dma\_memory\_map() to convert the DMA address to a local +virtual address. The emulation process memory region objects setup above +will be used to translate the DMA address to a local virtual address the +device emulation code can access. + +IOMMU +^^^^^ + +When an IOMMU is in use in QEMU, DMA translation uses IOMMU memory +regions to translate the DMA address to a guest physical address before +that physical address can be translated to a local virtual address. The +emulation process will need similar functionality. + +- IOTLB cache + +The emulation process will maintain a cache of recent IOMMU translations +(the IOTLB). When the translate() callback of an IOMMU memory region is +invoked, the IOTLB cache will be searched for an entry that will map the +DMA address to a guest PA. On a cache miss, a message will be sent back +to QEMU requesting the corresponding translation entry, which be both be +used to return a guest address and be added to the cache. + +- IOTLB purge + +The IOMMU emulation will also need to act on unmap requests from QEMU. +These happen when the guest IOMMU driver purges an entry from the +guest's translation table. + +live migration +^^^^^^^^^^^^^^ + +When a remote process receives a live migration indication from QEMU, it +will set up a channel using the received file descriptor with +``qio_channel_socket_new_fd()``. This channel will be used to create a +*QEMUfile* that can be passed to ``qemu_save_device_state()`` to send +the process's device state back to QEMU. This method will be reversed on +restore - the channel will be passed to ``qemu_loadvm_state()`` to +restore the device state. + +Accelerating device emulation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The messages that are required to be sent between QEMU and the emulation +process can add considerable latency to IO operations. The optimizations +described below attempt to ameliorate this effect by allowing the +emulation process to communicate directly with the kernel KVM driver. +The KVM file descriptors created would be passed to the emulation process +via initialization messages, much like the guest memory table is done. +#### MMIO acceleration + +Vhost user applications can receive guest virtio driver stores directly +from KVM. The issue with the eventfd mechanism used by vhost user is +that it does not pass any data with the event indication, so it cannot +handle guest loads or guest stores that carry store data. This concept +could, however, be expanded to cover more cases. + +The expanded idea would require a new type of KVM device: +*KVM\_DEV\_TYPE\_USER*. This device has two file descriptors: a master +descriptor that QEMU can use for configuration, and a slave descriptor +that the emulation process can use to receive MMIO notifications. QEMU +would create both descriptors using the KVM driver, and pass the slave +descriptor to the emulation process via an initialization message. + +data structures +^^^^^^^^^^^^^^^ + +- guest physical range + +The guest physical range structure describes the address range that a +device will respond to. It includes the base and length of the range, as +well as which bus the range resides on (e.g., on an x86machine, it can +specify whether the range refers to memory or IO addresses). + +A device can have multiple physical address ranges it responds to (e.g., +a PCI device can have multiple BARs), so the structure will also include +an enumerated identifier to specify which of the device's ranges is +being referred to. + ++--------+----------------------------+ +| Name | Description | ++========+============================+ +| addr | range base address | ++--------+----------------------------+ +| len | range length | ++--------+----------------------------+ +| bus | addr type (memory or IO) | ++--------+----------------------------+ +| id | range ID (e.g., PCI BAR) | ++--------+----------------------------+ + +- MMIO request structure + +This structure describes an MMIO operation. It includes which guest +physical range the MMIO was within, the offset within that range, the +MMIO type (e.g., load or store), and its length and data. It also +includes a sequence number that can be used to reply to the MMIO, and +the CPU that issued the MMIO. + ++----------+------------------------+ +| Name | Description | ++==========+========================+ +| rid | range MMIO is within | ++----------+------------------------+ +| offset | offset withing *rid* | ++----------+------------------------+ +| type | e.g., load or store | ++----------+------------------------+ +| len | MMIO length | ++----------+------------------------+ +| data | store data | ++----------+------------------------+ +| seq | sequence ID | ++----------+------------------------+ + +- MMIO request queues + +MMIO request queues are FIFO arrays of MMIO request structures. There +are two queues: pending queue is for MMIOs that haven't been read by the +emulation program, and the sent queue is for MMIOs that haven't been +acknowledged. The main use of the second queue is to validate MMIO +replies from the emulation program. + +- scoreboard + +Each CPU in the VM is emulated in QEMU by a separate thread, so multiple +MMIOs may be waiting to be consumed by an emulation program and multiple +threads may be waiting for MMIO replies. The scoreboard would contain a +wait queue and sequence number for the per-CPU threads, allowing them to +be individually woken when the MMIO reply is received from the emulation +program. It also tracks the number of posted MMIO stores to the device +that haven't been replied to, in order to satisfy the PCI constraint +that a load to a device will not complete until all previous stores to +that device have been completed. + +- device shadow memory + +Some MMIO loads do not have device side-effects. These MMIOs can be +completed without sending a MMIO request to the emulation program if the +emulation program shares a shadow image of the device's memory image +with the KVM driver. + +The emulation program will ask the KVM driver to allocate memory for the +shadow image, and will then use ``mmap()`` to directly access it. The +emulation program can control KVM access to the shadow image by sending +KVM an access map telling it which areas of the image have no +side-effects (and can be completed immediately), and which require a +MMIO request to the emulation program. The access map can also inform +the KVM drive which size accesses are allowed to the image. + +master descriptor +^^^^^^^^^^^^^^^^^ + +The master descriptor is used by QEMU to configure the new KVM device. +The descriptor would be returned by the KVM driver when QEMU issues a +*KVM\_CREATE\_DEVICE* ``ioctl()`` with a *KVM\_DEV\_TYPE\_USER* type. + +KVM\_DEV\_TYPE\_USER device ops + + +The *KVM\_DEV\_TYPE\_USER* operations vector will be registered by a +``kvm_register_device_ops()`` call when the KVM system in initialized by +``kvm_init()``. These device ops are called by the KVM driver when QEMU +executes certain ``ioctl()`` operations on its KVM file descriptor. They +include: + +- create + +This routine is called when QEMU issues a *KVM\_CREATE\_DEVICE* +``ioctl()`` on its per-VM file descriptor. It will allocate and +initialize a KVM user device specific data structure, and assign the +*kvm\_device* private field to it. + +- ioctl + +This routine is invoked when QEMU issues an ``ioctl()`` on the master +descriptor. The ``ioctl()`` commands supported are defined by the KVM +device type. *KVM\_DEV\_TYPE\_USER* ones will need several commands: + +*KVM\_DEV\_USER\_SLAVE\_FD* creates the slave file descriptor that will +be passed to the device emulation program. Only one slave can be created +by each master descriptor. The file operations performed by this +descriptor are described below. + +The *KVM\_DEV\_USER\_PA\_RANGE* command configures a guest physical +address range that the slave descriptor will receive MMIO notifications +for. The range is specified by a guest physical range structure +argument. For buses that assign addresses to devices dynamically, this +command can be executed while the guest is running, such as the case +when a guest changes a device's PCI BAR registers. + +*KVM\_DEV\_USER\_PA\_RANGE* will use ``kvm_io_bus_register_dev()`` to +register *kvm\_io\_device\_ops* callbacks to be invoked when the guest +performs a MMIO operation within the range. When a range is changed, +``kvm_io_bus_unregister_dev()`` is used to remove the previous +instantiation. + +*KVM\_DEV\_USER\_TIMEOUT* will configure a timeout value that specifies +how long KVM will wait for the emulation process to respond to a MMIO +indication. + +- destroy + +This routine is called when the VM instance is destroyed. It will need +to destroy the slave descriptor; and free any memory allocated by the +driver, as well as the *kvm\_device* structure itself. + +slave descriptor +^^^^^^^^^^^^^^^^ + +The slave descriptor will have its own file operations vector, which +responds to system calls on the descriptor performed by the device +emulation program. + +- read + +A read returns any pending MMIO requests from the KVM driver as MMIO +request structures. Multiple structures can be returned if there are +multiple MMIO operations pending. The MMIO requests are moved from the +pending queue to the sent queue, and if there are threads waiting for +space in the pending to add new MMIO operations, they will be woken +here. + +- write + +A write also consists of a set of MMIO requests. They are compared to +the MMIO requests in the sent queue. Matches are removed from the sent +queue, and any threads waiting for the reply are woken. If a store is +removed, then the number of posted stores in the per-CPU scoreboard is +decremented. When the number is zero, and a non side-effect load was +waiting for posted stores to complete, the load is continued. + +- ioctl + +There are several ioctl()s that can be performed on the slave +descriptor. + +A *KVM\_DEV\_USER\_SHADOW\_SIZE* ``ioctl()`` causes the KVM driver to +allocate memory for the shadow image. This memory can later be +``mmap()``\ ed by the emulation process to share the emulation's view of +device memory with the KVM driver. + +A *KVM\_DEV\_USER\_SHADOW\_CTRL* ``ioctl()`` controls access to the +shadow image. It will send the KVM driver a shadow control map, which +specifies which areas of the image can complete guest loads without +sending the load request to the emulation program. It will also specify +the size of load operations that are allowed. + +- poll + +An emulation program will use the ``poll()`` call with a *POLLIN* flag +to determine if there are MMIO requests waiting to be read. It will +return if the pending MMIO request queue is not empty. + +- mmap + +This call allows the emulation program to directly access the shadow +image allocated by the KVM driver. As device emulation updates device +memory, changes with no side-effects will be reflected in the shadow, +and the KVM driver can satisfy guest loads from the shadow image without +needing to wait for the emulation program. + +kvm\_io\_device ops +^^^^^^^^^^^^^^^^^^^ + +Each KVM per-CPU thread can handle MMIO operation on behalf of the guest +VM. KVM will use the MMIO's guest physical address to search for a +matching *kvm\_io\_device* to see if the MMIO can be handled by the KVM +driver instead of exiting back to QEMU. If a match is found, the +corresponding callback will be invoked. + +- read + +This callback is invoked when the guest performs a load to the device. +Loads with side-effects must be handled synchronously, with the KVM +driver putting the QEMU thread to sleep waiting for the emulation +process reply before re-starting the guest. Loads that do not have +side-effects may be optimized by satisfying them from the shadow image, +if there are no outstanding stores to the device by this CPU. PCI memory +ordering demands that a load cannot complete before all older stores to +the same device have been completed. + +- write + +Stores can be handled asynchronously unless the pending MMIO request +queue is full. In this case, the QEMU thread must sleep waiting for +space in the queue. Stores will increment the number of posted stores in +the per-CPU scoreboard, in order to implement the PCI ordering +constraint above. + +interrupt acceleration +^^^^^^^^^^^^^^^^^^^^^^ + +This performance optimization would work much like a vhost user +application does, where the QEMU process sets up *eventfds* that cause +the device's corresponding interrupt to be triggered by the KVM driver. +These irq file descriptors are sent to the emulation process at +initialization, and are used when the emulation code raises a device +interrupt. + +intx acceleration +''''''''''''''''' + +Traditional PCI pin interrupts are level based, so, in addition to an +irq file descriptor, a re-sampling file descriptor needs to be sent to +the emulation program. This second file descriptor allows multiple +devices sharing an irq to be notified when the interrupt has been +acknowledged by the guest, so they can re-trigger the interrupt if their +device has not de-asserted its interrupt. + +intx irq descriptor + + +The irq descriptors are created by the proxy object +``using event_notifier_init()`` to create the irq and re-sampling +*eventds*, and ``kvm_vm_ioctl(KVM_IRQFD)`` to bind them to an interrupt. +The interrupt route can be found with +``pci_device_route_intx_to_irq()``. + +intx routing changes + + +Intx routing can be changed when the guest programs the APIC the device +pin is connected to. The proxy object in QEMU will use +``pci_device_set_intx_routing_notifier()`` to be informed of any guest +changes to the route. This handler will broadly follow the VFIO +interrupt logic to change the route: de-assigning the existing irq +descriptor from its route, then assigning it the new route. (see +``vfio_intx_update()``) + +MSI/X acceleration +'''''''''''''''''' + +MSI/X interrupts are sent as DMA transactions to the host. The interrupt +data contains a vector that is programmed by the guest, A device may have +multiple MSI interrupts associated with it, so multiple irq descriptors +may need to be sent to the emulation program. + +MSI/X irq descriptor + + +This case will also follow the VFIO example. For each MSI/X interrupt, +an *eventfd* is created, a virtual interrupt is allocated by +``kvm_irqchip_add_msi_route()``, and the virtual interrupt is bound to +the eventfd with ``kvm_irqchip_add_irqfd_notifier()``. + +MSI/X config space changes + + +The guest may dynamically update several MSI-related tables in the +device's PCI config space. These include per-MSI interrupt enables and +vector data. Additionally, MSIX tables exist in device memory space, not +config space. Much like the BAR case above, the proxy object must look +at guest config space programming to keep the MSI interrupt state +consistent between QEMU and the emulation program. + +-------------- + +Disaggregated CPU emulation +--------------------------- + +After IO services have been disaggregated, a second phase would be to +separate a process to handle CPU instruction emulation from the main +QEMU control function. There are no object separation points for this +code, so the first task would be to create one. + +Host access controls +-------------------- + +Separating QEMU relies on the host OS's access restriction mechanisms to +enforce that the differing processes can only access the objects they +are entitled to. There are a couple types of mechanisms usually provided +by general purpose OSs. + +Discretionary access control +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Discretionary access control allows each user to control who can access +their files. In Linux, this type of control is usually too coarse for +QEMU separation, since it only provides three separate access controls: +one for the same user ID, the second for users IDs with the same group +ID, and the third for all other user IDs. Each device instance would +need a separate user ID to provide access control, which is likely to be +unwieldy for dynamically created VMs. + +Mandatory access control +~~~~~~~~~~~~~~~~~~~~~~~~ + +Mandatory access control allows the OS to add an additional set of +controls on top of discretionary access for the OS to control. It also +adds other attributes to processes and files such as types, roles, and +categories, and can establish rules for how processes and files can +interact. + +Type enforcement +^^^^^^^^^^^^^^^^ + +Type enforcement assigns a *type* attribute to processes and files, and +allows rules to be written on what operations a process with a given +type can perform on a file with a given type. QEMU separation could take +advantage of type enforcement by running the emulation processes with +different types, both from the main QEMU process, and from the emulation +processes of different classes of devices. + +For example, guest disk images and disk emulation processes could have +types separate from the main QEMU process and non-disk emulation +processes, and the type rules could prevent processes other than disk +emulation ones from accessing guest disk images. Similarly, network +emulation processes can have a type separate from the main QEMU process +and non-network emulation process, and only that type can access the +host tun/tap device used to provide guest networking. + +Category enforcement +^^^^^^^^^^^^^^^^^^^^ + +Category enforcement assigns a set of numbers within a given range to +the process or file. The process is granted access to the file if the +process's set is a superset of the file's set. This enforcement can be +used to separate multiple instances of devices in the same class. + +For example, if there are multiple disk devices provides to a guest, +each device emulation process could be provisioned with a separate +category. The different device emulation processes would not be able to +access each other's backing disk images. + +Alternatively, categories could be used in lieu of the type enforcement +scheme described above. In this scenario, different categories would be +used to prevent device emulation processes in different classes from +accessing resources assigned to other classes. -- 2.29.2
From: Elena Ufimtseva <elena.ufimtseva@oracle.com> Adds documentation explaining the command-line arguments needed to use multi-process. Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 49f757a84e5dd6fae14b22544897d1124c5fdbad.1611938319.git.jag.raman@oracle.com [Move orphan docs/multi-process.rst document into docs/system/ and add it to index.rst to prevent Sphinx "document isn't included in any toctree" error. --Stefan] Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 1 + docs/system/index.rst | 1 + docs/system/multi-process.rst | 64 +++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 docs/system/multi-process.rst diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ M: Jagannathan Raman <jag.raman@oracle.com> M: John G Johnson <john.g.johnson@oracle.com> S: Maintained F: docs/devel/multi-process.rst +F: docs/system/multi-process.rst Build and test automation ------------------------- diff --git a/docs/system/index.rst b/docs/system/index.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -XXX,XX +XXX,XX @@ Contents: pr-manager targets security + multi-process deprecated removed-features build-platforms diff --git a/docs/system/multi-process.rst b/docs/system/multi-process.rst new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/docs/system/multi-process.rst @@ -XXX,XX +XXX,XX @@ +Multi-process QEMU +================== + +This document describes how to configure and use multi-process qemu. +For the design document refer to docs/devel/qemu-multiprocess. + +1) Configuration +---------------- + +multi-process is enabled by default for targets that enable KVM + + +2) Usage +-------- + +Multi-process QEMU requires an orchestrator to launch. + +Following is a description of command-line used to launch mpqemu. + +* Orchestrator: + + - The Orchestrator creates a unix socketpair + + - It launches the remote process and passes one of the + sockets to it via command-line. + + - It then launches QEMU and specifies the other socket as an option + to the Proxy device object + +* Remote Process: + + - QEMU can enter remote process mode by using the "remote" machine + option. + + - The orchestrator creates a "remote-object" with details about + the device and the file descriptor for the device + + - The remaining options are no different from how one launches QEMU with + devices. + + - Example command-line for the remote process is as follows: + + /usr/bin/qemu-system-x86_64 \ + -machine x-remote \ + -device lsi53c895a,id=lsi0 \ + -drive id=drive_image2,file=/build/ol7-nvme-test-1.qcow2 \ + -device scsi-hd,id=drive2,drive=drive_image2,bus=lsi0.0,scsi-id=0 \ + -object x-remote-object,id=robj1,devid=lsi1,fd=4, + +* QEMU: + + - Since parts of the RAM are shared between QEMU & remote process, a + memory-backend-memfd is required to facilitate this, as follows: + + -object memory-backend-memfd,id=mem,size=2G + + - A "x-pci-proxy-dev" device is created for each of the PCI devices emulated + in the remote process. A "socket" sub-option specifies the other end of + unix channel created by orchestrator. The "id" sub-option must be specified + and should be the same as the "id" specified for the remote PCI device + + - Example commandline for QEMU is as follows: + + -device x-pci-proxy-dev,id=lsi0,socket=3 -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> Allow RAM MemoryRegion to be created from an offset in a file, instead of allocating at offset of 0 by default. This is needed to synchronize RAM between QEMU & remote process. Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 609996697ad8617e3b01df38accc5c208c24d74e.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- include/exec/memory.h | 2 ++ include/exec/ram_addr.h | 4 ++-- include/qemu/mmap-alloc.h | 4 +++- backends/hostmem-memfd.c | 2 +- hw/misc/ivshmem.c | 3 ++- softmmu/memory.c | 3 ++- softmmu/physmem.c | 12 +++++++----- util/mmap-alloc.c | 8 +++++--- util/oslib-posix.c | 2 +- 9 files changed, 25 insertions(+), 15 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_from_file(MemoryRegion *mr, * @size: size of the region. * @share: %true if memory must be mmaped with the MAP_SHARED flag * @fd: the fd to mmap. + * @offset: offset within the file referenced by fd * @errp: pointer to Error*, to store an error if it happens. * * Note that this function does not do anything to cause the data in the @@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_from_fd(MemoryRegion *mr, uint64_t size, bool share, int fd, + ram_addr_t offset, Error **errp); #endif diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index XXXXXXX..XXXXXXX 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -XXX,XX +XXX,XX @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr, uint32_t ram_flags, const char *mem_path, bool readonly, Error **errp); RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, - uint32_t ram_flags, int fd, bool readonly, - Error **errp); + uint32_t ram_flags, int fd, off_t offset, + bool readonly, Error **errp); RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, MemoryRegion *mr, Error **errp); diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h index XXXXXXX..XXXXXXX 100644 --- a/include/qemu/mmap-alloc.h +++ b/include/qemu/mmap-alloc.h @@ -XXX,XX +XXX,XX @@ size_t qemu_mempath_getpagesize(const char *mem_path); * @readonly: true for a read-only mapping, false for read/write. * @shared: map has RAM_SHARED flag. * @is_pmem: map has RAM_PMEM flag. + * @map_offset: map starts at offset of map_offset from the start of fd * * Return: * On success, return a pointer to the mapped area. @@ -XXX,XX +XXX,XX @@ void *qemu_ram_mmap(int fd, size_t align, bool readonly, bool shared, - bool is_pmem); + bool is_pmem, + off_t map_offset); void qemu_ram_munmap(int fd, void *ptr, size_t size); diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index XXXXXXX..XXXXXXX 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -XXX,XX +XXX,XX @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) name = host_memory_backend_get_name(backend); memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend), name, backend->size, - backend->share, fd, errp); + backend->share, fd, 0, errp); g_free(name); } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index XXXXXXX..XXXXXXX 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -XXX,XX +XXX,XX @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp) /* mmap the region and map into the BAR2 */ memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s), - "ivshmem.bar2", size, true, fd, &local_err); + "ivshmem.bar2", size, true, fd, 0, + &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/softmmu/memory.c b/softmmu/memory.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_from_fd(MemoryRegion *mr, uint64_t size, bool share, int fd, + ram_addr_t offset, Error **errp) { Error *err = NULL; @@ -XXX,XX +XXX,XX @@ void memory_region_init_ram_from_fd(MemoryRegion *mr, mr->destructor = memory_region_destructor_ram; mr->ram_block = qemu_ram_alloc_from_fd(size, mr, share ? RAM_SHARED : 0, - fd, false, &err); + fd, offset, false, &err); if (err) { mr->size = int128_zero(); object_unparent(OBJECT(mr)); diff --git a/softmmu/physmem.c b/softmmu/physmem.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -XXX,XX +XXX,XX @@ static void *file_ram_alloc(RAMBlock *block, int fd, bool readonly, bool truncate, + off_t offset, Error **errp) { void *area; @@ -XXX,XX +XXX,XX @@ static void *file_ram_alloc(RAMBlock *block, } area = qemu_ram_mmap(fd, memory, block->mr->align, readonly, - block->flags & RAM_SHARED, block->flags & RAM_PMEM); + block->flags & RAM_SHARED, block->flags & RAM_PMEM, + offset); if (area == MAP_FAILED) { error_setg_errno(errp, errno, "unable to map backing store for guest RAM"); @@ -XXX,XX +XXX,XX @@ static void ram_block_add(RAMBlock *new_block, Error **errp, bool shared) #ifdef CONFIG_POSIX RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, - uint32_t ram_flags, int fd, bool readonly, - Error **errp) + uint32_t ram_flags, int fd, off_t offset, + bool readonly, Error **errp) { RAMBlock *new_block; Error *local_err = NULL; @@ -XXX,XX +XXX,XX @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, new_block->max_length = size; new_block->flags = ram_flags; new_block->host = file_ram_alloc(new_block, size, fd, readonly, - !file_size, errp); + !file_size, offset, errp); if (!new_block->host) { g_free(new_block); return NULL; @@ -XXX,XX +XXX,XX @@ RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr, return NULL; } - block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, readonly, errp); + block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, 0, readonly, errp); if (!block) { if (created) { unlink(mem_path); diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c index XXXXXXX..XXXXXXX 100644 --- a/util/mmap-alloc.c +++ b/util/mmap-alloc.c @@ -XXX,XX +XXX,XX @@ void *qemu_ram_mmap(int fd, size_t align, bool readonly, bool shared, - bool is_pmem) + bool is_pmem, + off_t map_offset) { int prot; int flags; @@ -XXX,XX +XXX,XX @@ void *qemu_ram_mmap(int fd, prot = PROT_READ | (readonly ? 0 : PROT_WRITE); - ptr = mmap(guardptr + offset, size, prot, flags | map_sync_flags, fd, 0); + ptr = mmap(guardptr + offset, size, prot, + flags | map_sync_flags, fd, map_offset); if (ptr == MAP_FAILED && map_sync_flags) { if (errno == ENOTSUP) { @@ -XXX,XX +XXX,XX @@ void *qemu_ram_mmap(int fd, * if map failed with MAP_SHARED_VALIDATE | MAP_SYNC, * we will remove these flags to handle compatibility. */ - ptr = mmap(guardptr + offset, size, prot, flags, fd, 0); + ptr = mmap(guardptr + offset, size, prot, flags, fd, map_offset); } if (ptr == MAP_FAILED) { diff --git a/util/oslib-posix.c b/util/oslib-posix.c index XXXXXXX..XXXXXXX 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -XXX,XX +XXX,XX @@ void *qemu_memalign(size_t alignment, size_t size) void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared) { size_t align = QEMU_VMALLOC_ALIGN; - void *ptr = qemu_ram_mmap(-1, size, align, false, shared, false); + void *ptr = qemu_ram_mmap(-1, size, align, false, shared, false, 0); if (ptr == MAP_FAILED) { return NULL; -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> Add configuration options to enable or disable multiprocess QEMU code Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 6cc37253e35418ebd7b675a31a3df6e3c7a12dc1.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- configure | 10 ++++++++++ meson.build | 4 +++- Kconfig.host | 4 ++++ hw/Kconfig | 1 + hw/remote/Kconfig | 3 +++ 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 hw/remote/Kconfig diff --git a/configure b/configure index XXXXXXX..XXXXXXX 100755 --- a/configure +++ b/configure @@ -XXX,XX +XXX,XX @@ skip_meson=no gettext="auto" fuse="auto" fuse_lseek="auto" +multiprocess="no" malloc_trim="auto" @@ -XXX,XX +XXX,XX @@ Linux) linux="yes" linux_user="yes" vhost_user=${default_feature:-yes} + multiprocess=${default_feature:-yes} ;; esac @@ -XXX,XX +XXX,XX @@ for opt do ;; --disable-fuse-lseek) fuse_lseek="disabled" ;; + --enable-multiprocess) multiprocess="yes" + ;; + --disable-multiprocess) multiprocess="no" + ;; *) echo "ERROR: unknown option $opt" echo "Try '$0 --help' for more information" @@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available libdaxctl libdaxctl support fuse FUSE block device export fuse-lseek SEEK_HOLE/SEEK_DATA support for FUSE exports + multiprocess Multiprocess QEMU support NOTE: The object files are built at the place where configure is launched EOF @@ -XXX,XX +XXX,XX @@ fi if test "$have_mlockall" = "yes" ; then echo "HAVE_MLOCKALL=y" >> $config_host_mak fi +if test "$multiprocess" = "yes" ; then + echo "CONFIG_MULTIPROCESS_ALLOWED=y" >> $config_host_mak +fi if test "$fuzzing" = "yes" ; then # If LIB_FUZZING_ENGINE is set, assume we are running on OSS-Fuzz, and the # needed CFLAGS have already been provided diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ host_kconfig = \ ('CONFIG_VHOST_KERNEL' in config_host ? ['CONFIG_VHOST_KERNEL=y'] : []) + \ (have_virtfs ? ['CONFIG_VIRTFS=y'] : []) + \ ('CONFIG_LINUX' in config_host ? ['CONFIG_LINUX=y'] : []) + \ - ('CONFIG_PVRDMA' in config_host ? ['CONFIG_PVRDMA=y'] : []) + ('CONFIG_PVRDMA' in config_host ? ['CONFIG_PVRDMA=y'] : []) + \ + ('CONFIG_MULTIPROCESS_ALLOWED' in config_host ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ] @@ -XXX,XX +XXX,XX @@ summary_info += {'libpmem support': config_host.has_key('CONFIG_LIBPMEM')} summary_info += {'libdaxctl support': config_host.has_key('CONFIG_LIBDAXCTL')} summary_info += {'libudev': libudev.found()} summary_info += {'FUSE lseek': fuse_lseek.found()} +summary_info += {'Multiprocess QEMU': config_host.has_key('CONFIG_MULTIPROCESS_ALLOWED')} summary(summary_info, bool_yn: true, section: 'Dependencies') if not supported_cpus.contains(cpu) diff --git a/Kconfig.host b/Kconfig.host index XXXXXXX..XXXXXXX 100644 --- a/Kconfig.host +++ b/Kconfig.host @@ -XXX,XX +XXX,XX @@ config VIRTFS config PVRDMA bool + +config MULTIPROCESS_ALLOWED + bool + imply MULTIPROCESS diff --git a/hw/Kconfig b/hw/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -XXX,XX +XXX,XX @@ source pci-host/Kconfig source pcmcia/Kconfig source pci/Kconfig source rdma/Kconfig +source remote/Kconfig source rtc/Kconfig source scsi/Kconfig source sd/Kconfig diff --git a/hw/remote/Kconfig b/hw/remote/Kconfig new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/Kconfig @@ -XXX,XX +XXX,XX @@ +config MULTIPROCESS + bool + depends on PCI && KVM -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> PCI host bridge is setup for the remote device process. It is implemented using remote-pcihost object. It is an extension of the PCI host bridge setup by QEMU. Remote-pcihost configures a PCI bus which could be used by the remote PCI device to latch on to. Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 0871ba857abb2eafacde07e7fe66a3f12415bfb2.1611938319.git.jag.raman@oracle.com [Added PCI_EXPRESS condition in hw/remote/Kconfig since remote-pcihost needs PCIe. This solves "make check" failure on s390x. Fix suggested by Philippe Mathieu-Daudé <philmd@redhat.com> and Thomas Huth <thuth@redhat.com>. --Stefan] Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 2 + include/hw/pci-host/remote.h | 29 ++++++++++++++ hw/pci-host/remote.c | 75 ++++++++++++++++++++++++++++++++++++ hw/pci-host/Kconfig | 3 ++ hw/pci-host/meson.build | 1 + hw/remote/Kconfig | 3 +- 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 include/hw/pci-host/remote.h create mode 100644 hw/pci-host/remote.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ M: John G Johnson <john.g.johnson@oracle.com> S: Maintained F: docs/devel/multi-process.rst F: docs/system/multi-process.rst +F: hw/pci-host/remote.c +F: include/hw/pci-host/remote.h Build and test automation ------------------------- diff --git a/include/hw/pci-host/remote.h b/include/hw/pci-host/remote.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/pci-host/remote.h @@ -XXX,XX +XXX,XX @@ +/* + * PCI Host for remote device + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef REMOTE_PCIHOST_H +#define REMOTE_PCIHOST_H + +#include "exec/memory.h" +#include "hw/pci/pcie_host.h" + +#define TYPE_REMOTE_PCIHOST "remote-pcihost" +OBJECT_DECLARE_SIMPLE_TYPE(RemotePCIHost, REMOTE_PCIHOST) + +struct RemotePCIHost { + /*< private >*/ + PCIExpressHost parent_obj; + /*< public >*/ + + MemoryRegion *mr_pci_mem; + MemoryRegion *mr_sys_io; +}; + +#endif diff --git a/hw/pci-host/remote.c b/hw/pci-host/remote.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/pci-host/remote.c @@ -XXX,XX +XXX,XX @@ +/* + * Remote PCI host device + * + * Unlike PCI host devices that model physical hardware, the purpose + * of this PCI host is to host multi-process QEMU devices. + * + * Multi-process QEMU extends the PCI host of a QEMU machine into a + * remote process. Any PCI device attached to the remote process is + * visible in the QEMU guest. This allows existing QEMU device models + * to be reused in the remote process. + * + * This PCI host is purely a container for PCI devices. It's fake in the + * sense that the guest never sees this PCI host and has no way of + * accessing it. Its job is just to provide the environment that QEMU + * PCI device models need when running in a remote process. + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pcie_host.h" +#include "hw/qdev-properties.h" +#include "hw/pci-host/remote.h" +#include "exec/memory.h" + +static const char *remote_pcihost_root_bus_path(PCIHostState *host_bridge, + PCIBus *rootbus) +{ + return "0000:00"; +} + +static void remote_pcihost_realize(DeviceState *dev, Error **errp) +{ + PCIHostState *pci = PCI_HOST_BRIDGE(dev); + RemotePCIHost *s = REMOTE_PCIHOST(dev); + + pci->bus = pci_root_bus_new(DEVICE(s), "remote-pci", + s->mr_pci_mem, s->mr_sys_io, + 0, TYPE_PCIE_BUS); +} + +static void remote_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); + + hc->root_bus_path = remote_pcihost_root_bus_path; + dc->realize = remote_pcihost_realize; + + dc->user_creatable = false; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->fw_name = "pci"; +} + +static const TypeInfo remote_pcihost_info = { + .name = TYPE_REMOTE_PCIHOST, + .parent = TYPE_PCIE_HOST_BRIDGE, + .instance_size = sizeof(RemotePCIHost), + .class_init = remote_pcihost_class_init, +}; + +static void remote_pcihost_register(void) +{ + type_register_static(&remote_pcihost_info); +} + +type_init(remote_pcihost_register) diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -XXX,XX +XXX,XX @@ config PCI_POWERNV select PCI_EXPRESS select MSI_NONBROKEN select PCIE_PORT + +config REMOTE_PCIHOST + bool diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -XXX,XX +XXX,XX @@ pci_ss.add(when: 'CONFIG_PCI_EXPRESS_XILINX', if_true: files('xilinx-pcie.c')) pci_ss.add(when: 'CONFIG_PCI_I440FX', if_true: files('i440fx.c')) pci_ss.add(when: 'CONFIG_PCI_SABRE', if_true: files('sabre.c')) pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c')) +pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c')) # PPC devices pci_ss.add(when: 'CONFIG_PREP_PCI', if_true: files('prep.c')) diff --git a/hw/remote/Kconfig b/hw/remote/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/Kconfig +++ b/hw/remote/Kconfig @@ -XXX,XX +XXX,XX @@ config MULTIPROCESS bool - depends on PCI && KVM + depends on PCI && PCI_EXPRESS && KVM + select REMOTE_PCIHOST -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> x-remote-machine object sets up various subsystems of the remote device process. Instantiate PCI host bridge object and initialize RAM, IO & PCI memory regions. Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: c537f38d17f90453ca610c6b70cf3480274e0ba1.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 2 ++ include/hw/pci-host/remote.h | 1 + include/hw/remote/machine.h | 27 ++++++++++++++ hw/remote/machine.c | 70 ++++++++++++++++++++++++++++++++++++ hw/meson.build | 1 + hw/remote/meson.build | 5 +++ 6 files changed, 106 insertions(+) create mode 100644 include/hw/remote/machine.h create mode 100644 hw/remote/machine.c create mode 100644 hw/remote/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: docs/devel/multi-process.rst F: docs/system/multi-process.rst F: hw/pci-host/remote.c F: include/hw/pci-host/remote.h +F: hw/remote/machine.c +F: include/hw/remote/machine.h Build and test automation ------------------------- diff --git a/include/hw/pci-host/remote.h b/include/hw/pci-host/remote.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/pci-host/remote.h +++ b/include/hw/pci-host/remote.h @@ -XXX,XX +XXX,XX @@ struct RemotePCIHost { MemoryRegion *mr_pci_mem; MemoryRegion *mr_sys_io; + MemoryRegion *mr_sys_mem; }; #endif diff --git a/include/hw/remote/machine.h b/include/hw/remote/machine.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/remote/machine.h @@ -XXX,XX +XXX,XX @@ +/* + * Remote machine configuration + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef REMOTE_MACHINE_H +#define REMOTE_MACHINE_H + +#include "qom/object.h" +#include "hw/boards.h" +#include "hw/pci-host/remote.h" + +struct RemoteMachineState { + MachineState parent_obj; + + RemotePCIHost *host; +}; + +#define TYPE_REMOTE_MACHINE "x-remote-machine" +OBJECT_DECLARE_SIMPLE_TYPE(RemoteMachineState, REMOTE_MACHINE) + +#endif diff --git a/hw/remote/machine.c b/hw/remote/machine.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/machine.c @@ -XXX,XX +XXX,XX @@ +/* + * Machine for remote device + * + * This machine type is used by the remote device process in multi-process + * QEMU. QEMU device models depend on parent busses, interrupt controllers, + * memory regions, etc. The remote machine type offers this environment so + * that QEMU device models can be used as remote devices. + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "hw/remote/machine.h" +#include "exec/address-spaces.h" +#include "exec/memory.h" +#include "qapi/error.h" + +static void remote_machine_init(MachineState *machine) +{ + MemoryRegion *system_memory, *system_io, *pci_memory; + RemoteMachineState *s = REMOTE_MACHINE(machine); + RemotePCIHost *rem_host; + + system_memory = get_system_memory(); + system_io = get_system_io(); + + pci_memory = g_new(MemoryRegion, 1); + memory_region_init(pci_memory, NULL, "pci", UINT64_MAX); + + rem_host = REMOTE_PCIHOST(qdev_new(TYPE_REMOTE_PCIHOST)); + + rem_host->mr_pci_mem = pci_memory; + rem_host->mr_sys_mem = system_memory; + rem_host->mr_sys_io = system_io; + + s->host = rem_host; + + object_property_add_child(OBJECT(s), "remote-pcihost", OBJECT(rem_host)); + memory_region_add_subregion_overlap(system_memory, 0x0, pci_memory, -1); + + qdev_realize(DEVICE(rem_host), sysbus_get_default(), &error_fatal); +} + +static void remote_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->init = remote_machine_init; + mc->desc = "Experimental remote machine"; +} + +static const TypeInfo remote_machine = { + .name = TYPE_REMOTE_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(RemoteMachineState), + .class_init = remote_machine_class_init, +}; + +static void remote_machine_register_types(void) +{ + type_register_static(&remote_machine); +} + +type_init(remote_machine_register_types); diff --git a/hw/meson.build b/hw/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -XXX,XX +XXX,XX @@ subdir('moxie') subdir('nios2') subdir('openrisc') subdir('ppc') +subdir('remote') subdir('riscv') subdir('rx') subdir('s390x') diff --git a/hw/remote/meson.build b/hw/remote/meson.build new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/meson.build @@ -XXX,XX +XXX,XX @@ +remote_ss = ss.source_set() + +remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c')) + +softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss) -- 2.29.2
From: Elena Ufimtseva <elena.ufimtseva@oracle.com> Adds qio_channel_writev_full_all() to transmit both data and FDs. Refactors existing code to use this helper. Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Acked-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: 480fbf1fe4152495d60596c9b665124549b426a5.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- include/io/channel.h | 25 +++++++++++++++++++++++++ io/channel.c | 15 ++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/io/channel.h b/include/io/channel.h index XXXXXXX..XXXXXXX 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -XXX,XX +XXX,XX @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc, IOHandler *io_write, void *opaque); +/** + * qio_channel_writev_full_all: + * @ioc: the channel object + * @iov: the array of memory regions to write data from + * @niov: the length of the @iov array + * @fds: an array of file handles to send + * @nfds: number of file handles in @fds + * @errp: pointer to a NULL-initialized error object + * + * + * Behaves like qio_channel_writev_full but will attempt + * to send all data passed (file handles and memory regions). + * The function will wait for all requested data + * to be written, yielding from the current coroutine + * if required. + * + * Returns: 0 if all bytes were written, or -1 on error + */ + +int qio_channel_writev_full_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds, size_t nfds, + Error **errp); + #endif /* QIO_CHANNEL_H */ diff --git a/io/channel.c b/io/channel.c index XXXXXXX..XXXXXXX 100644 --- a/io/channel.c +++ b/io/channel.c @@ -XXX,XX +XXX,XX @@ int qio_channel_writev_all(QIOChannel *ioc, const struct iovec *iov, size_t niov, Error **errp) +{ + return qio_channel_writev_full_all(ioc, iov, niov, NULL, 0, errp); +} + +int qio_channel_writev_full_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int *fds, size_t nfds, + Error **errp) { int ret = -1; struct iovec *local_iov = g_new(struct iovec, niov); @@ -XXX,XX +XXX,XX @@ int qio_channel_writev_all(QIOChannel *ioc, while (nlocal_iov > 0) { ssize_t len; - len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp); + len = qio_channel_writev_full(ioc, local_iov, nlocal_iov, fds, nfds, + errp); if (len == QIO_CHANNEL_ERR_BLOCK) { if (qemu_in_coroutine()) { qio_channel_yield(ioc, G_IO_OUT); @@ -XXX,XX +XXX,XX @@ int qio_channel_writev_all(QIOChannel *ioc, } iov_discard_front(&local_iov, &nlocal_iov, len); + + fds = NULL; + nfds = 0; } ret = 0; -- 2.29.2
From: Elena Ufimtseva <elena.ufimtseva@oracle.com> Adds qio_channel_readv_full_all_eof() and qio_channel_readv_full_all() to read both data and FDs. Refactors existing code to use these helpers. Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Acked-by: Daniel P. Berrangé <berrange@redhat.com> Message-id: b059c4cc0fb741e794d644c144cc21372cad877d.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- include/io/channel.h | 53 +++++++++++++++++++++++ io/channel.c | 101 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 134 insertions(+), 20 deletions(-) diff --git a/include/io/channel.h b/include/io/channel.h index XXXXXXX..XXXXXXX 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -XXX,XX +XXX,XX @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc, IOHandler *io_write, void *opaque); +/** + * qio_channel_readv_full_all_eof: + * @ioc: the channel object + * @iov: the array of memory regions to read data to + * @niov: the length of the @iov array + * @fds: an array of file handles to read + * @nfds: number of file handles in @fds + * @errp: pointer to a NULL-initialized error object + * + * + * Performs same function as qio_channel_readv_all_eof. + * Additionally, attempts to read file descriptors shared + * over the channel. The function will wait for all + * requested data to be read, yielding from the current + * coroutine if required. data refers to both file + * descriptors and the iovs. + * + * Returns: 1 if all bytes were read, 0 if end-of-file + * occurs without data, or -1 on error + */ + +int qio_channel_readv_full_all_eof(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, size_t *nfds, + Error **errp); + +/** + * qio_channel_readv_full_all: + * @ioc: the channel object + * @iov: the array of memory regions to read data to + * @niov: the length of the @iov array + * @fds: an array of file handles to read + * @nfds: number of file handles in @fds + * @errp: pointer to a NULL-initialized error object + * + * + * Performs same function as qio_channel_readv_all_eof. + * Additionally, attempts to read file descriptors shared + * over the channel. The function will wait for all + * requested data to be read, yielding from the current + * coroutine if required. data refers to both file + * descriptors and the iovs. + * + * Returns: 0 if all bytes were read, or -1 on error + */ + +int qio_channel_readv_full_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, size_t *nfds, + Error **errp); + /** * qio_channel_writev_full_all: * @ioc: the channel object diff --git a/io/channel.c b/io/channel.c index XXXXXXX..XXXXXXX 100644 --- a/io/channel.c +++ b/io/channel.c @@ -XXX,XX +XXX,XX @@ int qio_channel_readv_all_eof(QIOChannel *ioc, const struct iovec *iov, size_t niov, Error **errp) +{ + return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, errp); +} + +int qio_channel_readv_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + Error **errp) +{ + return qio_channel_readv_full_all(ioc, iov, niov, NULL, NULL, errp); +} + +int qio_channel_readv_full_all_eof(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, size_t *nfds, + Error **errp) { int ret = -1; struct iovec *local_iov = g_new(struct iovec, niov); struct iovec *local_iov_head = local_iov; unsigned int nlocal_iov = niov; + int **local_fds = fds; + size_t *local_nfds = nfds; bool partial = false; + if (nfds) { + *nfds = 0; + } + + if (fds) { + *fds = NULL; + } + nlocal_iov = iov_copy(local_iov, nlocal_iov, iov, niov, 0, iov_size(iov, niov)); - while (nlocal_iov > 0) { + while ((nlocal_iov > 0) || local_fds) { ssize_t len; - len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp); + len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds, + local_nfds, errp); if (len == QIO_CHANNEL_ERR_BLOCK) { if (qemu_in_coroutine()) { qio_channel_yield(ioc, G_IO_IN); @@ -XXX,XX +XXX,XX @@ int qio_channel_readv_all_eof(QIOChannel *ioc, qio_channel_wait(ioc, G_IO_IN); } continue; - } else if (len < 0) { - goto cleanup; - } else if (len == 0) { - if (partial) { - error_setg(errp, - "Unexpected end-of-file before all bytes were read"); - } else { + } + + if (len == 0) { + if (local_nfds && *local_nfds) { + /* + * Got some FDs, but no data yet. This isn't an EOF + * scenario (yet), so carry on to try to read data + * on next loop iteration + */ + goto next_iter; + } else if (!partial) { + /* No fds and no data - EOF before any data read */ ret = 0; + goto cleanup; + } else { + len = -1; + error_setg(errp, + "Unexpected end-of-file before all data were read"); + /* Fallthrough into len < 0 handling */ + } + } + + if (len < 0) { + /* Close any FDs we previously received */ + if (nfds && fds) { + size_t i; + for (i = 0; i < (*nfds); i++) { + close((*fds)[i]); + } + g_free(*fds); + *fds = NULL; + *nfds = 0; } goto cleanup; } + if (nlocal_iov) { + iov_discard_front(&local_iov, &nlocal_iov, len); + } + +next_iter: partial = true; - iov_discard_front(&local_iov, &nlocal_iov, len); + local_fds = NULL; + local_nfds = NULL; } ret = 1; @@ -XXX,XX +XXX,XX @@ int qio_channel_readv_all_eof(QIOChannel *ioc, return ret; } -int qio_channel_readv_all(QIOChannel *ioc, - const struct iovec *iov, - size_t niov, - Error **errp) +int qio_channel_readv_full_all(QIOChannel *ioc, + const struct iovec *iov, + size_t niov, + int **fds, size_t *nfds, + Error **errp) { - int ret = qio_channel_readv_all_eof(ioc, iov, niov, errp); + int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp); if (ret == 0) { - ret = -1; - error_setg(errp, - "Unexpected end-of-file before all bytes were read"); - } else if (ret == 1) { - ret = 0; + error_prepend(errp, + "Unexpected end-of-file before all data were read."); + return -1; } + if (ret == 1) { + return 0; + } + return ret; } -- 2.29.2
From: Elena Ufimtseva <elena.ufimtseva@oracle.com> Defines MPQemuMsg, which is the message that is sent to the remote process. This message is sent over QIOChannel and is used to command the remote process to perform various tasks. Define transmission functions used by proxy and by remote. Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 56ca8bcf95195b2b195b08f6b9565b6d7410bce5.1611938319.git.jag.raman@oracle.com [Replace struct iovec send[2] = {0} with {} to make clang happy as suggested by Peter Maydell <peter.maydell@linaro.org>. --Stefan] Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 2 + meson.build | 1 + hw/remote/trace.h | 1 + include/hw/remote/mpqemu-link.h | 63 ++++++++++ include/sysemu/iothread.h | 6 + hw/remote/mpqemu-link.c | 205 ++++++++++++++++++++++++++++++++ iothread.c | 6 + hw/remote/meson.build | 1 + hw/remote/trace-events | 4 + 9 files changed, 289 insertions(+) create mode 100644 hw/remote/trace.h create mode 100644 include/hw/remote/mpqemu-link.h create mode 100644 hw/remote/mpqemu-link.c create mode 100644 hw/remote/trace-events diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/pci-host/remote.c F: include/hw/pci-host/remote.h F: hw/remote/machine.c F: include/hw/remote/machine.h +F: hw/remote/mpqemu-link.c +F: include/hw/remote/mpqemu-link.h Build and test automation ------------------------- diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ if have_system 'net', 'softmmu', 'ui', + 'hw/remote', ] endif if have_system or have_user diff --git a/hw/remote/trace.h b/hw/remote/trace.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/trace.h @@ -0,0 +1 @@ +#include "trace/trace-hw_remote.h" diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/remote/mpqemu-link.h @@ -XXX,XX +XXX,XX @@ +/* + * Communication channel between QEMU and remote device process + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef MPQEMU_LINK_H +#define MPQEMU_LINK_H + +#include "qom/object.h" +#include "qemu/thread.h" +#include "io/channel.h" + +#define REMOTE_MAX_FDS 8 + +#define MPQEMU_MSG_HDR_SIZE offsetof(MPQemuMsg, data.u64) + +/** + * MPQemuCmd: + * + * MPQemuCmd enum type to specify the command to be executed on the remote + * device. + * + * This uses a private protocol between QEMU and the remote process. vfio-user + * protocol would supersede this in the future. + * + */ +typedef enum { + MPQEMU_CMD_MAX, +} MPQemuCmd; + +/** + * MPQemuMsg: + * @cmd: The remote command + * @size: Size of the data to be shared + * @data: Structured data + * @fds: File descriptors to be shared with remote device + * + * MPQemuMsg Format of the message sent to the remote device from QEMU. + * + */ +typedef struct { + int cmd; + size_t size; + + union { + uint64_t u64; + } data; + + int fds[REMOTE_MAX_FDS]; + int num_fds; +} MPQemuMsg; + +bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp); +bool mpqemu_msg_recv(MPQemuMsg *msg, QIOChannel *ioc, Error **errp); + +bool mpqemu_msg_valid(MPQemuMsg *msg); + +#endif diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h index XXXXXXX..XXXXXXX 100644 --- a/include/sysemu/iothread.h +++ b/include/sysemu/iothread.h @@ -XXX,XX +XXX,XX @@ IOThread *iothread_create(const char *id, Error **errp); void iothread_stop(IOThread *iothread); void iothread_destroy(IOThread *iothread); +/* + * Returns true if executing withing IOThread context, + * false otherwise. + */ +bool qemu_in_iothread(void); + #endif /* IOTHREAD_H */ diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/mpqemu-link.c @@ -XXX,XX +XXX,XX @@ +/* + * Communication channel between QEMU and remote device process + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "qemu/module.h" +#include "hw/remote/mpqemu-link.h" +#include "qapi/error.h" +#include "qemu/iov.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" +#include "io/channel.h" +#include "sysemu/iothread.h" +#include "trace.h" + +/* + * Send message over the ioc QIOChannel. + * This function is safe to call from: + * - main loop in co-routine context. Will block the main loop if not in + * co-routine context; + * - vCPU thread with no co-routine context and if the channel is not part + * of the main loop handling; + * - IOThread within co-routine context, outside of co-routine context + * will block IOThread; + * Returns true if no errors were encountered, false otherwise. + */ +bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp) +{ + ERRP_GUARD(); + bool iolock = qemu_mutex_iothread_locked(); + bool iothread = qemu_in_iothread(); + struct iovec send[2] = {}; + int *fds = NULL; + size_t nfds = 0; + bool ret = false; + + send[0].iov_base = msg; + send[0].iov_len = MPQEMU_MSG_HDR_SIZE; + + send[1].iov_base = (void *)&msg->data; + send[1].iov_len = msg->size; + + if (msg->num_fds) { + nfds = msg->num_fds; + fds = msg->fds; + } + + /* + * Dont use in IOThread out of co-routine context as + * it will block IOThread. + */ + assert(qemu_in_coroutine() || !iothread); + + /* + * Skip unlocking/locking iothread lock when the IOThread is running + * in co-routine context. Co-routine context is asserted above + * for IOThread case. + * Also skip lock handling while in a co-routine in the main context. + */ + if (iolock && !iothread && !qemu_in_coroutine()) { + qemu_mutex_unlock_iothread(); + } + + if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send), + fds, nfds, errp)) { + ret = true; + } else { + trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds); + } + + if (iolock && !iothread && !qemu_in_coroutine()) { + /* See above comment why skip locking here. */ + qemu_mutex_lock_iothread(); + } + + return ret; +} + +/* + * Read message from the ioc QIOChannel. + * This function is safe to call from: + * - From main loop in co-routine context. Will block the main loop if not in + * co-routine context; + * - From vCPU thread with no co-routine context and if the channel is not part + * of the main loop handling; + * - From IOThread within co-routine context, outside of co-routine context + * will block IOThread; + */ +static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, size_t len, int **fds, + size_t *nfds, Error **errp) +{ + ERRP_GUARD(); + struct iovec iov = { .iov_base = buf, .iov_len = len }; + bool iolock = qemu_mutex_iothread_locked(); + bool iothread = qemu_in_iothread(); + int ret = -1; + + /* + * Dont use in IOThread out of co-routine context as + * it will block IOThread. + */ + assert(qemu_in_coroutine() || !iothread); + + if (iolock && !iothread && !qemu_in_coroutine()) { + qemu_mutex_unlock_iothread(); + } + + ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, errp); + + if (iolock && !iothread && !qemu_in_coroutine()) { + qemu_mutex_lock_iothread(); + } + + return (ret <= 0) ? ret : iov.iov_len; +} + +bool mpqemu_msg_recv(MPQemuMsg *msg, QIOChannel *ioc, Error **errp) +{ + ERRP_GUARD(); + g_autofree int *fds = NULL; + size_t nfds = 0; + ssize_t len; + bool ret = false; + + len = mpqemu_read(ioc, msg, MPQEMU_MSG_HDR_SIZE, &fds, &nfds, errp); + if (len <= 0) { + goto fail; + } else if (len != MPQEMU_MSG_HDR_SIZE) { + error_setg(errp, "Message header corrupted"); + goto fail; + } + + if (msg->size > sizeof(msg->data)) { + error_setg(errp, "Invalid size for message"); + goto fail; + } + + if (!msg->size) { + goto copy_fds; + } + + len = mpqemu_read(ioc, &msg->data, msg->size, NULL, NULL, errp); + if (len <= 0) { + goto fail; + } + if (len != msg->size) { + error_setg(errp, "Unable to read full message"); + goto fail; + } + +copy_fds: + msg->num_fds = nfds; + if (nfds > G_N_ELEMENTS(msg->fds)) { + error_setg(errp, + "Overflow error: received %zu fds, more than max of %d fds", + nfds, REMOTE_MAX_FDS); + goto fail; + } + if (nfds) { + memcpy(msg->fds, fds, nfds * sizeof(int)); + } + + ret = true; + +fail: + if (*errp) { + trace_mpqemu_recv_io_error(msg->cmd, msg->size, nfds); + } + while (*errp && nfds) { + close(fds[nfds - 1]); + nfds--; + } + + return ret; +} + +bool mpqemu_msg_valid(MPQemuMsg *msg) +{ + if (msg->cmd >= MPQEMU_CMD_MAX && msg->cmd < 0) { + return false; + } + + /* Verify FDs. */ + if (msg->num_fds >= REMOTE_MAX_FDS) { + return false; + } + + if (msg->num_fds > 0) { + for (int i = 0; i < msg->num_fds; i++) { + if (fcntl(msg->fds[i], F_GETFL) == -1) { + return false; + } + } + } + + return true; +} diff --git a/iothread.c b/iothread.c index XXXXXXX..XXXXXXX 100644 --- a/iothread.c +++ b/iothread.c @@ -XXX,XX +XXX,XX @@ IOThread *iothread_by_id(const char *id) { return IOTHREAD(object_resolve_path_type(id, TYPE_IOTHREAD, NULL)); } + +bool qemu_in_iothread(void) +{ + return qemu_get_current_aio_context() == qemu_get_aio_context() ? + false : true; +} diff --git a/hw/remote/meson.build b/hw/remote/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -XXX,XX +XXX,XX @@ remote_ss = ss.source_set() remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c')) +remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c')) softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss) diff --git a/hw/remote/trace-events b/hw/remote/trace-events new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/trace-events @@ -XXX,XX +XXX,XX @@ +# multi-process trace events + +mpqemu_send_io_error(int cmd, int size, int nfds) "send command %d size %d, %d file descriptors to remote process" +mpqemu_recv_io_error(int cmd, int size, int nfds) "failed to receive %d size %d, %d file descriptors to remote process" -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> Initializes the message handler function in the remote process. It is called whenever there's an event pending on QIOChannel that registers this function. Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 99d38d8b93753a6409ac2340e858858cda59ab1b.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 1 + include/hw/remote/machine.h | 9 ++++++ hw/remote/message.c | 57 +++++++++++++++++++++++++++++++++++++ hw/remote/meson.build | 1 + 4 files changed, 68 insertions(+) create mode 100644 hw/remote/message.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/remote/machine.c F: include/hw/remote/machine.h F: hw/remote/mpqemu-link.c F: include/hw/remote/mpqemu-link.h +F: hw/remote/message.c Build and test automation ------------------------- diff --git a/include/hw/remote/machine.h b/include/hw/remote/machine.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/machine.h +++ b/include/hw/remote/machine.h @@ -XXX,XX +XXX,XX @@ #include "qom/object.h" #include "hw/boards.h" #include "hw/pci-host/remote.h" +#include "io/channel.h" struct RemoteMachineState { MachineState parent_obj; @@ -XXX,XX +XXX,XX @@ struct RemoteMachineState { RemotePCIHost *host; }; +/* Used to pass to co-routine device and ioc. */ +typedef struct RemoteCommDev { + PCIDevice *dev; + QIOChannel *ioc; +} RemoteCommDev; + #define TYPE_REMOTE_MACHINE "x-remote-machine" OBJECT_DECLARE_SIMPLE_TYPE(RemoteMachineState, REMOTE_MACHINE) +void coroutine_fn mpqemu_remote_msg_loop_co(void *data); + #endif diff --git a/hw/remote/message.c b/hw/remote/message.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/message.c @@ -XXX,XX +XXX,XX @@ +/* + * Copyright © 2020, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL-v2, version 2 or later. + * + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "hw/remote/machine.h" +#include "io/channel.h" +#include "hw/remote/mpqemu-link.h" +#include "qapi/error.h" +#include "sysemu/runstate.h" + +void coroutine_fn mpqemu_remote_msg_loop_co(void *data) +{ + g_autofree RemoteCommDev *com = (RemoteCommDev *)data; + PCIDevice *pci_dev = NULL; + Error *local_err = NULL; + + assert(com->ioc); + + pci_dev = com->dev; + for (; !local_err;) { + MPQemuMsg msg = {0}; + + if (!mpqemu_msg_recv(&msg, com->ioc, &local_err)) { + break; + } + + if (!mpqemu_msg_valid(&msg)) { + error_setg(&local_err, "Received invalid message from proxy" + "in remote process pid="FMT_pid"", + getpid()); + break; + } + + switch (msg.cmd) { + default: + error_setg(&local_err, + "Unknown command (%d) received for device %s" + " (pid="FMT_pid")", + msg.cmd, DEVICE(pci_dev)->id, getpid()); + } + } + + if (local_err) { + error_report_err(local_err); + qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR); + } else { + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + } +} diff --git a/hw/remote/meson.build b/hw/remote/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -XXX,XX +XXX,XX @@ remote_ss = ss.source_set() remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c')) +remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c')) softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss) -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> Associate the file descriptor for a PCIDevice in remote process with DeviceState object. Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: f405a2ed5d7518b87bea7c59cfdf334d67e5ee51.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 1 + hw/remote/remote-obj.c | 203 +++++++++++++++++++++++++++++++++++++++++ hw/remote/meson.build | 1 + 3 files changed, 205 insertions(+) create mode 100644 hw/remote/remote-obj.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: include/hw/remote/machine.h F: hw/remote/mpqemu-link.c F: include/hw/remote/mpqemu-link.h F: hw/remote/message.c +F: hw/remote/remote-obj.c Build and test automation ------------------------- diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/remote-obj.c @@ -XXX,XX +XXX,XX @@ +/* + * Copyright © 2020, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL-v2, version 2 or later. + * + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "qemu/error-report.h" +#include "qemu/notify.h" +#include "qom/object_interfaces.h" +#include "hw/qdev-core.h" +#include "io/channel.h" +#include "hw/qdev-core.h" +#include "hw/remote/machine.h" +#include "io/channel-util.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/pci/pci.h" +#include "qemu/sockets.h" +#include "monitor/monitor.h" + +#define TYPE_REMOTE_OBJECT "x-remote-object" +OBJECT_DECLARE_TYPE(RemoteObject, RemoteObjectClass, REMOTE_OBJECT) + +struct RemoteObjectClass { + ObjectClass parent_class; + + unsigned int nr_devs; + unsigned int max_devs; +}; + +struct RemoteObject { + /* private */ + Object parent; + + Notifier machine_done; + + int32_t fd; + char *devid; + + QIOChannel *ioc; + + DeviceState *dev; + DeviceListener listener; +}; + +static void remote_object_set_fd(Object *obj, const char *str, Error **errp) +{ + RemoteObject *o = REMOTE_OBJECT(obj); + int fd = -1; + + fd = monitor_fd_param(monitor_cur(), str, errp); + if (fd == -1) { + error_prepend(errp, "Could not parse remote object fd %s:", str); + return; + } + + if (!fd_is_socket(fd)) { + error_setg(errp, "File descriptor '%s' is not a socket", str); + close(fd); + return; + } + + o->fd = fd; +} + +static void remote_object_set_devid(Object *obj, const char *str, Error **errp) +{ + RemoteObject *o = REMOTE_OBJECT(obj); + + g_free(o->devid); + + o->devid = g_strdup(str); +} + +static void remote_object_unrealize_listener(DeviceListener *listener, + DeviceState *dev) +{ + RemoteObject *o = container_of(listener, RemoteObject, listener); + + if (o->dev == dev) { + object_unref(OBJECT(o)); + } +} + +static void remote_object_machine_done(Notifier *notifier, void *data) +{ + RemoteObject *o = container_of(notifier, RemoteObject, machine_done); + DeviceState *dev = NULL; + QIOChannel *ioc = NULL; + Coroutine *co = NULL; + RemoteCommDev *comdev = NULL; + Error *err = NULL; + + dev = qdev_find_recursive(sysbus_get_default(), o->devid); + if (!dev || !object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { + error_report("%s is not a PCI device", o->devid); + return; + } + + ioc = qio_channel_new_fd(o->fd, &err); + if (!ioc) { + error_report_err(err); + return; + } + qio_channel_set_blocking(ioc, false, NULL); + + o->dev = dev; + + o->listener.unrealize = remote_object_unrealize_listener; + device_listener_register(&o->listener); + + /* co-routine should free this. */ + comdev = g_new0(RemoteCommDev, 1); + *comdev = (RemoteCommDev) { + .ioc = ioc, + .dev = PCI_DEVICE(dev), + }; + + co = qemu_coroutine_create(mpqemu_remote_msg_loop_co, comdev); + qemu_coroutine_enter(co); +} + +static void remote_object_init(Object *obj) +{ + RemoteObjectClass *k = REMOTE_OBJECT_GET_CLASS(obj); + RemoteObject *o = REMOTE_OBJECT(obj); + + if (k->nr_devs >= k->max_devs) { + error_report("Reached maximum number of devices: %u", k->max_devs); + return; + } + + o->ioc = NULL; + o->fd = -1; + o->devid = NULL; + + k->nr_devs++; + + o->machine_done.notify = remote_object_machine_done; + qemu_add_machine_init_done_notifier(&o->machine_done); +} + +static void remote_object_finalize(Object *obj) +{ + RemoteObjectClass *k = REMOTE_OBJECT_GET_CLASS(obj); + RemoteObject *o = REMOTE_OBJECT(obj); + + device_listener_unregister(&o->listener); + + if (o->ioc) { + qio_channel_shutdown(o->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); + qio_channel_close(o->ioc, NULL); + } + + object_unref(OBJECT(o->ioc)); + + k->nr_devs--; + g_free(o->devid); +} + +static void remote_object_class_init(ObjectClass *klass, void *data) +{ + RemoteObjectClass *k = REMOTE_OBJECT_CLASS(klass); + + /* + * Limit number of supported devices to 1. This is done to avoid devices + * from one VM accessing the RAM of another VM. This is done until we + * start using separate address spaces for individual devices. + */ + k->max_devs = 1; + k->nr_devs = 0; + + object_class_property_add_str(klass, "fd", NULL, remote_object_set_fd); + object_class_property_add_str(klass, "devid", NULL, + remote_object_set_devid); +} + +static const TypeInfo remote_object_info = { + .name = TYPE_REMOTE_OBJECT, + .parent = TYPE_OBJECT, + .instance_size = sizeof(RemoteObject), + .instance_init = remote_object_init, + .instance_finalize = remote_object_finalize, + .class_size = sizeof(RemoteObjectClass), + .class_init = remote_object_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void register_types(void) +{ + type_register_static(&remote_object_info); +} + +type_init(register_types); diff --git a/hw/remote/meson.build b/hw/remote/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -XXX,XX +XXX,XX @@ remote_ss = ss.source_set() remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c')) +remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c')) softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss) -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> SyncSysMemMsg message format is defined. It is used to send file descriptors of the RAM regions to remote device. RAM on the remote device is configured with a set of file descriptors. Old RAM regions are deleted and new regions, each with an fd, is added to the RAM. Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 7d2d1831d812e85f681e7a8ab99e032cf4704689.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 2 + include/hw/remote/memory.h | 19 ++++++++++ include/hw/remote/mpqemu-link.h | 10 +++++ hw/remote/memory.c | 65 +++++++++++++++++++++++++++++++++ hw/remote/mpqemu-link.c | 11 ++++++ hw/remote/meson.build | 2 + 6 files changed, 109 insertions(+) create mode 100644 include/hw/remote/memory.h create mode 100644 hw/remote/memory.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/remote/mpqemu-link.c F: include/hw/remote/mpqemu-link.h F: hw/remote/message.c F: hw/remote/remote-obj.c +F: include/hw/remote/memory.h +F: hw/remote/memory.c Build and test automation ------------------------- diff --git a/include/hw/remote/memory.h b/include/hw/remote/memory.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/remote/memory.h @@ -XXX,XX +XXX,XX @@ +/* + * Memory manager for remote device + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef REMOTE_MEMORY_H +#define REMOTE_MEMORY_H + +#include "exec/hwaddr.h" +#include "hw/remote/mpqemu-link.h" + +void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp); + +#endif diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/mpqemu-link.h +++ b/include/hw/remote/mpqemu-link.h @@ -XXX,XX +XXX,XX @@ #include "qom/object.h" #include "qemu/thread.h" #include "io/channel.h" +#include "exec/hwaddr.h" #define REMOTE_MAX_FDS 8 @@ -XXX,XX +XXX,XX @@ * */ typedef enum { + MPQEMU_CMD_SYNC_SYSMEM, MPQEMU_CMD_MAX, } MPQemuCmd; +typedef struct { + hwaddr gpas[REMOTE_MAX_FDS]; + uint64_t sizes[REMOTE_MAX_FDS]; + off_t offsets[REMOTE_MAX_FDS]; +} SyncSysmemMsg; + /** * MPQemuMsg: * @cmd: The remote command @@ -XXX,XX +XXX,XX @@ typedef enum { * MPQemuMsg Format of the message sent to the remote device from QEMU. * */ + typedef struct { int cmd; size_t size; union { uint64_t u64; + SyncSysmemMsg sync_sysmem; } data; int fds[REMOTE_MAX_FDS]; diff --git a/hw/remote/memory.c b/hw/remote/memory.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/memory.c @@ -XXX,XX +XXX,XX @@ +/* + * Memory manager for remote device + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "hw/remote/memory.h" +#include "exec/address-spaces.h" +#include "exec/ram_addr.h" +#include "qapi/error.h" + +static void remote_sysmem_reset(void) +{ + MemoryRegion *sysmem, *subregion, *next; + + sysmem = get_system_memory(); + + QTAILQ_FOREACH_SAFE(subregion, &sysmem->subregions, subregions_link, next) { + if (subregion->ram) { + memory_region_del_subregion(sysmem, subregion); + object_unparent(OBJECT(subregion)); + } + } +} + +void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp) +{ + ERRP_GUARD(); + SyncSysmemMsg *sysmem_info = &msg->data.sync_sysmem; + MemoryRegion *sysmem, *subregion; + static unsigned int suffix; + int region; + + sysmem = get_system_memory(); + + remote_sysmem_reset(); + + for (region = 0; region < msg->num_fds; region++) { + g_autofree char *name; + subregion = g_new(MemoryRegion, 1); + name = g_strdup_printf("remote-mem-%u", suffix++); + memory_region_init_ram_from_fd(subregion, NULL, + name, sysmem_info->sizes[region], + true, msg->fds[region], + sysmem_info->offsets[region], + errp); + + if (*errp) { + g_free(subregion); + remote_sysmem_reset(); + return; + } + + memory_region_add_subregion(sysmem, sysmem_info->gpas[region], + subregion); + + } +} diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -XXX,XX +XXX,XX @@ bool mpqemu_msg_valid(MPQemuMsg *msg) } } + /* Verify message specific fields. */ + switch (msg->cmd) { + case MPQEMU_CMD_SYNC_SYSMEM: + if (msg->num_fds == 0 || msg->size != sizeof(SyncSysmemMsg)) { + return false; + } + break; + default: + break; + } + return true; } diff --git a/hw/remote/meson.build b/hw/remote/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -XXX,XX +XXX,XX @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c')) +specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c')) + softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss) -- 2.29.2
From: Elena Ufimtseva <elena.ufimtseva@oracle.com> Defines a PCI Device proxy object as a child of TYPE_PCI_DEVICE. Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: b5186ebfedf8e557044d09a768846c59230ad3a7.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 2 + include/hw/remote/proxy.h | 33 +++++++++++++ hw/remote/proxy.c | 99 +++++++++++++++++++++++++++++++++++++++ hw/remote/meson.build | 1 + 4 files changed, 135 insertions(+) create mode 100644 include/hw/remote/proxy.h create mode 100644 hw/remote/proxy.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/remote/message.c F: hw/remote/remote-obj.c F: include/hw/remote/memory.h F: hw/remote/memory.c +F: hw/remote/proxy.c +F: include/hw/remote/proxy.h Build and test automation ------------------------- diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/remote/proxy.h @@ -XXX,XX +XXX,XX @@ +/* + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef PROXY_H +#define PROXY_H + +#include "hw/pci/pci.h" +#include "io/channel.h" + +#define TYPE_PCI_PROXY_DEV "x-pci-proxy-dev" +OBJECT_DECLARE_SIMPLE_TYPE(PCIProxyDev, PCI_PROXY_DEV) + +struct PCIProxyDev { + PCIDevice parent_dev; + char *fd; + + /* + * Mutex used to protect the QIOChannel fd from + * the concurrent access by the VCPUs since proxy + * blocks while awaiting for the replies from the + * process remote. + */ + QemuMutex io_mutex; + QIOChannel *ioc; + Error *migration_blocker; +}; + +#endif /* PROXY_H */ diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/proxy.c @@ -XXX,XX +XXX,XX @@ +/* + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "hw/remote/proxy.h" +#include "hw/pci/pci.h" +#include "qapi/error.h" +#include "io/channel-util.h" +#include "hw/qdev-properties.h" +#include "monitor/monitor.h" +#include "migration/blocker.h" +#include "qemu/sockets.h" + +static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) +{ + ERRP_GUARD(); + PCIProxyDev *dev = PCI_PROXY_DEV(device); + int fd; + + if (!dev->fd) { + error_setg(errp, "fd parameter not specified for %s", + DEVICE(device)->id); + return; + } + + fd = monitor_fd_param(monitor_cur(), dev->fd, errp); + if (fd == -1) { + error_prepend(errp, "proxy: unable to parse fd %s: ", dev->fd); + return; + } + + if (!fd_is_socket(fd)) { + error_setg(errp, "proxy: fd %d is not a socket", fd); + close(fd); + return; + } + + dev->ioc = qio_channel_new_fd(fd, errp); + + error_setg(&dev->migration_blocker, "%s does not support migration", + TYPE_PCI_PROXY_DEV); + migrate_add_blocker(dev->migration_blocker, errp); + + qemu_mutex_init(&dev->io_mutex); + qio_channel_set_blocking(dev->ioc, true, NULL); +} + +static void pci_proxy_dev_exit(PCIDevice *pdev) +{ + PCIProxyDev *dev = PCI_PROXY_DEV(pdev); + + if (dev->ioc) { + qio_channel_close(dev->ioc, NULL); + } + + migrate_del_blocker(dev->migration_blocker); + + error_free(dev->migration_blocker); +} + +static Property proxy_properties[] = { + DEFINE_PROP_STRING("fd", PCIProxyDev, fd), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = pci_proxy_dev_realize; + k->exit = pci_proxy_dev_exit; + device_class_set_props(dc, proxy_properties); +} + +static const TypeInfo pci_proxy_dev_type_info = { + .name = TYPE_PCI_PROXY_DEV, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIProxyDev), + .class_init = pci_proxy_dev_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + +static void pci_proxy_dev_register_types(void) +{ + type_register_static(&pci_proxy_dev_type_info); +} + +type_init(pci_proxy_dev_register_types) diff --git a/hw/remote/meson.build b/hw/remote/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -XXX,XX +XXX,XX @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('machine.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c')) +remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c')) specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c')) -- 2.29.2
From: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: d54edb4176361eed86b903e8f27058363b6c83b3.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- include/hw/remote/mpqemu-link.h | 4 ++++ hw/remote/mpqemu-link.c | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/mpqemu-link.h +++ b/include/hw/remote/mpqemu-link.h @@ -XXX,XX +XXX,XX @@ #include "qemu/thread.h" #include "io/channel.h" #include "exec/hwaddr.h" +#include "io/channel-socket.h" +#include "hw/remote/proxy.h" #define REMOTE_MAX_FDS 8 @@ -XXX,XX +XXX,XX @@ typedef struct { bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp); bool mpqemu_msg_recv(MPQemuMsg *msg, QIOChannel *ioc, Error **errp); +uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev, + Error **errp); bool mpqemu_msg_valid(MPQemuMsg *msg); #endif diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -XXX,XX +XXX,XX @@ fail: return ret; } +/* + * Send msg and wait for a reply with command code RET_MSG. + * Returns the message received of size u64 or UINT64_MAX + * on error. + * Called from VCPU thread in non-coroutine context. + * Used by the Proxy object to communicate to remote processes. + */ +uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev, + Error **errp) +{ + ERRP_GUARD(); + MPQemuMsg msg_reply = {0}; + uint64_t ret = UINT64_MAX; + + assert(!qemu_in_coroutine()); + + QEMU_LOCK_GUARD(&pdev->io_mutex); + if (!mpqemu_msg_send(msg, pdev->ioc, errp)) { + return ret; + } + + if (!mpqemu_msg_recv(&msg_reply, pdev->ioc, errp)) { + return ret; + } + + if (!mpqemu_msg_valid(&msg_reply)) { + error_setg(errp, "ERROR: Invalid reply received for command %d", + msg->cmd); + return ret; + } + + return msg_reply.data.u64; +} + bool mpqemu_msg_valid(MPQemuMsg *msg) { if (msg->cmd >= MPQEMU_CMD_MAX && msg->cmd < 0) { -- 2.29.2
From: Elena Ufimtseva <elena.ufimtseva@oracle.com> The Proxy Object sends the PCI config space accesses as messages to the remote process over the communication channel Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: d3c94f4618813234655356c60e6f0d0362ff42d6.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- include/hw/remote/mpqemu-link.h | 10 ++++++ hw/remote/message.c | 60 +++++++++++++++++++++++++++++++++ hw/remote/mpqemu-link.c | 8 ++++- hw/remote/proxy.c | 55 ++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/mpqemu-link.h +++ b/include/hw/remote/mpqemu-link.h @@ -XXX,XX +XXX,XX @@ */ typedef enum { MPQEMU_CMD_SYNC_SYSMEM, + MPQEMU_CMD_RET, + MPQEMU_CMD_PCI_CFGWRITE, + MPQEMU_CMD_PCI_CFGREAD, MPQEMU_CMD_MAX, } MPQemuCmd; @@ -XXX,XX +XXX,XX @@ typedef struct { off_t offsets[REMOTE_MAX_FDS]; } SyncSysmemMsg; +typedef struct { + uint32_t addr; + uint32_t val; + int len; +} PciConfDataMsg; + /** * MPQemuMsg: * @cmd: The remote command @@ -XXX,XX +XXX,XX @@ typedef struct { union { uint64_t u64; + PciConfDataMsg pci_conf_data; SyncSysmemMsg sync_sysmem; } data; diff --git a/hw/remote/message.c b/hw/remote/message.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/message.c +++ b/hw/remote/message.c @@ -XXX,XX +XXX,XX @@ #include "hw/remote/mpqemu-link.h" #include "qapi/error.h" #include "sysemu/runstate.h" +#include "hw/pci/pci.h" + +static void process_config_write(QIOChannel *ioc, PCIDevice *dev, + MPQemuMsg *msg, Error **errp); +static void process_config_read(QIOChannel *ioc, PCIDevice *dev, + MPQemuMsg *msg, Error **errp); void coroutine_fn mpqemu_remote_msg_loop_co(void *data) { @@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) } switch (msg.cmd) { + case MPQEMU_CMD_PCI_CFGWRITE: + process_config_write(com->ioc, pci_dev, &msg, &local_err); + break; + case MPQEMU_CMD_PCI_CFGREAD: + process_config_read(com->ioc, pci_dev, &msg, &local_err); + break; default: error_setg(&local_err, "Unknown command (%d) received for device %s" @@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); } } + +static void process_config_write(QIOChannel *ioc, PCIDevice *dev, + MPQemuMsg *msg, Error **errp) +{ + ERRP_GUARD(); + PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data; + MPQemuMsg ret = { 0 }; + + if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) { + error_setg(errp, "Bad address for PCI config write, pid "FMT_pid".", + getpid()); + ret.data.u64 = UINT64_MAX; + } else { + pci_default_write_config(dev, conf->addr, conf->val, conf->len); + } + + ret.cmd = MPQEMU_CMD_RET; + ret.size = sizeof(ret.data.u64); + + if (!mpqemu_msg_send(&ret, ioc, NULL)) { + error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ", + getpid()); + } +} + +static void process_config_read(QIOChannel *ioc, PCIDevice *dev, + MPQemuMsg *msg, Error **errp) +{ + ERRP_GUARD(); + PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data; + MPQemuMsg ret = { 0 }; + + if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) { + error_setg(errp, "Bad address for PCI config read, pid "FMT_pid".", + getpid()); + ret.data.u64 = UINT64_MAX; + } else { + ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->len); + } + + ret.cmd = MPQEMU_CMD_RET; + ret.size = sizeof(ret.data.u64); + + if (!mpqemu_msg_send(&ret, ioc, NULL)) { + error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ", + getpid()); + } +} diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -XXX,XX +XXX,XX @@ uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev, return ret; } - if (!mpqemu_msg_valid(&msg_reply)) { + if (!mpqemu_msg_valid(&msg_reply) || msg_reply.cmd != MPQEMU_CMD_RET) { error_setg(errp, "ERROR: Invalid reply received for command %d", msg->cmd); return ret; @@ -XXX,XX +XXX,XX @@ bool mpqemu_msg_valid(MPQemuMsg *msg) return false; } break; + case MPQEMU_CMD_PCI_CFGWRITE: + case MPQEMU_CMD_PCI_CFGREAD: + if (msg->size != sizeof(PciConfDataMsg)) { + return false; + } + break; default: break; } diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -XXX,XX +XXX,XX @@ #include "monitor/monitor.h" #include "migration/blocker.h" #include "qemu/sockets.h" +#include "hw/remote/mpqemu-link.h" +#include "qemu/error-report.h" static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) { @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_exit(PCIDevice *pdev) error_free(dev->migration_blocker); } +static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val, + int len, unsigned int op) +{ + MPQemuMsg msg = { 0 }; + uint64_t ret = -EINVAL; + Error *local_err = NULL; + + msg.cmd = op; + msg.data.pci_conf_data.addr = addr; + msg.data.pci_conf_data.val = (op == MPQEMU_CMD_PCI_CFGWRITE) ? *val : 0; + msg.data.pci_conf_data.len = len; + msg.size = sizeof(PciConfDataMsg); + + ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); + if (local_err) { + error_report_err(local_err); + } + + if (ret == UINT64_MAX) { + error_report("Failed to perform PCI config %s operation", + (op == MPQEMU_CMD_PCI_CFGREAD) ? "READ" : "WRITE"); + } + + if (op == MPQEMU_CMD_PCI_CFGREAD) { + *val = (uint32_t)ret; + } +} + +static uint32_t pci_proxy_read_config(PCIDevice *d, uint32_t addr, int len) +{ + uint32_t val; + + config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGREAD); + + return val; +} + +static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val, + int len) +{ + /* + * Some of the functions access the copy of remote device's PCI config + * space which is cached in the proxy device. Therefore, maintain + * it updated. + */ + pci_default_write_config(d, addr, val, len); + + config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGWRITE); +} + static Property proxy_properties[] = { DEFINE_PROP_STRING("fd", PCIProxyDev, fd), DEFINE_PROP_END_OF_LIST(), @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) k->realize = pci_proxy_dev_realize; k->exit = pci_proxy_dev_exit; + k->config_read = pci_proxy_read_config; + k->config_write = pci_proxy_write_config; + device_class_set_props(dc, proxy_properties); } -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> Proxy device object implements handler for PCI BAR writes and reads. The handler uses BAR_WRITE/BAR_READ message to communicate to the remote process with the BAR address and value to be written/read. The remote process implements handler for BAR_WRITE/BAR_READ message. Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: a8b76714a9688be5552c4c92d089bc9e8a4707ff.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- include/hw/remote/mpqemu-link.h | 10 ++++ include/hw/remote/proxy.h | 9 ++++ hw/remote/message.c | 83 +++++++++++++++++++++++++++++++++ hw/remote/mpqemu-link.c | 6 +++ hw/remote/proxy.c | 60 ++++++++++++++++++++++++ 5 files changed, 168 insertions(+) diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/mpqemu-link.h +++ b/include/hw/remote/mpqemu-link.h @@ -XXX,XX +XXX,XX @@ typedef enum { MPQEMU_CMD_RET, MPQEMU_CMD_PCI_CFGWRITE, MPQEMU_CMD_PCI_CFGREAD, + MPQEMU_CMD_BAR_WRITE, + MPQEMU_CMD_BAR_READ, MPQEMU_CMD_MAX, } MPQemuCmd; @@ -XXX,XX +XXX,XX @@ typedef struct { int len; } PciConfDataMsg; +typedef struct { + hwaddr addr; + uint64_t val; + unsigned size; + bool memory; +} BarAccessMsg; + /** * MPQemuMsg: * @cmd: The remote command @@ -XXX,XX +XXX,XX @@ typedef struct { uint64_t u64; PciConfDataMsg pci_conf_data; SyncSysmemMsg sync_sysmem; + BarAccessMsg bar_access; } data; int fds[REMOTE_MAX_FDS]; diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/proxy.h +++ b/include/hw/remote/proxy.h @@ -XXX,XX +XXX,XX @@ #define TYPE_PCI_PROXY_DEV "x-pci-proxy-dev" OBJECT_DECLARE_SIMPLE_TYPE(PCIProxyDev, PCI_PROXY_DEV) +typedef struct ProxyMemoryRegion { + PCIProxyDev *dev; + MemoryRegion mr; + bool memory; + bool present; + uint8_t type; +} ProxyMemoryRegion; + struct PCIProxyDev { PCIDevice parent_dev; char *fd; @@ -XXX,XX +XXX,XX @@ struct PCIProxyDev { QemuMutex io_mutex; QIOChannel *ioc; Error *migration_blocker; + ProxyMemoryRegion region[PCI_NUM_REGIONS]; }; #endif /* PROXY_H */ diff --git a/hw/remote/message.c b/hw/remote/message.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/message.c +++ b/hw/remote/message.c @@ -XXX,XX +XXX,XX @@ #include "qapi/error.h" #include "sysemu/runstate.h" #include "hw/pci/pci.h" +#include "exec/memattrs.h" static void process_config_write(QIOChannel *ioc, PCIDevice *dev, MPQemuMsg *msg, Error **errp); static void process_config_read(QIOChannel *ioc, PCIDevice *dev, MPQemuMsg *msg, Error **errp); +static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp); +static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp); void coroutine_fn mpqemu_remote_msg_loop_co(void *data) { @@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) case MPQEMU_CMD_PCI_CFGREAD: process_config_read(com->ioc, pci_dev, &msg, &local_err); break; + case MPQEMU_CMD_BAR_WRITE: + process_bar_write(com->ioc, &msg, &local_err); + break; + case MPQEMU_CMD_BAR_READ: + process_bar_read(com->ioc, &msg, &local_err); + break; default: error_setg(&local_err, "Unknown command (%d) received for device %s" @@ -XXX,XX +XXX,XX @@ static void process_config_read(QIOChannel *ioc, PCIDevice *dev, getpid()); } } + +static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp) +{ + ERRP_GUARD(); + BarAccessMsg *bar_access = &msg->data.bar_access; + AddressSpace *as = + bar_access->memory ? &address_space_memory : &address_space_io; + MPQemuMsg ret = { 0 }; + MemTxResult res; + uint64_t val; + + if (!is_power_of_2(bar_access->size) || + (bar_access->size > sizeof(uint64_t))) { + ret.data.u64 = UINT64_MAX; + goto fail; + } + + val = cpu_to_le64(bar_access->val); + + res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED, + (void *)&val, bar_access->size, true); + + if (res != MEMTX_OK) { + error_setg(errp, "Bad address %"PRIx64" for mem write, pid "FMT_pid".", + bar_access->addr, getpid()); + ret.data.u64 = -1; + } + +fail: + ret.cmd = MPQEMU_CMD_RET; + ret.size = sizeof(ret.data.u64); + + if (!mpqemu_msg_send(&ret, ioc, NULL)) { + error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ", + getpid()); + } +} + +static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp) +{ + ERRP_GUARD(); + BarAccessMsg *bar_access = &msg->data.bar_access; + MPQemuMsg ret = { 0 }; + AddressSpace *as; + MemTxResult res; + uint64_t val = 0; + + as = bar_access->memory ? &address_space_memory : &address_space_io; + + if (!is_power_of_2(bar_access->size) || + (bar_access->size > sizeof(uint64_t))) { + val = UINT64_MAX; + goto fail; + } + + res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED, + (void *)&val, bar_access->size, false); + + if (res != MEMTX_OK) { + error_setg(errp, "Bad address %"PRIx64" for mem read, pid "FMT_pid".", + bar_access->addr, getpid()); + val = UINT64_MAX; + } + +fail: + ret.cmd = MPQEMU_CMD_RET; + ret.data.u64 = le64_to_cpu(val); + ret.size = sizeof(ret.data.u64); + + if (!mpqemu_msg_send(&ret, ioc, NULL)) { + error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ", + getpid()); + } +} diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -XXX,XX +XXX,XX @@ bool mpqemu_msg_valid(MPQemuMsg *msg) return false; } break; + case MPQEMU_CMD_BAR_WRITE: + case MPQEMU_CMD_BAR_READ: + if ((msg->size != sizeof(BarAccessMsg)) || (msg->num_fds != 0)) { + return false; + } + break; default: break; } diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_register_types(void) } type_init(pci_proxy_dev_register_types) + +static void send_bar_access_msg(PCIProxyDev *pdev, MemoryRegion *mr, + bool write, hwaddr addr, uint64_t *val, + unsigned size, bool memory) +{ + MPQemuMsg msg = { 0 }; + long ret = -EINVAL; + Error *local_err = NULL; + + msg.size = sizeof(BarAccessMsg); + msg.data.bar_access.addr = mr->addr + addr; + msg.data.bar_access.size = size; + msg.data.bar_access.memory = memory; + + if (write) { + msg.cmd = MPQEMU_CMD_BAR_WRITE; + msg.data.bar_access.val = *val; + } else { + msg.cmd = MPQEMU_CMD_BAR_READ; + } + + ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); + if (local_err) { + error_report_err(local_err); + } + + if (!write) { + *val = ret; + } +} + +static void proxy_bar_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + ProxyMemoryRegion *pmr = opaque; + + send_bar_access_msg(pmr->dev, &pmr->mr, true, addr, &val, size, + pmr->memory); +} + +static uint64_t proxy_bar_read(void *opaque, hwaddr addr, unsigned size) +{ + ProxyMemoryRegion *pmr = opaque; + uint64_t val; + + send_bar_access_msg(pmr->dev, &pmr->mr, false, addr, &val, size, + pmr->memory); + + return val; +} + +const MemoryRegionOps proxy_mr_ops = { + .read = proxy_bar_read, + .write = proxy_bar_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> Add ProxyMemoryListener object which is used to keep the view of the RAM in sync between QEMU and remote process. A MemoryListener is registered for system-memory AddressSpace. The listener sends SYNC_SYSMEM message to the remote process when memory listener commits the changes to memory, the remote process receives the message and processes it in the handler for SYNC_SYSMEM message. Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 04fe4e6a9ca90d4f11ab6f59be7652f5b086a071.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 2 + include/hw/remote/proxy-memory-listener.h | 28 +++ include/hw/remote/proxy.h | 2 + hw/remote/message.c | 4 + hw/remote/proxy-memory-listener.c | 227 ++++++++++++++++++++++ hw/remote/proxy.c | 6 + hw/remote/meson.build | 1 + 7 files changed, 270 insertions(+) create mode 100644 include/hw/remote/proxy-memory-listener.h create mode 100644 hw/remote/proxy-memory-listener.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: include/hw/remote/memory.h F: hw/remote/memory.c F: hw/remote/proxy.c F: include/hw/remote/proxy.h +F: hw/remote/proxy-memory-listener.c +F: include/hw/remote/proxy-memory-listener.h Build and test automation ------------------------- diff --git a/include/hw/remote/proxy-memory-listener.h b/include/hw/remote/proxy-memory-listener.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/remote/proxy-memory-listener.h @@ -XXX,XX +XXX,XX @@ +/* + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef PROXY_MEMORY_LISTENER_H +#define PROXY_MEMORY_LISTENER_H + +#include "exec/memory.h" +#include "io/channel.h" + +typedef struct ProxyMemoryListener { + MemoryListener listener; + + int n_mr_sections; + MemoryRegionSection *mr_sections; + + QIOChannel *ioc; +} ProxyMemoryListener; + +void proxy_memory_listener_configure(ProxyMemoryListener *proxy_listener, + QIOChannel *ioc); +void proxy_memory_listener_deconfigure(ProxyMemoryListener *proxy_listener); + +#endif diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/proxy.h +++ b/include/hw/remote/proxy.h @@ -XXX,XX +XXX,XX @@ #include "hw/pci/pci.h" #include "io/channel.h" +#include "hw/remote/proxy-memory-listener.h" #define TYPE_PCI_PROXY_DEV "x-pci-proxy-dev" OBJECT_DECLARE_SIMPLE_TYPE(PCIProxyDev, PCI_PROXY_DEV) @@ -XXX,XX +XXX,XX @@ struct PCIProxyDev { QemuMutex io_mutex; QIOChannel *ioc; Error *migration_blocker; + ProxyMemoryListener proxy_listener; ProxyMemoryRegion region[PCI_NUM_REGIONS]; }; diff --git a/hw/remote/message.c b/hw/remote/message.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/message.c +++ b/hw/remote/message.c @@ -XXX,XX +XXX,XX @@ #include "sysemu/runstate.h" #include "hw/pci/pci.h" #include "exec/memattrs.h" +#include "hw/remote/memory.h" static void process_config_write(QIOChannel *ioc, PCIDevice *dev, MPQemuMsg *msg, Error **errp); @@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) case MPQEMU_CMD_BAR_READ: process_bar_read(com->ioc, &msg, &local_err); break; + case MPQEMU_CMD_SYNC_SYSMEM: + remote_sysmem_reconfig(&msg, &local_err); + break; default: error_setg(&local_err, "Unknown command (%d) received for device %s" diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/proxy-memory-listener.c @@ -XXX,XX +XXX,XX @@ +/* + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "qemu/compiler.h" +#include "qemu/int128.h" +#include "qemu/range.h" +#include "exec/memory.h" +#include "exec/cpu-common.h" +#include "cpu.h" +#include "exec/ram_addr.h" +#include "exec/address-spaces.h" +#include "qapi/error.h" +#include "hw/remote/mpqemu-link.h" +#include "hw/remote/proxy-memory-listener.h" + +/* + * TODO: get_fd_from_hostaddr(), proxy_mrs_can_merge() and + * proxy_memory_listener_commit() defined below perform tasks similar to the + * functions defined in vhost-user.c. These functions are good candidates + * for refactoring. + * + */ + +static void proxy_memory_listener_reset(MemoryListener *listener) +{ + ProxyMemoryListener *proxy_listener = container_of(listener, + ProxyMemoryListener, + listener); + int mrs; + + for (mrs = 0; mrs < proxy_listener->n_mr_sections; mrs++) { + memory_region_unref(proxy_listener->mr_sections[mrs].mr); + } + + g_free(proxy_listener->mr_sections); + proxy_listener->mr_sections = NULL; + proxy_listener->n_mr_sections = 0; +} + +static int get_fd_from_hostaddr(uint64_t host, ram_addr_t *offset) +{ + MemoryRegion *mr; + ram_addr_t off; + + /** + * Assumes that the host address is a valid address as it's + * coming from the MemoryListener system. In the case host + * address is not valid, the following call would return + * the default subregion of "system_memory" region, and + * not NULL. So it's not possible to check for NULL here. + */ + mr = memory_region_from_host((void *)(uintptr_t)host, &off); + + if (offset) { + *offset = off; + } + + return memory_region_get_fd(mr); +} + +static bool proxy_mrs_can_merge(uint64_t host, uint64_t prev_host, size_t size) +{ + if (((prev_host + size) != host)) { + return false; + } + + if (get_fd_from_hostaddr(host, NULL) != + get_fd_from_hostaddr(prev_host, NULL)) { + return false; + } + + return true; +} + +static bool try_merge(ProxyMemoryListener *proxy_listener, + MemoryRegionSection *section) +{ + uint64_t mrs_size, mrs_gpa, mrs_page; + MemoryRegionSection *prev_sec; + bool merged = false; + uintptr_t mrs_host; + RAMBlock *mrs_rb; + + if (!proxy_listener->n_mr_sections) { + return false; + } + + mrs_rb = section->mr->ram_block; + mrs_page = (uint64_t)qemu_ram_pagesize(mrs_rb); + mrs_size = int128_get64(section->size); + mrs_gpa = section->offset_within_address_space; + mrs_host = (uintptr_t)memory_region_get_ram_ptr(section->mr) + + section->offset_within_region; + + if (get_fd_from_hostaddr(mrs_host, NULL) < 0) { + return true; + } + + mrs_host = mrs_host & ~(mrs_page - 1); + mrs_gpa = mrs_gpa & ~(mrs_page - 1); + mrs_size = ROUND_UP(mrs_size, mrs_page); + + prev_sec = proxy_listener->mr_sections + + (proxy_listener->n_mr_sections - 1); + uint64_t prev_gpa_start = prev_sec->offset_within_address_space; + uint64_t prev_size = int128_get64(prev_sec->size); + uint64_t prev_gpa_end = range_get_last(prev_gpa_start, prev_size); + uint64_t prev_host_start = + (uintptr_t)memory_region_get_ram_ptr(prev_sec->mr) + + prev_sec->offset_within_region; + uint64_t prev_host_end = range_get_last(prev_host_start, prev_size); + + if (mrs_gpa <= (prev_gpa_end + 1)) { + g_assert(mrs_gpa > prev_gpa_start); + + if ((section->mr == prev_sec->mr) && + proxy_mrs_can_merge(mrs_host, prev_host_start, + (mrs_gpa - prev_gpa_start))) { + uint64_t max_end = MAX(prev_host_end, mrs_host + mrs_size); + merged = true; + prev_sec->offset_within_address_space = + MIN(prev_gpa_start, mrs_gpa); + prev_sec->offset_within_region = + MIN(prev_host_start, mrs_host) - + (uintptr_t)memory_region_get_ram_ptr(prev_sec->mr); + prev_sec->size = int128_make64(max_end - MIN(prev_host_start, + mrs_host)); + } + } + + return merged; +} + +static void proxy_memory_listener_region_addnop(MemoryListener *listener, + MemoryRegionSection *section) +{ + ProxyMemoryListener *proxy_listener = container_of(listener, + ProxyMemoryListener, + listener); + + if (!memory_region_is_ram(section->mr) || + memory_region_is_rom(section->mr)) { + return; + } + + if (try_merge(proxy_listener, section)) { + return; + } + + ++proxy_listener->n_mr_sections; + proxy_listener->mr_sections = g_renew(MemoryRegionSection, + proxy_listener->mr_sections, + proxy_listener->n_mr_sections); + proxy_listener->mr_sections[proxy_listener->n_mr_sections - 1] = *section; + proxy_listener->mr_sections[proxy_listener->n_mr_sections - 1].fv = NULL; + memory_region_ref(section->mr); +} + +static void proxy_memory_listener_commit(MemoryListener *listener) +{ + ProxyMemoryListener *proxy_listener = container_of(listener, + ProxyMemoryListener, + listener); + MPQemuMsg msg; + MemoryRegionSection *section; + ram_addr_t offset; + uintptr_t host_addr; + int region; + Error *local_err = NULL; + + memset(&msg, 0, sizeof(MPQemuMsg)); + + msg.cmd = MPQEMU_CMD_SYNC_SYSMEM; + msg.num_fds = proxy_listener->n_mr_sections; + msg.size = sizeof(SyncSysmemMsg); + if (msg.num_fds > REMOTE_MAX_FDS) { + error_report("Number of fds is more than %d", REMOTE_MAX_FDS); + return; + } + + for (region = 0; region < proxy_listener->n_mr_sections; region++) { + section = &proxy_listener->mr_sections[region]; + msg.data.sync_sysmem.gpas[region] = + section->offset_within_address_space; + msg.data.sync_sysmem.sizes[region] = int128_get64(section->size); + host_addr = (uintptr_t)memory_region_get_ram_ptr(section->mr) + + section->offset_within_region; + msg.fds[region] = get_fd_from_hostaddr(host_addr, &offset); + msg.data.sync_sysmem.offsets[region] = offset; + } + if (!mpqemu_msg_send(&msg, proxy_listener->ioc, &local_err)) { + error_report_err(local_err); + } +} + +void proxy_memory_listener_deconfigure(ProxyMemoryListener *proxy_listener) +{ + memory_listener_unregister(&proxy_listener->listener); + + proxy_memory_listener_reset(&proxy_listener->listener); +} + +void proxy_memory_listener_configure(ProxyMemoryListener *proxy_listener, + QIOChannel *ioc) +{ + proxy_listener->n_mr_sections = 0; + proxy_listener->mr_sections = NULL; + + proxy_listener->ioc = ioc; + + proxy_listener->listener.begin = proxy_memory_listener_reset; + proxy_listener->listener.commit = proxy_memory_listener_commit; + proxy_listener->listener.region_add = proxy_memory_listener_region_addnop; + proxy_listener->listener.region_nop = proxy_memory_listener_region_addnop; + proxy_listener->listener.priority = 10; + + memory_listener_register(&proxy_listener->listener, + &address_space_memory); +} diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -XXX,XX +XXX,XX @@ #include "qemu/sockets.h" #include "hw/remote/mpqemu-link.h" #include "qemu/error-report.h" +#include "hw/remote/proxy-memory-listener.h" +#include "qom/object.h" static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) { @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) qemu_mutex_init(&dev->io_mutex); qio_channel_set_blocking(dev->ioc, true, NULL); + + proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc); } static void pci_proxy_dev_exit(PCIDevice *pdev) @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_exit(PCIDevice *pdev) migrate_del_blocker(dev->migration_blocker); error_free(dev->migration_blocker); + + proxy_memory_listener_deconfigure(&dev->proxy_listener); } static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val, diff --git a/hw/remote/meson.build b/hw/remote/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -XXX,XX +XXX,XX @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c')) specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c')) +specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy-memory-listener.c')) softmmu_ss.add_all(when: 'CONFIG_MULTIPROCESS', if_true: remote_ss) -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> IOHUB object is added to manage PCI IRQs. It uses KVM_IRQFD ioctl to create irqfd to injecting PCI interrupts to the guest. IOHUB object forwards the irqfd to the remote process. Remote process uses this fd to directly send interrupts to the guest, bypassing QEMU. Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 51d5c3d54e28a68b002e3875c59599c9f5a424a1.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- MAINTAINERS | 2 + include/hw/pci/pci_ids.h | 3 + include/hw/remote/iohub.h | 42 +++++++++++ include/hw/remote/machine.h | 2 + include/hw/remote/mpqemu-link.h | 1 + include/hw/remote/proxy.h | 4 ++ hw/remote/iohub.c | 119 ++++++++++++++++++++++++++++++++ hw/remote/machine.c | 10 +++ hw/remote/message.c | 4 ++ hw/remote/mpqemu-link.c | 5 ++ hw/remote/proxy.c | 56 +++++++++++++++ hw/remote/meson.build | 1 + 12 files changed, 249 insertions(+) create mode 100644 include/hw/remote/iohub.h create mode 100644 hw/remote/iohub.c diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: hw/remote/proxy.c F: include/hw/remote/proxy.h F: hw/remote/proxy-memory-listener.c F: include/hw/remote/proxy-memory-listener.h +F: hw/remote/iohub.c +F: include/hw/remote/iohub.h Build and test automation ------------------------- diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -XXX,XX +XXX,XX @@ #define PCI_DEVICE_ID_SUN_SIMBA 0x5000 #define PCI_DEVICE_ID_SUN_SABRE 0xa000 +#define PCI_VENDOR_ID_ORACLE 0x108e +#define PCI_DEVICE_ID_REMOTE_IOHUB 0xb000 + #define PCI_VENDOR_ID_CMD 0x1095 #define PCI_DEVICE_ID_CMD_646 0x0646 diff --git a/include/hw/remote/iohub.h b/include/hw/remote/iohub.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/remote/iohub.h @@ -XXX,XX +XXX,XX @@ +/* + * IO Hub for remote device + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef REMOTE_IOHUB_H +#define REMOTE_IOHUB_H + +#include "hw/pci/pci.h" +#include "qemu/event_notifier.h" +#include "qemu/thread-posix.h" +#include "hw/remote/mpqemu-link.h" + +#define REMOTE_IOHUB_NB_PIRQS PCI_DEVFN_MAX + +typedef struct ResampleToken { + void *iohub; + int pirq; +} ResampleToken; + +typedef struct RemoteIOHubState { + PCIDevice d; + EventNotifier irqfds[REMOTE_IOHUB_NB_PIRQS]; + EventNotifier resamplefds[REMOTE_IOHUB_NB_PIRQS]; + unsigned int irq_level[REMOTE_IOHUB_NB_PIRQS]; + ResampleToken token[REMOTE_IOHUB_NB_PIRQS]; + QemuMutex irq_level_lock[REMOTE_IOHUB_NB_PIRQS]; +} RemoteIOHubState; + +int remote_iohub_map_irq(PCIDevice *pci_dev, int intx); +void remote_iohub_set_irq(void *opaque, int pirq, int level); +void process_set_irqfd_msg(PCIDevice *pci_dev, MPQemuMsg *msg); + +void remote_iohub_init(RemoteIOHubState *iohub); +void remote_iohub_finalize(RemoteIOHubState *iohub); + +#endif diff --git a/include/hw/remote/machine.h b/include/hw/remote/machine.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/machine.h +++ b/include/hw/remote/machine.h @@ -XXX,XX +XXX,XX @@ #include "hw/boards.h" #include "hw/pci-host/remote.h" #include "io/channel.h" +#include "hw/remote/iohub.h" struct RemoteMachineState { MachineState parent_obj; RemotePCIHost *host; + RemoteIOHubState iohub; }; /* Used to pass to co-routine device and ioc. */ diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/mpqemu-link.h +++ b/include/hw/remote/mpqemu-link.h @@ -XXX,XX +XXX,XX @@ typedef enum { MPQEMU_CMD_PCI_CFGREAD, MPQEMU_CMD_BAR_WRITE, MPQEMU_CMD_BAR_READ, + MPQEMU_CMD_SET_IRQFD, MPQEMU_CMD_MAX, } MPQemuCmd; diff --git a/include/hw/remote/proxy.h b/include/hw/remote/proxy.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/proxy.h +++ b/include/hw/remote/proxy.h @@ -XXX,XX +XXX,XX @@ #include "hw/pci/pci.h" #include "io/channel.h" #include "hw/remote/proxy-memory-listener.h" +#include "qemu/event_notifier.h" #define TYPE_PCI_PROXY_DEV "x-pci-proxy-dev" OBJECT_DECLARE_SIMPLE_TYPE(PCIProxyDev, PCI_PROXY_DEV) @@ -XXX,XX +XXX,XX @@ struct PCIProxyDev { QIOChannel *ioc; Error *migration_blocker; ProxyMemoryListener proxy_listener; + int virq; + EventNotifier intr; + EventNotifier resample; ProxyMemoryRegion region[PCI_NUM_REGIONS]; }; diff --git a/hw/remote/iohub.c b/hw/remote/iohub.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/hw/remote/iohub.c @@ -XXX,XX +XXX,XX @@ +/* + * Remote IO Hub + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "hw/pci/pci.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/pci_bus.h" +#include "qemu/thread.h" +#include "hw/boards.h" +#include "hw/remote/machine.h" +#include "hw/remote/iohub.h" +#include "qemu/main-loop.h" + +void remote_iohub_init(RemoteIOHubState *iohub) +{ + int pirq; + + memset(&iohub->irqfds, 0, sizeof(iohub->irqfds)); + memset(&iohub->resamplefds, 0, sizeof(iohub->resamplefds)); + + for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) { + qemu_mutex_init(&iohub->irq_level_lock[pirq]); + iohub->irq_level[pirq] = 0; + event_notifier_init_fd(&iohub->irqfds[pirq], -1); + event_notifier_init_fd(&iohub->resamplefds[pirq], -1); + } +} + +void remote_iohub_finalize(RemoteIOHubState *iohub) +{ + int pirq; + + for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) { + qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]), + NULL, NULL, NULL); + event_notifier_cleanup(&iohub->irqfds[pirq]); + event_notifier_cleanup(&iohub->resamplefds[pirq]); + qemu_mutex_destroy(&iohub->irq_level_lock[pirq]); + } +} + +int remote_iohub_map_irq(PCIDevice *pci_dev, int intx) +{ + return pci_dev->devfn; +} + +void remote_iohub_set_irq(void *opaque, int pirq, int level) +{ + RemoteIOHubState *iohub = opaque; + + assert(pirq >= 0); + assert(pirq < PCI_DEVFN_MAX); + + QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]); + + if (level) { + if (++iohub->irq_level[pirq] == 1) { + event_notifier_set(&iohub->irqfds[pirq]); + } + } else if (iohub->irq_level[pirq] > 0) { + iohub->irq_level[pirq]--; + } +} + +static void intr_resample_handler(void *opaque) +{ + ResampleToken *token = opaque; + RemoteIOHubState *iohub = token->iohub; + int pirq, s; + + pirq = token->pirq; + + s = event_notifier_test_and_clear(&iohub->resamplefds[pirq]); + + assert(s >= 0); + + QEMU_LOCK_GUARD(&iohub->irq_level_lock[pirq]); + + if (iohub->irq_level[pirq]) { + event_notifier_set(&iohub->irqfds[pirq]); + } +} + +void process_set_irqfd_msg(PCIDevice *pci_dev, MPQemuMsg *msg) +{ + RemoteMachineState *machine = REMOTE_MACHINE(current_machine); + RemoteIOHubState *iohub = &machine->iohub; + int pirq, intx; + + intx = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1; + + pirq = remote_iohub_map_irq(pci_dev, intx); + + if (event_notifier_get_fd(&iohub->irqfds[pirq]) != -1) { + qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]), + NULL, NULL, NULL); + event_notifier_cleanup(&iohub->irqfds[pirq]); + event_notifier_cleanup(&iohub->resamplefds[pirq]); + memset(&iohub->token[pirq], 0, sizeof(ResampleToken)); + } + + event_notifier_init_fd(&iohub->irqfds[pirq], msg->fds[0]); + event_notifier_init_fd(&iohub->resamplefds[pirq], msg->fds[1]); + + iohub->token[pirq].iohub = iohub; + iohub->token[pirq].pirq = pirq; + + qemu_set_fd_handler(msg->fds[1], intr_resample_handler, NULL, + &iohub->token[pirq]); +} diff --git a/hw/remote/machine.c b/hw/remote/machine.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -XXX,XX +XXX,XX @@ #include "exec/address-spaces.h" #include "exec/memory.h" #include "qapi/error.h" +#include "hw/pci/pci_host.h" +#include "hw/remote/iohub.h" static void remote_machine_init(MachineState *machine) { MemoryRegion *system_memory, *system_io, *pci_memory; RemoteMachineState *s = REMOTE_MACHINE(machine); RemotePCIHost *rem_host; + PCIHostState *pci_host; system_memory = get_system_memory(); system_io = get_system_io(); @@ -XXX,XX +XXX,XX @@ static void remote_machine_init(MachineState *machine) memory_region_add_subregion_overlap(system_memory, 0x0, pci_memory, -1); qdev_realize(DEVICE(rem_host), sysbus_get_default(), &error_fatal); + + pci_host = PCI_HOST_BRIDGE(rem_host); + + remote_iohub_init(&s->iohub); + + pci_bus_irqs(pci_host->bus, remote_iohub_set_irq, remote_iohub_map_irq, + &s->iohub, REMOTE_IOHUB_NB_PIRQS); } static void remote_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/remote/message.c b/hw/remote/message.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/message.c +++ b/hw/remote/message.c @@ -XXX,XX +XXX,XX @@ #include "hw/pci/pci.h" #include "exec/memattrs.h" #include "hw/remote/memory.h" +#include "hw/remote/iohub.h" static void process_config_write(QIOChannel *ioc, PCIDevice *dev, MPQemuMsg *msg, Error **errp); @@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) case MPQEMU_CMD_SYNC_SYSMEM: remote_sysmem_reconfig(&msg, &local_err); break; + case MPQEMU_CMD_SET_IRQFD: + process_set_irqfd_msg(pci_dev, &msg); + break; default: error_setg(&local_err, "Unknown command (%d) received for device %s" diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -XXX,XX +XXX,XX @@ bool mpqemu_msg_valid(MPQemuMsg *msg) return false; } break; + case MPQEMU_CMD_SET_IRQFD: + if (msg->size || (msg->num_fds != 2)) { + return false; + } + break; default: break; } diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -XXX,XX +XXX,XX @@ #include "qemu/error-report.h" #include "hw/remote/proxy-memory-listener.h" #include "qom/object.h" +#include "qemu/event_notifier.h" +#include "sysemu/kvm.h" +#include "util/event_notifier-posix.c" + +static void proxy_intx_update(PCIDevice *pci_dev) +{ + PCIProxyDev *dev = PCI_PROXY_DEV(pci_dev); + PCIINTxRoute route; + int pin = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1; + + if (dev->virq != -1) { + kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &dev->intr, dev->virq); + dev->virq = -1; + } + + route = pci_device_route_intx_to_irq(pci_dev, pin); + + dev->virq = route.irq; + + if (dev->virq != -1) { + kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &dev->intr, + &dev->resample, dev->virq); + } +} + +static void setup_irqfd(PCIProxyDev *dev) +{ + PCIDevice *pci_dev = PCI_DEVICE(dev); + MPQemuMsg msg; + Error *local_err = NULL; + + event_notifier_init(&dev->intr, 0); + event_notifier_init(&dev->resample, 0); + + memset(&msg, 0, sizeof(MPQemuMsg)); + msg.cmd = MPQEMU_CMD_SET_IRQFD; + msg.num_fds = 2; + msg.fds[0] = event_notifier_get_fd(&dev->intr); + msg.fds[1] = event_notifier_get_fd(&dev->resample); + msg.size = 0; + + if (!mpqemu_msg_send(&msg, dev->ioc, &local_err)) { + error_report_err(local_err); + } + + dev->virq = -1; + + proxy_intx_update(pci_dev); + + pci_device_set_intx_routing_notifier(pci_dev, proxy_intx_update); +} static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) { @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) qio_channel_set_blocking(dev->ioc, true, NULL); proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc); + + setup_irqfd(dev); } static void pci_proxy_dev_exit(PCIDevice *pdev) @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_exit(PCIDevice *pdev) error_free(dev->migration_blocker); proxy_memory_listener_deconfigure(&dev->proxy_listener); + + event_notifier_cleanup(&dev->intr); + event_notifier_cleanup(&dev->resample); } static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val, diff --git a/hw/remote/meson.build b/hw/remote/meson.build index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/meson.build +++ b/hw/remote/meson.build @@ -XXX,XX +XXX,XX @@ remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('mpqemu-link.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('message.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('remote-obj.c')) remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy.c')) +remote_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('iohub.c')) specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('memory.c')) specific_ss.add(when: 'CONFIG_MULTIPROCESS', if_true: files('proxy-memory-listener.c')) -- 2.29.2
From: Jagannathan Raman <jag.raman@oracle.com> Retrieve PCI configuration info about the remote device and configure the Proxy PCI object based on the returned information Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 85ee367bbb993aa23699b44cfedd83b4ea6d5221.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- hw/remote/proxy.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -XXX,XX +XXX,XX @@ #include "sysemu/kvm.h" #include "util/event_notifier-posix.c" +static void probe_pci_info(PCIDevice *dev, Error **errp); + static void proxy_intx_update(PCIDevice *pci_dev) { PCIProxyDev *dev = PCI_PROXY_DEV(pci_dev); @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) { ERRP_GUARD(); PCIProxyDev *dev = PCI_PROXY_DEV(device); + uint8_t *pci_conf = device->config; int fd; if (!dev->fd) { @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) qemu_mutex_init(&dev->io_mutex); qio_channel_set_blocking(dev->ioc, true, NULL); + pci_conf[PCI_LATENCY_TIMER] = 0xff; + pci_conf[PCI_INTERRUPT_PIN] = 0x01; + proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc); setup_irqfd(dev); + + probe_pci_info(PCI_DEVICE(dev), errp); } static void pci_proxy_dev_exit(PCIDevice *pdev) @@ -XXX,XX +XXX,XX @@ const MemoryRegionOps proxy_mr_ops = { .max_access_size = 8, }, }; + +static void probe_pci_info(PCIDevice *dev, Error **errp) +{ + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + uint32_t orig_val, new_val, base_class, val; + PCIProxyDev *pdev = PCI_PROXY_DEV(dev); + DeviceClass *dc = DEVICE_CLASS(pc); + uint8_t type; + int i, size; + + config_op_send(pdev, PCI_VENDOR_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD); + pc->vendor_id = (uint16_t)val; + + config_op_send(pdev, PCI_DEVICE_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD); + pc->device_id = (uint16_t)val; + + config_op_send(pdev, PCI_CLASS_DEVICE, &val, 2, MPQEMU_CMD_PCI_CFGREAD); + pc->class_id = (uint16_t)val; + + config_op_send(pdev, PCI_SUBSYSTEM_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD); + pc->subsystem_id = (uint16_t)val; + + base_class = pc->class_id >> 4; + switch (base_class) { + case PCI_BASE_CLASS_BRIDGE: + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + break; + case PCI_BASE_CLASS_STORAGE: + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + break; + case PCI_BASE_CLASS_NETWORK: + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + break; + case PCI_BASE_CLASS_INPUT: + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + break; + case PCI_BASE_CLASS_DISPLAY: + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + break; + case PCI_BASE_CLASS_PROCESSOR: + set_bit(DEVICE_CATEGORY_CPU, dc->categories); + break; + default: + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + break; + } + + for (i = 0; i < PCI_NUM_REGIONS; i++) { + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4, + MPQEMU_CMD_PCI_CFGREAD); + new_val = 0xffffffff; + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &new_val, 4, + MPQEMU_CMD_PCI_CFGWRITE); + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &new_val, 4, + MPQEMU_CMD_PCI_CFGREAD); + size = (~(new_val & 0xFFFFFFF0)) + 1; + config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4, + MPQEMU_CMD_PCI_CFGWRITE); + type = (new_val & 0x1) ? + PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY; + + if (size) { + g_autofree char *name; + pdev->region[i].dev = pdev; + pdev->region[i].present = true; + if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) { + pdev->region[i].memory = true; + } + name = g_strdup_printf("bar-region-%d", i); + memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev), + &proxy_mr_ops, &pdev->region[i], + name, size); + pci_register_bar(dev, i, type, &pdev->region[i].mr); + } + } +} -- 2.29.2
From: Elena Ufimtseva <elena.ufimtseva@oracle.com> Perform device reset in the remote process when QEMU performs device reset. This is required to reset the internal state (like registers, etc...) of emulated devices Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> Signed-off-by: John G Johnson <john.g.johnson@oracle.com> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 7cb220a51f565dc0817bd76e2f540e89c2d2b850.1611938319.git.jag.raman@oracle.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- include/hw/remote/mpqemu-link.h | 1 + hw/remote/message.c | 22 ++++++++++++++++++++++ hw/remote/proxy.c | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/remote/mpqemu-link.h +++ b/include/hw/remote/mpqemu-link.h @@ -XXX,XX +XXX,XX @@ typedef enum { MPQEMU_CMD_BAR_WRITE, MPQEMU_CMD_BAR_READ, MPQEMU_CMD_SET_IRQFD, + MPQEMU_CMD_DEVICE_RESET, MPQEMU_CMD_MAX, } MPQemuCmd; diff --git a/hw/remote/message.c b/hw/remote/message.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/message.c +++ b/hw/remote/message.c @@ -XXX,XX +XXX,XX @@ #include "exec/memattrs.h" #include "hw/remote/memory.h" #include "hw/remote/iohub.h" +#include "sysemu/reset.h" static void process_config_write(QIOChannel *ioc, PCIDevice *dev, MPQemuMsg *msg, Error **errp); @@ -XXX,XX +XXX,XX @@ static void process_config_read(QIOChannel *ioc, PCIDevice *dev, MPQemuMsg *msg, Error **errp); static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp); static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp); +static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev, + Error **errp); void coroutine_fn mpqemu_remote_msg_loop_co(void *data) { @@ -XXX,XX +XXX,XX @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) case MPQEMU_CMD_SET_IRQFD: process_set_irqfd_msg(pci_dev, &msg); break; + case MPQEMU_CMD_DEVICE_RESET: + process_device_reset_msg(com->ioc, pci_dev, &local_err); + break; default: error_setg(&local_err, "Unknown command (%d) received for device %s" @@ -XXX,XX +XXX,XX @@ fail: getpid()); } } + +static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev, + Error **errp) +{ + DeviceClass *dc = DEVICE_GET_CLASS(dev); + DeviceState *s = DEVICE(dev); + MPQemuMsg ret = { 0 }; + + if (dc->reset) { + dc->reset(s); + } + + ret.cmd = MPQEMU_CMD_RET; + + mpqemu_msg_send(&ret, ioc, errp); +} diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index XXXXXXX..XXXXXXX 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -XXX,XX +XXX,XX @@ #include "util/event_notifier-posix.c" static void probe_pci_info(PCIDevice *dev, Error **errp); +static void proxy_device_reset(DeviceState *dev); static void proxy_intx_update(PCIDevice *pci_dev) { @@ -XXX,XX +XXX,XX @@ static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) k->config_read = pci_proxy_read_config; k->config_write = pci_proxy_write_config; + dc->reset = proxy_device_reset; + device_class_set_props(dc, proxy_properties); } @@ -XXX,XX +XXX,XX @@ static void probe_pci_info(PCIDevice *dev, Error **errp) } } } + +static void proxy_device_reset(DeviceState *dev) +{ + PCIProxyDev *pdev = PCI_PROXY_DEV(dev); + MPQemuMsg msg = { 0 }; + Error *local_err = NULL; + + msg.cmd = MPQEMU_CMD_DEVICE_RESET; + msg.size = 0; + + mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); + if (local_err) { + error_report_err(local_err); + } + +} -- 2.29.2
From: "Denis V. Lunev" <den@openvz.org> Original specification says that l1 table size if 64 * l1_size, which is obviously wrong. The size of the l1 entry is 64 _bits_, not bytes. Thus 64 is to be replaces with 8 as specification says about bytes. There is also minor tweak, field name is renamed from l1 to l1_table, which matches with the later text. Signed-off-by: Denis V. Lunev <den@openvz.org> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Message-id: 20210128171313.2210947-1-den@openvz.org CC: Stefan Hajnoczi <stefanha@redhat.com> CC: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> [Replace the original commit message "docs: fix mistake in dirty bitmap feature description" as suggested by Eric Blake. --Stefan] Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> --- docs/interop/parallels.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/interop/parallels.txt b/docs/interop/parallels.txt index XXXXXXX..XXXXXXX 100644 --- a/docs/interop/parallels.txt +++ b/docs/interop/parallels.txt @@ -XXX,XX +XXX,XX @@ of its data area are: 28 - 31: l1_size The number of entries in the L1 table of the bitmap. - variable: l1 (64 * l1_size bytes) + variable: l1_table (8 * l1_size bytes) L1 offset table (in bytes) A dirty bitmap is stored using a one-level structure for the mapping to host -- 2.29.2