[RFC PATCH 05/16] virtio_ring: split: support copy from vring
From: Xuan Zhuo
Date: Sat Apr 23 2022 - 22:41:08 EST
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