Message ID | 1522846444-31725-8-git-send-email-wexu@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 2018年04月04日 20:54, wexu@redhat.com wrote: > From: Wei Xu <wexu@redhat.com> > > mostly as same as 1.0, copy it separately for > prototype, need a refactoring. > > Signed-off-by: Wei Xu <wexu@redhat.com> > --- > hw/virtio/virtio.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 139 insertions(+), 3 deletions(-) > > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > index def07c6..cf726f3 100644 > --- a/hw/virtio/virtio.c > +++ b/hw/virtio/virtio.c > @@ -836,9 +836,9 @@ static int virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, > return VIRTQUEUE_READ_DESC_MORE; > } > > -void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, > - unsigned int *out_bytes, > - unsigned max_in_bytes, unsigned max_out_bytes) > +static void virtqueue_get_avail_bytes_split(VirtQueue *vq, > + unsigned int *in_bytes, unsigned int *out_bytes, > + unsigned max_in_bytes, unsigned max_out_bytes) > { > VirtIODevice *vdev = vq->vdev; > unsigned int max, idx; > @@ -961,6 +961,142 @@ err: > goto done; > } > > +static void virtqueue_get_avail_bytes_packed(VirtQueue *vq, > + unsigned int *in_bytes, unsigned int *out_bytes, > + unsigned max_in_bytes, unsigned max_out_bytes) > +{ > + VirtIODevice *vdev = vq->vdev; > + unsigned int max, idx; > + unsigned int total_bufs, in_total, out_total; > + MemoryRegionCache *desc_cache; > + VRingMemoryRegionCaches *caches; > + MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; > + int64_t len = 0; > + VRingDescPacked desc; > + > + if (unlikely(!vq->packed.desc)) { > + if (in_bytes) { > + *in_bytes = 0; > + } > + if (out_bytes) { > + *out_bytes = 0; > + } > + return; > + } > + > + rcu_read_lock(); > + idx = vq->last_avail_idx; > + total_bufs = in_total = out_total = 0; > + > + max = vq->packed.num; > + caches = vring_get_region_caches(vq); > + if (caches->desc.len < max * sizeof(VRingDescPacked)) { > + virtio_error(vdev, "Cannot map descriptor ring"); > + goto err; > + } > + > + desc_cache = &caches->desc; > + vring_desc_read_packed(vdev, &desc, desc_cache, idx); > + while (is_desc_avail(&desc)) { > + unsigned int num_bufs; > + unsigned int i; > + > + num_bufs = total_bufs; > + > + if (desc.flags & VRING_DESC_F_INDIRECT) { > + if (desc.len % sizeof(VRingDescPacked)) { > + virtio_error(vdev, "Invalid size for indirect buffer table"); > + goto err; > + } > + > + /* If we've got too many, that implies a descriptor loop. */ > + if (num_bufs >= max) { > + virtio_error(vdev, "Looped descriptor"); > + goto err; > + } > + > + /* loop over the indirect descriptor table */ > + len = address_space_cache_init(&indirect_desc_cache, > + vdev->dma_as, > + desc.addr, desc.len, false); > + desc_cache = &indirect_desc_cache; > + if (len < desc.len) { > + virtio_error(vdev, "Cannot map indirect buffer"); > + goto err; > + } > + > + max = desc.len / sizeof(VRingDescPacked); > + num_bufs = i = 0; > + vring_desc_read_packed(vdev, &desc, desc_cache, i); > + } > + > + do { > + /* If we've got too many, that implies a descriptor loop. */ > + if (++num_bufs > max) { > + virtio_error(vdev, "Looped descriptor"); > + goto err; > + } > + > + if (desc.flags & VRING_DESC_F_WRITE) { > + in_total += desc.len; > + } else { > + out_total += desc.len; > + } > + if (in_total >= max_in_bytes && out_total >= max_out_bytes) { > + goto done; > + } > + > + if (desc_cache == &indirect_desc_cache) { > + vring_desc_read_packed(vdev, &desc, desc_cache, > + ++i % vq->packed.num); > + } else { > + vring_desc_read_packed(vdev, &desc, desc_cache, > + ++idx % vq->packed.num); > + } Need to make sure desc.flags was read before other fields, otherwise we may get stale address. Thanks > + } while (desc.flags & VRING_DESC_F_NEXT); > + > + if (desc_cache == &indirect_desc_cache) { > + address_space_cache_destroy(&indirect_desc_cache); > + total_bufs++; > + /* We missed one step on for indirect desc */ > + idx++; > + } else { > + total_bufs = num_bufs; > + } > + > + desc_cache = &caches->desc; > + vring_desc_read_packed(vdev, &desc, desc_cache, idx % vq->packed.num); > + } > + > +done: > + address_space_cache_destroy(&indirect_desc_cache); > + if (in_bytes) { > + *in_bytes = in_total; > + } > + if (out_bytes) { > + *out_bytes = out_total; > + } > + rcu_read_unlock(); > + return; > + > +err: > + in_total = out_total = 0; > + goto done; > +} > + > +void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, > + unsigned int *out_bytes, > + unsigned max_in_bytes, unsigned max_out_bytes) > +{ > + if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) { > + virtqueue_get_avail_bytes_packed(vq, in_bytes, out_bytes, > + max_in_bytes, max_out_bytes); > + } else { > + virtqueue_get_avail_bytes_split(vq, in_bytes, out_bytes, > + max_in_bytes, max_out_bytes); > + } > +} > + > int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, > unsigned int out_bytes) > {
On Wed, Apr 11, 2018 at 11:03:24AM +0800, Jason Wang wrote: > > > On 2018年04月04日 20:54, wexu@redhat.com wrote: > >From: Wei Xu <wexu@redhat.com> > > > >mostly as same as 1.0, copy it separately for > >prototype, need a refactoring. > > > >Signed-off-by: Wei Xu <wexu@redhat.com> > >--- > > hw/virtio/virtio.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++-- > > 1 file changed, 139 insertions(+), 3 deletions(-) > > > >diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > >index def07c6..cf726f3 100644 > >--- a/hw/virtio/virtio.c > >+++ b/hw/virtio/virtio.c > >@@ -836,9 +836,9 @@ static int virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, > > return VIRTQUEUE_READ_DESC_MORE; > > } > >-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, > >- unsigned int *out_bytes, > >- unsigned max_in_bytes, unsigned max_out_bytes) > >+static void virtqueue_get_avail_bytes_split(VirtQueue *vq, > >+ unsigned int *in_bytes, unsigned int *out_bytes, > >+ unsigned max_in_bytes, unsigned max_out_bytes) > > { > > VirtIODevice *vdev = vq->vdev; > > unsigned int max, idx; > >@@ -961,6 +961,142 @@ err: > > goto done; > > } > >+static void virtqueue_get_avail_bytes_packed(VirtQueue *vq, > >+ unsigned int *in_bytes, unsigned int *out_bytes, > >+ unsigned max_in_bytes, unsigned max_out_bytes) > >+{ > >+ VirtIODevice *vdev = vq->vdev; > >+ unsigned int max, idx; > >+ unsigned int total_bufs, in_total, out_total; > >+ MemoryRegionCache *desc_cache; > >+ VRingMemoryRegionCaches *caches; > >+ MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; > >+ int64_t len = 0; > >+ VRingDescPacked desc; > >+ > >+ if (unlikely(!vq->packed.desc)) { > >+ if (in_bytes) { > >+ *in_bytes = 0; > >+ } > >+ if (out_bytes) { > >+ *out_bytes = 0; > >+ } > >+ return; > >+ } > >+ > >+ rcu_read_lock(); > >+ idx = vq->last_avail_idx; > >+ total_bufs = in_total = out_total = 0; > >+ > >+ max = vq->packed.num; > >+ caches = vring_get_region_caches(vq); > >+ if (caches->desc.len < max * sizeof(VRingDescPacked)) { > >+ virtio_error(vdev, "Cannot map descriptor ring"); > >+ goto err; > >+ } > >+ > >+ desc_cache = &caches->desc; > >+ vring_desc_read_packed(vdev, &desc, desc_cache, idx); > >+ while (is_desc_avail(&desc)) { > >+ unsigned int num_bufs; > >+ unsigned int i; > >+ > >+ num_bufs = total_bufs; > >+ > >+ if (desc.flags & VRING_DESC_F_INDIRECT) { > >+ if (desc.len % sizeof(VRingDescPacked)) { > >+ virtio_error(vdev, "Invalid size for indirect buffer table"); > >+ goto err; > >+ } > >+ > >+ /* If we've got too many, that implies a descriptor loop. */ > >+ if (num_bufs >= max) { > >+ virtio_error(vdev, "Looped descriptor"); > >+ goto err; > >+ } > >+ > >+ /* loop over the indirect descriptor table */ > >+ len = address_space_cache_init(&indirect_desc_cache, > >+ vdev->dma_as, > >+ desc.addr, desc.len, false); > >+ desc_cache = &indirect_desc_cache; > >+ if (len < desc.len) { > >+ virtio_error(vdev, "Cannot map indirect buffer"); > >+ goto err; > >+ } > >+ > >+ max = desc.len / sizeof(VRingDescPacked); > >+ num_bufs = i = 0; > >+ vring_desc_read_packed(vdev, &desc, desc_cache, i); > >+ } > >+ > >+ do { > >+ /* If we've got too many, that implies a descriptor loop. */ > >+ if (++num_bufs > max) { > >+ virtio_error(vdev, "Looped descriptor"); > >+ goto err; > >+ } > >+ > >+ if (desc.flags & VRING_DESC_F_WRITE) { > >+ in_total += desc.len; > >+ } else { > >+ out_total += desc.len; > >+ } > >+ if (in_total >= max_in_bytes && out_total >= max_out_bytes) { > >+ goto done; > >+ } > >+ > >+ if (desc_cache == &indirect_desc_cache) { > >+ vring_desc_read_packed(vdev, &desc, desc_cache, > >+ ++i % vq->packed.num); > >+ } else { > >+ vring_desc_read_packed(vdev, &desc, desc_cache, > >+ ++idx % vq->packed.num); > >+ } > > Need to make sure desc.flags was read before other fields, otherwise we may > get stale address. OK, need a barrier here, thanks. Wei > > Thanks > > >+ } while (desc.flags & VRING_DESC_F_NEXT); > >+ > >+ if (desc_cache == &indirect_desc_cache) { > >+ address_space_cache_destroy(&indirect_desc_cache); > >+ total_bufs++; > >+ /* We missed one step on for indirect desc */ > >+ idx++; > >+ } else { > >+ total_bufs = num_bufs; > >+ } > >+ > >+ desc_cache = &caches->desc; > >+ vring_desc_read_packed(vdev, &desc, desc_cache, idx % vq->packed.num); > >+ } > >+ > >+done: > >+ address_space_cache_destroy(&indirect_desc_cache); > >+ if (in_bytes) { > >+ *in_bytes = in_total; > >+ } > >+ if (out_bytes) { > >+ *out_bytes = out_total; > >+ } > >+ rcu_read_unlock(); > >+ return; > >+ > >+err: > >+ in_total = out_total = 0; > >+ goto done; > >+} > >+ > >+void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, > >+ unsigned int *out_bytes, > >+ unsigned max_in_bytes, unsigned max_out_bytes) > >+{ > >+ if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) { > >+ virtqueue_get_avail_bytes_packed(vq, in_bytes, out_bytes, > >+ max_in_bytes, max_out_bytes); > >+ } else { > >+ virtqueue_get_avail_bytes_split(vq, in_bytes, out_bytes, > >+ max_in_bytes, max_out_bytes); > >+ } > >+} > >+ > > int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, > > unsigned int out_bytes) > > { > >
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index def07c6..cf726f3 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -836,9 +836,9 @@ static int virtqueue_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, return VIRTQUEUE_READ_DESC_MORE; } -void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, - unsigned int *out_bytes, - unsigned max_in_bytes, unsigned max_out_bytes) +static void virtqueue_get_avail_bytes_split(VirtQueue *vq, + unsigned int *in_bytes, unsigned int *out_bytes, + unsigned max_in_bytes, unsigned max_out_bytes) { VirtIODevice *vdev = vq->vdev; unsigned int max, idx; @@ -961,6 +961,142 @@ err: goto done; } +static void virtqueue_get_avail_bytes_packed(VirtQueue *vq, + unsigned int *in_bytes, unsigned int *out_bytes, + unsigned max_in_bytes, unsigned max_out_bytes) +{ + VirtIODevice *vdev = vq->vdev; + unsigned int max, idx; + unsigned int total_bufs, in_total, out_total; + MemoryRegionCache *desc_cache; + VRingMemoryRegionCaches *caches; + MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID; + int64_t len = 0; + VRingDescPacked desc; + + if (unlikely(!vq->packed.desc)) { + if (in_bytes) { + *in_bytes = 0; + } + if (out_bytes) { + *out_bytes = 0; + } + return; + } + + rcu_read_lock(); + idx = vq->last_avail_idx; + total_bufs = in_total = out_total = 0; + + max = vq->packed.num; + caches = vring_get_region_caches(vq); + if (caches->desc.len < max * sizeof(VRingDescPacked)) { + virtio_error(vdev, "Cannot map descriptor ring"); + goto err; + } + + desc_cache = &caches->desc; + vring_desc_read_packed(vdev, &desc, desc_cache, idx); + while (is_desc_avail(&desc)) { + unsigned int num_bufs; + unsigned int i; + + num_bufs = total_bufs; + + if (desc.flags & VRING_DESC_F_INDIRECT) { + if (desc.len % sizeof(VRingDescPacked)) { + virtio_error(vdev, "Invalid size for indirect buffer table"); + goto err; + } + + /* If we've got too many, that implies a descriptor loop. */ + if (num_bufs >= max) { + virtio_error(vdev, "Looped descriptor"); + goto err; + } + + /* loop over the indirect descriptor table */ + len = address_space_cache_init(&indirect_desc_cache, + vdev->dma_as, + desc.addr, desc.len, false); + desc_cache = &indirect_desc_cache; + if (len < desc.len) { + virtio_error(vdev, "Cannot map indirect buffer"); + goto err; + } + + max = desc.len / sizeof(VRingDescPacked); + num_bufs = i = 0; + vring_desc_read_packed(vdev, &desc, desc_cache, i); + } + + do { + /* If we've got too many, that implies a descriptor loop. */ + if (++num_bufs > max) { + virtio_error(vdev, "Looped descriptor"); + goto err; + } + + if (desc.flags & VRING_DESC_F_WRITE) { + in_total += desc.len; + } else { + out_total += desc.len; + } + if (in_total >= max_in_bytes && out_total >= max_out_bytes) { + goto done; + } + + if (desc_cache == &indirect_desc_cache) { + vring_desc_read_packed(vdev, &desc, desc_cache, + ++i % vq->packed.num); + } else { + vring_desc_read_packed(vdev, &desc, desc_cache, + ++idx % vq->packed.num); + } + } while (desc.flags & VRING_DESC_F_NEXT); + + if (desc_cache == &indirect_desc_cache) { + address_space_cache_destroy(&indirect_desc_cache); + total_bufs++; + /* We missed one step on for indirect desc */ + idx++; + } else { + total_bufs = num_bufs; + } + + desc_cache = &caches->desc; + vring_desc_read_packed(vdev, &desc, desc_cache, idx % vq->packed.num); + } + +done: + address_space_cache_destroy(&indirect_desc_cache); + if (in_bytes) { + *in_bytes = in_total; + } + if (out_bytes) { + *out_bytes = out_total; + } + rcu_read_unlock(); + return; + +err: + in_total = out_total = 0; + goto done; +} + +void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, + unsigned int *out_bytes, + unsigned max_in_bytes, unsigned max_out_bytes) +{ + if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) { + virtqueue_get_avail_bytes_packed(vq, in_bytes, out_bytes, + max_in_bytes, max_out_bytes); + } else { + virtqueue_get_avail_bytes_split(vq, in_bytes, out_bytes, + max_in_bytes, max_out_bytes); + } +} + int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes, unsigned int out_bytes) {