diff options
author | Cédric Le Goater <clg@fr.ibm.com> | 2014-06-16 11:51:03 +0200 |
---|---|---|
committer | Alexey Kardashevskiy <aik@ozlabs.ru> | 2014-08-08 19:25:56 +1000 |
commit | c7aa72595211cba1b375451cafb40c8bd5341bd4 (patch) | |
tree | 392cb1995847337fee5c312b7ff7ead278b5ae95 | |
parent | 34df1ee6fbcd5fbd0ce002c55c7c32bf63d3e2c4 (diff) | |
download | powerpc-c7aa72595211cba1b375451cafb40c8bd5341bd4.tar.gz |
vhost: Byteswap virtqueue attributes
The virtqueue structure shares a few attributes with the guest OS
which need to be byteswapped when the endian order of the host is
different.
This patch uses the vq->byteswap attribute to decide whether to
byteswap or not data being accessed in the guest memory.
Signed-off-by: Cédric Le Goater <clg@fr.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
(cherry picked from commit a9a8f7a5697686356fc0c0728f59a3379cf0a212)
Signed-off-by: Scott Garfinkle <seg@us.ibm.com>
-rw-r--r-- | drivers/vhost/vhost.c | 48 |
1 files changed, 38 insertions, 10 deletions
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index a6d4fb67cf3489..34d17f38f409a8 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1068,7 +1068,7 @@ static void vring_desc_swap(struct vring_desc *desc) static int vhost_update_used_flags(struct vhost_virtqueue *vq) { void __user *used; - if (__put_user(vq->used_flags, &vq->used->flags) < 0) + if (__vq_put_user(vq, vq->used_flags, &vq->used->flags) < 0) return -EFAULT; if (unlikely(vq->log_used)) { /* Make sure the flag is seen before log. */ @@ -1086,7 +1086,7 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq) static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event) { - if (__put_user(vq->avail_idx, vhost_avail_event(vq))) + if (__vq_put_user(vq, vq->avail_idx, vhost_avail_event(vq))) return -EFAULT; if (unlikely(vq->log_used)) { void __user *used; @@ -1113,7 +1113,7 @@ int vhost_init_used(struct vhost_virtqueue *vq) if (r) return r; vq->signalled_used_valid = false; - return get_user(vq->last_used_idx, &vq->used->idx); + return vq_get_user(vq, vq->last_used_idx, &vq->used->idx); } static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len, @@ -1227,6 +1227,10 @@ static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, i, (size_t)indirect->addr + i * sizeof desc); return -EINVAL; } + + if (vq->byteswap) + vring_desc_swap(&desc); + if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) { vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n", i, (size_t)indirect->addr + i * sizeof desc); @@ -1282,7 +1286,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vq->last_avail_idx; - if (unlikely(__get_user(vq->avail_idx, &vq->avail->idx))) { + if (unlikely(__vq_get_user(vq, vq->avail_idx, &vq->avail->idx))) { vq_err(vq, "Failed to access avail idx at %p\n", &vq->avail->idx); return -EFAULT; @@ -1303,7 +1307,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ - if (unlikely(__get_user(head, + if (unlikely(__vq_get_user(vq, head, &vq->avail->ring[last_avail_idx % vq->num]))) { vq_err(vq, "Failed to read head: idx %d address %p\n", last_avail_idx, @@ -1343,6 +1347,10 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, i, vq->desc + i); return -EFAULT; } + + if (vq->byteswap) + vring_desc_swap(&desc); + if (desc.flags & VRING_DESC_F_INDIRECT) { ret = get_indirect(dev, vq, iov, iov_size, out_num, in_num, @@ -1446,6 +1454,26 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len) return 0; } +static int __copyhead_to_user(struct vhost_virtqueue *vq, + struct vring_used_elem *heads, + struct vring_used_elem __user *used, + unsigned count) +{ + int i; + + for (i = 0; i < count; i++) { + if (__vq_put_user(vq, heads[i].id, &used[i].id)) { + vq_err(vq, "Failed to write used id"); + return -EFAULT; + } + if (__vq_put_user(vq, heads[i].len, &used[i].len)) { + vq_err(vq, "Failed to write used len"); + return -EFAULT; + } + } + return 0; +} + static int __vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads, unsigned count) @@ -1456,7 +1484,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq, start = vq->last_used_idx % vq->num; used = vq->used->ring + start; - if (__copy_to_user(used, heads, count * sizeof *used)) { + if (__copyhead_to_user(vq, heads, used, count)) { vq_err(vq, "Failed to write used"); return -EFAULT; } @@ -1500,7 +1528,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads, /* Make sure buffer is written before we update index. */ smp_wmb(); - if (put_user(vq->last_used_idx, &vq->used->idx)) { + if (vq_put_user(vq, vq->last_used_idx, &vq->used->idx)) { vq_err(vq, "Failed to increment used idx"); return -EFAULT; } @@ -1530,7 +1558,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) if (!vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) { __u16 flags; - if (__get_user(flags, &vq->avail->flags)) { + if (__vq_get_user(vq, flags, &vq->avail->flags)) { vq_err(vq, "Failed to get flags"); return true; } @@ -1544,7 +1572,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) if (unlikely(!v)) return true; - if (get_user(event, vhost_used_event(vq))) { + if (vq_get_user(vq, event, vhost_used_event(vq))) { vq_err(vq, "Failed to get used event idx"); return true; } @@ -1604,7 +1632,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) /* They could have slipped one in as we were doing that: make * sure it's written, then check again. */ smp_mb(); - r = __get_user(avail_idx, &vq->avail->idx); + r = __vq_get_user(vq, avail_idx, &vq->avail->idx); if (r) { vq_err(vq, "Failed to check avail idx at %p: %d\n", &vq->avail->idx, r); |