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_split(), but skips DMA. Use the function virtqueue_update_split() provided by the previous patch to update the state of the vq. Signed-off-by: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> --- drivers/virtio/virtio_ring.c | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index aa85058978cb..167442cfdb2a 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -703,6 +703,66 @@ static inline int virtqueue_add_split(struct virtqueue *_vq, return -ENOMEM; } +static u32 vring_copy_desc_split(struct vring_virtqueue *vq, u32 i, + struct vring_virtqueue_split *vring, + u32 src) +{ + struct vring_desc_extra *extra = vq->split.desc_extra; + struct vring_desc *desc = vq->split.vring.desc; + u16 next; + + desc[i].flags = vring->vring.desc[src].flags; + desc[i].addr = vring->vring.desc[src].addr; + desc[i].len = vring->vring.desc[src].len; + + next = extra[i].next; + + desc[i].next = cpu_to_virtio16(vq->vq.vdev, next); + + extra[i].addr = vring->desc_extra[src].addr; + extra[i].len = vring->desc_extra[src].len; + extra[i].flags = vring->desc_extra[src].flags; + + return next; +} + +static int vring_copy_to_vq_split(struct vring_virtqueue *vq, + struct vring_virtqueue_split *vring, + u32 old_index) +{ + __virtio16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT); + struct vring_desc_state_split *state; + u32 i, num = 1, old_idx; + + old_idx = old_index; + while (vring->vring.desc[old_idx].flags & nextflag) { + old_idx = vring->desc_extra[old_idx].next; + ++num; + } + + if (num > vq->vq.num_free) + return -ENOSPC; + + i = vq->free_head; + + old_idx = old_index; + while (vring->vring.desc[old_idx].flags & nextflag) { + i = vring_copy_desc_split(vq, i, vring, old_idx); + + old_idx = vring->desc_extra[old_idx].next; + } + + i = vring_copy_desc_split(vq, i, vring, old_idx); + + state = &vring->desc_state[old_index]; + + virtqueue_update_split(vq, num, i, state->indir_desc, state->data); + + state->data = NULL; + + return num; +} + static bool virtqueue_kick_prepare_split(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