To support reusing old buffers during resize. This patch implements copying a buffer from the detached vring to the vq where the new vring is attached. This process is similar to virtqueue_add_packed(), but skips DMA. Use the function virtqueue_update_packed() provided by the previous patch to update the state of the vq. Signed-off-by: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> --- drivers/virtio/virtio_ring.c | 76 ++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 1efb47b88b40..8ca9985ffb4b 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -1654,6 +1654,82 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq, return -EIO; } +static u32 vring_copy_desc_packed(struct vring_virtqueue *vq, + u32 idx, + u16 curr, + __le16 *head_flags, + struct vring_virtqueue_packed *vring, + u32 src) +{ + u16 old_flags = vring->desc_extra[src].flags; + u16 flags = vq->packed.avail_used_flags; + struct vring_packed_desc *desc; + struct vring_desc_extra *extra; + + if (old_flags & VRING_DESC_F_NEXT) + flags |= VRING_DESC_F_NEXT; + + if (old_flags & VRING_DESC_F_WRITE) + flags |= VRING_DESC_F_WRITE; + + if (old_flags & VRING_DESC_F_INDIRECT) + flags |= VRING_DESC_F_INDIRECT; + + desc = vq->packed.vring.desc + idx; + extra = vq->packed.desc_extra + curr; + + if (head_flags) + *head_flags = cpu_to_le16(flags); + else + desc->flags = cpu_to_le16(flags); + + desc->addr = cpu_to_le64(vring->desc_extra[src].addr); + desc->len = cpu_to_le32(vring->desc_extra[src].len); + desc->id = cpu_to_le16(vq->free_head); + + extra->addr = vring->desc_extra[src].addr; + extra->len = vring->desc_extra[src].len; + extra->flags = vring->desc_extra[src].flags; + + return vq->packed.desc_extra[curr].next; +} + +static int vring_copy_to_vq_packed(struct vring_virtqueue *vq, + struct vring_virtqueue_packed *vring, + u32 old_id) +{ + struct vring_desc_state_packed *state; + __le16 head_flags; + u16 prev, curr; + u32 i, n; + + state = &vring->desc_state[old_id]; + + if (state->num > vq->vq.num_free) + return -ENOSPC; + + i = vq->packed.next_avail_idx; + curr = vq->free_head; + + for (n = 0; n < state->num; n++) { + prev = curr; + curr = vring_copy_desc_packed(vq, i, curr, + n ? NULL : &head_flags, + vring, old_id); + + old_id = vring->desc_extra[old_id].next; + + i = next_idx(vq, i); + } + + virtqueue_update_packed(vq, state->num, curr, prev, i, head_flags, + state->indir_desc, state->data); + + state->data = NULL; + + return state->num; +} + static bool virtqueue_kick_prepare_packed(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); -- 2.31.0 _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linuxfoundation.org/mailman/listinfo/virtualization