[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220424024044.94749-14-xuanzhuo@linux.alibaba.com>
Date: Sun, 24 Apr 2022 10:40:41 +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 13/16] virtio_ring: packed: 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_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@...ux.alibaba.com>
---
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
Powered by blists - more mailing lists