On Thu, 7 Nov 2024 16:54:54 +0800, Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> wrote: > The subsequent commit needs to know whether every indirect buffer is > premapped or not. So we need to introduce an extra struct for every > indirect buffer to record this info. > > Signed-off-by: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> Hi, Jason This also needs a review. Thanks. > --- > drivers/virtio/virtio_ring.c | 60 +++++++++++++++++++++--------------- > 1 file changed, 36 insertions(+), 24 deletions(-) > > diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c > index 405d5a348795..cfe70c40f630 100644 > --- a/drivers/virtio/virtio_ring.c > +++ b/drivers/virtio/virtio_ring.c > @@ -78,7 +78,11 @@ struct vring_desc_state_split { > > struct vring_desc_state_packed { > void *data; /* Data for callback. */ > - struct vring_packed_desc *indir_desc; /* Indirect descriptor, if any. */ > + > + /* Indirect desc table and extra table, if any. These two will be > + * allocated together. So we won't stress more to the memory allocator. > + */ > + struct vring_packed_desc *indir_desc; > u16 num; /* Descriptor list length. */ > u16 last; /* The last desc state in a list. */ > }; > @@ -1238,27 +1242,12 @@ static void vring_unmap_extra_packed(const struct vring_virtqueue *vq, > } > } > > -static void vring_unmap_desc_packed(const struct vring_virtqueue *vq, > - const struct vring_packed_desc *desc) > -{ > - u16 flags; > - > - if (!vring_need_unmap_buffer(vq)) > - return; > - > - flags = le16_to_cpu(desc->flags); > - > - dma_unmap_page(vring_dma_dev(vq), > - le64_to_cpu(desc->addr), > - le32_to_cpu(desc->len), > - (flags & VRING_DESC_F_WRITE) ? > - DMA_FROM_DEVICE : DMA_TO_DEVICE); > -} > - > static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg, > gfp_t gfp) > { > + struct vring_desc_extra *extra; > struct vring_packed_desc *desc; > + int i, size; > > /* > * We require lowmem mappings for the descriptors because > @@ -1267,7 +1256,16 @@ static struct vring_packed_desc *alloc_indirect_packed(unsigned int total_sg, > */ > gfp &= ~__GFP_HIGHMEM; > > - desc = kmalloc_array(total_sg, sizeof(struct vring_packed_desc), gfp); > + size = (sizeof(*desc) + sizeof(*extra)) * total_sg; > + > + desc = kmalloc(size, gfp); > + if (!desc) > + return NULL; > + > + extra = (struct vring_desc_extra *)&desc[total_sg]; > + > + for (i = 0; i < total_sg; i++) > + extra[i].next = i + 1; > > return desc; > } > @@ -1280,6 +1278,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq, > void *data, > gfp_t gfp) > { > + struct vring_desc_extra *extra; > struct vring_packed_desc *desc; > struct scatterlist *sg; > unsigned int i, n, err_idx; > @@ -1291,6 +1290,8 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq, > if (!desc) > return -ENOMEM; > > + extra = (struct vring_desc_extra *)&desc[total_sg]; > + > if (unlikely(vq->vq.num_free < 1)) { > pr_debug("Can't add buf len 1 - avail = 0\n"); > kfree(desc); > @@ -1312,6 +1313,13 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq, > 0 : VRING_DESC_F_WRITE); > desc[i].addr = cpu_to_le64(addr); > desc[i].len = cpu_to_le32(sg->length); > + > + if (unlikely(vq->use_dma_api)) { > + extra[i].addr = addr; > + extra[i].len = sg->length; > + extra[i].flags = n < out_sgs ? 0 : VRING_DESC_F_WRITE; > + } > + > i++; > } > } > @@ -1381,7 +1389,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq, > err_idx = i; > > for (i = 0; i < err_idx; i++) > - vring_unmap_desc_packed(vq, &desc[i]); > + vring_unmap_extra_packed(vq, &extra[i]); > > free_desc: > kfree(desc); > @@ -1617,7 +1625,8 @@ static void detach_buf_packed(struct vring_virtqueue *vq, > } > > if (vq->indirect) { > - u32 len; > + struct vring_desc_extra *extra; > + u32 len, num; > > /* Free the indirect table, if any, now that it's unmapped. */ > desc = state->indir_desc; > @@ -1626,9 +1635,12 @@ static void detach_buf_packed(struct vring_virtqueue *vq, > > if (vring_need_unmap_buffer(vq)) { > len = vq->packed.desc_extra[id].len; > - for (i = 0; i < len / sizeof(struct vring_packed_desc); > - i++) > - vring_unmap_desc_packed(vq, &desc[i]); > + num = len / sizeof(struct vring_packed_desc); > + > + extra = (struct vring_desc_extra *)&desc[num]; > + > + for (i = 0; i < num; i++) > + vring_unmap_extra_packed(vq, &extra[i]); > } > kfree(desc); > state->indir_desc = NULL; > -- > 2.32.0.3.g01195cf9f >