Re: [Qemu-devel] [PATCH RFC 07/11] dataplane: allow virtio-1 devices
On Tue, 7 Oct 2014 16:40:03 +0200 Cornelia Huck wrote: > Handle endianness conversion for virtio-1 virtqueues correctly. > > Note that dataplane now needs to be built per-target. > It also affects hw/virtio/virtio-pci.c: In file included from include/hw/virtio/dataplane/vring.h:23:0, from include/hw/virtio/virtio-scsi.h:21, from hw/virtio/virtio-pci.c:24: include/hw/virtio/virtio-access.h: In function ‘virtio_access_is_big_endian’: include/hw/virtio/virtio-access.h:28:15: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN" #elif defined(TARGET_WORDS_BIGENDIAN) ^ FWIW when I added endian ambivalent support to virtio, I remember *some people* getting angry at the idea of turning common code into per-target... :) See comment below. > Signed-off-by: Cornelia Huck > --- > hw/block/dataplane/virtio-blk.c |3 +- > hw/scsi/virtio-scsi-dataplane.c |2 +- > hw/virtio/Makefile.objs |2 +- > hw/virtio/dataplane/Makefile.objs |2 +- > hw/virtio/dataplane/vring.c | 85 > +++ > include/hw/virtio/dataplane/vring.h | 64 -- > 6 files changed, 113 insertions(+), 45 deletions(-) > > diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c > index 5458f9d..eb45a3d 100644 > --- a/hw/block/dataplane/virtio-blk.c > +++ b/hw/block/dataplane/virtio-blk.c > @@ -16,6 +16,7 @@ > #include "qemu/iov.h" > #include "qemu/thread.h" > #include "qemu/error-report.h" > +#include "hw/virtio/virtio-access.h" > #include "hw/virtio/dataplane/vring.h" > #include "block/block.h" > #include "hw/virtio/virtio-blk.h" > @@ -75,7 +76,7 @@ static void complete_request_vring(VirtIOBlockReq *req, > unsigned char status) > VirtIOBlockDataPlane *s = req->dev->dataplane; > stb_p(&req->in->status, status); > > -vring_push(&req->dev->dataplane->vring, &req->elem, > +vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, > req->qiov.size + sizeof(*req->in)); > > /* Suppress notification to guest by BH and its scheduled > diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c > index b778e05..3e2b706 100644 > --- a/hw/scsi/virtio-scsi-dataplane.c > +++ b/hw/scsi/virtio-scsi-dataplane.c > @@ -81,7 +81,7 @@ VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, > > void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) > { > -vring_push(&req->vring->vring, &req->elem, > +vring_push((VirtIODevice *)req->dev, &req->vring->vring, &req->elem, > req->qsgl.size + req->resp_iov.size); > event_notifier_set(&req->vring->guest_notifier); > } > diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs > index d21c397..19b224a 100644 > --- a/hw/virtio/Makefile.objs > +++ b/hw/virtio/Makefile.objs > @@ -2,7 +2,7 @@ common-obj-y += virtio-rng.o > common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o > common-obj-y += virtio-bus.o > common-obj-y += virtio-mmio.o > -common-obj-$(CONFIG_VIRTIO) += dataplane/ > +obj-$(CONFIG_VIRTIO) += dataplane/ > > obj-y += virtio.o virtio-balloon.o > obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o > diff --git a/hw/virtio/dataplane/Makefile.objs > b/hw/virtio/dataplane/Makefile.objs > index 9a8cfc0..753a9ca 100644 > --- a/hw/virtio/dataplane/Makefile.objs > +++ b/hw/virtio/dataplane/Makefile.objs > @@ -1 +1 @@ > -common-obj-y += vring.o > +obj-y += vring.o > diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c > index b84957f..4624521 100644 > --- a/hw/virtio/dataplane/vring.c > +++ b/hw/virtio/dataplane/vring.c > @@ -18,6 +18,7 @@ > #include "hw/hw.h" > #include "exec/memory.h" > #include "exec/address-spaces.h" > +#include "hw/virtio/virtio-access.h" > #include "hw/virtio/dataplane/vring.h" > #include "qemu/error-report.h" > > @@ -83,7 +84,7 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) > vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096); > > vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n); > -vring->last_used_idx = vring->vr.used->idx; > +vring->last_used_idx = vring_get_used_idx(vdev, vring); > vring->signalled_used = 0; > vring->signalled_used_valid = false; > > @@ -104,7 +105,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int > n) > void vring_disable_notification(VirtIODevice *vdev, Vring *vring) > { > if (!(vdev->guest_features[0] & (1 << VIRTIO_RING_F_EVENT_IDX))) { > -vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY; > +vring_set_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY); > } > } > > @@ -117,10 +118,10 @@ bool vring_enable_notification(VirtIODevice *vdev, > Vring *vring) > if (vdev->guest_features[0] & (1 << VIRTIO_RING_F_EVENT_IDX)) { > vring_avail_event(&vring->vr) = vring->vr.avail->idx; > } else { > -vring->vr.used->flags &= ~VRIN
Re: [Qemu-devel] [PATCH RFC 05/11] virtio: introduce legacy virtio devices
On Tue, 7 Oct 2014 16:40:01 +0200 Cornelia Huck wrote: > Introduce a helper function to indicate whether a virtio device is > operating in legacy or virtio standard mode. > > It may be used to make decisions about the endianess of virtio accesses > and other virtio-1 specific changes, enabling us to support transitional > devices. > > Reviewed-by: Thomas Huth > Signed-off-by: Cornelia Huck > --- > hw/virtio/virtio.c|6 +- > include/hw/virtio/virtio-access.h |4 > include/hw/virtio/virtio.h| 13 +++-- > 3 files changed, 20 insertions(+), 3 deletions(-) > > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > index 7aaa953..e6ae3a0 100644 > --- a/hw/virtio/virtio.c > +++ b/hw/virtio/virtio.c > @@ -883,7 +883,11 @@ static bool virtio_device_endian_needed(void *opaque) > VirtIODevice *vdev = opaque; > > assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > -return vdev->device_endian != virtio_default_endian(); > +if (virtio_device_is_legacy(vdev)) { > +return vdev->device_endian != virtio_default_endian(); > +} > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > +return vdev->device_endian != VIRTIO_DEVICE_ENDIAN_LITTLE; > } > Shouldn't we have some code doing the following somewhere ? if (!virtio_device_is_legacy(vdev)) { vdev->device_endian = VIRTIO_DEVICE_ENDIAN_LITTLE; } also, since virtio-1 is LE only, do we expect device_endian to be different from VIRTIO_DEVICE_ENDIAN_LITTLE ? Cheers. -- Greg > static const VMStateDescription vmstate_virtio_device_endian = { > diff --git a/include/hw/virtio/virtio-access.h > b/include/hw/virtio/virtio-access.h > index 46456fd..c123ee0 100644 > --- a/include/hw/virtio/virtio-access.h > +++ b/include/hw/virtio/virtio-access.h > @@ -19,6 +19,10 @@ > > static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) > { > +if (!virtio_device_is_legacy(vdev)) { > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > +return false; > +} > #if defined(TARGET_IS_BIENDIAN) > return virtio_is_big_endian(vdev); > #elif defined(TARGET_WORDS_BIGENDIAN) > diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h > index b408166..40e567c 100644 > --- a/include/hw/virtio/virtio.h > +++ b/include/hw/virtio/virtio.h > @@ -275,9 +275,18 @@ void virtio_queue_set_host_notifier_fd_handler(VirtQueue > *vq, bool assign, > void virtio_queue_notify_vq(VirtQueue *vq); > void virtio_irq(VirtQueue *vq); > > +static inline bool virtio_device_is_legacy(VirtIODevice *vdev) > +{ > +return !(vdev->guest_features[1] & (1 << (VIRTIO_F_VERSION_1 - 32))); > +} > + > static inline bool virtio_is_big_endian(VirtIODevice *vdev) > { > -assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > -return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; > +if (virtio_device_is_legacy(vdev)) { > +assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > +return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; > +} > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > +return false; > } > #endif ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [Qemu-devel] [PATCH RFC 05/11] virtio: introduce legacy virtio devices
On Thu, 30 Oct 2014 19:02:01 +0100 Cornelia Huck wrote: > On Tue, 28 Oct 2014 16:40:18 +0100 > Greg Kurz wrote: > > > On Tue, 7 Oct 2014 16:40:01 +0200 > > Cornelia Huck wrote: > > > > > Introduce a helper function to indicate whether a virtio device is > > > operating in legacy or virtio standard mode. > > > > > > It may be used to make decisions about the endianess of virtio accesses > > > and other virtio-1 specific changes, enabling us to support transitional > > > devices. > > > > > > Reviewed-by: Thomas Huth > > > Signed-off-by: Cornelia Huck > > > --- > > > hw/virtio/virtio.c|6 +- > > > include/hw/virtio/virtio-access.h |4 > > > include/hw/virtio/virtio.h| 13 +++-- > > > 3 files changed, 20 insertions(+), 3 deletions(-) > > > > > > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > > > index 7aaa953..e6ae3a0 100644 > > > --- a/hw/virtio/virtio.c > > > +++ b/hw/virtio/virtio.c > > > @@ -883,7 +883,11 @@ static bool virtio_device_endian_needed(void *opaque) > > > VirtIODevice *vdev = opaque; > > > > > > assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > > > -return vdev->device_endian != virtio_default_endian(); > > > +if (virtio_device_is_legacy(vdev)) { > > > +return vdev->device_endian != virtio_default_endian(); > > > +} > > > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > > > +return vdev->device_endian != VIRTIO_DEVICE_ENDIAN_LITTLE; > > > } > > > > > > > Shouldn't we have some code doing the following somewhere ? > > > > if (!virtio_device_is_legacy(vdev)) { > > vdev->device_endian = VIRTIO_DEVICE_ENDIAN_LITTLE; > > } > > > > also, since virtio-1 is LE only, do we expect device_endian to > > be different from VIRTIO_DEVICE_ENDIAN_LITTLE ? > > device_endian should not depend on whether the device is legacy or not. > virtio_is_big_endian always returns false for virtio-1 devices, though. Sorry, I had missed the virtio_is_big_endian() change: it that makes device_endian a legacy virtio only matter. So why would we care to migrate the endian subsection when we have a virtio-1 device ? Shouldn't virtio_device_endian_needed() return false for virtio-1 ? -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH RFC v2 07/12] dataplane: allow virtio-1 devices
On Tue, 25 Nov 2014 14:24:18 +0100 Cornelia Huck wrote: > Handle endianness conversion for virtio-1 virtqueues correctly. > > Note that dataplane now needs to be built per-target. > > Signed-off-by: Cornelia Huck > --- We still have the same error as in your previous post... In file included from include/hw/virtio/dataplane/vring.h:23:0, from include/hw/virtio/virtio-scsi.h:21, from hw/virtio/virtio-pci.c:24: include/hw/virtio/virtio-access.h: In function ‘virtio_access_is_big_endian’: include/hw/virtio/virtio-access.h:28:15: error: attempt to use poisoned "TARGET_WORDS_BIGENDIAN" #elif defined(TARGET_WORDS_BIGENDIAN) Either build virtio-pci per-target or probably better move the target tainted accessors to another file. > hw/block/dataplane/virtio-blk.c |3 +- > hw/scsi/virtio-scsi-dataplane.c |2 +- > hw/virtio/Makefile.objs |2 +- > hw/virtio/dataplane/Makefile.objs |2 +- > hw/virtio/dataplane/vring.c | 85 > +++ > include/hw/virtio/dataplane/vring.h | 64 -- > 6 files changed, 113 insertions(+), 45 deletions(-) > > diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c > index 1222a37..c25878c 100644 > --- a/hw/block/dataplane/virtio-blk.c > +++ b/hw/block/dataplane/virtio-blk.c > @@ -16,6 +16,7 @@ > #include "qemu/iov.h" > #include "qemu/thread.h" > #include "qemu/error-report.h" > +#include "hw/virtio/virtio-access.h" > #include "hw/virtio/dataplane/vring.h" > #include "sysemu/block-backend.h" > #include "hw/virtio/virtio-blk.h" > @@ -75,7 +76,7 @@ static void complete_request_vring(VirtIOBlockReq *req, > unsigned char status) > VirtIOBlockDataPlane *s = req->dev->dataplane; > stb_p(&req->in->status, status); > > -vring_push(&req->dev->dataplane->vring, &req->elem, > +vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, > req->qiov.size + sizeof(*req->in)); > > /* Suppress notification to guest by BH and its scheduled > diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c > index 03a1e8c..418d73b 100644 > --- a/hw/scsi/virtio-scsi-dataplane.c > +++ b/hw/scsi/virtio-scsi-dataplane.c > @@ -94,7 +94,7 @@ void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) > { > VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent); > > -vring_push(&req->vring->vring, &req->elem, > +vring_push(vdev, &req->vring->vring, &req->elem, > req->qsgl.size + req->resp_iov.size); > > if (vring_should_notify(vdev, &req->vring->vring)) { > diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs > index d21c397..19b224a 100644 > --- a/hw/virtio/Makefile.objs > +++ b/hw/virtio/Makefile.objs > @@ -2,7 +2,7 @@ common-obj-y += virtio-rng.o > common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o > common-obj-y += virtio-bus.o > common-obj-y += virtio-mmio.o > -common-obj-$(CONFIG_VIRTIO) += dataplane/ > +obj-$(CONFIG_VIRTIO) += dataplane/ > > obj-y += virtio.o virtio-balloon.o > obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o > diff --git a/hw/virtio/dataplane/Makefile.objs > b/hw/virtio/dataplane/Makefile.objs > index 9a8cfc0..753a9ca 100644 > --- a/hw/virtio/dataplane/Makefile.objs > +++ b/hw/virtio/dataplane/Makefile.objs > @@ -1 +1 @@ > -common-obj-y += vring.o > +obj-y += vring.o > diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c > index a051775..69809ff 100644 > --- a/hw/virtio/dataplane/vring.c > +++ b/hw/virtio/dataplane/vring.c > @@ -18,6 +18,7 @@ > #include "hw/hw.h" > #include "exec/memory.h" > #include "exec/address-spaces.h" > +#include "hw/virtio/virtio-access.h" > #include "hw/virtio/dataplane/vring.h" > #include "qemu/error-report.h" > > @@ -83,7 +84,7 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) > vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096); > > vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n); > -vring->last_used_idx = vring->vr.used->idx; > +vring->last_used_idx = vring_get_used_idx(vdev, vring); > vring->signalled_used = 0; > vring->signalled_used_valid = false; > > @@ -104,7 +105,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int > n) > void vring_disable_notification(VirtIODevice *vdev, Vring *vring) > { > if (!(vdev->guest_features[0] & (1 << VIRTIO_RING_F_EVENT_IDX))) { > -vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY; > +vring_set_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY); > } > } > > @@ -117,10 +118,10 @@ bool vring_enable_notification(VirtIODevice *vdev, > Vring *vring) > if (vdev->guest_features[0] & (1 << VIRTIO_RING_F_EVENT_IDX)) { > vring_avail_event(&vring->vr) = vring->vr.avail->idx; > } else { > -vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY; > +vring_clear_used_flags(vdev, vring, VRIN
Re: [PATCH v4 02/42] virtio: add support for 64 bit features.
On Tue, 25 Nov 2014 18:41:22 +0200 "Michael S. Tsirkin" wrote: > From: Rusty Russell > > Change the u32 to a u64, and make sure to use 1ULL everywhere! > > Cc: Brian Swetland > Cc: Christian Borntraeger > [Thomas Huth: fix up virtio-ccw get_features] > Signed-off-by: Rusty Russell > Signed-off-by: Cornelia Huck > Acked-by: Pawel Moll > Acked-by: Ohad Ben-Cohen > > Signed-off-by: Michael S. Tsirkin > --- > include/linux/virtio.h | 2 +- > include/linux/virtio_config.h | 8 > tools/virtio/linux/virtio.h| 2 +- > tools/virtio/linux/virtio_config.h | 2 +- > drivers/char/virtio_console.c | 2 +- > drivers/lguest/lguest_device.c | 10 +- > drivers/misc/mic/card/mic_virtio.c | 10 +- > drivers/remoteproc/remoteproc_virtio.c | 5 - > drivers/s390/kvm/kvm_virtio.c | 10 +- > drivers/s390/kvm/virtio_ccw.c | 29 - > drivers/virtio/virtio.c| 12 ++-- > drivers/virtio/virtio_mmio.c | 14 +- > drivers/virtio/virtio_pci.c| 5 ++--- > drivers/virtio/virtio_ring.c | 2 +- > 14 files changed, 69 insertions(+), 44 deletions(-) > > diff --git a/include/linux/virtio.h b/include/linux/virtio.h > index 7828a7f..149284e 100644 > --- a/include/linux/virtio.h > +++ b/include/linux/virtio.h > @@ -101,7 +101,7 @@ struct virtio_device { > const struct virtio_config_ops *config; > const struct vringh_config_ops *vringh_config; > struct list_head vqs; > - u32 features; > + u64 features; > void *priv; > }; > > diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h > index aa84d0e..022d904 100644 > --- a/include/linux/virtio_config.h > +++ b/include/linux/virtio_config.h > @@ -66,7 +66,7 @@ struct virtio_config_ops { > vq_callback_t *callbacks[], > const char *names[]); > void (*del_vqs)(struct virtio_device *); > - u32 (*get_features)(struct virtio_device *vdev); > + u64 (*get_features)(struct virtio_device *vdev); > void (*finalize_features)(struct virtio_device *vdev); > const char *(*bus_name)(struct virtio_device *vdev); > int (*set_vq_affinity)(struct virtqueue *vq, int cpu); > @@ -86,14 +86,14 @@ static inline bool virtio_has_feature(const struct > virtio_device *vdev, > { > /* Did you forget to fix assumptions on max features? */ > if (__builtin_constant_p(fbit)) > - BUILD_BUG_ON(fbit >= 32); > + BUILD_BUG_ON(fbit >= 64); While you're here, maybe you could derive the max value from the .features field ? - BUILD_BUG_ON(fbit >= 64); + BUILD_BUG_ON(fbit >= (sizeof(vdev->features) << 3)); Two other locations below. > else > - BUG_ON(fbit >= 32); > + BUG_ON(fbit >= 64); > Here... > if (fbit < VIRTIO_TRANSPORT_F_START) > virtio_check_driver_offered_feature(vdev, fbit); > > - return vdev->features & (1 << fbit); > + return vdev->features & (1ULL << fbit); > } > > static inline > diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h > index 72bff70..8eb6421 100644 > --- a/tools/virtio/linux/virtio.h > +++ b/tools/virtio/linux/virtio.h > @@ -10,7 +10,7 @@ > > struct virtio_device { > void *dev; > - u32 features; > + u64 features; > }; > > struct virtqueue { > diff --git a/tools/virtio/linux/virtio_config.h > b/tools/virtio/linux/virtio_config.h > index 1f1636b..a254c2b 100644 > --- a/tools/virtio/linux/virtio_config.h > +++ b/tools/virtio/linux/virtio_config.h > @@ -2,5 +2,5 @@ > #define VIRTIO_TRANSPORT_F_END 32 > > #define virtio_has_feature(dev, feature) \ > - ((dev)->features & (1 << feature)) > + ((dev)->features & (1ULL << feature)) > > diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c > index 0074f9b..fda9a75 100644 > --- a/drivers/char/virtio_console.c > +++ b/drivers/char/virtio_console.c > @@ -355,7 +355,7 @@ static inline bool use_multiport(struct ports_device > *portdev) >*/ > if (!portdev->vdev) > return 0; > - return portdev->vdev->features & (1 << VIRTIO_CONSOLE_F_MULTIPORT); > + return portdev->vdev->features & (1ULL << VIRTIO_CONSOLE_F_MULTIPORT); > } > > static DEFINE_SPINLOCK(dma_bufs_lock); > diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c > index c831c47..4d29bcd 100644 > --- a/drivers/lguest/lguest_device.c > +++ b/drivers/lguest/lguest_device.c > @@ -94,17 +94,17 @@ static unsigned desc_size(const struct lguest_device_desc > *desc) > } > > /* This gets the device's feature bits. */ > -static u32 lg_get_features(struct virtio_device *vdev) > +static u64 lg_get_features(struct virtio_device *vdev) > { > unsigned int i; > - u32 features = 0; > + u64 fea
Re: [PATCH RFC v3 07/12] dataplane: allow virtio-1 devices
On Wed, 26 Nov 2014 18:28:38 +0100 Cornelia Huck wrote: > Handle endianness conversion for virtio-1 virtqueues correctly. > > Note that dataplane now needs to be built per-target. > > Signed-off-by: Cornelia Huck Build is ok now. Acked-by: Greg Kurz > --- > hw/block/dataplane/virtio-blk.c |4 +- > hw/scsi/virtio-scsi-dataplane.c |2 +- > hw/virtio/Makefile.objs |2 +- > hw/virtio/dataplane/Makefile.objs |2 +- > hw/virtio/dataplane/vring.c | 86 > ++--- > include/hw/virtio/dataplane/vring-accessors.h | 75 + > include/hw/virtio/dataplane/vring.h | 14 +--- > 7 files changed, 131 insertions(+), 54 deletions(-) > create mode 100644 include/hw/virtio/dataplane/vring-accessors.h > > diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c > index 1222a37..2d8cc15 100644 > --- a/hw/block/dataplane/virtio-blk.c > +++ b/hw/block/dataplane/virtio-blk.c > @@ -16,7 +16,9 @@ > #include "qemu/iov.h" > #include "qemu/thread.h" > #include "qemu/error-report.h" > +#include "hw/virtio/virtio-access.h" > #include "hw/virtio/dataplane/vring.h" > +#include "hw/virtio/dataplane/vring-accessors.h" > #include "sysemu/block-backend.h" > #include "hw/virtio/virtio-blk.h" > #include "virtio-blk.h" > @@ -75,7 +77,7 @@ static void complete_request_vring(VirtIOBlockReq *req, > unsigned char status) > VirtIOBlockDataPlane *s = req->dev->dataplane; > stb_p(&req->in->status, status); > > -vring_push(&req->dev->dataplane->vring, &req->elem, > +vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, > req->qiov.size + sizeof(*req->in)); > > /* Suppress notification to guest by BH and its scheduled > diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c > index 03a1e8c..418d73b 100644 > --- a/hw/scsi/virtio-scsi-dataplane.c > +++ b/hw/scsi/virtio-scsi-dataplane.c > @@ -94,7 +94,7 @@ void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) > { > VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent); > > -vring_push(&req->vring->vring, &req->elem, > +vring_push(vdev, &req->vring->vring, &req->elem, > req->qsgl.size + req->resp_iov.size); > > if (vring_should_notify(vdev, &req->vring->vring)) { > diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs > index d21c397..19b224a 100644 > --- a/hw/virtio/Makefile.objs > +++ b/hw/virtio/Makefile.objs > @@ -2,7 +2,7 @@ common-obj-y += virtio-rng.o > common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o > common-obj-y += virtio-bus.o > common-obj-y += virtio-mmio.o > -common-obj-$(CONFIG_VIRTIO) += dataplane/ > +obj-$(CONFIG_VIRTIO) += dataplane/ > > obj-y += virtio.o virtio-balloon.o > obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o > diff --git a/hw/virtio/dataplane/Makefile.objs > b/hw/virtio/dataplane/Makefile.objs > index 9a8cfc0..753a9ca 100644 > --- a/hw/virtio/dataplane/Makefile.objs > +++ b/hw/virtio/dataplane/Makefile.objs > @@ -1 +1 @@ > -common-obj-y += vring.o > +obj-y += vring.o > diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c > index a051775..0da8d6b 100644 > --- a/hw/virtio/dataplane/vring.c > +++ b/hw/virtio/dataplane/vring.c > @@ -18,7 +18,9 @@ > #include "hw/hw.h" > #include "exec/memory.h" > #include "exec/address-spaces.h" > +#include "hw/virtio/virtio-access.h" > #include "hw/virtio/dataplane/vring.h" > +#include "hw/virtio/dataplane/vring-accessors.h" > #include "qemu/error-report.h" > > /* vring_map can be coupled with vring_unmap or (if you still have the > @@ -83,7 +85,7 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) > vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096); > > vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n); > -vring->last_used_idx = vring->vr.used->idx; > +vring->last_used_idx = vring_get_used_idx(vdev, vring); > vring->signalled_used = 0; > vring->signalled_used_valid = false; > > @@ -104,7 +106,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int > n) > void vring_disable_notification(VirtIODevice *vdev, Vring *vring) > { > if (!(vdev->guest_features[0] & (1 << VIRTIO_RING_F_EVENT_IDX))) { >
Re: [Qemu-devel] [PATCH RFC v3 05/12] virtio: introduce legacy virtio devices
On Wed, 26 Nov 2014 18:28:36 +0100 Cornelia Huck wrote: > Introduce a helper function to indicate whether a virtio device is > operating in legacy or virtio standard mode. > > It may be used to make decisions about the endianess of virtio accesses > and other virtio-1 specific changes, enabling us to support transitional > devices. > > Reviewed-by: Thomas Huth > Signed-off-by: Cornelia Huck > --- > hw/virtio/virtio.c|6 +- > include/hw/virtio/virtio-access.h |4 > include/hw/virtio/virtio.h| 13 +++-- > 3 files changed, 20 insertions(+), 3 deletions(-) > > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > index 2eb5d3c..4149f45 100644 > --- a/hw/virtio/virtio.c > +++ b/hw/virtio/virtio.c > @@ -883,7 +883,11 @@ static bool virtio_device_endian_needed(void *opaque) > VirtIODevice *vdev = opaque; > > assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > -return vdev->device_endian != virtio_default_endian(); > +if (virtio_device_is_legacy(vdev)) { > +return vdev->device_endian != virtio_default_endian(); > +} > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > +return vdev->device_endian != VIRTIO_DEVICE_ENDIAN_LITTLE; > } > Sorry but I still don't understand why we need to stream the device_endian subsection if we have a virtio-1 device... this field is only used on legacy device paths. Can you share an example where it is needed ? > static const VMStateDescription vmstate_virtio_device_endian = { > diff --git a/include/hw/virtio/virtio-access.h > b/include/hw/virtio/virtio-access.h > index 46456fd..c123ee0 100644 > --- a/include/hw/virtio/virtio-access.h > +++ b/include/hw/virtio/virtio-access.h > @@ -19,6 +19,10 @@ > > static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) > { > +if (!virtio_device_is_legacy(vdev)) { > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > +return false; > +} > #if defined(TARGET_IS_BIENDIAN) > return virtio_is_big_endian(vdev); > #elif defined(TARGET_WORDS_BIGENDIAN) > diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h > index b408166..40e567c 100644 > --- a/include/hw/virtio/virtio.h > +++ b/include/hw/virtio/virtio.h > @@ -275,9 +275,18 @@ void virtio_queue_set_host_notifier_fd_handler(VirtQueue > *vq, bool assign, > void virtio_queue_notify_vq(VirtQueue *vq); > void virtio_irq(VirtQueue *vq); > > +static inline bool virtio_device_is_legacy(VirtIODevice *vdev) > +{ > +return !(vdev->guest_features[1] & (1 << (VIRTIO_F_VERSION_1 - 32))); > +} > + > static inline bool virtio_is_big_endian(VirtIODevice *vdev) > { > -assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > -return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; > +if (virtio_device_is_legacy(vdev)) { > +assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > +return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; > +} > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > +return false; > } > #endif ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v8 34/50] vhost/net: virtio 1.0 byte swap
On Tue, 06 Jan 2015 16:55:30 -0700 Alex Williamson wrote: > On Mon, 2014-12-01 at 18:05 +0200, Michael S. Tsirkin wrote: > > I had to add an explicit tag to suppress compiler warning: > > gcc isn't smart enough to notice that > > len is always initialized since function is called with size > 0. > > I'm getting a panic inside a guest when this change is applied on the > host. I identified this patch via bisect and confirmed by reverting it > from v3.19-rc2. Guest is centos6. Thanks, > > Alex > > commit 8b38694a2dc8b18374310df50174f1e4376d6824 > Author: Michael S. Tsirkin > Date: Fri Oct 24 14:19:48 2014 +0300 > > vhost/net: virtio 1.0 byte swap > > I had to add an explicit tag to suppress compiler warning: > gcc isn't smart enough to notice that > len is always initialized since function is called with size > 0. > > Signed-off-by: Michael S. Tsirkin > Reviewed-by: Cornelia Huck > This chunk looks suspicious: - heads[headcount - 1].len += datalen; + heads[headcount - 1].len = cpu_to_vhost32(vq, len - datalen); s/len - datalen/len + datalen/ ? > XML chunk: > > > > > >function='0x0'/> > > > Panic log: > > <1>BUG: unable to handle kernel NULL pointer dereference at 0010 > <1>IP: [] virtnet_poll+0x4f9/0x910 [virtio_net] > <4>PGD 1aa2f4067 PUD 1aa2f5067 PMD 0 > <4>Oops: [#1] SMP > <4>last sysfs file: > /sys/devices/pci:00/:00:03.0/virtio0/net/eth9/ifindex > <4>CPU 0 > <4>Modules linked in: 8021q garp stp llc ipt_REJECT nf_conntrack_ipv4 > nf_defrag_ipv4 iptable_filter ip_tables ip6t_REJECT nf_conntrack_ipv6 > nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables ipv6 uinput > microcode snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq > snd_seq_device snd_pcm snd_timer snd soundcore snd_page_alloc igbvf > nvidia(P)(U) i2c_core tg3 ptp pps_core virtio_balloon virtio_net > virtio_console ext4 jbd2 mbcache virtio_blk virtio_pci virtio_ring virtio > pata_acpi ata_generic ata_piix dm_mirror dm_region_hash dm_log dm_mod [last > unloaded: speedstep_lib] > <4> > <4>Pid: 1374, comm: NetworkManager Tainted: P --- > 2.6.32-431.23.3.el6.centos.plus.x86_64 #1 QEMU Standard PC (i440FX + PIIX, > 1996) > <4>RIP: 0010:[] [] > virtnet_poll+0x4f9/0x910 [virtio_net] > <4>RSP: 0018:880028203e48 EFLAGS: 00010246 > <4>RAX: 8801a3383d00 RBX: 8801a6aaf480 RCX: 8801aa20b6e0 > <4>RDX: 00c0 RSI: 8801a3383c00 RDI: 8801a3383cc0 > <4>RBP: 880028203ed8 R08: 009e R09: 8801aa1d800c > <4>R10: 0218 R11: R12: 8801aa20b6e0 > <4>R13: R14: R15: > <4>FS: 7febf114d800() GS:88002820() > knlGS: > <4>CS: 0010 DS: ES: CR0: 80050033 > <4>CR2: 0010 CR3: 0001aa793000 CR4: 06f0 > <4>DR0: DR1: DR2: > <4>DR3: DR6: 0ff0 DR7: 0400 > <4>Process NetworkManager (pid: 1374, threadinfo 8801a74ba000, task > 8801a8d56040) > <4>Stack: > <4> 8801aa1d8000 009e 8801aa20b6e0 8801aa20b718 > <4> 8801aa20b780 8801aa1d800c 8801a6aaf4b8 8801aa20b020 > <4> 0080 8801aa20b708 0001 1f5981a830c8 > <4>Call Trace: > <4> > <4> [] net_rx_action+0x103/0x2f0 > <4> [] __do_softirq+0xc1/0x1e0 > <4> [] ? call_softirq+0x1c/0x30 > <4> [] call_softirq+0x1c/0x30 > <4> > <4> [] ? do_softirq+0x65/0xa0 > <4> [] local_bh_enable+0x9a/0xb0 > <4> [] virtnet_napi_enable+0x4a/0x60 [virtio_net] > <4> [] virtnet_open+0x4f/0x60 [virtio_net] > <4> [] dev_open+0xa1/0x100 > <4> [] dev_change_flags+0xa1/0x1d0 > <4> [] do_setlink+0x169/0x8b0 > <4> [] ? rtnl_fill_ifinfo+0x946/0xcb0 > <4> [] ? nla_parse+0x34/0x110 > <4> [] rtnl_setlink+0xee/0x130 > <4> [] rtnetlink_rcv_msg+0x2d7/0x340 > <4> [] ? socket_has_perm+0x74/0x90 > <4> [] ? rtnetlink_rcv_msg+0x0/0x340 > <4> [] netlink_rcv_skb+0xa9/0xd0 > <4> [] rtnetlink_rcv+0x25/0x40 > <4> [] netlink_unicast+0x2db/0x320 > <4> [] netlink_sendmsg+0x2c0/0x3d0 > <4> [] sock_sendmsg+0x123/0x150 > <4> [] ? sock_recvmsg+0x133/0x160 > <4> [] ? autoremove_wake_function+0x0/0x40 > <4> [] ? lru_cache_add_lru+0x21/0x40 > <4> [] ? page_add_new_anon_rmap+0x9d/0xf0 > <4> [] ? handle_pte_fault+0x4af/0xb00 > <4> [] ? move_addr_to_kernel+0x64/0x70 > <4> [] __sys_sendmsg+0x406/0x420 > <4> [] ? __do_page_fault+0x1ec/0x480 > <4> [] ? sys_sendto+0x139/0x190 > <4> [] ? kvm_clock_read+0x1c/0x20 > <4> [] sys_sendmsg+0x49/0x90 > <4> [] system_call_fastpath+0x16/0x1b > <4>Code: 83 e0 00 00 00 00 10 00 00 48 03 93 d0 00 00 00 66 83 42 04 01 8b 93 > cc 00 00 00 48 8b b3 d0 00 00 00 80 4c 16 10 20 44 2b 68 0c <4d> 8b 76 10 75 > 89 e9 d1 fd ff ff 0f 1f 40 00 a8 02 74 0d 0f b6 > <1>RIP [] virtnet_poll+0x4f9/0x91
Re: [Qemu-devel] [PATCH RFC v6 06/20] virtio: endianness checks for virtio 1.0 devices
On Thu, 22 Jan 2015 12:54:09 +1100 David Gibson wrote: > On Thu, Dec 11, 2014 at 02:25:08PM +0100, Cornelia Huck wrote: > > Add code that checks for the VERSION_1 feature bit in order to make > > decisions about the device's endianness. This allows us to support > > transitional devices. > > > > Signed-off-by: Cornelia Huck > > --- > > hw/virtio/virtio.c|6 +- > > include/hw/virtio/virtio-access.h |4 > > include/hw/virtio/virtio.h|8 ++-- > > 3 files changed, 15 insertions(+), 3 deletions(-) > > > > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > > index 7f74ae5..8f69ffa 100644 > > --- a/hw/virtio/virtio.c > > +++ b/hw/virtio/virtio.c > > @@ -881,7 +881,11 @@ static bool virtio_device_endian_needed(void *opaque) > > VirtIODevice *vdev = opaque; > > > > assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > > -return vdev->device_endian != virtio_default_endian(); > > +if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { > > +return vdev->device_endian != virtio_default_endian(); > > +} > > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > > +return vdev->device_endian != VIRTIO_DEVICE_ENDIAN_LITTLE; > > This doesn't seem quite right. Since virtio 1.0 is always LE, this > should just assert that device_endian == LE and return false, > right? > The device_endian field is ONLY used by devices when the software is legacy. It is set at device reset time (see virtio_reset()) since we can reasonably assume that when the software changes endianness, it always reset the device before using it again (aka. reboot or kexec). In the case we would have a BE guest, device_endian would be BE, even if the software is virtio 1.0. So, no, we shouldn't assert. I had questioned Cornelia about why we care to migrate device_endian when in virtio 1.0 mode. I got these answers: https://lists.nongnu.org/archive/html/qemu-devel/2014-10/msg03979.html https://lists.nongnu.org/archive/html/qemu-devel/2014-11/msg03888.html My understanding is that a transitional device will necessarily be reset if the software changes from legacy to 1.0 or vice-versa. So, yes, I still think virtio_device_endian_needed() should return false. > > } > > > > static const VMStateDescription vmstate_virtio_device_endian = { > > diff --git a/include/hw/virtio/virtio-access.h > > b/include/hw/virtio/virtio-access.h > > index 46456fd..ee28c21 100644 > > --- a/include/hw/virtio/virtio-access.h > > +++ b/include/hw/virtio/virtio-access.h > > @@ -19,6 +19,10 @@ > > > > static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) > > { > > +if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { > > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > > +return false; > > +} > > #if defined(TARGET_IS_BIENDIAN) > > return virtio_is_big_endian(vdev); > > #elif defined(TARGET_WORDS_BIGENDIAN) > > diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h > > index 08141c7..68c40db 100644 > > --- a/include/hw/virtio/virtio.h > > +++ b/include/hw/virtio/virtio.h > > @@ -297,7 +297,11 @@ static inline bool virtio_has_feature(VirtIODevice > > *vdev, unsigned int fbit) > > > > static inline bool virtio_is_big_endian(VirtIODevice *vdev) > > { > > -assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > > -return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; > > +if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { > > +assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); > > +return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; > > +} > > +/* Devices conforming to VIRTIO 1.0 or later are always LE. */ > > +return false; > > } > > #endif > > AFAICT, the only real difference between virtio_is_big_endian() and > virtio_access_is_big_endian() is that the latter will become > compile-time constant on targets that don't do bi-endian. > > With virtio 1.0 support, that's no longer true, so those two macros > should just be merged, I think. > pgp8Kc3xUSH86.pgp Description: OpenPGP digital signature ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH 0/3] vhost_net: support for cross endian guests
Hi, This patchset allows vhost_net to be used with legacy virtio when guest and host have a different endianness. It is based on previous work by Cédric Le Goater: https://www.mail-archive.com/kvm-ppc@vger.kernel.org/msg09848.html As suggested by MST: - the API now asks for a specific format (big endian) instead of the hint whether byteswap is needed or not (patch 1) - rebased on top of the virtio-1 accessors (patch 2) Patch 3 is a separate fix: I think it is also valid for virtio-1. Please comment. --- Greg Kurz (3): vhost: add VHOST_VRING_F_LEGACY_BIG_ENDIAN flag vhost: add support for legacy virtio vhost_net: fix virtio_net header endianness drivers/vhost/net.c| 32 ++-- drivers/vhost/vhost.c |6 +- drivers/vhost/vhost.h | 23 +-- include/uapi/linux/vhost.h |2 ++ 4 files changed, 50 insertions(+), 13 deletions(-) -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH 1/3] vhost: add VHOST_VRING_F_LEGACY_BIG_ENDIAN flag
The VHOST_VRING_F_LEGACY_BIG_ENDIAN flag informs the kernel that the associated device is big endian. Of course, this only makes sense for legacy virtio devices since modern virtio devices are always little endian. It will be used by the vhost memory accessors to byteswap vring data when we have a legacy device, in case host and guest endianness differ. Signed-off-by: Greg Kurz --- drivers/vhost/vhost.c |6 +- drivers/vhost/vhost.h |3 +++ include/uapi/linux/vhost.h |2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ee2826..dad3c37 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -199,6 +199,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call = NULL; vq->log_ctx = NULL; vq->memory = NULL; + vq->legacy_big_endian = false; } static int vhost_worker(void *data) @@ -701,7 +702,8 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) r = -EFAULT; break; } - if (a.flags & ~(0x1 << VHOST_VRING_F_LOG)) { + if (a.flags & ~(0x1 << VHOST_VRING_F_LOG| + 0x1 << VHOST_VRING_F_LEGACY_BIG_ENDIAN)) { r = -EOPNOTSUPP; break; } @@ -751,6 +753,8 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) vq->avail = (void __user *)(unsigned long)a.avail_user_addr; vq->log_addr = a.log_guest_addr; vq->used = (void __user *)(unsigned long)a.used_user_addr; + vq->legacy_big_endian = + !!(a.flags & (0x1 << VHOST_VRING_F_LEGACY_BIG_ENDIAN)); break; case VHOST_SET_VRING_KICK: if (copy_from_user(&f, argp, sizeof f)) { diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 8c1c792..ce2c68e 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -106,6 +106,9 @@ struct vhost_virtqueue { /* Log write descriptors */ void __user *log_base; struct vhost_log *log; + + /* We need to know the device endianness with legacy virtio. */ + bool legacy_big_endian; }; struct vhost_dev { diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h index bb6a5b4..0bf4491 100644 --- a/include/uapi/linux/vhost.h +++ b/include/uapi/linux/vhost.h @@ -34,6 +34,8 @@ struct vhost_vring_addr { /* Flag values: */ /* Whether log address is valid. If set enables logging. */ #define VHOST_VRING_F_LOG 0 + /* Whether we have a big-endian legacy virtio device. */ +#define VHOST_VRING_F_LEGACY_BIG_ENDIAN 1 /* Start of array of descriptors (virtually contiguous) */ __u64 desc_user_addr; ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH 2/3] vhost: add support for legacy virtio
Signed-off-by: Greg Kurz --- drivers/vhost/vhost.h | 20 ++-- 1 file changed, 14 insertions(+), 6 deletions(-) Michael, The vhost_is_little_endian() helper adds unconditionnal overhead to fixed endian architectures: that is all architectures except arm and ppc64. This was addressed in QEMU with a TARGET_IS_BIENDIAN macro. Please give an advice about how to address this in the vhost code. Thanks. diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index ce2c68e..21e7d6a 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -176,34 +176,42 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) return vq->acked_features & (1ULL << bit); } +static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) +{ + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + return true; + else + return !vq->legacy_big_endian; +} + /* Memory accessors */ static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) { - return __virtio16_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio16 cpu_to_vhost16(struct vhost_virtqueue *vq, u16 val) { - return __cpu_to_virtio16(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(vhost_is_little_endian(vq), val); } static inline u32 vhost32_to_cpu(struct vhost_virtqueue *vq, __virtio32 val) { - return __virtio32_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio32 cpu_to_vhost32(struct vhost_virtqueue *vq, u32 val) { - return __cpu_to_virtio32(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(vhost_is_little_endian(vq), val); } static inline u64 vhost64_to_cpu(struct vhost_virtqueue *vq, __virtio64 val) { - return __virtio64_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio64 cpu_to_vhost64(struct vhost_virtqueue *vq, u64 val) { - return __cpu_to_virtio64(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(vhost_is_little_endian(vq), val); } #endif ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH 3/3] vhost_net: fix virtio_net header endianness
Without this patch, packets are being silently dropped by the tap backend. Signed-off-by: Greg Kurz --- drivers/vhost/net.c | 32 ++-- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index afa06d2..2923eee 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -288,6 +288,16 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) rcu_read_unlock_bh(); } +static void fix_virtio_net_hdr(struct vhost_virtqueue *vq) +{ + struct virtio_net_hdr *hdr = vq->iov[0].iov_base; + + hdr->hdr_len = vhost16_to_cpu(vq, hdr->hdr_len); + hdr->gso_size = vhost16_to_cpu(vq, hdr->gso_size); + hdr->csum_start = vhost16_to_cpu(vq, hdr->csum_start); + hdr->csum_offset = vhost16_to_cpu(vq, hdr->csum_offset); +} + /* Expects to be always run from workqueue - which acts as * read-size critical section for our kind of RCU. */ static void handle_tx(struct vhost_net *net) @@ -352,6 +362,10 @@ static void handle_tx(struct vhost_net *net) "out %d, int %d\n", out, in); break; } + + if (!hdr_size) + fix_virtio_net_hdr(vq); + /* Skip header. TODO: support TSO. */ len = iov_length(vq->iov, out); iov_iter_init(&msg.msg_iter, WRITE, vq->iov, out, len); @@ -609,12 +623,18 @@ static void handle_rx(struct vhost_net *net) continue; } /* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ - if (unlikely(vhost_hlen) && - copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) { - vq_err(vq, "Unable to write vnet_hdr at addr %p\n", - vq->iov->iov_base); - break; - } + if (unlikely(vhost_hlen)) { + size_t len = copy_to_iter(&hdr, sizeof(hdr), &fixup); + + if (len != sizeof(hdr)) { + vq_err(vq, + "Unable to write vnet_hdr at addr %p\n", + vq->iov->iov_base); + break; + } + } else + fix_virtio_net_hdr(vq); + /* TODO: Should check and handle checksum. */ num_buffers = cpu_to_vhost16(vq, headcount); ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH 0/3] vhost_net: support for cross endian guests
On Sun, 22 Feb 2015 10:53:51 +0100 "Michael S. Tsirkin" wrote: > On Fri, Feb 20, 2015 at 11:07:24AM +0100, Greg Kurz wrote: > > Hi, > > > > This patchset allows vhost_net to be used with legacy virtio > > when guest and host have a different endianness. It is based > > on previous work by Cédric Le Goater: > > > > https://www.mail-archive.com/kvm-ppc@vger.kernel.org/msg09848.html > > > > As suggested by MST: > > - the API now asks for a specific format (big endian) instead of the hint > > whether byteswap is needed or not (patch 1) > > - rebased on top of the virtio-1 accessors (patch 2) > > > > Patch 3 is a separate fix: I think it is also valid for virtio-1. > > I don't think so. See e.g. this code in tun: > gso.csum_offset = cpu_to_tun16(tun, skb->csum_offset); > looks like it has the correct endian-ness for virtio-1. > > Indeed. I will fix tun/macvtap as you suggested. Thanks for the review. -- Greg > > > Please comment. > > > > --- > > > > Greg Kurz (3): > > vhost: add VHOST_VRING_F_LEGACY_BIG_ENDIAN flag > > vhost: add support for legacy virtio > > vhost_net: fix virtio_net header endianness > > > > > > drivers/vhost/net.c| 32 ++-- > > drivers/vhost/vhost.c |6 +- > > drivers/vhost/vhost.h | 23 +-- > > include/uapi/linux/vhost.h |2 ++ > > 4 files changed, 50 insertions(+), 13 deletions(-) > > > > -- > > Greg > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] virtio-pci: fix host notifiers on bi-endian architectures
vhost is seriously broken with ppc64le guests, even in the supposedly supported case where the host is ppc64le and we don't need cross-endian support. The TX virtqueue fails to be handled by vhost and falls back to QEMU. Despite this unexpected scenario where RX is vhost and TX is QEMU, the guest runs well with reduced upload performances... until you reboot, migrate, managed save or in fact any operation that causes vhost_net to be re-started. Network connectivity is then permanantly lost for the guest. TX falling back to QEMU is the result of a failed MMIO store emulation in KVM. Debugging shows that: kvmppc_emulate_mmio() | +-> kvmppc_handle_store() | +-> kvm_io_bus_write() | +-> __kvm_io_bus_write() returns -EOPNOTSUPP This happens because no matching device was found: __kvm_io_bus_write() | +->kvm_iodevice_write() | +->ioeventfd_write() | +->ioeventfd_in_range() returns false for all registered vrings Extra debugging shows that the TX vring number (16-bit) is supposed to be 0x0100 but QEMU passes 0x0001 to KVM... This happens *again* because QEMU still assumes powerpc is big endian (TARGET_WORDS_BIGENDIAN) by default. This patch adds an extra swap in virtio_pci_set_host_notifier_internal() to negate the one that is done in adjust_endianness(). Since this is not a hot path and we want to keep virtio-pci.o in common-obj, we don't care whether the guest is bi-endian or not. Reported-by: Cédric Le Goater Suggested-by: Michael Roth Signed-off-by: Greg Kurz --- I guess it is also a fix for virtio-1 but I didn't check. hw/virtio/virtio-pci.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index e7baf7b..62b04c9 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -133,6 +133,11 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) return 0; } +static uint16_t cpu_to_host_notifier16(VirtIODevice *vdev, uint16_t val) +{ +return virtio_is_big_endian(vdev) ? val : bswap16(val); +} + static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, int n, bool assign, bool set_handler) { @@ -150,10 +155,12 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, } virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, - true, n, notifier); + true, cpu_to_host_notifier16(vdev, n), + notifier); } else { memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, - true, n, notifier); + true, cpu_to_host_notifier16(vdev, n), + notifier); virtio_queue_set_host_notifier_fd_handler(vq, false, false); event_notifier_cleanup(notifier); } ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH] virtio-pci: fix host notifiers on bi-endian architectures
On Wed, 11 Mar 2015 21:06:05 +0100 "Michael S. Tsirkin" wrote: > On Wed, Mar 11, 2015 at 07:04:38PM +0100, Greg Kurz wrote: > > vhost is seriously broken with ppc64le guests, even in the supposedly > > supported case where the host is ppc64le and we don't need cross-endian > > support. > > > > The TX virtqueue fails to be handled by vhost and falls back to QEMU. > > Despite this unexpected scenario where RX is vhost and TX is QEMU, the > > guest runs well with reduced upload performances... until you reboot, > > migrate, managed save or in fact any operation that causes vhost_net > > to be re-started. Network connectivity is then permanantly lost for > > the guest. > > > > TX falling back to QEMU is the result of a failed MMIO store emulation > > in KVM. Debugging shows that: > > > > kvmppc_emulate_mmio() > > | > > +-> kvmppc_handle_store() > > | > > +-> kvm_io_bus_write() > >| > >+-> __kvm_io_bus_write() returns -EOPNOTSUPP > > > > This happens because no matching device was found: > > > > __kvm_io_bus_write() > > | > > +->kvm_iodevice_write() > > | > > +->ioeventfd_write() > > | > > +->ioeventfd_in_range() returns false for all registered vrings > > > > Extra debugging shows that the TX vring number (16-bit) is supposed to > > be 0x0100 but QEMU passes 0x0001 to KVM... This happens *again* because > > QEMU still assumes powerpc is big endian (TARGET_WORDS_BIGENDIAN) by > > default. > > > > This patch adds an extra swap in virtio_pci_set_host_notifier_internal() > > to negate the one that is done in adjust_endianness(). Since this is not > > a hot path and we want to keep virtio-pci.o in common-obj, we don't care > > whether the guest is bi-endian or not. > > > > Reported-by: Cédric Le Goater > > Suggested-by: Michael Roth > > Signed-off-by: Greg Kurz > > I am confused. > The value that notifications use is always LE. True but adjust_endianness() does swap unconditionally for ppc64 because of TARGET_WORDS_BIGENDIAN. > Can't we avoid multiple swaps? That would mean adding an extra endianness argument down to memory_region_wrong_endianness()... not sure we want to do that. > They make my head spin. > I understand that the current fixed target endianness paradigm is best suited for most architectures. Extra swaps in specific non-critical locations allows to support odd beasts like ppc64le and arm64be without trashing more common paths. Maybe I can add a comment for better clarity (see below). > > --- > > > > I guess it is also a fix for virtio-1 but I didn't check. > > > > hw/virtio/virtio-pci.c | 11 +-- > > 1 file changed, 9 insertions(+), 2 deletions(-) > > > > diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c > > index e7baf7b..62b04c9 100644 > > --- a/hw/virtio/virtio-pci.c > > +++ b/hw/virtio/virtio-pci.c > > @@ -133,6 +133,11 @@ static int virtio_pci_load_queue(DeviceState *d, int > > n, QEMUFile *f) > > return 0; > > } > > /* The host notifier will be swapped in adjust_endianness() according to the * target default endianness. We need to negate this swap if the device uses * an endianness that is not the default (ppc64le for example). */ > > +static uint16_t cpu_to_host_notifier16(VirtIODevice *vdev, uint16_t val) > > +{ > > +return virtio_is_big_endian(vdev) ? val : bswap16(val); > > +} > > + > > static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, > > int n, bool assign, bool > > set_handler) > > { > > @@ -150,10 +155,12 @@ static int > > virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, > > } > > virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); > > memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, > > - true, n, notifier); > > + true, cpu_to_host_notifier16(vdev, n), > > + notifier); > > } else { > > memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, > > - true, n, notifier); > > + true, cpu_to_host_notifier16(vdev, n), > > + notifier); > > virtio_queue_set_host_notifier_fd_handler(vq, false, false); > > event_notifier_cleanup(notifier); > > } > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [Qemu-ppc] [PATCH] virtio-pci: fix host notifiers on bi-endian architectures
On Thu, 12 Mar 2015 09:18:38 +1100 Benjamin Herrenschmidt wrote: > On Wed, 2015-03-11 at 23:03 +0100, Greg Kurz wrote: > > > /* The host notifier will be swapped in adjust_endianness() according to the > > * target default endianness. We need to negate this swap if the device uses > > * an endianness that is not the default (ppc64le for example). > > */ > > > > > > +static uint16_t cpu_to_host_notifier16(VirtIODevice *vdev, uint16_t > > > > val) > > > > +{ > > > > +return virtio_is_big_endian(vdev) ? val : bswap16(val); > > > > +} > > But but but ... The above ... won't it do things like break x86 ? Ie, > shouldn't we swap only if TARGET_BIG_ENDIAN and !virtio_is_big_endian ? > Or better, "fixed target endian" ^ "virtio endian" to cover all cases ? > Yeah you're right, it's a mess :) To avoid virtio-pci.o being built per target, we can use virtio_default_endian() instead (to be exported from virtio.c): return vdev->device_endian() != virtio_default_endian() ? val : bswap16(val); I shall test on x86 and post a v2. Thanks. -- G > Cheers, > Ben. > > > > > static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, > > > > int n, bool assign, > > > > bool set_handler) > > > > { > > > > @@ -150,10 +155,12 @@ static int > > > > virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, > > > > } > > > > virtio_queue_set_host_notifier_fd_handler(vq, true, > > > > set_handler); > > > > memory_region_add_eventfd(&proxy->bar, > > > > VIRTIO_PCI_QUEUE_NOTIFY, 2, > > > > - true, n, notifier); > > > > + true, cpu_to_host_notifier16(vdev, > > > > n), > > > > + notifier); > > > > } else { > > > > memory_region_del_eventfd(&proxy->bar, > > > > VIRTIO_PCI_QUEUE_NOTIFY, 2, > > > > - true, n, notifier); > > > > + true, cpu_to_host_notifier16(vdev, > > > > n), > > > > + notifier); > > > > virtio_queue_set_host_notifier_fd_handler(vq, false, false); > > > > event_notifier_cleanup(notifier); > > > > } > > > > > > > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH] virtio-pci: fix host notifiers on bi-endian architectures
On Thu, 12 Mar 2015 17:25:15 +0100 Paolo Bonzini wrote: > > > On 12/03/2015 08:08, Michael S. Tsirkin wrote: > > But common header format is simple, it's always LE. > > It does not depend on target. > > To me this looks like a bug in memory_region_add_eventfd, > > it should do the right thing depending on device > > endian-ness. > > I agree it seems to be a QEMU bug. > > Paolo > Yes you're right ! QEMU swaps the virtqueue id (adjust_endianness) according to TARGET_WORDS, like it was coming from the guest but in fact it comes from the host. The id should be fixed according to HOST_WORDS instead. Of course this went unnoticed until TARGET_WORDS_BIGENDIAN != HOST_WORDS_BIGENDIAN, which we have now with ppc64le hosts. Patches to follow. Thanks. -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v2 0/7] vhost: support for cross endian guests
Hi, This patchset allows vhost to be used with legacy virtio when guest and host have a different endianness. It is a complete rework of my initial post. Patches 1 to 5 are preliminary work: we move the endianness check out of all memory accessors to separate functions. Patch 6 changes the semantics of the accessors so that they have explicit big endian support. Patch 7 brings the cross-endian feature, with the following changes since v1: - conditionnal enablement through a kernel config - introduction of a new vhost feature to advertise cross-endian to userspace The tentative to fix vnet headers was dropped for the moment. As a consequnce, vhost_net still fails to work with cross-endian. It will be fixed in another patchset I'm currently working on. --- Greg Kurz (7): virtio: introduce virtio_is_little_endian() helper tun: add tun_is_little_endian() helper macvtap: introduce macvtap_is_little_endian() helper vringh: introduce vringh_is_little_endian() helper vhost: introduce vhost_is_little_endian() helper virtio: add explicit big-endian support to memory accessors vhost: feature to set the vring endianness drivers/net/macvtap.c| 11 +-- drivers/net/tun.c| 11 +-- drivers/vhost/Kconfig| 10 ++ drivers/vhost/net.c |5 + drivers/vhost/scsi.c |4 drivers/vhost/test.c |4 drivers/vhost/vhost.c| 19 +++ drivers/vhost/vhost.h| 32 +--- include/linux/virtio_byteorder.h | 24 ++-- include/linux/virtio_config.h| 19 +-- include/linux/vringh.h | 19 +-- include/uapi/linux/vhost.h | 10 ++ 12 files changed, 135 insertions(+), 33 deletions(-) -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v2 3/7] macvtap: introduce macvtap_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/net/macvtap.c |9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 27ecc5c..a2f2958 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -49,14 +49,19 @@ struct macvtap_queue { #define MACVTAP_VNET_LE 0x8000 +static inline bool macvtap_is_little_endian(struct macvtap_queue *q) +{ + return q->flags & MACVTAP_VNET_LE; +} + static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) { - return __virtio16_to_cpu(q->flags & MACVTAP_VNET_LE, val); + return __virtio16_to_cpu(macvtap_is_little_endian(q), val); } static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val) { - return __cpu_to_virtio16(q->flags & MACVTAP_VNET_LE, val); + return __cpu_to_virtio16(macvtap_is_little_endian(q), val); } static struct proto macvtap_proto = { ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v2 1/7] virtio: introduce virtio_is_little_endian() helper
Signed-off-by: Greg Kurz --- include/linux/virtio_config.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index ca3ed78..bd1a582 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -205,35 +205,40 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu) return 0; } +static inline bool virtio_is_little_endian(struct virtio_device *vdev) +{ + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) { - return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) { - return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(virtio_is_little_endian(vdev), val); } static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) { - return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) { - return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(virtio_is_little_endian(vdev), val); } static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) { - return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) { - return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); } /* Config space accessors. */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v2 4/7] vringh: introduce vringh_is_little_endian() helper
Signed-off-by: Greg Kurz --- include/linux/vringh.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/vringh.h b/include/linux/vringh.h index a3fa537..3ed62ef 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -226,33 +226,38 @@ static inline void vringh_notify(struct vringh *vrh) vrh->notify(vrh); } +static inline bool vringh_is_little_endian(const struct vringh *vrh) +{ + return vrh->little_endian; +} + static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val) { - return __virtio16_to_cpu(vrh->little_endian, val); + return __virtio16_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio16 cpu_to_vringh16(const struct vringh *vrh, u16 val) { - return __cpu_to_virtio16(vrh->little_endian, val); + return __cpu_to_virtio16(vringh_is_little_endian(vrh), val); } static inline u32 vringh32_to_cpu(const struct vringh *vrh, __virtio32 val) { - return __virtio32_to_cpu(vrh->little_endian, val); + return __virtio32_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio32 cpu_to_vringh32(const struct vringh *vrh, u32 val) { - return __cpu_to_virtio32(vrh->little_endian, val); + return __cpu_to_virtio32(vringh_is_little_endian(vrh), val); } static inline u64 vringh64_to_cpu(const struct vringh *vrh, __virtio64 val) { - return __virtio64_to_cpu(vrh->little_endian, val); + return __virtio64_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio64 cpu_to_vringh64(const struct vringh *vrh, u64 val) { - return __cpu_to_virtio64(vrh->little_endian, val); + return __cpu_to_virtio64(vringh_is_little_endian(vrh), val); } #endif /* _LINUX_VRINGH_H */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v2 2/7] tun: add tun_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/net/tun.c |9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 857dca4..3c3d6c0 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -206,14 +206,19 @@ struct tun_struct { u32 flow_count; }; +static inline bool tun_is_little_endian(struct tun_struct *tun) +{ + return tun->flags & TUN_VNET_LE; +} + static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) { - return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val); + return __virtio16_to_cpu(tun_is_little_endian(tun), val); } static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) { - return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val); + return __cpu_to_virtio16(tun_is_little_endian(tun), val); } static inline u32 tun_hashfn(u32 rxhash) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v2 5/7] vhost: introduce vhost_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/vhost/vhost.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 8c1c792..6a49960 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -173,34 +173,39 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) return vq->acked_features & (1ULL << bit); } +static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) +{ + return vhost_has_feature(vq, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) { - return __virtio16_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio16 cpu_to_vhost16(struct vhost_virtqueue *vq, u16 val) { - return __cpu_to_virtio16(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(vhost_is_little_endian(vq), val); } static inline u32 vhost32_to_cpu(struct vhost_virtqueue *vq, __virtio32 val) { - return __virtio32_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio32 cpu_to_vhost32(struct vhost_virtqueue *vq, u32 val) { - return __cpu_to_virtio32(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(vhost_is_little_endian(vq), val); } static inline u64 vhost64_to_cpu(struct vhost_virtqueue *vq, __virtio64 val) { - return __virtio64_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio64 cpu_to_vhost64(struct vhost_virtqueue *vq, u64 val) { - return __cpu_to_virtio64(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(vhost_is_little_endian(vq), val); } #endif ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v2 6/7] virtio: add explicit big-endian support to memory accessors
The current memory accessors logic is: - little endian if little_endian - native endian (i.e. no byteswap) if !little_endian If we want to fully support cross-endian vhost, we also need to be able to convert to big endian. Instead of changing the little_endian argument to some 3-value enum, this patch changes the logic to: - little endian if little_endian - big endian if !little_endian The native endian case is handled by all users with a trivial helper. This patch doesn't change any functionality, nor it does add overhead. Signed-off-by: Greg Kurz --- drivers/net/macvtap.c|4 +++- drivers/net/tun.c|4 +++- drivers/vhost/vhost.h|4 +++- include/linux/virtio_byteorder.h | 24 ++-- include/linux/virtio_config.h|4 +++- include/linux/vringh.h |4 +++- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index a2f2958..0a03a66 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -51,7 +51,9 @@ struct macvtap_queue { static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { - return q->flags & MACVTAP_VNET_LE; + if (q->flags & MACVTAP_VNET_LE) + return true; + return virtio_legacy_is_little_endian(); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3c3d6c0..053f9b6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -208,7 +208,9 @@ struct tun_struct { static inline bool tun_is_little_endian(struct tun_struct *tun) { - return tun->flags & TUN_VNET_LE; + if (tun->flags & TUN_VNET_LE) + return true; + return virtio_legacy_is_little_endian(); } static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 6a49960..4e9a186 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -175,7 +175,9 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) { - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + return true; + return virtio_legacy_is_little_endian(); } /* Memory accessors */ diff --git a/include/linux/virtio_byteorder.h b/include/linux/virtio_byteorder.h index 51865d0..ce63a2c 100644 --- a/include/linux/virtio_byteorder.h +++ b/include/linux/virtio_byteorder.h @@ -3,17 +3,21 @@ #include #include -/* - * Low-level memory accessors for handling virtio in modern little endian and in - * compatibility native endian format. - */ +static inline bool virtio_legacy_is_little_endian(void) +{ +#ifdef __LITTLE_ENDIAN + return true; +#else + return false; +#endif +} static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) { if (little_endian) return le16_to_cpu((__force __le16)val); else - return (__force u16)val; + return be16_to_cpu((__force __be16)val); } static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) if (little_endian) return (__force __virtio16)cpu_to_le16(val); else - return (__force __virtio16)val; + return (__force __virtio16)cpu_to_be16(val); } static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) @@ -29,7 +33,7 @@ static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) if (little_endian) return le32_to_cpu((__force __le32)val); else - return (__force u32)val; + return be32_to_cpu((__force __be32)val); } static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) @@ -37,7 +41,7 @@ static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) if (little_endian) return (__force __virtio32)cpu_to_le32(val); else - return (__force __virtio32)val; + return (__force __virtio32)cpu_to_be32(val); } static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) @@ -45,7 +49,7 @@ static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) if (little_endian) return le64_to_cpu((__force __le64)val); else - return (__force u64)val; + return be64_to_cpu((__force __be64)val); } static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) @@ -53,7 +57,7 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) if (little_endian) return (__force __virtio64)cpu_to_le64(val); els
[PATCH v2 7/7] vhost: feature to set the vring endianness
This patch brings cross-endian support to vhost when used to implement legacy virtio devices. Since it is a relatively rare situation, the feature availability is controlled by a kernel config option (not set by default). If cross-endian support is compiled in, vhost abvertises a new feature to be negotiated with userspace. If userspace acknowledges the feature, it can inform vhost about the endianness to use with a new ioctl. This feature is mutually exclusive with virtio 1.0. Even if the vhost device advertises virtio 1.0 and legacy cross-endian features, it cannot receive aknowledgement for both at the same time. Hot paths are being preserved from any penalty when the config option is disabled or when virtio 1.0 is being used. Signed-off-by: Greg Kurz --- drivers/vhost/Kconfig | 10 ++ drivers/vhost/net.c|5 + drivers/vhost/scsi.c |4 drivers/vhost/test.c |4 drivers/vhost/vhost.c | 19 +++ drivers/vhost/vhost.h | 13 - include/uapi/linux/vhost.h | 10 ++ 7 files changed, 64 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 017a1e8..5bb8da9 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -32,3 +32,13 @@ config VHOST ---help--- This option is selected by any driver which needs to access the core of vhost. + +config VHOST_SET_ENDIAN_LEGACY + bool "Cross-endian support for host kernel accelerator" + default n + ---help--- + This option allows vhost to support guests with a different byte + ordering. It is disabled by default since it adds overhead and it + is only needed by a few platforms (powerpc and arm). + + If unsure, say "n". diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 2bbfc25..5274a44 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1011,6 +1011,11 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features) vhost_hlen = 0; sock_hlen = hdr_len; } + + if (features & ((1ULL << VHOST_F_SET_ENDIAN_LEGACY) | + (1ULL << VIRTIO_F_VERSION_1))) + return -EINVAL; + mutex_lock(&n->dev.mutex); if ((features & (1 << VHOST_F_LOG_ALL)) && !vhost_log_access_ok(&n->dev)) { diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 71df240..b53e9c2 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1544,6 +1544,10 @@ static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features) if (features & ~VHOST_SCSI_FEATURES) return -EOPNOTSUPP; + if (features & ((1ULL << VHOST_F_SET_ENDIAN_LEGACY) | + (1ULL << VIRTIO_F_VERSION_1))) + return -EINVAL; + mutex_lock(&vs->dev.mutex); if ((features & (1 << VHOST_F_LOG_ALL)) && !vhost_log_access_ok(&vs->dev)) { diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index d9c501e..cfefdad 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -243,6 +243,10 @@ static int vhost_test_set_features(struct vhost_test *n, u64 features) { struct vhost_virtqueue *vq; + if (features & ((1ULL << VHOST_F_SET_ENDIAN_LEGACY) | + (1ULL << VIRTIO_F_VERSION_1))) + return -EINVAL; + mutex_lock(&n->dev.mutex); if ((features & (1 << VHOST_F_LOG_ALL)) && !vhost_log_access_ok(&n->dev)) { diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ee2826..60a0f32 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -199,6 +199,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call = NULL; vq->log_ctx = NULL; vq->memory = NULL; + vq->legacy_big_endian = false; } static int vhost_worker(void *data) @@ -806,6 +807,24 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) } else filep = eventfp; break; +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY + case VHOST_SET_VRING_ENDIAN_LEGACY: + { + struct vhost_vring_endian e; + + if (!vhost_has_feature(vq, VHOST_F_SET_ENDIAN_LEGACY)) { + r = -EINVAL; + break; + } + + if (copy_from_user(&e, argp, sizeof(e))) { + r = -EFAULT; + break; + } + vq->legacy_big_endian = e.is_big_endian; + break; + } +#endif default: r = -ENOIOCTLCMD; } diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 4e9
Re: [PATCH v2 7/7] vhost: feature to set the vring endianness
On Thu, 2 Apr 2015 16:20:46 +0200 "Michael S. Tsirkin" wrote: > On Thu, Apr 02, 2015 at 03:17:13PM +0200, Greg Kurz wrote: > > This patch brings cross-endian support to vhost when used to implement > > legacy virtio devices. Since it is a relatively rare situation, the feature > > availability is controlled by a kernel config option (not set by default). > > > > If cross-endian support is compiled in, vhost abvertises a new feature > > to be negotiated with userspace. If userspace acknowledges the feature, > > it can inform vhost about the endianness to use with a new ioctl. > > > > This feature is mutually exclusive with virtio 1.0. Even if the vhost device > > advertises virtio 1.0 and legacy cross-endian features, it cannot receive > > aknowledgement for both at the same time. > > > > Hot paths are being preserved from any penalty when the config option is > > disabled or when virtio 1.0 is being used. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/vhost/Kconfig | 10 ++ > > drivers/vhost/net.c|5 + > > drivers/vhost/scsi.c |4 > > drivers/vhost/test.c |4 > > drivers/vhost/vhost.c | 19 +++ > > drivers/vhost/vhost.h | 13 - > > include/uapi/linux/vhost.h | 10 ++ > > 7 files changed, 64 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig > > index 017a1e8..5bb8da9 100644 > > --- a/drivers/vhost/Kconfig > > +++ b/drivers/vhost/Kconfig > > @@ -32,3 +32,13 @@ config VHOST > > ---help--- > > This option is selected by any driver which needs to access > > the core of vhost. > > + > > +config VHOST_SET_ENDIAN_LEGACY > > + bool "Cross-endian support for host kernel accelerator" > > + default n > > + ---help--- > > + This option allows vhost to support guests with a different byte > > + ordering > > from host > > >. It is disabled by default since it adds overhead and it > > + is only needed by a few platforms (powerpc and arm). > > + > > + If unsure, say "n". > > "N" > > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c > > index 2bbfc25..5274a44 100644 > > --- a/drivers/vhost/net.c > > +++ b/drivers/vhost/net.c > > @@ -1011,6 +1011,11 @@ static int vhost_net_set_features(struct vhost_net > > *n, u64 features) > > vhost_hlen = 0; > > sock_hlen = hdr_len; > > } > > + > > + if (features & ((1ULL << VHOST_F_SET_ENDIAN_LEGACY) | > > + (1ULL << VIRTIO_F_VERSION_1))) > > + return -EINVAL; > > + > > mutex_lock(&n->dev.mutex); > > if ((features & (1 << VHOST_F_LOG_ALL)) && > > !vhost_log_access_ok(&n->dev)) { > > diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c > > index 71df240..b53e9c2 100644 > > --- a/drivers/vhost/scsi.c > > +++ b/drivers/vhost/scsi.c > > @@ -1544,6 +1544,10 @@ static int vhost_scsi_set_features(struct vhost_scsi > > *vs, u64 features) > > if (features & ~VHOST_SCSI_FEATURES) > > return -EOPNOTSUPP; > > > > + if (features & ((1ULL << VHOST_F_SET_ENDIAN_LEGACY) | > > + (1ULL << VIRTIO_F_VERSION_1))) > > + return -EINVAL; > > + > > mutex_lock(&vs->dev.mutex); > > if ((features & (1 << VHOST_F_LOG_ALL)) && > > !vhost_log_access_ok(&vs->dev)) { > > diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c > > index d9c501e..cfefdad 100644 > > --- a/drivers/vhost/test.c > > +++ b/drivers/vhost/test.c > > @@ -243,6 +243,10 @@ static int vhost_test_set_features(struct vhost_test > > *n, u64 features) > > { > > struct vhost_virtqueue *vq; > > > > + if (features & ((1ULL << VHOST_F_SET_ENDIAN_LEGACY) | > > + (1ULL << VIRTIO_F_VERSION_1))) > > + return -EINVAL; > > + > > mutex_lock(&n->dev.mutex); > > if ((features & (1 << VHOST_F_LOG_ALL)) && > > !vhost_log_access_ok(&n->dev)) { > > Above seems to prevent users from specifying either > VIRTIO_F_VERSION_1 or VHOST_F_SET_ENDIAN_LEGACY. > Does it actually work? > Arggg no it doesn't *of course*... I've added these bogus checks lately and didn'
[PATCH v3 0/7] vhost: support for cross endian guests
Hi, This patchset allows vhost to be used with legacy virtio when guest and host have a different endianness. Patches 1-6 remain the same as the previous post. Patch 7 was heavily changed according to MST's comments. --- Greg Kurz (7): virtio: introduce virtio_is_little_endian() helper tun: add tun_is_little_endian() helper macvtap: introduce macvtap_is_little_endian() helper vringh: introduce vringh_is_little_endian() helper vhost: introduce vhost_is_little_endian() helper virtio: add explicit big-endian support to memory accessors vhost: feature to set the vring endianness drivers/net/macvtap.c| 11 ++-- drivers/net/tun.c| 11 ++-- drivers/vhost/Kconfig| 10 +++ drivers/vhost/vhost.c| 55 ++ drivers/vhost/vhost.h| 34 +++ include/linux/virtio_byteorder.h | 24 ++--- include/linux/virtio_config.h| 19 + include/linux/vringh.h | 19 + include/uapi/linux/vhost.h |5 +++ 9 files changed, 156 insertions(+), 32 deletions(-) -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v3 2/7] tun: add tun_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/net/tun.c |9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 857dca4..3c3d6c0 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -206,14 +206,19 @@ struct tun_struct { u32 flow_count; }; +static inline bool tun_is_little_endian(struct tun_struct *tun) +{ + return tun->flags & TUN_VNET_LE; +} + static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) { - return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val); + return __virtio16_to_cpu(tun_is_little_endian(tun), val); } static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) { - return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val); + return __cpu_to_virtio16(tun_is_little_endian(tun), val); } static inline u32 tun_hashfn(u32 rxhash) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v3 1/7] virtio: introduce virtio_is_little_endian() helper
Signed-off-by: Greg Kurz --- include/linux/virtio_config.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index ca3ed78..bd1a582 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -205,35 +205,40 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu) return 0; } +static inline bool virtio_is_little_endian(struct virtio_device *vdev) +{ + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) { - return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) { - return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(virtio_is_little_endian(vdev), val); } static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) { - return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) { - return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(virtio_is_little_endian(vdev), val); } static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) { - return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) { - return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); } /* Config space accessors. */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v3 3/7] macvtap: introduce macvtap_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/net/macvtap.c |9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 27ecc5c..a2f2958 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -49,14 +49,19 @@ struct macvtap_queue { #define MACVTAP_VNET_LE 0x8000 +static inline bool macvtap_is_little_endian(struct macvtap_queue *q) +{ + return q->flags & MACVTAP_VNET_LE; +} + static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) { - return __virtio16_to_cpu(q->flags & MACVTAP_VNET_LE, val); + return __virtio16_to_cpu(macvtap_is_little_endian(q), val); } static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val) { - return __cpu_to_virtio16(q->flags & MACVTAP_VNET_LE, val); + return __cpu_to_virtio16(macvtap_is_little_endian(q), val); } static struct proto macvtap_proto = { ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v3 4/7] vringh: introduce vringh_is_little_endian() helper
Signed-off-by: Greg Kurz --- include/linux/vringh.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/vringh.h b/include/linux/vringh.h index a3fa537..3ed62ef 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -226,33 +226,38 @@ static inline void vringh_notify(struct vringh *vrh) vrh->notify(vrh); } +static inline bool vringh_is_little_endian(const struct vringh *vrh) +{ + return vrh->little_endian; +} + static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val) { - return __virtio16_to_cpu(vrh->little_endian, val); + return __virtio16_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio16 cpu_to_vringh16(const struct vringh *vrh, u16 val) { - return __cpu_to_virtio16(vrh->little_endian, val); + return __cpu_to_virtio16(vringh_is_little_endian(vrh), val); } static inline u32 vringh32_to_cpu(const struct vringh *vrh, __virtio32 val) { - return __virtio32_to_cpu(vrh->little_endian, val); + return __virtio32_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio32 cpu_to_vringh32(const struct vringh *vrh, u32 val) { - return __cpu_to_virtio32(vrh->little_endian, val); + return __cpu_to_virtio32(vringh_is_little_endian(vrh), val); } static inline u64 vringh64_to_cpu(const struct vringh *vrh, __virtio64 val) { - return __virtio64_to_cpu(vrh->little_endian, val); + return __virtio64_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio64 cpu_to_vringh64(const struct vringh *vrh, u64 val) { - return __cpu_to_virtio64(vrh->little_endian, val); + return __cpu_to_virtio64(vringh_is_little_endian(vrh), val); } #endif /* _LINUX_VRINGH_H */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v3 5/7] vhost: introduce vhost_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/vhost/vhost.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 8c1c792..6a49960 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -173,34 +173,39 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) return vq->acked_features & (1ULL << bit); } +static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) +{ + return vhost_has_feature(vq, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) { - return __virtio16_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio16 cpu_to_vhost16(struct vhost_virtqueue *vq, u16 val) { - return __cpu_to_virtio16(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(vhost_is_little_endian(vq), val); } static inline u32 vhost32_to_cpu(struct vhost_virtqueue *vq, __virtio32 val) { - return __virtio32_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio32 cpu_to_vhost32(struct vhost_virtqueue *vq, u32 val) { - return __cpu_to_virtio32(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(vhost_is_little_endian(vq), val); } static inline u64 vhost64_to_cpu(struct vhost_virtqueue *vq, __virtio64 val) { - return __virtio64_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio64 cpu_to_vhost64(struct vhost_virtqueue *vq, u64 val) { - return __cpu_to_virtio64(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(vhost_is_little_endian(vq), val); } #endif ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v3 6/7] virtio: add explicit big-endian support to memory accessors
The current memory accessors logic is: - little endian if little_endian - native endian (i.e. no byteswap) if !little_endian If we want to fully support cross-endian vhost, we also need to be able to convert to big endian. Instead of changing the little_endian argument to some 3-value enum, this patch changes the logic to: - little endian if little_endian - big endian if !little_endian The native endian case is handled by all users with a trivial helper. This patch doesn't change any functionality, nor it does add overhead. Signed-off-by: Greg Kurz --- drivers/net/macvtap.c|4 +++- drivers/net/tun.c|4 +++- drivers/vhost/vhost.h|4 +++- include/linux/virtio_byteorder.h | 24 ++-- include/linux/virtio_config.h|4 +++- include/linux/vringh.h |4 +++- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index a2f2958..0a03a66 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -51,7 +51,9 @@ struct macvtap_queue { static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { - return q->flags & MACVTAP_VNET_LE; + if (q->flags & MACVTAP_VNET_LE) + return true; + return virtio_legacy_is_little_endian(); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3c3d6c0..053f9b6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -208,7 +208,9 @@ struct tun_struct { static inline bool tun_is_little_endian(struct tun_struct *tun) { - return tun->flags & TUN_VNET_LE; + if (tun->flags & TUN_VNET_LE) + return true; + return virtio_legacy_is_little_endian(); } static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 6a49960..4e9a186 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -175,7 +175,9 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) { - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + return true; + return virtio_legacy_is_little_endian(); } /* Memory accessors */ diff --git a/include/linux/virtio_byteorder.h b/include/linux/virtio_byteorder.h index 51865d0..ce63a2c 100644 --- a/include/linux/virtio_byteorder.h +++ b/include/linux/virtio_byteorder.h @@ -3,17 +3,21 @@ #include #include -/* - * Low-level memory accessors for handling virtio in modern little endian and in - * compatibility native endian format. - */ +static inline bool virtio_legacy_is_little_endian(void) +{ +#ifdef __LITTLE_ENDIAN + return true; +#else + return false; +#endif +} static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) { if (little_endian) return le16_to_cpu((__force __le16)val); else - return (__force u16)val; + return be16_to_cpu((__force __be16)val); } static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) if (little_endian) return (__force __virtio16)cpu_to_le16(val); else - return (__force __virtio16)val; + return (__force __virtio16)cpu_to_be16(val); } static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) @@ -29,7 +33,7 @@ static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) if (little_endian) return le32_to_cpu((__force __le32)val); else - return (__force u32)val; + return be32_to_cpu((__force __be32)val); } static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) @@ -37,7 +41,7 @@ static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) if (little_endian) return (__force __virtio32)cpu_to_le32(val); else - return (__force __virtio32)val; + return (__force __virtio32)cpu_to_be32(val); } static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) @@ -45,7 +49,7 @@ static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) if (little_endian) return le64_to_cpu((__force __le64)val); else - return (__force u64)val; + return be64_to_cpu((__force __be64)val); } static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) @@ -53,7 +57,7 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) if (little_endian) return (__force __virtio64)cpu_to_le64(val); els
[PATCH v3 7/7] vhost: feature to set the vring endianness
This patch brings cross-endian support to vhost when used to implement legacy virtio devices. Since it is a relatively rare situation, the feature availability is controlled by a kernel config option (not set by default). The ioctls introduced by this patch are for legacy only: virtio 1.0 devices are returned EPERM. Signed-off-by: Greg Kurz --- drivers/vhost/Kconfig | 10 drivers/vhost/vhost.c | 55 drivers/vhost/vhost.h | 17 +- include/uapi/linux/vhost.h |5 4 files changed, 86 insertions(+), 1 deletion(-) Changes since v2: - fixed typos in Kconfig description - renamed vq->legacy_big_endian to vq->legacy_is_little_endian - vq->legacy_is_little_endian reset to default in vhost_vq_reset() - dropped VHOST_F_SET_ENDIAN_LEGACY feature - dropped struct vhost_vring_endian from the user API (re-use struct vhost_vring_state instead) - added VHOST_GET_VRING_ENDIAN_LEGACY ioctl - introduced more helpers and stubs to avoid polluting the code with ifdefs diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 017a1e8..0aec88c 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -32,3 +32,13 @@ config VHOST ---help--- This option is selected by any driver which needs to access the core of vhost. + +config VHOST_SET_ENDIAN_LEGACY + bool "Cross-endian support for host kernel accelerator" + default n + ---help--- + This option allows vhost to support guests with a different byte + ordering from host. It is disabled by default since it adds overhead + and it is only needed by a few platforms (powerpc and arm). + + If unsure, say "N". diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ee2826..3529a3c 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -199,6 +199,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call = NULL; vq->log_ctx = NULL; vq->memory = NULL; + vq->legacy_is_little_endian = virtio_legacy_is_little_endian(); } static int vhost_worker(void *data) @@ -630,6 +631,54 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) return 0; } +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY +static long vhost_set_vring_endian_legacy(struct vhost_virtqueue *vq, + void __user *argp) +{ + struct vhost_vring_state s; + + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + return -EPERM; + + if (copy_from_user(&s, argp, sizeof(s))) + return -EFAULT; + + vq->legacy_is_little_endian = !!s.num; + return 0; +} + +static long vhost_get_vring_endian_legacy(struct vhost_virtqueue *vq, + u32 idx, + void __user *argp) +{ + struct vhost_vring_state s = { + .index = idx, + .num = vq->legacy_is_little_endian + }; + + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + return -EPERM; + + if (copy_to_user(argp, &s, sizeof(s))) + return -EFAULT; + + return 0; +} +#else +static long vhost_set_vring_endian_legacy(struct vhost_virtqueue *vq, + void __user *argp) +{ + return 0; +} + +static long vhost_get_vring_endian_legacy(struct vhost_virtqueue *vq, + u32 idx, + void __user *argp) +{ + return 0; +} +#endif /* CONFIG_VHOST_SET_ENDIAN_LEGACY */ + long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) { struct file *eventfp, *filep = NULL; @@ -806,6 +855,12 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) } else filep = eventfp; break; + case VHOST_SET_VRING_ENDIAN_LEGACY: + r = vhost_set_vring_endian_legacy(vq, argp); + break; + case VHOST_GET_VRING_ENDIAN_LEGACY: + r = vhost_get_vring_endian_legacy(vq, idx, argp); + break; default: r = -ENOIOCTLCMD; } diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 4e9a186..981ba06 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -106,6 +106,9 @@ struct vhost_virtqueue { /* Log write descriptors */ void __user *log_base; struct vhost_log *log; + + /* We need to know the device endianness with legacy virtio. */ + bool legacy_is_little_endian; }; struct vhost_dev { @@ -173,11 +176,23 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) return vq->acked_features & (1ULL << bit); } +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY +static
Re: [PATCH v3 0/7] vhost: support for cross endian guests
On Tue, 7 Apr 2015 17:55:08 +0200 "Michael S. Tsirkin" wrote: > On Tue, Apr 07, 2015 at 02:09:29PM +0200, Greg Kurz wrote: > > Hi, > > > > This patchset allows vhost to be used with legacy virtio when guest and host > > have a different endianness. > > > > Patches 1-6 remain the same as the previous post. Patch 7 was heavily > > changed > > according to MST's comments. > > This still doesn't actually work, right? > tun and macvtap need new ioctls too ... > Yes they do. I already have a patch but I wasn't sure if I should send it along this series... Since it looks like there will be a v4, I'll add the tun/macvtap patch. Thanks. -- Greg > > --- > > > > Greg Kurz (7): > > virtio: introduce virtio_is_little_endian() helper > > tun: add tun_is_little_endian() helper > > macvtap: introduce macvtap_is_little_endian() helper > > vringh: introduce vringh_is_little_endian() helper > > vhost: introduce vhost_is_little_endian() helper > > virtio: add explicit big-endian support to memory accessors > > vhost: feature to set the vring endianness > > > > > > drivers/net/macvtap.c| 11 ++-- > > drivers/net/tun.c| 11 ++-- > > drivers/vhost/Kconfig| 10 +++ > > drivers/vhost/vhost.c| 55 > > ++ > > drivers/vhost/vhost.h| 34 +++ > > include/linux/virtio_byteorder.h | 24 ++--- > > include/linux/virtio_config.h| 19 + > > include/linux/vringh.h | 19 + > > include/uapi/linux/vhost.h |5 +++ > > 9 files changed, 156 insertions(+), 32 deletions(-) > > > > -- > > Greg > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v3 7/7] vhost: feature to set the vring endianness
On Tue, 7 Apr 2015 17:01:31 +0200 Cornelia Huck wrote: > On Tue, 07 Apr 2015 14:19:31 +0200 > Greg Kurz wrote: > > > This patch brings cross-endian support to vhost when used to implement > > legacy virtio devices. Since it is a relatively rare situation, the > > feature availability is controlled by a kernel config option (not set > > by default). > > > > The ioctls introduced by this patch are for legacy only: virtio 1.0 > > devices are returned EPERM. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/vhost/Kconfig | 10 > > drivers/vhost/vhost.c | 55 > > > > drivers/vhost/vhost.h | 17 +- > > include/uapi/linux/vhost.h |5 > > 4 files changed, 86 insertions(+), 1 deletion(-) > > > +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY > > +static long vhost_set_vring_endian_legacy(struct vhost_virtqueue *vq, > > + void __user *argp) > > +{ > > + struct vhost_vring_state s; > > + > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + return -EPERM; > > + > > + if (copy_from_user(&s, argp, sizeof(s))) > > + return -EFAULT; > > + > > + vq->legacy_is_little_endian = !!s.num; > > + return 0; > > +} > > + > > +static long vhost_get_vring_endian_legacy(struct vhost_virtqueue *vq, > > + u32 idx, > > + void __user *argp) > > +{ > > + struct vhost_vring_state s = { > > + .index = idx, > > + .num = vq->legacy_is_little_endian > > + }; > > + > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + return -EPERM; > > + > > + if (copy_to_user(argp, &s, sizeof(s))) > > + return -EFAULT; > > + > > + return 0; > > +} > > +#else > > +static long vhost_set_vring_endian_legacy(struct vhost_virtqueue *vq, > > + void __user *argp) > > +{ > > + return 0; > > I'm wondering whether this handler should return an error if the > feature is not configured for the kernel? How can the userspace caller > find out whether it has successfully prompted the kernel to handle the > endianness correctly? > Yes you're right. I think -ENOIOCTLCMD as suggested by Michael is a good candidate. Thanks. > > +} > > + > > +static long vhost_get_vring_endian_legacy(struct vhost_virtqueue *vq, > > + u32 idx, > > + void __user *argp) > > +{ > > + return 0; > > +} > > +#endif /* CONFIG_VHOST_SET_ENDIAN_LEGACY */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v3 7/7] vhost: feature to set the vring endianness
On Tue, 7 Apr 2015 17:52:28 +0200 "Michael S. Tsirkin" wrote: > On Tue, Apr 07, 2015 at 02:19:31PM +0200, Greg Kurz wrote: > > This patch brings cross-endian support to vhost when used to implement > > legacy virtio devices. Since it is a relatively rare situation, the > > feature availability is controlled by a kernel config option (not set > > by default). > > > > The ioctls introduced by this patch are for legacy only: virtio 1.0 > > devices are returned EPERM. > > > > Signed-off-by: Greg Kurz > > EINVAL probably makes more sense? > I had choosen EPERM because the error isn't related to the arguments being passed by userspace. It simply does not make sense to set the vring endianness for a virtio 1.0 device. That being said, I am perfectly fine with EINVAL. :) > > --- > > drivers/vhost/Kconfig | 10 > > drivers/vhost/vhost.c | 55 > > > > drivers/vhost/vhost.h | 17 +- > > include/uapi/linux/vhost.h |5 > > 4 files changed, 86 insertions(+), 1 deletion(-) > > > > Changes since v2: > > - fixed typos in Kconfig description > > - renamed vq->legacy_big_endian to vq->legacy_is_little_endian > > - vq->legacy_is_little_endian reset to default in vhost_vq_reset() > > - dropped VHOST_F_SET_ENDIAN_LEGACY feature > > - dropped struct vhost_vring_endian from the user API (re-use > > struct vhost_vring_state instead) > > - added VHOST_GET_VRING_ENDIAN_LEGACY ioctl > > - introduced more helpers and stubs to avoid polluting the code with ifdefs > > > > > > diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig > > index 017a1e8..0aec88c 100644 > > --- a/drivers/vhost/Kconfig > > +++ b/drivers/vhost/Kconfig > > @@ -32,3 +32,13 @@ config VHOST > > ---help--- > > This option is selected by any driver which needs to access > > the core of vhost. > > + > > +config VHOST_SET_ENDIAN_LEGACY > > + bool "Cross-endian support for host kernel accelerator" > > + default n > > + ---help--- > > + This option allows vhost to support guests with a different byte > > + ordering from host. It is disabled by default since it adds overhead > > + and it is only needed by a few platforms (powerpc and arm). > > + > > + If unsure, say "N". > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > index 2ee2826..3529a3c 100644 > > --- a/drivers/vhost/vhost.c > > +++ b/drivers/vhost/vhost.c > > @@ -199,6 +199,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, > > vq->call = NULL; > > vq->log_ctx = NULL; > > vq->memory = NULL; > > + vq->legacy_is_little_endian = virtio_legacy_is_little_endian(); > > } > > > > static int vhost_worker(void *data) > > @@ -630,6 +631,54 @@ static long vhost_set_memory(struct vhost_dev *d, > > struct vhost_memory __user *m) > > return 0; > > } > > > > +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY > > +static long vhost_set_vring_endian_legacy(struct vhost_virtqueue *vq, > > + void __user *argp) > > +{ > > + struct vhost_vring_state s; > > + > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + return -EPERM; > > EINVAL probably makes more sense? But I'm not sure this > is helpful: one can set VIRTIO_F_VERSION_1 afterwards, > and your patch does not seem to detect this. > Yeah, when I dropped the *bogus* feature from v2, I forgot to patch VHOST_SET_FEATURES accordingly... But thinking about it now, the choice to error out when setting VIRTIO_F_VERSION_1 because cross-endian legacy was set before looks terrible... :-\ > > > > + > > + if (copy_from_user(&s, argp, sizeof(s))) > > + return -EFAULT; > > + > > + vq->legacy_is_little_endian = !!s.num; > > + return 0; > > +} > > + > > +static long vhost_get_vring_endian_legacy(struct vhost_virtqueue *vq, > > + u32 idx, > > + void __user *argp) > > +{ > > + struct vhost_vring_state s = { > > + .index = idx, > > + .num = vq->legacy_is_little_endian > > + }; > > + > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + return -EPERM; > > + > > + if (copy_to_user(argp, &s, sizeof(s))) > > + return -EFAULT; > > + > > +
Re: [PATCH v3 7/7] vhost: feature to set the vring endianness
On Tue, 7 Apr 2015 18:11:29 +0200 "Michael S. Tsirkin" wrote: > On Tue, Apr 07, 2015 at 02:19:31PM +0200, Greg Kurz wrote: > > This patch brings cross-endian support to vhost when used to implement > > legacy virtio devices. Since it is a relatively rare situation, the > > feature availability is controlled by a kernel config option (not set > > by default). > > > > The ioctls introduced by this patch are for legacy only: virtio 1.0 > > devices are returned EPERM. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/vhost/Kconfig | 10 > > drivers/vhost/vhost.c | 55 > > > > drivers/vhost/vhost.h | 17 +- > > include/uapi/linux/vhost.h |5 > > 4 files changed, 86 insertions(+), 1 deletion(-) > > > > Changes since v2: > > - fixed typos in Kconfig description > > - renamed vq->legacy_big_endian to vq->legacy_is_little_endian > > - vq->legacy_is_little_endian reset to default in vhost_vq_reset() > > - dropped VHOST_F_SET_ENDIAN_LEGACY feature > > - dropped struct vhost_vring_endian from the user API (re-use > > struct vhost_vring_state instead) > > - added VHOST_GET_VRING_ENDIAN_LEGACY ioctl > > - introduced more helpers and stubs to avoid polluting the code with ifdefs > > > > > > diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig > > index 017a1e8..0aec88c 100644 > > --- a/drivers/vhost/Kconfig > > +++ b/drivers/vhost/Kconfig > > @@ -32,3 +32,13 @@ config VHOST > > ---help--- > > This option is selected by any driver which needs to access > > the core of vhost. > > + > > +config VHOST_SET_ENDIAN_LEGACY > > + bool "Cross-endian support for host kernel accelerator" > > + default n > > + ---help--- > > + This option allows vhost to support guests with a different byte > > + ordering from host. It is disabled by default since it adds overhead > > + and it is only needed by a few platforms (powerpc and arm). > > + > > + If unsure, say "N". > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > index 2ee2826..3529a3c 100644 > > --- a/drivers/vhost/vhost.c > > +++ b/drivers/vhost/vhost.c > > @@ -199,6 +199,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, > > vq->call = NULL; > > vq->log_ctx = NULL; > > vq->memory = NULL; > > + vq->legacy_is_little_endian = virtio_legacy_is_little_endian(); > > } > > > > static int vhost_worker(void *data) > > @@ -630,6 +631,54 @@ static long vhost_set_memory(struct vhost_dev *d, > > struct vhost_memory __user *m) > > return 0; > > } > > > > +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY > > +static long vhost_set_vring_endian_legacy(struct vhost_virtqueue *vq, > > + void __user *argp) > > +{ > > + struct vhost_vring_state s; > > + > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + return -EPERM; > > + > > + if (copy_from_user(&s, argp, sizeof(s))) > > + return -EFAULT; > > + > > + vq->legacy_is_little_endian = !!s.num; > > + return 0; > > +} > > + > > +static long vhost_get_vring_endian_legacy(struct vhost_virtqueue *vq, > > + u32 idx, > > + void __user *argp) > > +{ > > + struct vhost_vring_state s = { > > + .index = idx, > > + .num = vq->legacy_is_little_endian > > + }; > > + > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + return -EPERM; > > + > > + if (copy_to_user(argp, &s, sizeof(s))) > > + return -EFAULT; > > + > > + return 0; > > +} > > +#else > > +static long vhost_set_vring_endian_legacy(struct vhost_virtqueue *vq, > > + void __user *argp) > > +{ > > + return 0; > > +} > > + > > +static long vhost_get_vring_endian_legacy(struct vhost_virtqueue *vq, > > + u32 idx, > > + void __user *argp) > > +{ > > + return 0; > > +} > > +#endif /* CONFIG_VHOST_SET_ENDIAN_LEGACY */ > > + > > long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) > > { > > struct file *eventfp, *filep = NULL; > > @@ -806,6 +855,1
Re: [PATCH v4 7/8] vhost: feature to set the vring endianness
On Tue, 14 Apr 2015 16:20:23 +0200 Cornelia Huck wrote: > On Fri, 10 Apr 2015 12:19:16 +0200 > Greg Kurz wrote: > > > This patch brings cross-endian support to vhost when used to implement > > legacy virtio devices. Since it is a relatively rare situation, the > > feature availability is controlled by a kernel config option (not set > > by default). > > > > The vq->is_le boolean field is added to cache the endianness to be > > used for ring accesses. It defaults to native endian, as expected > > by legacy virtio devices. When the ring gets active, we force little > > endian if the device is modern. When the ring is deactivated, we > > revert to the native endian default. > > > > If cross-endian was compiled in, a vq->user_be boolean field is added > > so that userspace may request a specific endianness. This field is > > used to override the default when activating the ring of a legacy > > device. It has no effect on modern devices. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/vhost/Kconfig | 10 ++ > > drivers/vhost/vhost.c | 76 > > +++- > > drivers/vhost/vhost.h | 12 +-- > > include/uapi/linux/vhost.h |9 + > > 4 files changed, 103 insertions(+), 4 deletions(-) > > > +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY > > +static long vhost_set_vring_big_endian(struct vhost_virtqueue *vq, > > + int __user *argp) > > +{ > > + struct vhost_vring_state s; > > + > > + if (vq->private_data) > > + return -EBUSY; > > + > > + if (copy_from_user(&s, argp, sizeof(s))) > > + return -EFAULT; > > + > > + if (s.num && s.num != 1) > > Checking for s.num > 1 might be more obvious at a glance? > Sure since s.num is unsigned. > > + return -EINVAL; > > + > > + vq->user_be = s.num; > > + > > + return 0; > > +} > > + > > (...) > > > +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY > > +static void vhost_init_is_le(struct vhost_virtqueue *vq) > > +{ > > + vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; > > So if the endianness is not explicitly set to BE, it will be forced to > LE (instead of native endian)? Won't that break userspace that does not > yet use the new interface when CONFIG_VHOST_SET_ENDIAN_LEGACY is set? > If userspace doesn't use the new interface, then vq->user_be will retain its default value that was set in vhost_vq_reset(), i.e. : vq->user_be = !virtio_legacy_is_little_endian(); This means default is native endian. What about adding this comment ? static void vhost_init_is_le(struct vhost_virtqueue *vq) { /* Note for legacy virtio: user_be is initialized in vhost_vq_reset() * according to the host endianness. If userspace does not set an * explicit endianness, the default behavior is native endian, as * expected by legacy virtio. */ vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; } > > +} > > +#else > > +static void vhost_init_is_le(struct vhost_virtqueue *vq) > > +{ > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + vq->is_le = true; > > +} > > +#endif > > + > > int vhost_init_used(struct vhost_virtqueue *vq) > > { > > __virtio16 last_used_idx; > > int r; > > - if (!vq->private_data) > > + if (!vq->private_data) { > > + vq->is_le = virtio_legacy_is_little_endian(); > > return 0; > > + } > > + > > + vhost_init_is_le(vq); > > > > r = vhost_update_used_flags(vq); > > if (r) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v4 0/8] vhost: support for cross endian guests
On Fri, 10 Apr 2015 12:15:00 +0200 Greg Kurz wrote: > Hi, > > This patchset allows vhost to be used with legacy virtio when guest and host > have a different endianness. > > Patch 7 got rewritten according to Cornelia's and Michael's comments. I have > also introduced patch 8 that brings BE vnet headers support to tun/macvtap. > > This series is enough to have vhost_net working flawlessly. I could > succesfully reboot guests from ppc64 to ppc64le and vice-versa on ppc64 > and ppc64le hosts. > Michael, I am ready to post v5 with the changes suggested by Cornelia... Do you have any extra comments on this v4 ? -- Greg > --- > > Greg Kurz (8): > virtio: introduce virtio_is_little_endian() helper > tun: add tun_is_little_endian() helper > macvtap: introduce macvtap_is_little_endian() helper > vringh: introduce vringh_is_little_endian() helper > vhost: introduce vhost_is_little_endian() helper > virtio: add explicit big-endian support to memory accessors > vhost: feature to set the vring endianness > macvtap/tun: add VNET_BE flag > > > drivers/net/Kconfig | 12 ++ > drivers/net/macvtap.c| 69 ++- > drivers/net/tun.c| 71 +++- > drivers/vhost/Kconfig| 10 + > drivers/vhost/vhost.c| 76 > ++ > drivers/vhost/vhost.h| 25 ++--- > include/linux/virtio_byteorder.h | 24 +++- > include/linux/virtio_config.h| 19 +++--- > include/linux/vringh.h | 19 +++--- > include/uapi/linux/if_tun.h |2 + > include/uapi/linux/vhost.h |9 + > 11 files changed, 303 insertions(+), 33 deletions(-) > > -- > Greg > > ___ > Virtualization mailing list > Virtualization@lists.linux-foundation.org > https://lists.linuxfoundation.org/mailman/listinfo/virtualization > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v3 6/7] virtio: add explicit big-endian support to memory accessors
On Tue, 7 Apr 2015 17:56:25 +0200 "Michael S. Tsirkin" wrote: > On Tue, Apr 07, 2015 at 02:15:52PM +0200, Greg Kurz wrote: > > The current memory accessors logic is: > > - little endian if little_endian > > - native endian (i.e. no byteswap) if !little_endian > > > > If we want to fully support cross-endian vhost, we also need to be > > able to convert to big endian. > > > > Instead of changing the little_endian argument to some 3-value enum, this > > patch changes the logic to: > > - little endian if little_endian > > - big endian if !little_endian > > > > The native endian case is handled by all users with a trivial helper. This > > patch doesn't change any functionality, nor it does add overhead. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/net/macvtap.c|4 +++- > > drivers/net/tun.c|4 +++- > > drivers/vhost/vhost.h|4 +++- > > include/linux/virtio_byteorder.h | 24 ++-- > > include/linux/virtio_config.h|4 +++- > > include/linux/vringh.h |4 +++- > > 6 files changed, 29 insertions(+), 15 deletions(-) > > > > diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c > > index a2f2958..0a03a66 100644 > > --- a/drivers/net/macvtap.c > > +++ b/drivers/net/macvtap.c > > @@ -51,7 +51,9 @@ struct macvtap_queue { > > > > static inline bool macvtap_is_little_endian(struct macvtap_queue *q) > > { > > - return q->flags & MACVTAP_VNET_LE; > > + if (q->flags & MACVTAP_VNET_LE) > > + return true; > > + return virtio_legacy_is_little_endian(); > > } > > > > static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) > > Hmm I'm not sure how well this will work once you > actually make it dynamic. > Remains to be seen. > Oops I overlooked this mail... FWIW I could reboot/kexec from a ppc64 guest to ppc64le and back with the following QEMU: https://github.com/gkurz/qemu/commits/vhost/cross-endian > > diff --git a/drivers/net/tun.c b/drivers/net/tun.c > > index 3c3d6c0..053f9b6 100644 > > --- a/drivers/net/tun.c > > +++ b/drivers/net/tun.c > > @@ -208,7 +208,9 @@ struct tun_struct { > > > > static inline bool tun_is_little_endian(struct tun_struct *tun) > > { > > - return tun->flags & TUN_VNET_LE; > > + if (tun->flags & TUN_VNET_LE) > > + return true; > > + return virtio_legacy_is_little_endian(); > > } > > > > static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) > > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h > > index 6a49960..4e9a186 100644 > > --- a/drivers/vhost/vhost.h > > +++ b/drivers/vhost/vhost.h > > @@ -175,7 +175,9 @@ static inline bool vhost_has_feature(struct > > vhost_virtqueue *vq, int bit) > > > > static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) > > { > > - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + return true; > > + return virtio_legacy_is_little_endian(); > > } > > > > /* Memory accessors */ > > diff --git a/include/linux/virtio_byteorder.h > > b/include/linux/virtio_byteorder.h > > index 51865d0..ce63a2c 100644 > > --- a/include/linux/virtio_byteorder.h > > +++ b/include/linux/virtio_byteorder.h > > @@ -3,17 +3,21 @@ > > #include > > #include > > > > -/* > > - * Low-level memory accessors for handling virtio in modern little endian > > and in > > - * compatibility native endian format. > > - */ > > +static inline bool virtio_legacy_is_little_endian(void) > > +{ > > +#ifdef __LITTLE_ENDIAN > > + return true; > > +#else > > + return false; > > +#endif > > +} > > > > static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) > > { > > if (little_endian) > > return le16_to_cpu((__force __le16)val); > > else > > - return (__force u16)val; > > + return be16_to_cpu((__force __be16)val); > > } > > > > static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) > > @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_to_virtio16(bool > > little_endian, u16 val) > > if (little_endian) > > return (__force __virtio16)cpu_to_le16(val); > > else > > - return (_
Re: [PATCH v4 0/8] vhost: support for cross endian guests
On Fri, 17 Apr 2015 11:18:13 +0200 Greg Kurz wrote: > On Fri, 10 Apr 2015 12:15:00 +0200 > Greg Kurz wrote: > > > Hi, > > > > This patchset allows vhost to be used with legacy virtio when guest and host > > have a different endianness. > > > > Patch 7 got rewritten according to Cornelia's and Michael's comments. I have > > also introduced patch 8 that brings BE vnet headers support to tun/macvtap. > > > > This series is enough to have vhost_net working flawlessly. I could > > succesfully reboot guests from ppc64 to ppc64le and vice-versa on ppc64 > > and ppc64le hosts. > > > > Michael, > > I am ready to post v5 with the changes suggested by Cornelia... Do you have > any > extra comments on this v4 ? > Ping ? > -- > Greg > > > --- > > > > Greg Kurz (8): > > virtio: introduce virtio_is_little_endian() helper > > tun: add tun_is_little_endian() helper > > macvtap: introduce macvtap_is_little_endian() helper > > vringh: introduce vringh_is_little_endian() helper > > vhost: introduce vhost_is_little_endian() helper > > virtio: add explicit big-endian support to memory accessors > > vhost: feature to set the vring endianness > > macvtap/tun: add VNET_BE flag > > > > > > drivers/net/Kconfig | 12 ++ > > drivers/net/macvtap.c| 69 ++- > > drivers/net/tun.c| 71 > > +++- > > drivers/vhost/Kconfig| 10 + > > drivers/vhost/vhost.c| 76 > > ++ > > drivers/vhost/vhost.h| 25 ++--- > > include/linux/virtio_byteorder.h | 24 +++- > > include/linux/virtio_config.h| 19 +++--- > > include/linux/vringh.h | 19 +++--- > > include/uapi/linux/if_tun.h |2 + > > include/uapi/linux/vhost.h |9 + > > 11 files changed, 303 insertions(+), 33 deletions(-) > > > > -- > > Greg > > > > ___ > > Virtualization mailing list > > Virtualization@lists.linux-foundation.org > > https://lists.linuxfoundation.org/mailman/listinfo/virtualization > > > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v4 7/8] vhost: feature to set the vring endianness
On Tue, 21 Apr 2015 16:04:23 +0200 "Michael S. Tsirkin" wrote: > On Fri, Apr 10, 2015 at 12:19:16PM +0200, Greg Kurz wrote: > > This patch brings cross-endian support to vhost when used to implement > > legacy virtio devices. Since it is a relatively rare situation, the > > feature availability is controlled by a kernel config option (not set > > by default). > > > > The vq->is_le boolean field is added to cache the endianness to be > > used for ring accesses. It defaults to native endian, as expected > > by legacy virtio devices. When the ring gets active, we force little > > endian if the device is modern. When the ring is deactivated, we > > revert to the native endian default. > > > > If cross-endian was compiled in, a vq->user_be boolean field is added > > so that userspace may request a specific endianness. This field is > > used to override the default when activating the ring of a legacy > > device. It has no effect on modern devices. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/vhost/Kconfig | 10 ++the > > drivers/vhost/vhost.c | 76 > > +++- > > drivers/vhost/vhost.h | 12 +-- > > include/uapi/linux/vhost.h |9 + > > 4 files changed, 103 insertions(+), 4 deletions(-) > > > > Changes since v3: > > - VHOST_SET_VRING_ENDIAN_LEGACY ioctl renamed to VHOST_SET_VRING_BIG_ENDIAN > > - ioctl API is now: 0 for le, 1 for be, other values are EINVAL > > - ioctl doesn't filter out modern devices > > - ioctl stubs return ENOIOCTLCMD > > - forbid endianness changes when vring is active > > - logic now handled with vq->is_le and vq->user_be according to device > > start/stop as suggested by Michael > > > > diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig > > index 017a1e8..0aec88c 100644 > > --- a/drivers/vhost/Kconfig > > +++ b/drivers/vhost/Kconfig > > @@ -32,3 +32,13 @@ config VHOST > > ---help--- > > This option is selected by any driver which needs to access > > the core of vhost. > > + > > +config VHOST_SET_ENDIAN_LEGACY > > I'd prefer namin this VHOST_CROSS_ENDIAN_LEGACY > Yes, makes sense. I'll make sure most of the cross-endian changes are easy to grep. > > + bool "Cross-endian support for host kernel accelerator" > > + default n > > + ---help--- > > + This option allows vhost to support guests with a different byte > > + ordering from host. It is disabled by default since it adds overhead > > + and it is only needed by a few platforms (powerpc and arm). > > and is only useful on a few platforms (powerpc and arm). > > "it" seems to refer to "overhead", which is rarely needed. > needed is a bit too strong, you can always e.g. run virtio > in userspace. > My poor English again... it seems you understood what I wanted to write though :) > > + > > + If unsure, say "N". > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > index 2ee2826..3eb756b 100644the > > --- a/drivers/vhost/vhost.c > > +++ b/drivers/vhost/vhost.c > > @@ -199,6 +199,10 @@ static void vhost_vq_reset(struct vhost_dev *dev, > > vq->call = NULL; > > vq->log_ctx = NULL; > > vq->memory = NULL; > > + vq->is_le = virtio_legacy_is_little_endian(); > > +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY > > + vq->user_be = !vq->is_le; > > +#endif > > add a wrapper for this too? > Will do. > > } > > > > static int vhost_worker(void *data) > > @@ -630,6 +634,53 @@ static long vhost_set_memory(struct vhost_dev *d, > > struct vhost_memory __user *m) > > return 0; > > } > > > > +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY > > +static long vhost_set_vring_big_endian(struct vhost_virtqueue *vq, > > + int __user *argp) > > +{ > > + struct vhost_vring_state s; > > + > > + if (vq->private_data) > > + return -EBUSY; > > + > > + if (copy_from_user(&s, argp, sizeof(s))) > > + return -EFAULT; > > + > > + if (s.num && s.num != 1) > > s.num & ~0x1 > Since s.num is unsigned and I assume this won't change, what about s.num > 1 as suggested by Cornelia ? > > > + return -EINVAL; > > + > > + vq->user_be = s.num; > > + > > + return 0; > > +} > > + > > +static long vho
Re: [PATCH v4 8/8] macvtap/tun: add VNET_BE flag
On Tue, 21 Apr 2015 16:06:33 +0200 "Michael S. Tsirkin" wrote: > On Fri, Apr 10, 2015 at 12:20:21PM +0200, Greg Kurz wrote: > > The VNET_LE flag was introduced to fix accesses to virtio 1.0 headers > > that are always little-endian. It can also be used to handle the special > > case of a legacy little-endian device implemented by a big-endian host. > > > > Let's add a flag and ioctls for big-endian devices as well. If both flags > > are set, little-endian wins. > > > > Since this is isn't a common usecase, the feature is controlled by a kernel > > config option (not set by default). > > > > Both macvtap and tun are covered by this patch since they share the same > > API with userland. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/net/Kconfig | 12 > > drivers/net/macvtap.c | 60 > > +- > > drivers/net/tun.c | 62 > > ++- > > include/uapi/linux/if_tun.h |2 + > > 4 files changed, 134 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig > > index df51d60..f0e23a0 100644 > > --- a/drivers/net/Kconfig > > +++ b/drivers/net/Kconfig > > @@ -244,6 +244,18 @@ config TUN > > > > If you don't know what to use this for, you don't need it. > > > > +config TUN_VNET_BE > > + bool "Support for big-endian vnet headers" > > + default n > > + ---help--- > > + This option allows TUN/TAP and MACVTAP device drivers to parse > > + vnet headers that are in big-endian byte order. It is useful > > + when the headers come from a big-endian legacy virtio driver and > > + the host is little-endian. > > + > > + Unless you have a little-endian system hosting a big-endian virtual > > + machine with a virtio NIC, you should say N. > > + > > should mention cross-endian, not big-endian, right? > The current TUN_VNET_LE related code is already doing cross-endian: without this patch, one can already run a LE guest on a BE host... wouldn't it be confusing to mention cross-endian only when the guest is BE ? What about having a completely distinct implementation for cross-endian that don't reuse the existing code and defines then ? > > config VETH > > tristate "Virtual ethernet pair device" > > ---help--- > > diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c > > index 0a03a66..e0ab1b7 100644 > > --- a/drivers/net/macvtap.c > > +++ b/drivers/net/macvtap.c > > @@ -48,12 +48,27 @@ struct macvtap_queue { > > #define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE) > > > > #define MACVTAP_VNET_LE 0x8000 > > +#define MACVTAP_VNET_BE 0x4000 > > + > > +#ifdef CONFIG_TUN_VNET_BE > > +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) > > +{ > > + if (q->flags & MACVTAP_VNET_BE) > > + return false; > > + return virtio_legacy_is_little_endian(); > > +} > > +#else > > +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) > > +{ > > + return virtio_legacy_is_little_endian(); > > +} > > +#endif > > > > static inline bool macvtap_is_little_endian(struct macvtap_queue *q) > > { > > if (q->flags & MACVTAP_VNET_LE) > > return true; > > - return virtio_legacy_is_little_endian(); > > + return macvtap_legacy_is_little_endian(q); > > } > > > > static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) > > @@ -1000,6 +1015,43 @@ static int set_offload(struct macvtap_queue *q, > > unsigned long arg) > > return 0; > > } > > > > +#ifdef CONFIG_TUN_VNET_BE > > +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *sp) > > +{ > > + int s = !!(q->flags & MACVTAP_VNET_BE); > > + > > + if (put_user(s, sp)) > > + return -EFAULT; > > + > > + return 0; > > +} > > + > > +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *sp) > > +{ > > + int s; > > + > > + if (get_user(s, sp)) > > + return -EFAULT; > > + > > + if (s) > > + q->flags |= MACVTAP_VNET_BE; > > + else > > + q->flags &= ~MACVTAP_VNET_BE; > > + > > + return 0; > > +} > > +#else > > +static long macvtap_
Re: [PATCH v4 6/8] virtio: add explicit big-endian support to memory accessors
On Tue, 21 Apr 2015 16:09:44 +0200 "Michael S. Tsirkin" wrote: > On Fri, Apr 10, 2015 at 12:16:20PM +0200, Greg Kurz wrote: > > The current memory accessors logic is: > > - little endian if little_endian > > - native endian (i.e. no byteswap) if !little_endian > > > > If we want to fully support cross-endian vhost, we also need to be > > able to convert to big endian. > > > > Instead of changing the little_endian argument to some 3-value enum, this > > patch changes the logic to: > > - little endian if little_endian > > - big endian if !little_endian > > > > The native endian case is handled by all users with a trivial helper. This > > patch doesn't change any functionality, nor it does add overhead. > > > > Signed-off-by: Greg Kurz > > --- > > OK overall. Style comment: > > > drivers/net/macvtap.c|4 +++- > > drivers/net/tun.c|4 +++- > > drivers/vhost/vhost.h|4 +++- > > include/linux/virtio_byteorder.h | 24 ++-- > > include/linux/virtio_config.h|4 +++- > > include/linux/vringh.h |4 +++- > > 6 files changed, 29 insertions(+), 15 deletions(-) > > > > diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c > > index a2f2958..0a03a66 100644 > > --- a/drivers/net/macvtap.c > > +++ b/drivers/net/macvtap.c > > @@ -51,7 +51,9 @@ struct macvtap_queue { > > > > static inline bool macvtap_is_little_endian(struct macvtap_queue *q) > > { > > - return q->flags & MACVTAP_VNET_LE; > > + if (q->flags & MACVTAP_VNET_LE) > > + return true; > > + return virtio_legacy_is_little_endian(); > > } > > > > I'd prefer a bit more symmetry: > > + if (q->flags & MACVTAP_VNET_LE) > + return true; > + else > + return virtio_legacy_is_little_endian(); > > Or better just: > return (q->flags & MACVTAP_VNET_LE) ? true : > virtio_legacy_is_little_endian(); > > might make line long, but your follow-up patch makes it short again, > so that's ok. > Will do. > > > static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) > > diff --git a/drivers/net/tun.c b/drivers/net/tun.c > > index 3c3d6c0..053f9b6 100644 > > --- a/drivers/net/tun.c > > +++ b/drivers/net/tun.c > > @@ -208,7 +208,9 @@ struct tun_struct { > > > > static inline bool tun_is_little_endian(struct tun_struct *tun) > > { > > - return tun->flags & TUN_VNET_LE; > > + if (tun->flags & TUN_VNET_LE) > > + return true; > > + return virtio_legacy_is_little_endian(); > > } > > > > static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) > > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h > > index 6a49960..4e9a186 100644 > > --- a/drivers/vhost/vhost.h > > +++ b/drivers/vhost/vhost.h > > @@ -175,7 +175,9 @@ static inline bool vhost_has_feature(struct > > vhost_virtqueue *vq, int bit) > > > > static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) > > { > > - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); > > + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > > + return true; > > + return virtio_legacy_is_little_endian(); > > } > > > > /* Memory accessors */ > > diff --git a/include/linux/virtio_byteorder.h > > b/include/linux/virtio_byteorder.h > > index 51865d0..ce63a2c 100644 > > --- a/include/linux/virtio_byteorder.h > > +++ b/include/linux/virtio_byteorder.h > > @@ -3,17 +3,21 @@ > > #include > > #include > > > > -/* > > - * Low-level memory accessors for handling virtio in modern little endian > > and in > > - * compatibility native endian format. > > - */ > > +static inline bool virtio_legacy_is_little_endian(void) > > +{ > > +#ifdef __LITTLE_ENDIAN > > + return true; > > +#else > > + return false; > > +#endif > > +} > > > > static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) > > { > > if (little_endian) > > return le16_to_cpu((__force __le16)val); > > else > > - return (__force u16)val; > > + return be16_to_cpu((__force __be16)val); > > } > > > > static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) > > @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_t
Re: [PATCH v4 0/8] vhost: support for cross endian guests
On Tue, 21 Apr 2015 16:10:18 +0200 "Michael S. Tsirkin" wrote: > On Fri, Apr 10, 2015 at 12:15:00PM +0200, Greg Kurz wrote: > > Hi, > > > > This patchset allows vhost to be used with legacy virtio when guest and host > > have a different endianness. > > > > Patch 7 got rewritten according to Cornelia's and Michael's comments. I have > > also introduced patch 8 that brings BE vnet headers support to tun/macvtap. > > > > This series is enough to have vhost_net working flawlessly. I could > > succesfully reboot guests from ppc64 to ppc64le and vice-versa on ppc64 > > and ppc64le hosts. > > Looks good overall. > A couple of style comments. > > Thanks! > Thanks for your time Michael. > > --- > > > > Greg Kurz (8): > > virtio: introduce virtio_is_little_endian() helper > > tun: add tun_is_little_endian() helper > > macvtap: introduce macvtap_is_little_endian() helper > > vringh: introduce vringh_is_little_endian() helper > > vhost: introduce vhost_is_little_endian() helper > > virtio: add explicit big-endian support to memory accessors > > vhost: feature to set the vring endianness > > macvtap/tun: add VNET_BE flag > > > > > > drivers/net/Kconfig | 12 ++ > > drivers/net/macvtap.c| 69 ++- > > drivers/net/tun.c| 71 > > +++- > > drivers/vhost/Kconfig| 10 + > > drivers/vhost/vhost.c| 76 > > ++ > > drivers/vhost/vhost.h| 25 ++--- > > include/linux/virtio_byteorder.h | 24 +++- > > include/linux/virtio_config.h| 19 +++--- > > include/linux/vringh.h | 19 +++--- > > include/uapi/linux/if_tun.h |2 + > > include/uapi/linux/vhost.h |9 + > > 11 files changed, 303 insertions(+), 33 deletions(-) > > > > -- > > Greg > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v4 7/8] vhost: feature to set the vring endianness
On Tue, 21 Apr 2015 20:25:03 +0200 "Michael S. Tsirkin" wrote: [ ... ] > > > > @@ -630,6 +634,53 @@ static long vhost_set_memory(struct vhost_dev *d, > > > > struct vhost_memory __user *m) > > > > return 0; > > > > } > > > > > > > > +#ifdef CONFIG_VHOST_SET_ENDIAN_LEGACY > > > > +static long vhost_set_vring_big_endian(struct vhost_virtqueue *vq, > > > > + int __user *argp) > > > > +{ > > > > + struct vhost_vring_state s; > > > > + > > > > + if (vq->private_data) > > > > + return -EBUSY; > > > > + > > > > + if (copy_from_user(&s, argp, sizeof(s))) > > > > + return -EFAULT; > > > > + > > > > + if (s.num && s.num != 1) > > > > > > s.num & ~0x1 > > > > > > > Since s.num is unsigned and I assume this won't change, what about > > s.num > 1 as suggested by Cornelia ? > > I just tried and gcc optimizes > s.num != 0 && s.num != 1 to s.num > 1 > > The former will be more readable once we > replace 0 and 1 with defines. > > So ignore my advice, keep code as is but use defines. > Ok. [ ... ] > > > > --- a/include/uapi/linux/vhost.h > > > > +++ b/include/uapi/linux/vhost.h > > > > @@ -103,6 +103,15 @@ struct vhost_memory { > > > > /* Get accessor: reads index, writes value in num */ > > > > #define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct > > > > vhost_vring_state) > > > > > > > > +/* Set the vring byte order in num. This is a legacy only API that is > > > > simply > > > > + * ignored when VIRTIO_F_VERSION_1 is set. > > > > + * 0 to set to little-endian > > > > + * 1 to set to big-endian > > > > > > How about defines for these? > > > > > > > Ok. I'll put the defines here so that all the cross-endian stuff > > lies in the same hunk. Is it ok for you ? > > Fine. > > > > > + * other values return EINVAL. > > Pls also add a note saying that not all kernel configurations support this > ioctl, > but all configurations that support SET also support GET. > Ok. > > > > + */ > > > > +#define VHOST_SET_VRING_BIG_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct > > > > vhost_vring_state) > > > > +#define VHOST_GET_VRING_BIG_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct > > > > vhost_vring_state) > > > > + > > > > /* The following ioctls use eventfd file descriptors to signal and poll > > > > * for events. */ > > > > > > > > > I'm inclined to think VHOST_SET_VRING_ENDIAN is a slightly better name. > What do you think? > Or VHOST_SET_VRING_CROSS_ENDIAN ? I like the idea to keep a hint that this API is for cross-endian only... like the rest of this series. -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v4 8/8] macvtap/tun: add VNET_BE flag
On Tue, 21 Apr 2015 20:30:23 +0200 "Michael S. Tsirkin" wrote: > On Tue, Apr 21, 2015 at 06:22:20PM +0200, Greg Kurz wrote: > > On Tue, 21 Apr 2015 16:06:33 +0200 > > "Michael S. Tsirkin" wrote: > > > > > On Fri, Apr 10, 2015 at 12:20:21PM +0200, Greg Kurz wrote: > > > > The VNET_LE flag was introduced to fix accesses to virtio 1.0 headers > > > > that are always little-endian. It can also be used to handle the special > > > > case of a legacy little-endian device implemented by a big-endian host. > > > > > > > > Let's add a flag and ioctls for big-endian devices as well. If both > > > > flags > > > > are set, little-endian wins. > > > > > > > > Since this is isn't a common usecase, the feature is controlled by a > > > > kernel > > > > config option (not set by default). > > > > > > > > Both macvtap and tun are covered by this patch since they share the same > > > > API with userland. > > > > > > > > Signed-off-by: Greg Kurz > > > > --- > > > > drivers/net/Kconfig | 12 > > > > drivers/net/macvtap.c | 60 > > > > +- > > > > drivers/net/tun.c | 62 > > > > ++- > > > > include/uapi/linux/if_tun.h |2 + > > > > 4 files changed, 134 insertions(+), 2 deletions(-) > > > > > > > > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig > > > > index df51d60..f0e23a0 100644 > > > > --- a/drivers/net/Kconfig > > > > +++ b/drivers/net/Kconfig > > > > @@ -244,6 +244,18 @@ config TUN > > > > > > > > If you don't know what to use this for, you don't need it. > > > > > > > > +config TUN_VNET_BE > > > > + bool "Support for big-endian vnet headers" > > > > + default n > > > > + ---help--- > > > > + This option allows TUN/TAP and MACVTAP device drivers to parse > > > > + vnet headers that are in big-endian byte order. It is useful > > > > + when the headers come from a big-endian legacy virtio driver > > > > and > > > > + the host is little-endian. > > > > + > > > > + Unless you have a little-endian system hosting a big-endian > > > > virtual > > > > + machine with a virtio NIC, you should say N. > > > > + > > > > > > should mention cross-endian, not big-endian, right? > > > > > > > The current TUN_VNET_LE related code is already doing cross-endian: without > > this patch, one can already run a LE guest on a BE host... wouldn't it be > > confusing to mention cross-endian only when the guest is BE ? > > Hmm I think no - LE is also useful for virtio 1 - this is what it was > intended for after all. > > > What about having a completely distinct implementation for cross-endian that > > don't reuse the existing code and defines then ? > > I think implementation and interface are fine, just the documentation > can be improved a bit. > > How about: > "Support for cross-endian vnet headers on little-endian kernels". > > Accordingly CONFIG_TUN_VNET_CROSS_LE > > ? > Sure. And what about also renaming the ioctl to TUNSETVNETCROSSLE then ? -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v5 0/8] vhost: support for cross endian guests
Hi, This patchset allows vhost to be used with legacy virtio when guest and host have a different endianness. It is compatible with modern virtio and can be fully compiled out through kernel config. FWIW, I could flawlessly kexec/reboot guests from ppc64 to ppc64le and back. I could also migrate from a ppc64 to a ppc64le host and back. No regressions on x86 as expected. My experimental QEMU tree is here: https://github.com/gkurz/qemu.git vhost/cross-endian I'd be glad if this series could make it to 4.1. Cheers. --- Greg Kurz (8): virtio: introduce virtio_is_little_endian() helper tun: add tun_is_little_endian() helper macvtap: introduce macvtap_is_little_endian() helper vringh: introduce vringh_is_little_endian() helper vhost: introduce vhost_is_little_endian() helper virtio: add explicit big-endian support to memory accessors vhost: cross-endian support for legacy devices macvtap/tun: cross-endian support for little-endian hosts drivers/net/Kconfig | 14 ++ drivers/net/macvtap.c| 68 +- drivers/net/tun.c| 70 ++- drivers/vhost/Kconfig| 15 +++ drivers/vhost/vhost.c| 86 ++ drivers/vhost/vhost.h| 25 --- include/linux/virtio_byteorder.h | 24 ++- include/linux/virtio_config.h| 20 ++--- include/linux/vringh.h | 17 +--- include/uapi/linux/if_tun.h |6 +++ include/uapi/linux/vhost.h | 12 + 11 files changed, 324 insertions(+), 33 deletions(-) -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v5 1/8] virtio: introduce virtio_is_little_endian() helper
Signed-off-by: Greg Kurz --- include/linux/virtio_config.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index ca3ed78..bd1a582 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -205,35 +205,40 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu) return 0; } +static inline bool virtio_is_little_endian(struct virtio_device *vdev) +{ + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) { - return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) { - return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(virtio_is_little_endian(vdev), val); } static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) { - return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) { - return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(virtio_is_little_endian(vdev), val); } static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) { - return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) { - return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); } /* Config space accessors. */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v5 2/8] tun: add tun_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/net/tun.c |9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 857dca4..3c3d6c0 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -206,14 +206,19 @@ struct tun_struct { u32 flow_count; }; +static inline bool tun_is_little_endian(struct tun_struct *tun) +{ + return tun->flags & TUN_VNET_LE; +} + static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) { - return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val); + return __virtio16_to_cpu(tun_is_little_endian(tun), val); } static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) { - return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val); + return __cpu_to_virtio16(tun_is_little_endian(tun), val); } static inline u32 tun_hashfn(u32 rxhash) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v5 3/8] macvtap: introduce macvtap_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/net/macvtap.c |9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 27ecc5c..a2f2958 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -49,14 +49,19 @@ struct macvtap_queue { #define MACVTAP_VNET_LE 0x8000 +static inline bool macvtap_is_little_endian(struct macvtap_queue *q) +{ + return q->flags & MACVTAP_VNET_LE; +} + static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) { - return __virtio16_to_cpu(q->flags & MACVTAP_VNET_LE, val); + return __virtio16_to_cpu(macvtap_is_little_endian(q), val); } static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val) { - return __cpu_to_virtio16(q->flags & MACVTAP_VNET_LE, val); + return __cpu_to_virtio16(macvtap_is_little_endian(q), val); } static struct proto macvtap_proto = { ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v5 4/8] vringh: introduce vringh_is_little_endian() helper
Signed-off-by: Greg Kurz --- include/linux/vringh.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/vringh.h b/include/linux/vringh.h index a3fa537..3ed62ef 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -226,33 +226,38 @@ static inline void vringh_notify(struct vringh *vrh) vrh->notify(vrh); } +static inline bool vringh_is_little_endian(const struct vringh *vrh) +{ + return vrh->little_endian; +} + static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val) { - return __virtio16_to_cpu(vrh->little_endian, val); + return __virtio16_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio16 cpu_to_vringh16(const struct vringh *vrh, u16 val) { - return __cpu_to_virtio16(vrh->little_endian, val); + return __cpu_to_virtio16(vringh_is_little_endian(vrh), val); } static inline u32 vringh32_to_cpu(const struct vringh *vrh, __virtio32 val) { - return __virtio32_to_cpu(vrh->little_endian, val); + return __virtio32_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio32 cpu_to_vringh32(const struct vringh *vrh, u32 val) { - return __cpu_to_virtio32(vrh->little_endian, val); + return __cpu_to_virtio32(vringh_is_little_endian(vrh), val); } static inline u64 vringh64_to_cpu(const struct vringh *vrh, __virtio64 val) { - return __virtio64_to_cpu(vrh->little_endian, val); + return __virtio64_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio64 cpu_to_vringh64(const struct vringh *vrh, u64 val) { - return __cpu_to_virtio64(vrh->little_endian, val); + return __cpu_to_virtio64(vringh_is_little_endian(vrh), val); } #endif /* _LINUX_VRINGH_H */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v5 5/8] vhost: introduce vhost_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/vhost/vhost.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 8c1c792..6a49960 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -173,34 +173,39 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) return vq->acked_features & (1ULL << bit); } +static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) +{ + return vhost_has_feature(vq, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) { - return __virtio16_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio16 cpu_to_vhost16(struct vhost_virtqueue *vq, u16 val) { - return __cpu_to_virtio16(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(vhost_is_little_endian(vq), val); } static inline u32 vhost32_to_cpu(struct vhost_virtqueue *vq, __virtio32 val) { - return __virtio32_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio32 cpu_to_vhost32(struct vhost_virtqueue *vq, u32 val) { - return __cpu_to_virtio32(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(vhost_is_little_endian(vq), val); } static inline u64 vhost64_to_cpu(struct vhost_virtqueue *vq, __virtio64 val) { - return __virtio64_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio64 cpu_to_vhost64(struct vhost_virtqueue *vq, u64 val) { - return __cpu_to_virtio64(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(vhost_is_little_endian(vq), val); } #endif ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v5 6/8] virtio: add explicit big-endian support to memory accessors
The current memory accessors logic is: - little endian if little_endian - native endian (i.e. no byteswap) if !little_endian If we want to fully support cross-endian vhost, we also need to be able to convert to big endian. Instead of changing the little_endian argument to some 3-value enum, this patch changes the logic to: - little endian if little_endian - big endian if !little_endian The native endian case is handled by all users with a trivial helper. This patch doesn't change any functionality, nor it does add overhead. Signed-off-by: Greg Kurz --- Changes since v4: - style fixes (I have chosen if ... else in most places to stay below 80 columns, with the notable exception of the vhost helper which gets shorten in a later patch) drivers/net/macvtap.c|5 - drivers/net/tun.c|5 - drivers/vhost/vhost.h|2 +- include/linux/virtio_byteorder.h | 24 ++-- include/linux/virtio_config.h|5 - include/linux/vringh.h |2 +- 6 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index a2f2958..6cf6b3e 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -51,7 +51,10 @@ struct macvtap_queue { static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { - return q->flags & MACVTAP_VNET_LE; + if (q->flags & MACVTAP_VNET_LE) + return true; + else + return virtio_legacy_is_little_endian(); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3c3d6c0..5b044d4 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -208,7 +208,10 @@ struct tun_struct { static inline bool tun_is_little_endian(struct tun_struct *tun) { - return tun->flags & TUN_VNET_LE; + if (tun->flags & TUN_VNET_LE) + return true; + else + return virtio_legacy_is_little_endian(); } static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 6a49960..954c657 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -175,7 +175,7 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) { - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); + return vhost_has_feature(vq, VIRTIO_F_VERSION_1) ? true : virtio_legacy_is_little_endian(); } /* Memory accessors */ diff --git a/include/linux/virtio_byteorder.h b/include/linux/virtio_byteorder.h index 51865d0..ce63a2c 100644 --- a/include/linux/virtio_byteorder.h +++ b/include/linux/virtio_byteorder.h @@ -3,17 +3,21 @@ #include #include -/* - * Low-level memory accessors for handling virtio in modern little endian and in - * compatibility native endian format. - */ +static inline bool virtio_legacy_is_little_endian(void) +{ +#ifdef __LITTLE_ENDIAN + return true; +#else + return false; +#endif +} static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) { if (little_endian) return le16_to_cpu((__force __le16)val); else - return (__force u16)val; + return be16_to_cpu((__force __be16)val); } static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) if (little_endian) return (__force __virtio16)cpu_to_le16(val); else - return (__force __virtio16)val; + return (__force __virtio16)cpu_to_be16(val); } static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) @@ -29,7 +33,7 @@ static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) if (little_endian) return le32_to_cpu((__force __le32)val); else - return (__force u32)val; + return be32_to_cpu((__force __be32)val); } static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) @@ -37,7 +41,7 @@ static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) if (little_endian) return (__force __virtio32)cpu_to_le32(val); else - return (__force __virtio32)val; + return (__force __virtio32)cpu_to_be32(val); } static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) @@ -45,7 +49,7 @@ static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) if (little_endian) return le64_to_cpu((__force __le64)val); else - return (__force u64)val; + return be64_to_cpu((__force __be64)val); } static inline __virtio64 __cpu_to_virtio64(bool little_endian,
[PATCH v5 7/8] vhost: cross-endian support for legacy devices
This patch brings cross-endian support to vhost when used to implement legacy virtio devices. Since it is a relatively rare situation, the feature availability is controlled by a kernel config option (not set by default). The vq->is_le boolean field is added to cache the endianness to be used for ring accesses. It defaults to native endian, as expected by legacy virtio devices. When the ring gets active, we force little endian if the device is modern. When the ring is deactivated, we revert to the native endian default. If cross-endian was compiled in, a vq->user_be boolean field is added so that userspace may request a specific endianness. This field is used to override the default when activating the ring of a legacy device. It has no effect on modern devices. Signed-off-by: Greg Kurz --- Changes since v4: - rewrote patch title to mention cross-endian - renamed config to VHOST_CROSS_ENDIAN_LEGACY - rewrote config description and help - moved ifdefery to top of vhost.c - added a detailed comment about the lifecycle of vq->user_be in vhost_init_is_le() - renamed ioctls to VHOST_[GS]ET_VRING_ENDIAN - added LE/BE defines to the ioctl API - rewrote ioctl sanity check with the LE/BE defines - updated comment in to mention that the availibility of both SET and GET ioctls depends on the kernel config drivers/vhost/Kconfig | 15 drivers/vhost/vhost.c | 86 +++- drivers/vhost/vhost.h | 10 + include/uapi/linux/vhost.h | 12 ++ 4 files changed, 121 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 017a1e8..74d7380 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -32,3 +32,18 @@ config VHOST ---help--- This option is selected by any driver which needs to access the core of vhost. + +config VHOST_CROSS_ENDIAN_LEGACY + bool "Cross-endian support for vhost" + default n + ---help--- + This option allows vhost to support guests with a different byte + ordering from host. + + Userspace programs can control the feature using the + VHOST_SET_VRING_ENDIAN and VHOST_GET_VRING_ENDIAN ioctls. + + This is only useful on a few platforms (ppc64 and arm64). Since it + adds some overhead, it is disabled default. + + If unsure, say "N". diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ee2826..8c4390d 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -36,6 +36,78 @@ enum { #define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num]) #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num]) +#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +{ + vq->user_be = !virtio_legacy_is_little_endian(); +} + +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) +{ + struct vhost_vring_state s; + + if (vq->private_data) + return -EBUSY; + + if (copy_from_user(&s, argp, sizeof(s))) + return -EFAULT; + + if (s.num != VHOST_VRING_LITTLE_ENDIAN && + s.num != VHOST_VRING_BIG_ENDIAN) + return -EINVAL; + + vq->user_be = s.num; + + return 0; +} + +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, + int __user *argp) +{ + struct vhost_vring_state s = { + .index = idx, + .num = vq->user_be + }; + + if (copy_to_user(argp, &s, sizeof(s))) + return -EFAULT; + + return 0; +} + +static void vhost_init_is_le(struct vhost_virtqueue *vq) +{ + /* Note for legacy virtio: user_be is initialized at reset time +* according to the host endianness. If userspace does not set an +* explicit endianness, the default behavior is native endian, as +* expected by legacy virtio. +*/ + vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; +} +#else +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +{ + ; +} + +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) +{ + return -ENOIOCTLCMD; +} + +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, + int __user *argp) +{ + return -ENOIOCTLCMD; +} + +static void vhost_init_is_le(struct vhost_virtqueue *vq) +{ + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + vq->is_le = true; +} +#endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -199,6 +271,8 @@ static void vhost_vq_reset(struct vhost_dev *dev,
[PATCH v5 8/8] macvtap/tun: cross-endian support for little-endian hosts
The VNET_LE flag was introduced to fix accesses to virtio 1.0 headers that are always little-endian. It can also be used to handle the special case of a legacy little-endian device implemented by a big-endian host. Let's add a flag and ioctls for big-endian devices as well. If both flags are set, little-endian wins. Since this is isn't a common usecase, the feature is controlled by a kernel config option (not set by default). Both macvtap and tun are covered by this patch since they share the same API with userland. Signed-off-by: Greg Kurz --- Changes since v4: - rewrote patch title to mention cross-endian - renamed config to TUN_VNET_CROSS_LE - rewrote config description and help - moved ifdefery to top of tun.c and macvtap.c - updated comment in to mention that the availibility of both SET and GET ioctls depends on the kernel config drivers/net/Kconfig | 14 ++ drivers/net/macvtap.c | 58 +- drivers/net/tun.c | 60 ++- include/uapi/linux/if_tun.h |6 4 files changed, 136 insertions(+), 2 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index df51d60..71ac0ec 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -244,6 +244,20 @@ config TUN If you don't know what to use this for, you don't need it. +config TUN_VNET_CROSS_LE + bool "Support for cross-endian vnet headers on little-endian kernels" + default n + ---help--- + This option allows TUN/TAP and MACVTAP device drivers in a + little-endian kernel to parse vnet headers that come from a + big-endian legacy virtio device. + + Userspace programs can control the feature using the TUNSETVNETBE + and TUNGETVNETBE ioctls. + + Unless you have a little-endian system hosting a big-endian virtual + machine with a legacy virtio NIC, you should say N. + config VETH tristate "Virtual ethernet pair device" ---help--- diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 6cf6b3e..460ed9f 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -48,13 +48,63 @@ struct macvtap_queue { #define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE) #define MACVTAP_VNET_LE 0x8000 +#define MACVTAP_VNET_BE 0x4000 + +#ifdef CONFIG_TUN_VNET_CROSS_LE +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) +{ + if (q->flags & MACVTAP_VNET_BE) + return false; + return virtio_legacy_is_little_endian(); +} + +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *sp) +{ + int s = !!(q->flags & MACVTAP_VNET_BE); + + if (put_user(s, sp)) + return -EFAULT; + + return 0; +} + +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *sp) +{ + int s; + + if (get_user(s, sp)) + return -EFAULT; + + if (s) + q->flags |= MACVTAP_VNET_BE; + else + q->flags &= ~MACVTAP_VNET_BE; + + return 0; +} +#else +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) +{ + return virtio_legacy_is_little_endian(); +} + +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *argp) +{ + return -EINVAL; +} + +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *argp) +{ + return -EINVAL; +} +#endif /* CONFIG_TUN_VNET_CROSS_LE */ static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { if (q->flags & MACVTAP_VNET_LE) return true; else - return virtio_legacy_is_little_endian(); + return macvtap_legacy_is_little_endian(q); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) @@ -1098,6 +1148,12 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, q->flags &= ~MACVTAP_VNET_LE; return 0; + case TUNGETVNETBE: + return macvtap_get_vnet_be(q, sp); + + case TUNSETVNETBE: + return macvtap_set_vnet_be(q, sp); + case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 5b044d4..1b0afa9 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -111,6 +111,7 @@ do { \ #define TUN_FASYNC IFF_ATTACH_QUEUE /* High bits in flags field are unused. */ #define TUN_VNET_LE 0x8000 +#define TUN_VNET_BE 0x4000 #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ IFF_MULTI_QUEUE) @@ -206,12 +207,61 @@ struct tun_struct {
Re: [PATCH v5 6/8] virtio: add explicit big-endian support to memory accessors
On Fri, 24 Apr 2015 09:04:21 +0200 Cornelia Huck wrote: > On Thu, 23 Apr 2015 21:27:19 +0200 > Thomas Huth wrote: > Thomas's e-mail did not make it to my mailbox... weird. :-\ > > On Thu, 23 Apr 2015 17:29:06 +0200 > > Greg Kurz wrote: > > > > > The current memory accessors logic is: > > > - little endian if little_endian > > > - native endian (i.e. no byteswap) if !little_endian > > > > > > If we want to fully support cross-endian vhost, we also need to be > > > able to convert to big endian. > > > > > > Instead of changing the little_endian argument to some 3-value enum, this > > > patch changes the logic to: > > > - little endian if little_endian > > > - big endian if !little_endian > > > > > > The native endian case is handled by all users with a trivial helper. This > > > patch doesn't change any functionality, nor it does add overhead. > > > > > > Signed-off-by: Greg Kurz > > > --- > > > > > > Changes since v4: > > > - style fixes (I have chosen if ... else in most places to stay below > > > 80 columns, with the notable exception of the vhost helper which gets > > > shorten in a later patch) > > > > > > drivers/net/macvtap.c|5 - > > > drivers/net/tun.c|5 - > > > drivers/vhost/vhost.h|2 +- > > > include/linux/virtio_byteorder.h | 24 ++-- > > > include/linux/virtio_config.h|5 - > > > include/linux/vringh.h |2 +- > > > 6 files changed, 28 insertions(+), 15 deletions(-) > > > > > > diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c > > > index a2f2958..6cf6b3e 100644 > > > --- a/drivers/net/macvtap.c > > > +++ b/drivers/net/macvtap.c > > > @@ -51,7 +51,10 @@ struct macvtap_queue { > > > > > > static inline bool macvtap_is_little_endian(struct macvtap_queue *q) > > > { > > > - return q->flags & MACVTAP_VNET_LE; > > > + if (q->flags & MACVTAP_VNET_LE) > > > + return true; > > > + else > > > + return virtio_legacy_is_little_endian(); > > > > simply: > > > > return (q->flags & MACVTAP_VNET_LE) || > >virtio_legacy_is_little_endian(); > > > > ? > > ISTR that MST preferred the current notation, but I like either your > way or ?: (with linebreak) even better. > MST did not like the initial notation I had used actually. FWIW I like the simplicity of Thomas's suggestion... even better than ?: which is: some_LE_check() ? true : some_default_endianness() > > > > > } > > > > (...) > > > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h > > > index 6a49960..954c657 100644 > > > --- a/drivers/vhost/vhost.h > > > +++ b/drivers/vhost/vhost.h > > > @@ -175,7 +175,7 @@ static inline bool vhost_has_feature(struct > > > vhost_virtqueue *vq, int bit) > > > > > > static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) > > > { > > > - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); > > > + return vhost_has_feature(vq, VIRTIO_F_VERSION_1) ? true : > > > virtio_legacy_is_little_endian(); > > > } > > > > That line is way longer than 80 characters ... may I suggest to switch > > at least here to: > > > > return vhost_has_feature(vq, VIRTIO_F_VERSION_1) || > >virtio_legacy_is_little_endian(); > > I think the line will collapse in a further patch anyway. > Yes, as mentionned in the changelog :) > -- > To unsubscribe from this list: send the line "unsubscribe kvm" in > the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v5 7/8] vhost: cross-endian support for legacy devices
On Fri, 24 Apr 2015 09:19:26 +0200 Cornelia Huck wrote: > On Thu, 23 Apr 2015 17:29:42 +0200 > Greg Kurz wrote: > > > This patch brings cross-endian support to vhost when used to implement > > legacy virtio devices. Since it is a relatively rare situation, the > > feature availability is controlled by a kernel config option (not set > > by default). > > > > The vq->is_le boolean field is added to cache the endianness to be > > used for ring accesses. It defaults to native endian, as expected > > by legacy virtio devices. When the ring gets active, we force little > > endian if the device is modern. When the ring is deactivated, we > > revert to the native endian default. > > > > If cross-endian was compiled in, a vq->user_be boolean field is added > > so that userspace may request a specific endianness. This field is > > used to override the default when activating the ring of a legacy > > device. It has no effect on modern devices. > > > > Signed-off-by: Greg Kurz > > --- > > > > Changes since v4: > > - rewrote patch title to mention cross-endian > > - renamed config to VHOST_CROSS_ENDIAN_LEGACY > > - rewrote config description and help > > - moved ifdefery to top of vhost.c > > - added a detailed comment about the lifecycle of vq->user_be in > > vhost_init_is_le() > > - renamed ioctls to VHOST_[GS]ET_VRING_ENDIAN > > - added LE/BE defines to the ioctl API > > - rewrote ioctl sanity check with the LE/BE defines > > - updated comment in to mention that the availibility > > of both SET and GET ioctls depends on the kernel config > > > > drivers/vhost/Kconfig | 15 > > drivers/vhost/vhost.c | 86 > > +++- > > drivers/vhost/vhost.h | 10 + > > include/uapi/linux/vhost.h | 12 ++ > > 4 files changed, 121 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig > > index 017a1e8..74d7380 100644 > > --- a/drivers/vhost/Kconfig > > +++ b/drivers/vhost/Kconfig > > @@ -32,3 +32,18 @@ config VHOST > > ---help--- > > This option is selected by any driver which needs to access > > the core of vhost. > > + > > +config VHOST_CROSS_ENDIAN_LEGACY > > + bool "Cross-endian support for vhost" > > + default n > > + ---help--- > > + This option allows vhost to support guests with a different byte > > + ordering from host. > > "...while using legacy virtio." > > Might help to explain the "LEGACY" in the config option ;) > Makes sense indeed ! > > + > > + Userspace programs can control the feature using the > > + VHOST_SET_VRING_ENDIAN and VHOST_GET_VRING_ENDIAN ioctls. > > + > > + This is only useful on a few platforms (ppc64 and arm64). Since it > > + adds some overhead, it is disabled default. > > s/default/by default/ > Ok. > > + > > + If unsure, say "N". > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > index 2ee2826..8c4390d 100644 > > --- a/drivers/vhost/vhost.c > > +++ b/drivers/vhost/vhost.c > > @@ -36,6 +36,78 @@ enum { > > #define vhost_used_event(vq) ((__virtio16 __user > > *)&vq->avail->ring[vq->num]) > > #define vhost_avail_event(vq) ((__virtio16 __user > > *)&vq->used->ring[vq->num]) > > > > +#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY > > +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) > > +{ > > + vq->user_be = !virtio_legacy_is_little_endian(); > > +} > > + > > +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user > > *argp) > > +{ > > + struct vhost_vring_state s; > > + > > + if (vq->private_data) > > + return -EBUSY; > > + > > + if (copy_from_user(&s, argp, sizeof(s))) > > + return -EFAULT; > > + > > + if (s.num != VHOST_VRING_LITTLE_ENDIAN && > > + s.num != VHOST_VRING_BIG_ENDIAN) > > + return -EINVAL; > > + > > + vq->user_be = s.num; > > + > > + return 0; > > +} > > + > > +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, > > + int __user *argp) > > +{ > > + struct vhost_vring_state s = { > > + .index = idx, > > + .num = vq->user_be > > + }; > > + > > + if (cop
[PATCH v6 0/8] vhost: support for cross endian guests
Only cosmetic and documentation changes since v5. --- Greg Kurz (8): virtio: introduce virtio_is_little_endian() helper tun: add tun_is_little_endian() helper macvtap: introduce macvtap_is_little_endian() helper vringh: introduce vringh_is_little_endian() helper vhost: introduce vhost_is_little_endian() helper virtio: add explicit big-endian support to memory accessors vhost: cross-endian support for legacy devices macvtap/tun: cross-endian support for little-endian hosts drivers/net/Kconfig | 14 ++ drivers/net/macvtap.c| 66 +- drivers/net/tun.c| 68 ++ drivers/vhost/Kconfig| 15 +++ drivers/vhost/vhost.c| 85 ++ drivers/vhost/vhost.h| 25 --- include/linux/virtio_byteorder.h | 24 ++- include/linux/virtio_config.h| 18 +--- include/linux/vringh.h | 18 +--- include/uapi/linux/if_tun.h |6 +++ include/uapi/linux/vhost.h | 14 ++ 11 files changed, 320 insertions(+), 33 deletions(-) -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v6 4/8] vringh: introduce vringh_is_little_endian() helper
Signed-off-by: Greg Kurz --- include/linux/vringh.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/vringh.h b/include/linux/vringh.h index a3fa537..3ed62ef 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -226,33 +226,38 @@ static inline void vringh_notify(struct vringh *vrh) vrh->notify(vrh); } +static inline bool vringh_is_little_endian(const struct vringh *vrh) +{ + return vrh->little_endian; +} + static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val) { - return __virtio16_to_cpu(vrh->little_endian, val); + return __virtio16_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio16 cpu_to_vringh16(const struct vringh *vrh, u16 val) { - return __cpu_to_virtio16(vrh->little_endian, val); + return __cpu_to_virtio16(vringh_is_little_endian(vrh), val); } static inline u32 vringh32_to_cpu(const struct vringh *vrh, __virtio32 val) { - return __virtio32_to_cpu(vrh->little_endian, val); + return __virtio32_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio32 cpu_to_vringh32(const struct vringh *vrh, u32 val) { - return __cpu_to_virtio32(vrh->little_endian, val); + return __cpu_to_virtio32(vringh_is_little_endian(vrh), val); } static inline u64 vringh64_to_cpu(const struct vringh *vrh, __virtio64 val) { - return __virtio64_to_cpu(vrh->little_endian, val); + return __virtio64_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio64 cpu_to_vringh64(const struct vringh *vrh, u64 val) { - return __cpu_to_virtio64(vrh->little_endian, val); + return __cpu_to_virtio64(vringh_is_little_endian(vrh), val); } #endif /* _LINUX_VRINGH_H */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v6 2/8] tun: add tun_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/net/tun.c |9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 857dca4..3c3d6c0 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -206,14 +206,19 @@ struct tun_struct { u32 flow_count; }; +static inline bool tun_is_little_endian(struct tun_struct *tun) +{ + return tun->flags & TUN_VNET_LE; +} + static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) { - return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val); + return __virtio16_to_cpu(tun_is_little_endian(tun), val); } static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val) { - return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val); + return __cpu_to_virtio16(tun_is_little_endian(tun), val); } static inline u32 tun_hashfn(u32 rxhash) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v6 1/8] virtio: introduce virtio_is_little_endian() helper
Signed-off-by: Greg Kurz --- include/linux/virtio_config.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index ca3ed78..bd1a582 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -205,35 +205,40 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu) return 0; } +static inline bool virtio_is_little_endian(struct virtio_device *vdev) +{ + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) { - return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) { - return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(virtio_is_little_endian(vdev), val); } static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) { - return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) { - return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(virtio_is_little_endian(vdev), val); } static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) { - return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) { - return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); } /* Config space accessors. */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v6 3/8] macvtap: introduce macvtap_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/net/macvtap.c |9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 27ecc5c..a2f2958 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -49,14 +49,19 @@ struct macvtap_queue { #define MACVTAP_VNET_LE 0x8000 +static inline bool macvtap_is_little_endian(struct macvtap_queue *q) +{ + return q->flags & MACVTAP_VNET_LE; +} + static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) { - return __virtio16_to_cpu(q->flags & MACVTAP_VNET_LE, val); + return __virtio16_to_cpu(macvtap_is_little_endian(q), val); } static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val) { - return __cpu_to_virtio16(q->flags & MACVTAP_VNET_LE, val); + return __cpu_to_virtio16(macvtap_is_little_endian(q), val); } static struct proto macvtap_proto = { ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v6 5/8] vhost: introduce vhost_is_little_endian() helper
Signed-off-by: Greg Kurz --- drivers/vhost/vhost.h | 17 +++-- 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 8c1c792..6a49960 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -173,34 +173,39 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) return vq->acked_features & (1ULL << bit); } +static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) +{ + return vhost_has_feature(vq, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) { - return __virtio16_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio16 cpu_to_vhost16(struct vhost_virtqueue *vq, u16 val) { - return __cpu_to_virtio16(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(vhost_is_little_endian(vq), val); } static inline u32 vhost32_to_cpu(struct vhost_virtqueue *vq, __virtio32 val) { - return __virtio32_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio32 cpu_to_vhost32(struct vhost_virtqueue *vq, u32 val) { - return __cpu_to_virtio32(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(vhost_is_little_endian(vq), val); } static inline u64 vhost64_to_cpu(struct vhost_virtqueue *vq, __virtio64 val) { - return __virtio64_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(vhost_is_little_endian(vq), val); } static inline __virtio64 cpu_to_vhost64(struct vhost_virtqueue *vq, u64 val) { - return __cpu_to_virtio64(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(vhost_is_little_endian(vq), val); } #endif ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH v6 6/8] virtio: add explicit big-endian support to memory accessors
The current memory accessors logic is: - little endian if little_endian - native endian (i.e. no byteswap) if !little_endian If we want to fully support cross-endian vhost, we also need to be able to convert to big endian. Instead of changing the little_endian argument to some 3-value enum, this patch changes the logic to: - little endian if little_endian - big endian if !little_endian The native endian case is handled by all users with a trivial helper. This patch doesn't change any functionality, nor it does add overhead. Signed-off-by: Greg Kurz --- Changes since v5: - changed endian checking helpers as suggested by Thomas (use || and line breaker) drivers/net/macvtap.c|3 ++- drivers/net/tun.c|3 ++- drivers/vhost/vhost.h|3 ++- include/linux/virtio_byteorder.h | 24 ++-- include/linux/virtio_config.h|3 ++- include/linux/vringh.h |3 ++- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index a2f2958..0327d9d 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -51,7 +51,8 @@ struct macvtap_queue { static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { - return q->flags & MACVTAP_VNET_LE; + return q->flags & MACVTAP_VNET_LE || + virtio_legacy_is_little_endian(); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3c3d6c0..7c4f6b6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -208,7 +208,8 @@ struct tun_struct { static inline bool tun_is_little_endian(struct tun_struct *tun) { - return tun->flags & TUN_VNET_LE; + return tun->flags & TUN_VNET_LE || + virtio_legacy_is_little_endian(); } static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 6a49960..a4fa33a 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -175,7 +175,8 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) { - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); + return vhost_has_feature(vq, VIRTIO_F_VERSION_1) || + virtio_legacy_is_little_endian(); } /* Memory accessors */ diff --git a/include/linux/virtio_byteorder.h b/include/linux/virtio_byteorder.h index 51865d0..ce63a2c 100644 --- a/include/linux/virtio_byteorder.h +++ b/include/linux/virtio_byteorder.h @@ -3,17 +3,21 @@ #include #include -/* - * Low-level memory accessors for handling virtio in modern little endian and in - * compatibility native endian format. - */ +static inline bool virtio_legacy_is_little_endian(void) +{ +#ifdef __LITTLE_ENDIAN + return true; +#else + return false; +#endif +} static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) { if (little_endian) return le16_to_cpu((__force __le16)val); else - return (__force u16)val; + return be16_to_cpu((__force __be16)val); } static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) if (little_endian) return (__force __virtio16)cpu_to_le16(val); else - return (__force __virtio16)val; + return (__force __virtio16)cpu_to_be16(val); } static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) @@ -29,7 +33,7 @@ static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) if (little_endian) return le32_to_cpu((__force __le32)val); else - return (__force u32)val; + return be32_to_cpu((__force __be32)val); } static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) @@ -37,7 +41,7 @@ static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) if (little_endian) return (__force __virtio32)cpu_to_le32(val); else - return (__force __virtio32)val; + return (__force __virtio32)cpu_to_be32(val); } static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) @@ -45,7 +49,7 @@ static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) if (little_endian) return le64_to_cpu((__force __le64)val); else - return (__force u64)val; + return be64_to_cpu((__force __be64)val); } static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) @@ -53,7 +57,7 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) if (little_endian) return (__force __virtio
[PATCH v6 7/8] vhost: cross-endian support for legacy devices
This patch brings cross-endian support to vhost when used to implement legacy virtio devices. Since it is a relatively rare situation, the feature availability is controlled by a kernel config option (not set by default). The vq->is_le boolean field is added to cache the endianness to be used for ring accesses. It defaults to native endian, as expected by legacy virtio devices. When the ring gets active, we force little endian if the device is modern. When the ring is deactivated, we revert to the native endian default. If cross-endian was compiled in, a vq->user_be boolean field is added so that userspace may request a specific endianness. This field is used to override the default when activating the ring of a legacy device. It has no effect on modern devices. Signed-off-by: Greg Kurz --- Changes since v5: - fixed description in Kconfig - fixed error description in uapi header - dropped useless semi-colon in the vhost_vq_reset_user_be() stub drivers/vhost/Kconfig | 15 drivers/vhost/vhost.c | 85 +++- drivers/vhost/vhost.h | 11 +- include/uapi/linux/vhost.h | 14 +++ 4 files changed, 122 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 017a1e8..533eaf0 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -32,3 +32,18 @@ config VHOST ---help--- This option is selected by any driver which needs to access the core of vhost. + +config VHOST_CROSS_ENDIAN_LEGACY + bool "Cross-endian support for vhost" + default n + ---help--- + This option allows vhost to support guests with a different byte + ordering from host while using legacy virtio. + + Userspace programs can control the feature using the + VHOST_SET_VRING_ENDIAN and VHOST_GET_VRING_ENDIAN ioctls. + + This is only useful on a few platforms (ppc64 and arm64). Since it + adds some overhead, it is disabled by default. + + If unsure, say "N". diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ee2826..9e8e004 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -36,6 +36,77 @@ enum { #define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num]) #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num]) +#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +{ + vq->user_be = !virtio_legacy_is_little_endian(); +} + +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) +{ + struct vhost_vring_state s; + + if (vq->private_data) + return -EBUSY; + + if (copy_from_user(&s, argp, sizeof(s))) + return -EFAULT; + + if (s.num != VHOST_VRING_LITTLE_ENDIAN && + s.num != VHOST_VRING_BIG_ENDIAN) + return -EINVAL; + + vq->user_be = s.num; + + return 0; +} + +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, + int __user *argp) +{ + struct vhost_vring_state s = { + .index = idx, + .num = vq->user_be + }; + + if (copy_to_user(argp, &s, sizeof(s))) + return -EFAULT; + + return 0; +} + +static void vhost_init_is_le(struct vhost_virtqueue *vq) +{ + /* Note for legacy virtio: user_be is initialized at reset time +* according to the host endianness. If userspace does not set an +* explicit endianness, the default behavior is native endian, as +* expected by legacy virtio. +*/ + vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; +} +#else +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +{ +} + +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) +{ + return -ENOIOCTLCMD; +} + +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, + int __user *argp) +{ + return -ENOIOCTLCMD; +} + +static void vhost_init_is_le(struct vhost_virtqueue *vq) +{ + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + vq->is_le = true; +} +#endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -199,6 +270,8 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call = NULL; vq->log_ctx = NULL; vq->memory = NULL; + vq->is_le = virtio_legacy_is_little_endian(); + vhost_vq_reset_user_be(vq); } static int vhost_worker(void *data) @@ -806,6 +879,12 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) } else
[PATCH v6 8/8] macvtap/tun: cross-endian support for little-endian hosts
The VNET_LE flag was introduced to fix accesses to virtio 1.0 headers that are always little-endian. It can also be used to handle the special case of a legacy little-endian device implemented by a big-endian host. Let's add a flag and ioctls for big-endian devices as well. If both flags are set, little-endian wins. Since this is isn't a common usecase, the feature is controlled by a kernel config option (not set by default). Both macvtap and tun are covered by this patch since they share the same API with userland. Signed-off-by: Greg Kurz --- Changes since v5: - changed {macvtapi,tun}_legacy_is_little_endian() to use ?: drivers/net/Kconfig | 14 ++ drivers/net/macvtap.c | 57 +- drivers/net/tun.c | 59 ++- include/uapi/linux/if_tun.h |6 4 files changed, 134 insertions(+), 2 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index df51d60..71ac0ec 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -244,6 +244,20 @@ config TUN If you don't know what to use this for, you don't need it. +config TUN_VNET_CROSS_LE + bool "Support for cross-endian vnet headers on little-endian kernels" + default n + ---help--- + This option allows TUN/TAP and MACVTAP device drivers in a + little-endian kernel to parse vnet headers that come from a + big-endian legacy virtio device. + + Userspace programs can control the feature using the TUNSETVNETBE + and TUNGETVNETBE ioctls. + + Unless you have a little-endian system hosting a big-endian virtual + machine with a legacy virtio NIC, you should say N. + config VETH tristate "Virtual ethernet pair device" ---help--- diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 0327d9d..dc0a47c 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -48,11 +48,60 @@ struct macvtap_queue { #define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE) #define MACVTAP_VNET_LE 0x8000 +#define MACVTAP_VNET_BE 0x4000 + +#ifdef CONFIG_TUN_VNET_CROSS_LE +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) +{ + return q->flags & MACVTAP_VNET_BE ? false : + virtio_legacy_is_little_endian(); +} + +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *sp) +{ + int s = !!(q->flags & MACVTAP_VNET_BE); + + if (put_user(s, sp)) + return -EFAULT; + + return 0; +} + +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *sp) +{ + int s; + + if (get_user(s, sp)) + return -EFAULT; + + if (s) + q->flags |= MACVTAP_VNET_BE; + else + q->flags &= ~MACVTAP_VNET_BE; + + return 0; +} +#else +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) +{ + return virtio_legacy_is_little_endian(); +} + +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *argp) +{ + return -EINVAL; +} + +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *argp) +{ + return -EINVAL; +} +#endif /* CONFIG_TUN_VNET_CROSS_LE */ static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { return q->flags & MACVTAP_VNET_LE || - virtio_legacy_is_little_endian(); + macvtap_legacy_is_little_endian(q); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) @@ -1096,6 +1145,12 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, q->flags &= ~MACVTAP_VNET_LE; return 0; + case TUNGETVNETBE: + return macvtap_get_vnet_be(q, sp); + + case TUNSETVNETBE: + return macvtap_set_vnet_be(q, sp); + case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 7c4f6b6..9fa05d6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -111,6 +111,7 @@ do { \ #define TUN_FASYNC IFF_ATTACH_QUEUE /* High bits in flags field are unused. */ #define TUN_VNET_LE 0x8000 +#define TUN_VNET_BE 0x4000 #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ IFF_MULTI_QUEUE) @@ -206,10 +207,58 @@ struct tun_struct { u32 flow_count; }; +#ifdef CONFIG_TUN_VNET_CROSS_LE +static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) +{ + return tun->flags & TUN_VNET_BE ? false : + virtio_legacy_is_little_endian(); +} + +static long tun_get_vnet_be(struct tun_struct *tun, int __user
[PATCH RFC 1/7] virtio: relax feature check
Unlike with add and clear, there is no valid reason to abort when checking for a feature. It makes more sense to return false (i.e. the feature bit isn't set). This is exactly what __virtio_has_feature() does if fbit >= 32. This allows to introduce code that is aware about new 64-bit features like VIRTIO_F_VERSION_1, even if they are still not implemented. Signed-off-by: Greg Kurz --- include/hw/virtio/virtio.h |1 - 1 file changed, 1 deletion(-) diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index d95f8b6..6ef70f1 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -233,7 +233,6 @@ static inline void virtio_clear_feature(uint32_t *features, unsigned int fbit) static inline bool __virtio_has_feature(uint32_t features, unsigned int fbit) { -assert(fbit < 32); return !!(features & (1 << fbit)); } ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH RFC 2/7] linux-headers: sync vhost.h
This patch brings the cross-endian vhost API to QEMU. Signed-off-by: Greg Kurz --- linux-headers/linux/vhost.h | 14 ++ 1 file changed, 14 insertions(+) diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index c656f61..ead86db 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -103,6 +103,20 @@ struct vhost_memory { /* Get accessor: reads index, writes value in num */ #define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state) +/* Set the vring byte order in num. Valid values are VHOST_VRING_LITTLE_ENDIAN + * or VHOST_VRING_BIG_ENDIAN (other values return -EINVAL). + * The byte order cannot be changed while the device is active: trying to do so + * returns -EBUSY. + * This is a legacy only API that is simply ignored when VIRTIO_F_VERSION_1 is + * set. + * Not all kernel configurations support this ioctl, but all configurations that + * support SET also support GET. + */ +#define VHOST_VRING_LITTLE_ENDIAN 0 +#define VHOST_VRING_BIG_ENDIAN 1 +#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state) +#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state) + /* The following ioctls use eventfd file descriptors to signal and poll * for events. */ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH RFC 0/7] vhost: cross-endian support (vhost-net only)
Hi, This series allows QEMU to use vhost with legacy virtio devices when host and target don't have the same endianness. Only network devices are covered for the moment. I had already posted a series some monthes ago but it never got reviewed. Moreover, the underlying kernel support was entirely re-written and is still waiting to be applied by Michael. I hence post as RFC. The corresponding kernel patches are available here: http://lists.linuxfoundation.org/pipermail/virtualization/2015-April/029885.html Please comment. --- Cédric Le Goater (1): vhost_net: re-enable when cross endian Greg Kurz (6): virtio: relax feature check linux-headers: sync vhost.h virtio: introduce virtio_legacy_is_cross_endian() vhost: set vring endianness for legacy virtio tap: add VNET_LE/VNET_BE operations vhost-net: tell tap backend about the vnet endianness hw/net/vhost_net.c| 50 +++-- hw/virtio/vhost.c | 50 - include/hw/virtio/virtio-access.h | 13 ++ include/hw/virtio/virtio.h|1 - include/net/net.h |6 linux-headers/linux/vhost.h | 14 ++ net/net.c | 18 + net/tap-linux.c | 34 + net/tap-linux.h |2 + net/tap.c | 16 net/tap_int.h |2 + 11 files changed, 185 insertions(+), 21 deletions(-) -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH RFC 3/7] virtio: introduce virtio_legacy_is_cross_endian()
This helper will be used by vhost and tap to detect cross-endianness in the legacy virtio case. Signed-off-by: Greg Kurz --- include/hw/virtio/virtio-access.h | 13 + 1 file changed, 13 insertions(+) diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index 46456fd..caf0940 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -28,6 +28,19 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) #endif } +static inline bool virtio_legacy_is_cross_endian(VirtIODevice *vdev) +{ +#ifdef TARGET_IS_BIENDIAN +#ifdef HOST_WORDS_BIGENDIAN +return !virtio_is_big_endian(vdev); +#else +return virtio_is_big_endian(vdev); +#endif +#else +return false; +#endif +} + static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa) { if (virtio_access_is_big_endian(vdev)) { ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH RFC 5/7] tap: add VNET_LE/VNET_BE operations
The linux tap and macvtap backends can be told to parse vnet headers according to little or big endian. This is done through the TUNSETVNETLE and TUNSETVNETBE ioctls. This patch brings all the plumbing for QEMU to use these APIs. Signed-off-by: Greg Kurz --- include/net/net.h |6 ++ net/net.c | 18 ++ net/tap-linux.c | 34 ++ net/tap-linux.h |2 ++ net/tap.c | 16 net/tap_int.h |2 ++ 6 files changed, 78 insertions(+) diff --git a/include/net/net.h b/include/net/net.h index 50ffcb9..86f57f7 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -55,6 +55,8 @@ typedef bool (HasVnetHdrLen)(NetClientState *, int); typedef void (UsingVnetHdr)(NetClientState *, bool); typedef void (SetOffload)(NetClientState *, int, int, int, int, int); typedef void (SetVnetHdrLen)(NetClientState *, int); +typedef int (SetVnetLE)(NetClientState *, bool); +typedef int (SetVnetBE)(NetClientState *, bool); typedef struct NetClientInfo { NetClientOptionsKind type; @@ -73,6 +75,8 @@ typedef struct NetClientInfo { UsingVnetHdr *using_vnet_hdr; SetOffload *set_offload; SetVnetHdrLen *set_vnet_hdr_len; +SetVnetLE *set_vnet_le; +SetVnetBE *set_vnet_be; } NetClientInfo; struct NetClientState { @@ -138,6 +142,8 @@ void qemu_using_vnet_hdr(NetClientState *nc, bool enable); void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo); void qemu_set_vnet_hdr_len(NetClientState *nc, int len); +int qemu_set_vnet_le(NetClientState *nc, bool is_le); +int qemu_set_vnet_be(NetClientState *nc, bool is_be); void qemu_macaddr_default_if_unset(MACAddr *macaddr); int qemu_show_nic_models(const char *arg, const char *const *models); void qemu_check_nic_model(NICInfo *nd, const char *model); diff --git a/net/net.c b/net/net.c index 0be084d..eb8ef3e 100644 --- a/net/net.c +++ b/net/net.c @@ -452,6 +452,24 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len) nc->info->set_vnet_hdr_len(nc, len); } +int qemu_set_vnet_le(NetClientState *nc, bool is_le) +{ +if (!nc || !nc->info->set_vnet_le) { +return -ENOSYS; +} + +return nc->info->set_vnet_le(nc, is_le); +} + +int qemu_set_vnet_be(NetClientState *nc, bool is_be) +{ +if (!nc || !nc->info->set_vnet_be) { +return -ENOSYS; +} + +return nc->info->set_vnet_be(nc, is_be); +} + int qemu_can_send_packet(NetClientState *sender) { int vm_running = runstate_is_running(); diff --git a/net/tap-linux.c b/net/tap-linux.c index 812bf2d..15b57a7 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -198,6 +198,40 @@ void tap_fd_set_vnet_hdr_len(int fd, int len) } } +int tap_fd_set_vnet_le(int fd, int is_le) +{ +int arg = is_le ? 1 : 0; + +if (!ioctl(fd, TUNSETVNETLE, &arg)) { +return 0; +} + +/* Check if our kernel supports TUNSETVNETLE */ +if (errno == EINVAL) { +return -errno; +} + +error_report("TUNSETVNETLE ioctl() failed: %s.\n", strerror(errno)); +abort(); +} + +int tap_fd_set_vnet_be(int fd, int is_be) +{ +int arg = is_be ? 1 : 0; + +if (!ioctl(fd, TUNSETVNETBE, &arg)) { +return 0; +} + +/* Check if our kernel supports TUNSETVNETBE */ +if (errno == EINVAL) { +return -errno; +} + +error_report("TUNSETVNETBE ioctl() failed: %s.\n", strerror(errno)); +abort(); +} + void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo) { diff --git a/net/tap-linux.h b/net/tap-linux.h index 1cf35d4..01dc6f8 100644 --- a/net/tap-linux.h +++ b/net/tap-linux.h @@ -30,6 +30,8 @@ #define TUNGETVNETHDRSZ _IOR('T', 215, int) #define TUNSETVNETHDRSZ _IOW('T', 216, int) #define TUNSETQUEUE _IOW('T', 217, int) +#define TUNSETVNETLE _IOW('T', 220, int) +#define TUNSETVNETBE _IOW('T', 222, int) #endif diff --git a/net/tap.c b/net/tap.c index 968df46..c6f9a7d 100644 --- a/net/tap.c +++ b/net/tap.c @@ -274,6 +274,20 @@ static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr) s->using_vnet_hdr = using_vnet_hdr; } +static int tap_set_vnet_le(NetClientState *nc, bool is_le) +{ +TAPState *s = DO_UPCAST(TAPState, nc, nc); + +return tap_fd_set_vnet_le(s->fd, is_le); +} + +static int tap_set_vnet_be(NetClientState *nc, bool is_be) +{ +TAPState *s = DO_UPCAST(TAPState, nc, nc); + +return tap_fd_set_vnet_be(s->fd, is_be); +} + static void tap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo) { @@ -335,6 +349,8 @@ static NetClientInfo net_tap_info = { .using_vnet_hdr = tap_using_vnet_hdr, .set_offload = tap_set_offload, .set_vnet_hdr_len = tap_set_vnet_hdr_len, +.set_vnet_le = tap_set_vnet_le, +.set_
[PATCH RFC 6/7] vhost-net: tell tap backend about the vnet endianness
The default behaviour for TAP/MACVTAP is to consider vnet as native endian. This patch handles the cases when this is not true: - virtio 1.0: always little-endian - legacy cross-endian Signed-off-by: Greg Kurz --- hw/net/vhost_net.c | 33 - 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index cf23335..1884e59 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -38,6 +38,7 @@ #include "standard-headers/linux/virtio_ring.h" #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-access.h" struct vhost_net { struct vhost_dev dev; @@ -194,6 +195,27 @@ static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index) net->dev.vq_index = vq_index; } +static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer, + bool set) +{ +int r = 0; + +if (virtio_has_feature(dev, VIRTIO_F_VERSION_1) || +(virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) { +r = qemu_set_vnet_le(peer, set); +if (r) { +error_report("backend does not support LE vnet headers"); +} +} else if (virtio_legacy_is_cross_endian(dev)) { +r = qemu_set_vnet_be(peer, set); +if (r) { +error_report("backend does not support BE vnet headers"); +} +} + +return r; +} + static int vhost_net_start_one(struct vhost_net *net, VirtIODevice *dev) { @@ -304,6 +326,11 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, goto err; } +r = vhost_net_set_vnet_endian(dev, ncs[0].peer, true); +if (r < 0) { +goto err; +} + for (i = 0; i < total_queues; i++) { vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2); } @@ -311,7 +338,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true); if (r < 0) { error_report("Error binding guest notifier: %d", -r); -goto err; +goto err_endian; } for (i = 0; i < total_queues; i++) { @@ -333,6 +360,8 @@ err_start: fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e); fflush(stderr); } +err_endian: +vhost_net_set_vnet_endian(dev, ncs[0].peer, false); err: return r; } @@ -355,6 +384,8 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, fflush(stderr); } assert(r >= 0); + +assert(vhost_net_set_vnet_endian(dev, ncs[0].peer, false) >= 0); } void vhost_net_cleanup(struct vhost_net *net) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH RFC 4/7] vhost: set vring endianness for legacy virtio
Legacy virtio is native endian: if the guest and host endianness differ, we have to tell vhost so it can swap bytes where appropriate. This is done through a vhost ring ioctl. Signed-off-by: Greg Kurz --- hw/virtio/vhost.c | 50 +- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 54851b7..1d7b939 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -17,9 +17,11 @@ #include "hw/hw.h" #include "qemu/atomic.h" #include "qemu/range.h" +#include "qemu/error-report.h" #include #include "exec/address-spaces.h" #include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-access.h" #include "migration/migration.h" static void vhost_dev_sync_region(struct vhost_dev *dev, @@ -647,6 +649,27 @@ static void vhost_log_stop(MemoryListener *listener, /* FIXME: implement */ } +static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev, + bool is_big_endian, + int vhost_vq_index) +{ +struct vhost_vring_state s = { +.index = vhost_vq_index, +.num = is_big_endian +}; + +if (!dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ENDIAN, &s)) { +return 0; +} + +if (errno == ENOTTY) { +error_report("vhost does not support cross-endian"); +return -ENOSYS; +} + +return -errno; +} + static int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev, struct vhost_virtqueue *vq, @@ -677,6 +700,16 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, return -errno; } +if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) && +virtio_legacy_is_cross_endian(vdev)) { +r = vhost_virtqueue_set_vring_endian_legacy(dev, +virtio_is_big_endian(vdev), +vhost_vq_index); +if (r) { +return -errno; +} +} + s = l = virtio_queue_get_desc_size(vdev, idx); a = virtio_queue_get_desc_addr(vdev, idx); vq->desc = cpu_physical_memory_map(a, &l, 0); @@ -747,8 +780,9 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, struct vhost_virtqueue *vq, unsigned idx) { +int vhost_vq_index = idx - dev->vq_index; struct vhost_vring_state state = { -.index = idx - dev->vq_index +.index = vhost_vq_index, }; int r; assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); @@ -759,6 +793,20 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, } virtio_queue_set_last_avail_idx(vdev, idx, state.num); virtio_queue_invalidate_signalled_used(vdev, idx); + +/* In the cross-endian case, we need to reset the vring endianness to + * native as legacy devices expect so by default. + */ +if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) && +virtio_legacy_is_cross_endian(vdev)) { +r = vhost_virtqueue_set_vring_endian_legacy(dev, + !virtio_is_big_endian(vdev), +vhost_vq_index); +if (r < 0) { +error_report("failed to reset vring endianness"); +} +} + assert (r >= 0); cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx), 0, virtio_queue_get_ring_size(vdev, idx)); ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH RFC 7/7] vhost_net: re-enable when cross endian
From: Cédric Le Goater Cross-endianness is now checked by the core vhost code. revert 371df9f5e0f1 "vhost-net: disable when cross-endian" Signed-off-by: Cédric Le Goater [ added commit message, Greg Kurz ] Signed-off-by: Greg Kurz --- hw/net/vhost_net.c | 19 --- 1 file changed, 19 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 1884e59..3e4b0f2 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -293,19 +293,6 @@ static void vhost_net_stop_one(struct vhost_net *net, vhost_dev_disable_notifiers(&net->dev, dev); } -static bool vhost_net_device_endian_ok(VirtIODevice *vdev) -{ -#ifdef TARGET_IS_BIENDIAN -#ifdef HOST_WORDS_BIGENDIAN -return virtio_is_big_endian(vdev); -#else -return !virtio_is_big_endian(vdev); -#endif -#else -return true; -#endif -} - int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, int total_queues) { @@ -314,12 +301,6 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); int r, e, i; -if (!vhost_net_device_endian_ok(dev)) { -error_report("vhost-net does not support cross-endian"); -r = -ENOSYS; -goto err; -} - if (!k->set_guest_notifiers) { error_report("binding does not support guest notifiers"); r = -ENOSYS; ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v6 0/8] vhost: support for cross endian guests
On Fri, 24 Apr 2015 15:31:54 +0200 "Michael S. Tsirkin" wrote: > On Fri, Apr 24, 2015 at 02:24:15PM +0200, Greg Kurz wrote: > > Only cosmetic and documentation changes since v5. > > > > --- > > Looks sane to me. I plan to review and apply next week. > Hi Michael, I realize you just got back and have tons of things to do... Do you still plan to apply shortly ? Would you also have time to comment the QEMU part ? Thanks. -- Greg > > Greg Kurz (8): > > virtio: introduce virtio_is_little_endian() helper > > tun: add tun_is_little_endian() helper > > macvtap: introduce macvtap_is_little_endian() helper > > vringh: introduce vringh_is_little_endian() helper > > vhost: introduce vhost_is_little_endian() helper > > virtio: add explicit big-endian support to memory accessors > > vhost: cross-endian support for legacy devices > > macvtap/tun: cross-endian support for little-endian hosts > > > > > > drivers/net/Kconfig | 14 ++ > > drivers/net/macvtap.c| 66 +- > > drivers/net/tun.c| 68 ++ > > drivers/vhost/Kconfig| 15 +++ > > drivers/vhost/vhost.c| 85 > > ++ > > drivers/vhost/vhost.h| 25 --- > > include/linux/virtio_byteorder.h | 24 ++- > > include/linux/virtio_config.h| 18 +--- > > include/linux/vringh.h | 18 +--- > > include/uapi/linux/if_tun.h |6 +++ > > include/uapi/linux/vhost.h | 14 ++ > > 11 files changed, 320 insertions(+), 33 deletions(-) > > > > -- > > Greg > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [Qemu-devel] [PATCH RFC 1/7] virtio: relax feature check
On Tue, 12 May 2015 15:14:53 +0200 Cornelia Huck wrote: > On Wed, 06 May 2015 14:07:37 +0200 > Greg Kurz wrote: > > > Unlike with add and clear, there is no valid reason to abort when checking > > for a feature. It makes more sense to return false (i.e. the feature bit > > isn't set). This is exactly what __virtio_has_feature() does if fbit >= 32. > > > > This allows to introduce code that is aware about new 64-bit features like > > VIRTIO_F_VERSION_1, even if they are still not implemented. > > > > Signed-off-by: Greg Kurz > > --- > > include/hw/virtio/virtio.h |1 - > > 1 file changed, 1 deletion(-) > > > > diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h > > index d95f8b6..6ef70f1 100644 > > --- a/include/hw/virtio/virtio.h > > +++ b/include/hw/virtio/virtio.h > > @@ -233,7 +233,6 @@ static inline void virtio_clear_feature(uint32_t > > *features, unsigned int fbit) > > > > static inline bool __virtio_has_feature(uint32_t features, unsigned int > > fbit) > > { > > -assert(fbit < 32); > > return !!(features & (1 << fbit)); > > } > > > > > > > > I must say I'm not very comfortable with knowingly passing out-of-rage > values to this function. > I take that as a valid reason then :) > Can we perhaps apply at least the feature-bit-size extending patches > prior to your patchset, if the remainder of the virtio-1 patchset still > takes some time? Hmm... if I remember well, it still lacks migration support. -- Greg ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v6 0/8] vhost: support for cross endian guests
On Tue, 12 May 2015 12:52:55 +0200 "Michael S. Tsirkin" wrote: > On Tue, May 12, 2015 at 12:44:26PM +0200, Greg Kurz wrote: > > On Fri, 24 Apr 2015 15:31:54 +0200 > > "Michael S. Tsirkin" wrote: > > > > > On Fri, Apr 24, 2015 at 02:24:15PM +0200, Greg Kurz wrote: > > > > Only cosmetic and documentation changes since v5. > > > > > > > > --- > > > > > > Looks sane to me. I plan to review and apply next week. > > > > > > > Hi Michael, > > > > I realize you just got back and have tons of things to do... Do > > you still plan to apply shortly ? Would you also have time to > > comment the QEMU part ? > > > > Thanks. > > > > -- > > Greg > > Yes, sorry about the delay - I also got virtio upstream landed on my lap. > I'll do my best to prioritize. > Hi Michael, This is just a friendly reminder. Are there chances you pick up this kernel series before virtio 1.0 is in upstream QEMU ? Cheers. -- Greg > > > > Greg Kurz (8): > > > > virtio: introduce virtio_is_little_endian() helper > > > > tun: add tun_is_little_endian() helper > > > > macvtap: introduce macvtap_is_little_endian() helper > > > > vringh: introduce vringh_is_little_endian() helper > > > > vhost: introduce vhost_is_little_endian() helper > > > > virtio: add explicit big-endian support to memory accessors > > > > vhost: cross-endian support for legacy devices > > > > macvtap/tun: cross-endian support for little-endian hosts > > > > > > > > > > > > drivers/net/Kconfig | 14 ++ > > > > drivers/net/macvtap.c| 66 +- > > > > drivers/net/tun.c| 68 ++ > > > > drivers/vhost/Kconfig| 15 +++ > > > > drivers/vhost/vhost.c| 85 > > > > ++ > > > > drivers/vhost/vhost.h| 25 --- > > > > include/linux/virtio_byteorder.h | 24 ++- > > > > include/linux/virtio_config.h| 18 +--- > > > > include/linux/vringh.h | 18 +--- > > > > include/uapi/linux/if_tun.h |6 +++ > > > > include/uapi/linux/vhost.h | 14 ++ > > > > 11 files changed, 320 insertions(+), 33 deletions(-) > > > > > > > > -- > > > > Greg > > > > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PULL] virtio/vhost: cross endian support
On Thu, 2 Jul 2015 08:01:28 +0200 "Michael S. Tsirkin" wrote: > On Wed, Jul 01, 2015 at 12:02:50PM -0700, Linus Torvalds wrote: > > On Wed, Jul 1, 2015 at 2:31 AM, Michael S. Tsirkin wrote: > > > virtio/vhost: cross endian support > > > > Ugh. Does this really have to be dynamic? > > > > Can't virtio do the sane thing, and just use a _fixed_ endianness? > > > > Doing a unconditional byte swap is faster and simpler than the crazy > > conditionals. That's true regardless of endianness, but gets to be > > even more so if the fixed endianness is little-endian, since BE is > > not-so-slowly fading from the world. > > > >Linus > > Yea, well - support for legacy BE guests on the new LE hosts is > exactly the motivation for this. > > I dislike it too, but there are two redeeming properties that > made me merge this: > > 1. It's a trivial amount of code: since we wrap host/guest accesses > anyway, almost all of it is well hidden from drivers. > > 2. Sane platforms would never set flags like VHOST_CROSS_ENDIAN_LEGACY - > and when it's clear, there's zero overhead (as some point it was > tested by compiling with and without the patches, got the same > stripped binary). > > Maybe we could create a Kconfig symbol to enforce point (2): prevent > people from enabling it e.g. on x86. I will look into this - but it can > be done by a patch on top, so I think this can be merged as is. > This cross-endian *oddity* is targeting PowerPC book3s_64 processors... I am not aware of any other users. Maybe create a symbol that would be only selected by PPC_BOOK3S_64 ? > Or do you know of someone using kernel with all config options enabled > undiscriminately? > > Thanks, > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH] KVM: Add Kconfig option to signal cross-endian guests
On Thu, 9 Jul 2015 09:49:05 +0200 Thomas Huth wrote: > The option for supporting cross-endianness legacy guests in > the vhost and tun code should only be available on systems > that support cross-endian guests. > > Signed-off-by: Thomas Huth Acked-by: Greg Kurz ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH v2] Fix AF_PACKET ABI breakage in 4.2
On Wed, 23 Sep 2015 19:45:08 +0100 David Woodhouse wrote: > Commit 7d82410950aa ("virtio: add explicit big-endian support to memory > accessors") accidentally changed the virtio_net header used by > AF_PACKET with PACKET_VNET_HDR from host-endian to big-endian. > Hi David, Oops my bad... I obviously overlooked this one when adding cross-endian support. > Since virtio_legacy_is_little_endian() is a very long identifier, > define a VIO_LE macro and use that throughout the code instead of the VIO usually refers to virtual IO adapters for the PowerPC pSeries platform. > hard-coded 'false' for little-endian. > What about introducing dedicated accessors as it is done in many other locations where we do virtio byteswap ? Something like: static inline bool packet_is_little_endian(void) { return virtio_legacy_is_little_endian(); } static inline u16 packet16_to_cpu(__virtio16 val) { return __virtio16_to_cpu(packet_is_little_endian(), val); } static inline __virtio16 cpu_to_packet16(u16 val) { return __cpu_to_virtio16(packet_is_little_endian(), val); } It results in prettier code IMHO. Have a look at drivers/net/tun.c or drivers/vhost/vhost.c. > This restores the ABI to match 4.1 and earlier kernels, and makes my > test program work again. > BTW, there is still work to do if we want to support cross-endian legacy or virtio 1 on a big endian arch... Cheers. -- Greg > Signed-off-by: David Woodhouse > --- > On Wed, 2015-09-23 at 11:09 -0700, David Miller wrote: > > > +#define VIO_LE virtio_legacy_is_little_endian() > > > > When you define a shorthand macro, the defines to a function call, > > make the macro have parenthesis too. > > In which case I suppose it also wants to be lower-case. Although > "function call" is a bit strong since it's effectively just a constant. > I'm still wondering if it'd be nicer just to use (__force u16) instead. > > diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c > index 7b8e39a..aa4b15c 100644 > --- a/net/packet/af_packet.c > +++ b/net/packet/af_packet.c > @@ -230,6 +230,8 @@ struct packet_skb_cb { > } sa; > }; > > +#define vio_le() virtio_legacy_is_little_endian() > + > #define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb)) > > #define GET_PBDQC_FROM_RB(x) ((struct tpacket_kbdq_core *)(&(x)->prb_bdqc)) > @@ -2680,15 +2682,15 @@ static int packet_snd(struct socket *sock, struct > msghdr *msg, size_t len) > goto out_unlock; > > if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && > - (__virtio16_to_cpu(false, vnet_hdr.csum_start) + > - __virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2 > > - __virtio16_to_cpu(false, vnet_hdr.hdr_len))) > - vnet_hdr.hdr_len = __cpu_to_virtio16(false, > - __virtio16_to_cpu(false, vnet_hdr.csum_start) + > - __virtio16_to_cpu(false, vnet_hdr.csum_offset) > + 2); > + (__virtio16_to_cpu(vio_le(), vnet_hdr.csum_start) + > + __virtio16_to_cpu(vio_le(), vnet_hdr.csum_offset) + 2 > > + __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len))) > + vnet_hdr.hdr_len = __cpu_to_virtio16(vio_le(), > + __virtio16_to_cpu(vio_le(), > vnet_hdr.csum_start) + > + __virtio16_to_cpu(vio_le(), > vnet_hdr.csum_offset) + 2); > > err = -EINVAL; > - if (__virtio16_to_cpu(false, vnet_hdr.hdr_len) > len) > + if (__virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len) > len) > goto out_unlock; > > if (vnet_hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) { > @@ -2731,7 +2733,7 @@ static int packet_snd(struct socket *sock, struct > msghdr *msg, size_t len) > hlen = LL_RESERVED_SPACE(dev); > tlen = dev->needed_tailroom; > skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, > -__virtio16_to_cpu(false, vnet_hdr.hdr_len), > +__virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len), > msg->msg_flags & MSG_DONTWAIT, &err); > if (skb == NULL) > goto out_unlock; > @@ -2778,8 +2780,8 @@ static int packet_snd(struct socket *sock, struct > msghdr *msg, size_t len) > > if (po->has_vnet_hdr) { > if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { > - u16 s = __virtio16_to_cpu(false, vnet_hdr.csum_start); > - u16 o = __virtio16_to_cpu(false, vnet_hdr.csum_offset); > + u16 s = __virtio16_to_cpu(vio_le(), > vnet_hdr.csum_start); > + u16 o = __virtio16_to_cpu(vio_le(), > vnet_hdr.csum_offset); > if (!skb_partial_csum_set(skb, s, o)) { > err = -EINVAL; > goto out_free; > @@ -2787,7 +2
Re: [PATCH v2] Fix AF_PACKET ABI breakage in 4.2
On Thu, 24 Sep 2015 12:50:59 +0300 "Michael S. Tsirkin" wrote: > On Thu, Sep 24, 2015 at 09:25:45AM +0200, Greg Kurz wrote: > > On Wed, 23 Sep 2015 19:45:08 +0100 > > David Woodhouse wrote: > > > > > Commit 7d82410950aa ("virtio: add explicit big-endian support to memory > > > accessors") accidentally changed the virtio_net header used by > > > AF_PACKET with PACKET_VNET_HDR from host-endian to big-endian. > > > > > > > Hi David, > > > > Oops my bad... I obviously overlooked this one when adding cross-endian > > support. > > > > > Since virtio_legacy_is_little_endian() is a very long identifier, > > > define a VIO_LE macro and use that throughout the code instead of the > > > > VIO usually refers to virtual IO adapters for the PowerPC pSeries platform. > > > > > hard-coded 'false' for little-endian. > > > > > > > What about introducing dedicated accessors as it is done in many other > > locations where we do virtio byteswap ? Something like: > > > > static inline bool packet_is_little_endian(void) > > { > > return virtio_legacy_is_little_endian(); > > } > > > > static inline u16 packet16_to_cpu(__virtio16 val) > > { > > return __virtio16_to_cpu(packet_is_little_endian(), val); > > } > > > > static inline __virtio16 cpu_to_packet16(u16 val) > > { > > return __cpu_to_virtio16(packet_is_little_endian(), val); > > } > > > > It results in prettier code IMHO. Have a look at drivers/net/tun.c or > > drivers/vhost/vhost.c. > > > > > This restores the ABI to match 4.1 and earlier kernels, and makes my > > > test program work again. > > > > > > > BTW, there is still work to do if we want to support cross-endian legacy or > > virtio 1 on a big endian arch... > > > > Cheers. > > > > -- > > Greg > > It seems the API that we have is a confusing one. > > virtio endian-ness is either native or little, depending on a flag, so > __virtio16_to_cpu seems to mean "either native to cpu or little to cpu > depending on flag". > > It used to be like that, but not anymore. > > This leads to all kind of bugs. > > For example, I have only now realized vhost_is_little_endian isn't a > constant on LE hosts if cross-endian support is not compiled. > > I think we need to fix it, but also think about a better API. > Your original API is good and works well for all the callers that don't care for cross-endian support. I guess we'd rather move the cross-endian burden to the few callers who need it, i.e. tun, macvtap and vhost when cross-endian is compiled. More or less like this: /* Original API : either little-endian or native */ static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) { if (little_endian) return le16_to_cpu((__force __le16)val); else return (__force u16)val; } #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) { /* little-endian because of virtio 1 */ if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) return __virtio16_to_cpu(true, val); #ifdef __LITTLE_ENDIAN /* native little-endian */ return (__force u16)val; #else /* native big-endian */ return be16_to_cpu((__force __be16)val); #endif } #else static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) { #ifdef __LITTLE_ENDIAN /* fast path for little-endian host */ return __virtio16_to_cpu(true, val); #else /* slow path for big-endian host */ return __virtio16_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val); #endif } #endif Does it make sense ? > > > > Signed-off-by: David Woodhouse > > > --- > > > On Wed, 2015-09-23 at 11:09 -0700, David Miller wrote: > > > > > +#define VIO_LE virtio_legacy_is_little_endian() > > > > > > > > When you define a shorthand macro, the defines to a function call, > > > > make the macro have parenthesis too. > > > > > > In which case I suppose it also wants to be lower-case. Although > > > "function call" is a bit strong since it's effectively just a constant. > > > I'm still wondering if it'd be nicer just to use (__force u16) instead. > > > > > > diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c > > > index 7b8e39a..aa4b15c 100644 > > > --- a/net/packet/af_packet.c > > > +++ b/net
Re: [PATCH] vhost: fix performance on LE hosts
On Tue, 27 Oct 2015 11:37:39 +0200 "Michael S. Tsirkin" wrote: > commit 2751c9882b947292fcfb084c4f604e01724af804 ("vhost: cross-endian > support for legacy devices") introduced a minor regression: even with > cross-endian disabled, and even on LE host, vhost_is_little_endian is > checking is_le flag so there's always a branch. > > To fix, simply check virtio_legacy_is_little_endian first. > > Cc: Greg Kurz > Signed-off-by: Michael S. Tsirkin Oops my bad for this oversight... Reviewed-by: Greg Kurz > --- > drivers/vhost/vhost.h | 7 +++ > 1 file changed, 7 insertions(+) > > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h > index 4772862..d3f7674 100644 > --- a/drivers/vhost/vhost.h > +++ b/drivers/vhost/vhost.h > @@ -183,10 +183,17 @@ static inline bool vhost_has_feature(struct > vhost_virtqueue *vq, int bit) > return vq->acked_features & (1ULL << bit); > } > > +#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY > static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) > { > return vq->is_le; > } > +#else > +static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) > +{ > + return virtio_legacy_is_little_endian() || vq->is_le; > +} > +#endif > > /* Memory accessors */ > static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH] vhost: move is_le setup to the backend
The vq->is_le field is used to fix endianness when accessing the vring via the cpu_to_vhost16() and vhost16_to_cpu() helpers in the following cases: 1) host is big endian and device is modern virtio 2) host has cross-endian support and device is legacy virtio with a different endianness than the host Both cases rely on the VHOST_SET_FEATURES ioctl, but 2) also needs the VHOST_SET_VRING_ENDIAN ioctl to be called by userspace. Since vq->is_le is only needed when the backend is active, it was decided to set it at backend start. This is currently done in vhost_init_used()->vhost_init_is_le() but it obfuscates the core vhost code. This patch moves the is_le setup to a dedicated function that is called from the backend code. Note vhost_net is the only backend that can pass vq->private_data == NULL to vhost_init_used(), hence the "if (sock)" branch. No behaviour change. Signed-off-by: Greg Kurz --- drivers/vhost/net.c |6 ++ drivers/vhost/scsi.c |3 +++ drivers/vhost/test.c |2 ++ drivers/vhost/vhost.c | 12 +++- drivers/vhost/vhost.h |1 + 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9eda69e40678..d6319cb2664c 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -917,6 +917,12 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) vhost_net_disable_vq(n, vq); vq->private_data = sock; + + if (sock) + vhost_set_is_le(vq); + else + vq->is_le = virtio_legacy_is_little_endian(); + r = vhost_init_used(vq); if (r) goto err_used; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index e25a23692822..e2644a301fa5 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1276,6 +1276,9 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, vq = &vs->vqs[i].vq; mutex_lock(&vq->mutex); vq->private_data = vs_tpg; + + vhost_set_is_le(vq); + vhost_init_used(vq); mutex_unlock(&vq->mutex); } diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index f2882ac98726..b1c7df502211 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -196,6 +196,8 @@ static long vhost_test_run(struct vhost_test *n, int test) oldpriv = vq->private_data; vq->private_data = priv; + vhost_set_is_le(vq); + r = vhost_init_used(&n->vqs[index]); mutex_unlock(&vq->mutex); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index eec2f11809ff..6be863dcbd13 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -113,6 +113,12 @@ static void vhost_init_is_le(struct vhost_virtqueue *vq) } #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ +void vhost_set_is_le(struct vhost_virtqueue *vq) +{ + vhost_init_is_le(vq); +} +EXPORT_SYMBOL_GPL(vhost_set_is_le); + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -1156,12 +1162,8 @@ int vhost_init_used(struct vhost_virtqueue *vq) { __virtio16 last_used_idx; int r; - if (!vq->private_data) { - vq->is_le = virtio_legacy_is_little_endian(); + if (!vq->private_data) return 0; - } - - vhost_init_is_le(vq); r = vhost_update_used_flags(vq); if (r) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 4772862b71a7..8a62041959fe 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -162,6 +162,7 @@ bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *); int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, unsigned int log_num, u64 len); +void vhost_set_is_le(struct vhost_virtqueue *vq); #define vq_err(vq, fmt, ...) do { \ pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH] vhost: move is_le setup to the backend
On Fri, 30 Oct 2015 12:42:35 +0100 Greg Kurz wrote: > The vq->is_le field is used to fix endianness when accessing the vring via > the cpu_to_vhost16() and vhost16_to_cpu() helpers in the following cases: > > 1) host is big endian and device is modern virtio > > 2) host has cross-endian support and device is legacy virtio with a different >endianness than the host > > Both cases rely on the VHOST_SET_FEATURES ioctl, but 2) also needs the > VHOST_SET_VRING_ENDIAN ioctl to be called by userspace. Since vq->is_le > is only needed when the backend is active, it was decided to set it at > backend start. > > This is currently done in vhost_init_used()->vhost_init_is_le() but it > obfuscates the core vhost code. This patch moves the is_le setup to a > dedicated function that is called from the backend code. > > Note vhost_net is the only backend that can pass vq->private_data == NULL to > vhost_init_used(), hence the "if (sock)" branch. > > No behaviour change. > > Signed-off-by: Greg Kurz > --- Ping ? > drivers/vhost/net.c |6 ++ > drivers/vhost/scsi.c |3 +++ > drivers/vhost/test.c |2 ++ > drivers/vhost/vhost.c | 12 +++- > drivers/vhost/vhost.h |1 + > 5 files changed, 19 insertions(+), 5 deletions(-) > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c > index 9eda69e40678..d6319cb2664c 100644 > --- a/drivers/vhost/net.c > +++ b/drivers/vhost/net.c > @@ -917,6 +917,12 @@ static long vhost_net_set_backend(struct vhost_net *n, > unsigned index, int fd) > > vhost_net_disable_vq(n, vq); > vq->private_data = sock; > + > + if (sock) > + vhost_set_is_le(vq); > + else > + vq->is_le = virtio_legacy_is_little_endian(); > + > r = vhost_init_used(vq); > if (r) > goto err_used; > diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c > index e25a23692822..e2644a301fa5 100644 > --- a/drivers/vhost/scsi.c > +++ b/drivers/vhost/scsi.c > @@ -1276,6 +1276,9 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, > vq = &vs->vqs[i].vq; > mutex_lock(&vq->mutex); > vq->private_data = vs_tpg; > + > + vhost_set_is_le(vq); > + > vhost_init_used(vq); > mutex_unlock(&vq->mutex); > } > diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c > index f2882ac98726..b1c7df502211 100644 > --- a/drivers/vhost/test.c > +++ b/drivers/vhost/test.c > @@ -196,6 +196,8 @@ static long vhost_test_run(struct vhost_test *n, int test) > oldpriv = vq->private_data; > vq->private_data = priv; > > + vhost_set_is_le(vq); > + > r = vhost_init_used(&n->vqs[index]); > > mutex_unlock(&vq->mutex); > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > index eec2f11809ff..6be863dcbd13 100644 > --- a/drivers/vhost/vhost.c > +++ b/drivers/vhost/vhost.c > @@ -113,6 +113,12 @@ static void vhost_init_is_le(struct vhost_virtqueue *vq) > } > #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ > > +void vhost_set_is_le(struct vhost_virtqueue *vq) > +{ > + vhost_init_is_le(vq); > +} > +EXPORT_SYMBOL_GPL(vhost_set_is_le); > + > static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, > poll_table *pt) > { > @@ -1156,12 +1162,8 @@ int vhost_init_used(struct vhost_virtqueue *vq) > { > __virtio16 last_used_idx; > int r; > - if (!vq->private_data) { > - vq->is_le = virtio_legacy_is_little_endian(); > + if (!vq->private_data) > return 0; > - } > - > - vhost_init_is_le(vq); > > r = vhost_update_used_flags(vq); > if (r) > diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h > index 4772862b71a7..8a62041959fe 100644 > --- a/drivers/vhost/vhost.h > +++ b/drivers/vhost/vhost.h > @@ -162,6 +162,7 @@ bool vhost_enable_notify(struct vhost_dev *, struct > vhost_virtqueue *); > > int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, > unsigned int log_num, u64 len); > +void vhost_set_is_le(struct vhost_virtqueue *vq); > > #define vq_err(vq, fmt, ...) do { \ > pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \ > > -- > To unsubscribe from this list: send the line "unsubscribe kvm" in > the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH] vhost: move is_le setup to the backend
On Thu, 12 Nov 2015 15:46:30 +0200 "Michael S. Tsirkin" wrote: > On Fri, Oct 30, 2015 at 12:42:35PM +0100, Greg Kurz wrote: > > The vq->is_le field is used to fix endianness when accessing the vring via > > the cpu_to_vhost16() and vhost16_to_cpu() helpers in the following cases: > > > > 1) host is big endian and device is modern virtio > > > > 2) host has cross-endian support and device is legacy virtio with a > > different > >endianness than the host > > > > Both cases rely on the VHOST_SET_FEATURES ioctl, but 2) also needs the > > VHOST_SET_VRING_ENDIAN ioctl to be called by userspace. Since vq->is_le > > is only needed when the backend is active, it was decided to set it at > > backend start. > > > > This is currently done in vhost_init_used()->vhost_init_is_le() but it > > obfuscates the core vhost code. This patch moves the is_le setup to a > > dedicated function that is called from the backend code. > > > > Note vhost_net is the only backend that can pass vq->private_data == NULL to > > vhost_init_used(), hence the "if (sock)" branch. > > > > No behaviour change. > > > > Signed-off-by: Greg Kurz > > I plan to look at this next week, busy with QEMU 2.5 now. > I don't have any deadline for this since this is only a cleanup tentative. Thanks. > > --- > > drivers/vhost/net.c |6 ++ > > drivers/vhost/scsi.c |3 +++ > > drivers/vhost/test.c |2 ++ > > drivers/vhost/vhost.c | 12 +++- > > drivers/vhost/vhost.h |1 + > > 5 files changed, 19 insertions(+), 5 deletions(-) > > > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c > > index 9eda69e40678..d6319cb2664c 100644 > > --- a/drivers/vhost/net.c > > +++ b/drivers/vhost/net.c > > @@ -917,6 +917,12 @@ static long vhost_net_set_backend(struct vhost_net *n, > > unsigned index, int fd) > > > > vhost_net_disable_vq(n, vq); > > vq->private_data = sock; > > + > > + if (sock) > > + vhost_set_is_le(vq); > > + else > > + vq->is_le = virtio_legacy_is_little_endian(); > > + > > r = vhost_init_used(vq); > > if (r) > > goto err_used; > > diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c > > index e25a23692822..e2644a301fa5 100644 > > --- a/drivers/vhost/scsi.c > > +++ b/drivers/vhost/scsi.c > > @@ -1276,6 +1276,9 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, > > vq = &vs->vqs[i].vq; > > mutex_lock(&vq->mutex); > > vq->private_data = vs_tpg; > > + > > + vhost_set_is_le(vq); > > + > > vhost_init_used(vq); > > mutex_unlock(&vq->mutex); > > } > > diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c > > index f2882ac98726..b1c7df502211 100644 > > --- a/drivers/vhost/test.c > > +++ b/drivers/vhost/test.c > > @@ -196,6 +196,8 @@ static long vhost_test_run(struct vhost_test *n, int > > test) > > oldpriv = vq->private_data; > > vq->private_data = priv; > > > > + vhost_set_is_le(vq); > > + > > r = vhost_init_used(&n->vqs[index]); > > > > mutex_unlock(&vq->mutex); > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > index eec2f11809ff..6be863dcbd13 100644 > > --- a/drivers/vhost/vhost.c > > +++ b/drivers/vhost/vhost.c > > @@ -113,6 +113,12 @@ static void vhost_init_is_le(struct vhost_virtqueue > > *vq) > > } > > #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ > > > > +void vhost_set_is_le(struct vhost_virtqueue *vq) > > +{ > > + vhost_init_is_le(vq); > > +} > > +EXPORT_SYMBOL_GPL(vhost_set_is_le); > > + > > static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, > > poll_table *pt) > > { > > @@ -1156,12 +1162,8 @@ int vhost_init_used(struct vhost_virtqueue *vq) > > { > > __virtio16 last_used_idx; > > int r; > > - if (!vq->private_data) { > > - vq->is_le = virtio_legacy_is_little_endian(); > > + if (!vq->private_data) > > return 0; > > - } > > - > > - vhost_init_is_le(vq); > > > > r = vhost_update_used_flags(vq); > > if (r
Re: [PATCH] tools/virtio: fix byteswap logic
On Mon, 30 Nov 2015 10:33:34 +0200 "Michael S. Tsirkin" wrote: > commit cf561f0d2eb74574ad9985a2feab134267a9d298 ("virtio: introduce > virtio_is_little_endian() helper") changed byteswap logic to > skip feature bit checks for LE platforms, but didn't > update tools/virtio, so vring_bench started failing. > Oops... yet another oversight... > Update the copy under tools/virtio/ (TODO: find a way to avoid this code > duplication). > > Cc: Greg Kurz > Signed-off-by: Michael S. Tsirkin > --- Reviewed-by: Greg Kurz > tools/virtio/linux/virtio_config.h | 20 +--- > 1 file changed, 13 insertions(+), 7 deletions(-) > > diff --git a/tools/virtio/linux/virtio_config.h > b/tools/virtio/linux/virtio_config.h > index 806d683..57a6964 100644 > --- a/tools/virtio/linux/virtio_config.h > +++ b/tools/virtio/linux/virtio_config.h > @@ -40,33 +40,39 @@ static inline void __virtio_clear_bit(struct > virtio_device *vdev, > #define virtio_has_feature(dev, feature) \ > (__virtio_test_bit((dev), feature)) > > +static inline bool virtio_is_little_endian(struct virtio_device *vdev) > +{ > + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) || > + virtio_legacy_is_little_endian(); > +} > + > +/* Memory accessors */ > static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) > { > - return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), > val); > + return __virtio16_to_cpu(virtio_is_little_endian(vdev), val); > } > > static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) > { > - return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), > val); > + return __cpu_to_virtio16(virtio_is_little_endian(vdev), val); > } > > static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) > { > - return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), > val); > + return __virtio32_to_cpu(virtio_is_little_endian(vdev), val); > } > > static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) > { > - return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), > val); > + return __cpu_to_virtio32(virtio_is_little_endian(vdev), val); > } > > static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) > { > - return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), > val); > + return __virtio64_to_cpu(virtio_is_little_endian(vdev), val); > } > > static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) > { > - return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), > val); > + return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); > } > - ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH] vhost: move is_le setup to the backend
On Thu, 12 Nov 2015 15:28:19 +0100 Greg Kurz wrote: > On Thu, 12 Nov 2015 15:46:30 +0200 > "Michael S. Tsirkin" wrote: > > > On Fri, Oct 30, 2015 at 12:42:35PM +0100, Greg Kurz wrote: > > > The vq->is_le field is used to fix endianness when accessing the vring via > > > the cpu_to_vhost16() and vhost16_to_cpu() helpers in the following cases: > > > > > > 1) host is big endian and device is modern virtio > > > > > > 2) host has cross-endian support and device is legacy virtio with a > > > different > > >endianness than the host > > > > > > Both cases rely on the VHOST_SET_FEATURES ioctl, but 2) also needs the > > > VHOST_SET_VRING_ENDIAN ioctl to be called by userspace. Since vq->is_le > > > is only needed when the backend is active, it was decided to set it at > > > backend start. > > > > > > This is currently done in vhost_init_used()->vhost_init_is_le() but it > > > obfuscates the core vhost code. This patch moves the is_le setup to a > > > dedicated function that is called from the backend code. > > > > > > Note vhost_net is the only backend that can pass vq->private_data == NULL > > > to > > > vhost_init_used(), hence the "if (sock)" branch. > > > > > > No behaviour change. > > > > > > Signed-off-by: Greg Kurz > > > > I plan to look at this next week, busy with QEMU 2.5 now. > > > > I don't have any deadline for this since this is only a cleanup tentative. > > Thanks. > ... but ping anyway since it was a month ago :) Cheers. -- Greg > > > --- > > > drivers/vhost/net.c |6 ++ > > > drivers/vhost/scsi.c |3 +++ > > > drivers/vhost/test.c |2 ++ > > > drivers/vhost/vhost.c | 12 +++- > > > drivers/vhost/vhost.h |1 + > > > 5 files changed, 19 insertions(+), 5 deletions(-) > > > > > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c > > > index 9eda69e40678..d6319cb2664c 100644 > > > --- a/drivers/vhost/net.c > > > +++ b/drivers/vhost/net.c > > > @@ -917,6 +917,12 @@ static long vhost_net_set_backend(struct vhost_net > > > *n, unsigned index, int fd) > > > > > > vhost_net_disable_vq(n, vq); > > > vq->private_data = sock; > > > + > > > + if (sock) > > > + vhost_set_is_le(vq); > > > + else > > > + vq->is_le = virtio_legacy_is_little_endian(); > > > + > > > r = vhost_init_used(vq); > > > if (r) > > > goto err_used; > > > diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c > > > index e25a23692822..e2644a301fa5 100644 > > > --- a/drivers/vhost/scsi.c > > > +++ b/drivers/vhost/scsi.c > > > @@ -1276,6 +1276,9 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, > > > vq = &vs->vqs[i].vq; > > > mutex_lock(&vq->mutex); > > > vq->private_data = vs_tpg; > > > + > > > + vhost_set_is_le(vq); > > > + > > > vhost_init_used(vq); > > > mutex_unlock(&vq->mutex); > > > } > > > diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c > > > index f2882ac98726..b1c7df502211 100644 > > > --- a/drivers/vhost/test.c > > > +++ b/drivers/vhost/test.c > > > @@ -196,6 +196,8 @@ static long vhost_test_run(struct vhost_test *n, int > > > test) > > > oldpriv = vq->private_data; > > > vq->private_data = priv; > > > > > > + vhost_set_is_le(vq); > > > + > > > r = vhost_init_used(&n->vqs[index]); > > > > > > mutex_unlock(&vq->mutex); > > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > > index eec2f11809ff..6be863dcbd13 100644 > > > --- a/drivers/vhost/vhost.c > > > +++ b/drivers/vhost/vhost.c > > > @@ -113,6 +113,12 @@ static void vhost_init_is_le(struct vhost_virtqueue > > > *vq) > > > } > > > #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ > > > > > > +void vhost_set_is_le(struct vhost_virtqueue *vq) > > > +{ > > > + vhost_init_is_le(vq); > > > +} > > > +EXPORT_SYMBOL_GPL(vhost_set_is_le); > > > + >
[PATCH] vhost: move is_le setup to the backend
The vq->is_le field is used to fix endianness when accessing the vring via the cpu_to_vhost16() and vhost16_to_cpu() helpers in the following cases: 1) host is big endian and device is modern virtio 2) host has cross-endian support and device is legacy virtio with a different endianness than the host Both cases rely on the VHOST_SET_FEATURES ioctl, but 2) also needs the VHOST_SET_VRING_ENDIAN ioctl to be called by userspace. Since vq->is_le is only needed when the backend is active, it was decided to set it at backend start. This is currently done in vhost_init_used()->vhost_init_is_le() but it obfuscates the core vhost code. This patch moves the is_le setup to a dedicated function that is called from the backend code. Note vhost_net is the only backend that can pass vq->private_data == NULL to vhost_init_used(), hence the "if (sock)" branch. No behaviour change. Reviewed-by: Cornelia Huck Signed-off-by: Greg Kurz --- Hi Michael, This is a cleanup patch I had posted last year: http://patchwork.ozlabs.org/patch/538277/ I am just reposting with Cornelia's R-b. Cheers. -- Greg drivers/vhost/net.c |6 ++ drivers/vhost/scsi.c |3 +++ drivers/vhost/test.c |2 ++ drivers/vhost/vhost.c | 12 +++- drivers/vhost/vhost.h |1 + 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9eda69e40678..d6319cb2664c 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -917,6 +917,12 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) vhost_net_disable_vq(n, vq); vq->private_data = sock; + + if (sock) + vhost_set_is_le(vq); + else + vq->is_le = virtio_legacy_is_little_endian(); + r = vhost_init_used(vq); if (r) goto err_used; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 29cfc57d496e..1f4f405ebba8 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1274,6 +1274,9 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, vq = &vs->vqs[i].vq; mutex_lock(&vq->mutex); vq->private_data = vs_tpg; + + vhost_set_is_le(vq); + vhost_init_used(vq); mutex_unlock(&vq->mutex); } diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index f2882ac98726..b1c7df502211 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -196,6 +196,8 @@ static long vhost_test_run(struct vhost_test *n, int test) oldpriv = vq->private_data; vq->private_data = priv; + vhost_set_is_le(vq); + r = vhost_init_used(&n->vqs[index]); mutex_unlock(&vq->mutex); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index ad2146a9ab2d..e688eb801d43 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -113,6 +113,12 @@ static void vhost_init_is_le(struct vhost_virtqueue *vq) } #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ +void vhost_set_is_le(struct vhost_virtqueue *vq) +{ + vhost_init_is_le(vq); +} +EXPORT_SYMBOL_GPL(vhost_set_is_le); + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -1156,12 +1162,8 @@ int vhost_init_used(struct vhost_virtqueue *vq) { __virtio16 last_used_idx; int r; - if (!vq->private_data) { - vq->is_le = virtio_legacy_is_little_endian(); + if (!vq->private_data) return 0; - } - - vhost_init_is_le(vq); r = vhost_update_used_flags(vq); if (r) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index d3f767448a72..af5d33797937 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -162,6 +162,7 @@ bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *); int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, unsigned int log_num, u64 len); +void vhost_set_is_le(struct vhost_virtqueue *vq); #define vq_err(vq, fmt, ...) do { \ pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH] vhost: move is_le setup to the backend
On Tue, 12 Jan 2016 12:01:32 +0200 "Michael S. Tsirkin" wrote: > On Mon, Jan 11, 2016 at 03:39:38PM +0100, Greg Kurz wrote: > > The vq->is_le field is used to fix endianness when accessing the vring via > > the cpu_to_vhost16() and vhost16_to_cpu() helpers in the following cases: > > > > 1) host is big endian and device is modern virtio > > > > 2) host has cross-endian support and device is legacy virtio with a > > different > >endianness than the host > > > > Both cases rely on the VHOST_SET_FEATURES ioctl, but 2) also needs the > > VHOST_SET_VRING_ENDIAN ioctl to be called by userspace. Since vq->is_le > > is only needed when the backend is active, it was decided to set it at > > backend start. > > > > This is currently done in vhost_init_used()->vhost_init_is_le() but it > > obfuscates the core vhost code. This patch moves the is_le setup to a > > dedicated function that is called from the backend code. > > > > Note vhost_net is the only backend that can pass vq->private_data == NULL to > > vhost_init_used(), hence the "if (sock)" branch. > > > > No behaviour change. > > > > Reviewed-by: Cornelia Huck > > Signed-off-by: Greg Kurz > > --- > > > > Hi Michael, > > > > This is a cleanup patch I had posted last year: > > > > http://patchwork.ozlabs.org/patch/538277/ > > > > I am just reposting with Cornelia's R-b. > > > > Cheers. > > > > -- > > Greg > > > > drivers/vhost/net.c |6 ++ > > drivers/vhost/scsi.c |3 +++ > > drivers/vhost/test.c |2 ++ > > drivers/vhost/vhost.c | 12 +++- > > drivers/vhost/vhost.h |1 + > > 5 files changed, 19 insertions(+), 5 deletions(-) > > > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c > > index 9eda69e40678..d6319cb2664c 100644 > > --- a/drivers/vhost/net.c > > +++ b/drivers/vhost/net.c > > @@ -917,6 +917,12 @@ static long vhost_net_set_backend(struct vhost_net *n, > > unsigned index, int fd) > > > > vhost_net_disable_vq(n, vq); > > vq->private_data = sock; > > + > > + if (sock) > > + vhost_set_is_le(vq); > > + else > > + vq->is_le = virtio_legacy_is_little_endian(); > > + > > r = vhost_init_used(vq); > > if (r) > > goto err_used; > > This part is kind of ugly. I think it's cleaner is the generic code. > How about we teach vhost_set_is_le to test vq->private_data and DTRT? > You're right. I'll try that. > > diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c > > index 29cfc57d496e..1f4f405ebba8 100644 > > --- a/drivers/vhost/scsi.c > > +++ b/drivers/vhost/scsi.c > > @@ -1274,6 +1274,9 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, > > vq = &vs->vqs[i].vq; > > mutex_lock(&vq->mutex); > > vq->private_data = vs_tpg; > > + > > + vhost_set_is_le(vq); > > + > > vhost_init_used(vq); > > mutex_unlock(&vq->mutex); > > } > > diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c > > index f2882ac98726..b1c7df502211 100644 > > --- a/drivers/vhost/test.c > > +++ b/drivers/vhost/test.c > > @@ -196,6 +196,8 @@ static long vhost_test_run(struct vhost_test *n, int > > test) > > oldpriv = vq->private_data; > > vq->private_data = priv; > > > > + vhost_set_is_le(vq); > > + > > r = vhost_init_used(&n->vqs[index]); > > > > mutex_unlock(&vq->mutex); > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > index ad2146a9ab2d..e688eb801d43 100644 > > --- a/drivers/vhost/vhost.c > > +++ b/drivers/vhost/vhost.c > > @@ -113,6 +113,12 @@ static void vhost_init_is_le(struct vhost_virtqueue > > *vq) > > } > > #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ > > > > +void vhost_set_is_le(struct vhost_virtqueue *vq) > > +{ > > + vhost_init_is_le(vq); > > +} > > +EXPORT_SYMBOL_GPL(vhost_set_is_le); > > + > > static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, > > poll_table *pt) > > { > > Why do we need this wrapper? Why not just export vhost_init_is_le? This is a
[PATCH 1/2] vhost: helpers to enable/disable vring endianness
The default use case for vhost is when the host and the vring have the same endianness (default native endianness). But there are cases where they differ and vhost should byteswap when accessing the vring: - the host is big endian and the vring comes from a virtio 1.0 device which is always little endian - the architecture is bi-endian and the vring comes from a legacy virtio device with a different endianness than the endianness of the host (aka legacy cross-endian) These cases are handled by the vq->is_le and the optional vq->user_be, with the following logic: - if none of the fields is enabled, vhost access the vring without byteswap - if the vring is virtio 1.0 and the host is big endian, vq->is_le is enabled to enforce little endian access to the vring - if the vring is legacy cross-endian, userspace enables vq->user_be to inform vhost about the vring endianness. This endianness is then enforced for vring accesses through vq->is_le again The logic is unclear in the current code. This patch introduces helpers with explicit enable and disable semantics, for better clarity. No behaviour change. Signed-off-by: Greg Kurz --- drivers/vhost/vhost.c | 28 +++- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index ad2146a9ab2d..e02e06755ab7 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -43,11 +43,16 @@ enum { #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num]) #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY -static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +static void vhost_disable_user_be(struct vhost_virtqueue *vq) { vq->user_be = !virtio_legacy_is_little_endian(); } +static void vhost_enable_user_be(struct vhost_virtqueue *vq, bool user_be) +{ + vq->user_be = user_be; +} + static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) { struct vhost_vring_state s; @@ -62,7 +67,7 @@ static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) s.num != VHOST_VRING_BIG_ENDIAN) return -EINVAL; - vq->user_be = s.num; + vhost_enable_user_be(vq, !!s.num); return 0; } @@ -81,7 +86,7 @@ static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, return 0; } -static void vhost_init_is_le(struct vhost_virtqueue *vq) +static void vhost_enable_is_le(struct vhost_virtqueue *vq) { /* Note for legacy virtio: user_be is initialized at reset time * according to the host endianness. If userspace does not set an @@ -91,7 +96,7 @@ static void vhost_init_is_le(struct vhost_virtqueue *vq) vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; } #else -static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +static void vhost_disable_user_be(struct vhost_virtqueue *vq) { } @@ -106,13 +111,18 @@ static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, return -ENOIOCTLCMD; } -static void vhost_init_is_le(struct vhost_virtqueue *vq) +static void vhost_enable_is_le(struct vhost_virtqueue *vq) { if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) vq->is_le = true; } #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ +static void vhost_disable_is_le(struct vhost_virtqueue *vq) +{ + vq->is_le = virtio_legacy_is_little_endian(); +} + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -276,8 +286,8 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call = NULL; vq->log_ctx = NULL; vq->memory = NULL; - vq->is_le = virtio_legacy_is_little_endian(); - vhost_vq_reset_user_be(vq); + vhost_disable_is_le(vq); + vhost_disable_user_be(vq); } static int vhost_worker(void *data) @@ -1157,11 +1167,11 @@ int vhost_init_used(struct vhost_virtqueue *vq) __virtio16 last_used_idx; int r; if (!vq->private_data) { - vq->is_le = virtio_legacy_is_little_endian(); + vhost_disable_is_le(vq); return 0; } - vhost_init_is_le(vq); + vhost_enable_is_le(vq); r = vhost_update_used_flags(vq); if (r) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH 2/2] vhost: disentangle vring endianness stuff from the core code
The way vring endianness is being handled currently obfuscates the code in vhost_init_used(). This patch tries to fix that by doing the following: - move the the code that adjusts endianness to a dedicated helper - export this helper so that backends explicitely call it No behaviour change. Signed-off-by: Greg Kurz --- drivers/vhost/net.c |3 +++ drivers/vhost/scsi.c |3 +++ drivers/vhost/test.c |2 ++ drivers/vhost/vhost.c | 16 +++- drivers/vhost/vhost.h |1 + 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9eda69e40678..df01c939cd00 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -917,6 +917,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) vhost_net_disable_vq(n, vq); vq->private_data = sock; + + vhost_adjust_vring_endian(vq); + r = vhost_init_used(vq); if (r) goto err_used; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 29cfc57d496e..5a8363bfcb74 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1274,6 +1274,9 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, vq = &vs->vqs[i].vq; mutex_lock(&vq->mutex); vq->private_data = vs_tpg; + + vhost_adjust_vring_endian(vq); + vhost_init_used(vq); mutex_unlock(&vq->mutex); } diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index f2882ac98726..75e3e0e9f5a8 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -196,6 +196,8 @@ static long vhost_test_run(struct vhost_test *n, int test) oldpriv = vq->private_data; vq->private_data = priv; + vhost_adjust_vring_endian(vq); + r = vhost_init_used(&n->vqs[index]); mutex_unlock(&vq->mutex); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index e02e06755ab7..b0a00340309e 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -123,6 +123,15 @@ static void vhost_disable_is_le(struct vhost_virtqueue *vq) vq->is_le = virtio_legacy_is_little_endian(); } +void vhost_adjust_vring_endian(struct vhost_virtqueue *vq) +{ + if (!vq->private_data) + vhost_disable_is_le(vq); + else + vhost_enable_is_le(vq); +} +EXPORT_SYMBOL_GPL(vhost_adjust_vring_endian); + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -1166,12 +1175,9 @@ int vhost_init_used(struct vhost_virtqueue *vq) { __virtio16 last_used_idx; int r; - if (!vq->private_data) { - vhost_disable_is_le(vq); - return 0; - } - vhost_enable_is_le(vq); + if (!vq->private_data) + return 0; r = vhost_update_used_flags(vq); if (r) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index d3f767448a72..88d86f45f756 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -162,6 +162,7 @@ bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *); int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, unsigned int log_num, u64 len); +void vhost_adjust_vring_endian(struct vhost_virtqueue *vq); #define vq_err(vq, fmt, ...) do { \ pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \ ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
[PATCH 0/2] vhost: cross-endian code cleanup
This series is a respin of the following patch: http://patchwork.ozlabs.org/patch/565921/ Patch 1 is preliminary work: it gives better names to the helpers that are involved in cross-endian support. Patch 2 is actually a v2 of the original patch. All devices now call a helper in the generic code, which DTRT according to vq->private_data, as suggested by Michael. --- Greg Kurz (2): vhost: helpers to enable/disable vring endianness vhost: disentangle vring endianness stuff from the core code drivers/vhost/net.c |3 +++ drivers/vhost/scsi.c |3 +++ drivers/vhost/test.c |2 ++ drivers/vhost/vhost.c | 40 drivers/vhost/vhost.h |1 + 5 files changed, 37 insertions(+), 12 deletions(-) ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH 0/2] vhost: cross-endian code cleanup
On Wed, 13 Jan 2016 18:09:34 +0100 Greg Kurz wrote: > This series is a respin of the following patch: > > http://patchwork.ozlabs.org/patch/565921/ > > Patch 1 is preliminary work: it gives better names to the helpers that are > involved in cross-endian support. > > Patch 2 is actually a v2 of the original patch. All devices now call a > helper in the generic code, which DTRT according to vq->private_data, as > suggested by Michael. > Hi Michael, This is just a friendly reminder for this series, which was reviewed by Cornelia already. Thanks. -- Greg > --- > > Greg Kurz (2): > vhost: helpers to enable/disable vring endianness > vhost: disentangle vring endianness stuff from the core code > > > drivers/vhost/net.c |3 +++ > drivers/vhost/scsi.c |3 +++ > drivers/vhost/test.c |2 ++ > drivers/vhost/vhost.c | 40 > drivers/vhost/vhost.h |1 + > 5 files changed, 37 insertions(+), 12 deletions(-) > > ___ > Virtualization mailing list > Virtualization@lists.linux-foundation.org > https://lists.linuxfoundation.org/mailman/listinfo/virtualization > ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH 1/2] vhost: helpers to enable/disable vring endianness
On Wed, 10 Feb 2016 13:21:22 +0200 "Michael S. Tsirkin" wrote: > On Wed, Jan 13, 2016 at 06:09:41PM +0100, Greg Kurz wrote: > > The default use case for vhost is when the host and the vring have the > > same endianness (default native endianness). But there are cases where > > they differ and vhost should byteswap when accessing the vring: > > - the host is big endian and the vring comes from a virtio 1.0 device > > which is always little endian > > - the architecture is bi-endian and the vring comes from a legacy virtio > > device with a different endianness than the endianness of the host (aka > > legacy cross-endian) > > > > These cases are handled by the vq->is_le and the optional vq->user_be, > > with the following logic: > > - if none of the fields is enabled, vhost access the vring without byteswap > > - if the vring is virtio 1.0 and the host is big endian, vq->is_le is > > enabled to enforce little endian access to the vring > > - if the vring is legacy cross-endian, userspace enables vq->user_be > > to inform vhost about the vring endianness. This endianness is then > > enforced for vring accesses through vq->is_le again > > > > The logic is unclear in the current code. > > > > This patch introduces helpers with explicit enable and disable semantics, > > for better clarity. > > > > No behaviour change. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/vhost/vhost.c | 28 +++- > > 1 file changed, 19 insertions(+), 9 deletions(-) > > > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > index ad2146a9ab2d..e02e06755ab7 100644 > > --- a/drivers/vhost/vhost.c > > +++ b/drivers/vhost/vhost.c > > @@ -43,11 +43,16 @@ enum { > > #define vhost_avail_event(vq) ((__virtio16 __user > > *)&vq->used->ring[vq->num]) > > > > #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY > > -static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) > > +static void vhost_disable_user_be(struct vhost_virtqueue *vq) > > { > > vq->user_be = !virtio_legacy_is_little_endian(); > > } > > > > Hmm this doesn't look like an improvement to me. > What does it mean to disable big endian? Make it little endian? The default behavior for the device is native endian. The SET_VRING_ENDIAN ioctl is used to make the device big endian on little endian hosts, hence "enabling" cross-endian mode... > Existing reset seems to make sense. > ... and we "disable" cross-endian mode on reset. > > +static void vhost_enable_user_be(struct vhost_virtqueue *vq, bool user_be) > > +{ > > + vq->user_be = user_be; > > +} > > + > > And this is maybe "init_user_be"? > Anyway I don't mind changing the names to reset/init_user_be if you think it is clearer. > > static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user > > *argp) > > { > > struct vhost_vring_state s; > > @@ -62,7 +67,7 @@ static long vhost_set_vring_endian(struct vhost_virtqueue > > *vq, int __user *argp) > > s.num != VHOST_VRING_BIG_ENDIAN) > > return -EINVAL; > > > > - vq->user_be = s.num; > > + vhost_enable_user_be(vq, !!s.num); > > > > return 0; > > } > > @@ -81,7 +86,7 @@ static long vhost_get_vring_endian(struct vhost_virtqueue > > *vq, u32 idx, > > return 0; > > } > > > > -static void vhost_init_is_le(struct vhost_virtqueue *vq) > > +static void vhost_enable_is_le(struct vhost_virtqueue *vq) > > { > > /* Note for legacy virtio: user_be is initialized at reset time > > * according to the host endianness. If userspace does not set an > > Same thing really. I'd rather add "reset_is_le". > > > @@ -91,7 +96,7 @@ static void vhost_init_is_le(struct vhost_virtqueue *vq) > > vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; > > } > > #else > > -static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) > > +static void vhost_disable_user_be(struct vhost_virtqueue *vq) > > { > > } > > > > @@ -106,13 +111,18 @@ static long vhost_get_vring_endian(struct > > vhost_virtqueue *vq, u32 idx, > > return -ENOIOCTLCMD; > > } > > > > -static void vhost_init_is_le(struct vhost_virtqueue *vq) > > +static void vhost_enable_is_le(struct vhost_virtqueue *vq) > > { > > if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) > >
Re: [PATCH 2/2] vhost: disentangle vring endianness stuff from the core code
On Wed, 10 Feb 2016 13:48:09 +0200 "Michael S. Tsirkin" wrote: > On Wed, Jan 13, 2016 at 06:09:47PM +0100, Greg Kurz wrote: > > The way vring endianness is being handled currently obfuscates > > the code in vhost_init_used(). > > > > This patch tries to fix that by doing the following: > > - move the the code that adjusts endianness to a dedicated helper > > - export this helper so that backends explicitely call it > > > > No behaviour change. > > > > Signed-off-by: Greg Kurz > > --- > > drivers/vhost/net.c |3 +++ > > drivers/vhost/scsi.c |3 +++ > > drivers/vhost/test.c |2 ++ > > drivers/vhost/vhost.c | 16 +++- > > drivers/vhost/vhost.h |1 + > > 5 files changed, 20 insertions(+), 5 deletions(-) > > > > diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c > > index 9eda69e40678..df01c939cd00 100644 > > --- a/drivers/vhost/net.c > > +++ b/drivers/vhost/net.c > > @@ -917,6 +917,9 @@ static long vhost_net_set_backend(struct vhost_net *n, > > unsigned index, int fd) > > > > vhost_net_disable_vq(n, vq); > > vq->private_data = sock; > > + > > + vhost_adjust_vring_endian(vq); > > + > > r = vhost_init_used(vq); > > if (r) > > goto err_used; > > > This is in fact a bug in existing code: if vhost_init_used > fails, it preferably should not have side-effects. > It's best to update it last thing. > I'm afraid we can't because the following path needs the vring endianness: vhost_init_used()->vhost_update_used_flags()->cpu_to_vhost16() But you are right, there is a bug: we should rollback if vhost_init_used() fails. Something like below: err_used: vq->private_data = oldsock; vhost_net_enable_vq(n, vq); + vhost_adjust_vring_endian(vq); if (ubufs) vhost_net_ubuf_put_wait_and_free(ubufs); err_ubufs: > > diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c > > index 29cfc57d496e..5a8363bfcb74 100644 > > --- a/drivers/vhost/scsi.c > > +++ b/drivers/vhost/scsi.c > > @@ -1274,6 +1274,9 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, > > vq = &vs->vqs[i].vq; > > mutex_lock(&vq->mutex); > > vq->private_data = vs_tpg; > > + > > + vhost_adjust_vring_endian(vq); > > + > > vhost_init_used(vq); > > mutex_unlock(&vq->mutex); > > } > > diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c > > index f2882ac98726..75e3e0e9f5a8 100644 > > --- a/drivers/vhost/test.c > > +++ b/drivers/vhost/test.c > > @@ -196,6 +196,8 @@ static long vhost_test_run(struct vhost_test *n, int > > test) > > oldpriv = vq->private_data; > > vq->private_data = priv; > > > > + vhost_adjust_vring_endian(vq); > > + > > r = vhost_init_used(&n->vqs[index]); > > > > mutex_unlock(&vq->mutex); > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > index e02e06755ab7..b0a00340309e 100644 > > --- a/drivers/vhost/vhost.c > > +++ b/drivers/vhost/vhost.c > > @@ -123,6 +123,15 @@ static void vhost_disable_is_le(struct vhost_virtqueue > > *vq) > > vq->is_le = virtio_legacy_is_little_endian(); > > } > > > > +void vhost_adjust_vring_endian(struct vhost_virtqueue *vq) > > +{ > > + if (!vq->private_data) > > + vhost_disable_is_le(vq); > > + else > > + vhost_enable_is_le(vq); > > +} > > +EXPORT_SYMBOL_GPL(vhost_adjust_vring_endian); > > + > > static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, > > poll_table *pt) > > { > > I'd prefer "vhost_update_is_le" here. "endian" might also mean > "user_be". But see below pls. > Ok, I will rename if this patch survives the review. > > > @@ -1166,12 +1175,9 @@ int vhost_init_used(struct vhost_virtqueue *vq) > > { > > __virtio16 last_used_idx; > > int r; > > - if (!vq->private_data) { > > - vhost_disable_is_le(vq); > > - return 0; > > - } > > > > - vhost_enable_is_le(vq); > > + if (!vq->private_data) > > + return 0; > > > > r = vhost_update_used_flags(vq); > > if (r) > >
Re: [PATCH 2/2] vhost: disentangle vring endianness stuff from the core code
On Wed, 10 Feb 2016 14:23:33 +0100 Cornelia Huck wrote: > On Wed, 10 Feb 2016 14:08:43 +0100 > Greg Kurz wrote: > > > But you are right, there is a bug: we should rollback if vhost_init_used() > > fails. Something like below: > > > > err_used: > > vq->private_data = oldsock; > > vhost_net_enable_vq(n, vq); > > + vhost_adjust_vring_endian(vq); > > Shouldn't we switch back before we reenable? Or have I lost myself in > this maze here again? > I haven't spotted any path under vhost_net_enable_vq() that needs the vring endianness, but indeed it looks safer to switch back before a worker thread may be woken up. > > if (ubufs) > > vhost_net_ubuf_put_wait_and_free(ubufs); > > err_ubufs: ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Re: [PATCH 1/2] vhost: helpers to enable/disable vring endianness
On Wed, 10 Feb 2016 17:08:52 +0200 "Michael S. Tsirkin" wrote: > On Wed, Feb 10, 2016 at 01:11:34PM +0100, Greg Kurz wrote: > > On Wed, 10 Feb 2016 13:21:22 +0200 > > "Michael S. Tsirkin" wrote: > > > > > On Wed, Jan 13, 2016 at 06:09:41PM +0100, Greg Kurz wrote: > > > > The default use case for vhost is when the host and the vring have the > > > > same endianness (default native endianness). But there are cases where > > > > they differ and vhost should byteswap when accessing the vring: > > > > - the host is big endian and the vring comes from a virtio 1.0 device > > > > which is always little endian > > > > - the architecture is bi-endian and the vring comes from a legacy virtio > > > > device with a different endianness than the endianness of the host > > > > (aka > > > > legacy cross-endian) > > > > > > > > These cases are handled by the vq->is_le and the optional vq->user_be, > > > > with the following logic: > > > > - if none of the fields is enabled, vhost access the vring without > > > > byteswap > > > > - if the vring is virtio 1.0 and the host is big endian, vq->is_le is > > > > enabled to enforce little endian access to the vring > > > > - if the vring is legacy cross-endian, userspace enables vq->user_be > > > > to inform vhost about the vring endianness. This endianness is then > > > > enforced for vring accesses through vq->is_le again > > > > > > > > The logic is unclear in the current code. > > > > > > > > This patch introduces helpers with explicit enable and disable > > > > semantics, > > > > for better clarity. > > > > > > > > No behaviour change. > > > > > > > > Signed-off-by: Greg Kurz > > > > --- > > > > drivers/vhost/vhost.c | 28 +++- > > > > 1 file changed, 19 insertions(+), 9 deletions(-) > > > > > > > > diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c > > > > index ad2146a9ab2d..e02e06755ab7 100644 > > > > --- a/drivers/vhost/vhost.c > > > > +++ b/drivers/vhost/vhost.c > > > > @@ -43,11 +43,16 @@ enum { > > > > #define vhost_avail_event(vq) ((__virtio16 __user > > > > *)&vq->used->ring[vq->num]) > > > > > > > > #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY > > > > -static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) > > > > +static void vhost_disable_user_be(struct vhost_virtqueue *vq) > > > > { > > > > vq->user_be = !virtio_legacy_is_little_endian(); > > > > } > > > > > > > > > > Hmm this doesn't look like an improvement to me. > > > What does it mean to disable big endian? Make it little endian? > > > > The default behavior for the device is native endian. > > > > The SET_VRING_ENDIAN ioctl is used to make the device big endian > > on little endian hosts, hence "enabling" cross-endian mode... > > > > > Existing reset seems to make sense. > > > > > > > ... and we "disable" cross-endian mode on reset. > > OK but that's enable cross-endian. Not enable be. We could have > something like vhost_disable_user_byte_swap though each time we try, > the result makes my head hurt: "swap" is a relative thing and hard to > keep track of. > What about having something like below then ? vhost_enable_cross_endian_big() to be called on little endian hosts with big endian devices vhost_enable_cross_endian_little() to be called on big endian hosts with little endian devices vhost_disable_cross_endian() to go back to the native endian default > > > > +static void vhost_enable_user_be(struct vhost_virtqueue *vq, bool > > > > user_be) > > > > +{ > > > > + vq->user_be = user_be; > > > > +} > > > > + > > > > > > And this is maybe "init_user_be"? > > > > > > > Anyway I don't mind changing the names to reset/init_user_be if you think it > > is clearer. > > > > > > static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int > > > > __user *argp) > > > > { > > > > struct vhost_vring_state s; > > > > @@ -62,7 +67,7 @@ static long vhost_set_vring_endian(struct