Re: [PATCH net-next 1/5] virtio_ring: introduce virtqueue_get_buf_ctx_dma()
From: Jason Wang <jasowang@redhat.com>
Date: 2024-01-24 06:54:20
Also in:
bpf, virtualization
On Tue, Jan 16, 2024 at 3:59 PM Xuan Zhuo [off-list ref] wrote:
introduce virtqueue_get_buf_ctx_dma() to collect the dma info when get buf from virtio core for premapped mode. If the virtio queue is premapped mode, the virtio-net send buf may have many desc.
This feature is not specific to virtio-net, so we can let "for example ..."
Every desc dma address need to be unmap. So here we introduce a new helper to collect the dma address of the buffer from the virtio core.
Let's explain why we can't (or suboptimal to) depend on a driver to do this.
quoted hunk ↗ jump to hunk
Because the BAD_RING is called (that may set vq->broken), so the relative "const" of vq is removed. Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com> --- drivers/virtio/virtio_ring.c | 174 +++++++++++++++++++++++++---------- include/linux/virtio.h | 16 ++++ 2 files changed, 142 insertions(+), 48 deletions(-)diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 49299b1f9ec7..82f72428605b 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c@@ -362,6 +362,45 @@ static struct device *vring_dma_dev(const struct vring_virtqueue *vq) return vq->dma_dev; } +/* + * use_dma_api premapped -> do_unmap + * 1. false false false + * 2. true false true + * 3. true true false + * + * Only #3, we should return the DMA info to the driver.
So the code has a check for dma:
if (!dma)
return false;
For whatever the case, we need a better comment here.
So we had: use_dma_api, premapped, do_unmap and dma now. I must say
I'm totally lost in this maze. It's a strong hint the API is too
complicated and needs to be tweaked.
For example, is it legal to have do_unmap be false buf DMA is true?
Here're suggestions:
1) rename premapped to buffer_is_premapped
2) rename do_unmap to buffer_need_unmap or introduce a helper
bool vring_need_unmap_buffer()
{
return use_dma_api && !premapped;
}
3) split the getting dma info logic into an helper like vritqueue_get_dma_info()
so we can do
if (!vring_need_unmap_buffer()) {
virtqueue_get_dma_info()
return;
}
4) explain why we still need to check dma assuming we had
vring_need_unmap_buffer():
If vring_need_unmap_buffer() is true, we don't need to care about dma at all.
If vring_need_unmap_buffer() is false, we must return dma info
otherwise there's a leak?
+ * + * Return: + * true: the virtio core must unmap the desc + * false: the virtio core skip the desc unmap
Might it be better to say "It's up to the driver to unmap"?
+ */
+static bool vring_need_unmap(struct vring_virtqueue *vq,
+ struct virtio_dma_head *dma,
+ dma_addr_t addr, unsigned int length)
+{
+ if (vq->do_unmap)
+ return true;
+
+ if (!vq->premapped)
+ return false;
+
+ if (!dma)
+ return false;
So the logic here is odd.
if (!dma)
return false;
...
return false;
A strong hint to split the below getting info logic into another
helper. The root cause is the function do more than just a "yes or
no".
+
+ if (unlikely(dma->next >= dma->num)) {
+ BAD_RING(vq, "premapped vq: collect dma overflow: %pad %u\n",
+ &addr, length);
+ return false;
+ }
+
+ dma->items[dma->next].addr = addr;
+ dma->items[dma->next].length = length;
+
+ ++dma->next;
+
+ return false;
+}
+Thanks ....