[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220424024044.94749-6-xuanzhuo@linux.alibaba.com>
Date: Sun, 24 Apr 2022 10:40:33 +0800
From: Xuan Zhuo <xuanzhuo@...ux.alibaba.com>
To: linux-kernel@...r.kernel.org
Cc: "Michael S. Tsirkin" <mst@...hat.com>,
Jason Wang <jasowang@...hat.com>,
virtualization@...ts.linux-foundation.org
Subject: [RFC PATCH 05/16] virtio_ring: split: support copy from vring
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@...ux.alibaba.com>
---
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
Powered by blists - more mailing lists