virtio: add gfp_t parameter to add_buf
Subsystems (3)
Michael S. Tsirkin
maintainerPATCH 2/2 virtio-net: pass gfp to add_buf
In reply to Michael S. Tsirkinvirtio-net bounces buffer allocations off to
a thread if it can't allocate buffers from the atomic pool. However, if posting buffers still requires atomic buffers, this is unlikely to succeed.
Fix by passing in the proper gfp_t parameter.
--- drivers/net/virtio_net.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
drivers/net/virtio_net.c +4 -4
@@ -339,7 +339,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)skb_to_sgvec (skb, sg +1 ,0 , skb->len); - err =virtqueue_add_buf (vi->rvq, sg,0 ,2 , skb); + err =virtqueue_add_buf_gfp (vi->rvq, sg,0 ,2 , skb, gfp);if (err <0 )dev_kfree_skb (skb);
@@ -386,8 +386,8 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)/* chain first in list head */ first->private = (unsigned long )list; - err =virtqueue_add_buf (vi->rvq, sg,0 ,MAX_SKB_FRAGS +2 , - first); + err =virtqueue_add_buf_gfp (vi->rvq, sg,0 ,MAX_SKB_FRAGS +2 , + first, gfp);if (err <0 )give_pages (vi, first);
@@ -406,7 +406,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)sg_init_one (&sg,page_address (page),PAGE_SIZE ); - err =virtqueue_add_buf (vi->rvq, &sg,0 ,1 , page); + err =virtqueue_add_buf_gfp (vi->rvq, &sg,0 ,1 , page, gfp);if (err <0 )give_pages (vi, page);
Signature · 1 line
1.7.1.rc1.22.g3163
Michael S. Tsirkin
maintainercover virtio: add gfp_t parameter to add_buf
We need to allocate memory to post indirect buffers, and sometimes drivers do this from a thread context, so it helps to pass in a gfp_t parameter.
To avoid churn changing all drivers, add a new API with a _gfp prefix, and make the old call lacking gfp_t an inline wrapper.
Signature · 11 lines
MST Michael S. Tsirkin (2): virtio: add_buf_gfp virtio-net: pass gfp to add_buf drivers/net/virtio_net.c | 8 ++++---- drivers/virtio/virtio_ring.c | 20 +++++++++++--------- include/linux/virtio.h | 22 +++++++++++++++++----- 3 files changed, 32 insertions(+), 18 deletions(-)
Michael S. Tsirkin
maintainerPATCH 1/2 virtio: add_buf_gfp
Add an add_buf variant that gets gfp parameter. Use that to allocate indirect buffers.
--- drivers/virtio/virtio_ring.c | 20 +++++++++++--------- include/linux/virtio.h | 22 +++++++++++++++++----- 2 files changed, 28 insertions(+), 14 deletions(-)
drivers/virtio/virtio_ring.c +11 -9
@@ -110,13 +110,14 @@ struct vring_virtqueuestatic int vring_add_indirect (struct vring_virtqueue *vq,struct scatterlist sg[],unsigned int out, -unsigned int in) +unsigned int in, +gfp_t gfp) {struct vring_desc *desc;unsigned head;int i; - desc =kmalloc ((out + in) *sizeof (struct vring_desc ),GFP_ATOMIC ); + desc =kmalloc ((out + in) *sizeof (struct vring_desc ), gfp);if (!desc)return vq->vring.num;
@@ -155,11 +156,12 @@ static int vring_add_indirect(struct vring_virtqueue *vq,return head; } -int virtqueue_add_buf (struct virtqueue *_vq, -struct scatterlist sg[], -unsigned int out, -unsigned int in, -void *data) +int virtqueue_add_buf_gfp (struct virtqueue *_vq, +struct scatterlist sg[], +unsigned int out, +unsigned int in, +void *data, +gfp_t gfp) {struct vring_virtqueue *vq =to_vvq (_vq);unsigned int i, avail, head,uninitialized_var (prev );
@@ -171,7 +173,7 @@ int virtqueue_add_buf(struct virtqueue *_vq,/* If the host supports indirect descriptor tables, and we have multiple * buffers, then go indirect. FIXME: tune this threshold */ if (vq->indirect && (out + in) >1 && vq->num_free) { - head =vring_add_indirect (vq, sg, out, in); + head =vring_add_indirect (vq, sg, out, in, gfp);if (head != vq->vring.num) goto add_head; }
@@ -232,7 +234,7 @@ add_head:return vq->num_free ? vq->vring.num :0 ;return vq->num_free; } -EXPORT_SYMBOL_GPL (virtqueue_add_buf); +EXPORT_SYMBOL_GPL (virtqueue_add_buf_gfp);void virtqueue_kick (struct virtqueue *_vq) {
include/linux/virtio.h +17 -5
@@ -7,6 +7,7 @@#include <linux/spinlock.h> #include <linux/device.h> #include <linux/mod_devicetable.h> +#include <linux/gfp.h> /** * virtqueue - a queue to register buffers for sending or receiving.
@@ -32,6 +33,7 @@ struct virtqueue {* out_num: the number of sg readable by other side * in_num: the number of sg which are writable (after readable ones) * data: the token identifying the buffer. +* gfp: how to do memory allocations (if necessary). * Returns remaining capacity of queue (sg segments) or a negative error. * virtqueue_kick: update after add_buf * vq: the struct virtqueue
@@ -60,11 +62,21 @@ struct virtqueue {* All operations can be called in any context. */ -int virtqueue_add_buf (struct virtqueue *vq, -struct scatterlist sg[], -unsigned int out_num, -unsigned int in_num, -void *data); +int virtqueue_add_buf_gfp (struct virtqueue *vq, +struct scatterlist sg[], +unsigned int out_num, +unsigned int in_num, +void *data, +gfp_t gfp); + +static inline int virtqueue_add_buf (struct virtqueue *vq, +struct scatterlist sg[], +unsigned int out_num, +unsigned int in_num, +void *data) +{ +return virtqueue_add_buf_gfp (vq, sg, out_num, in_num, data,GFP_ATOMIC ); +}void virtqueue_kick (struct virtqueue *vq);
Signature · 1 line
1.7.1.rc1.22.g3163
Rusty Russell
AppliedRe: [PATCH 2/2] virtio-net: pass gfp to add_buf
In reply to Michael S. TsirkinQuoted 5 lines · Michael S. Tsirkin
virtio-net bounces buffer allocations off to
a thread if it can't allocate buffers from the atomic pool. However, if posting buffers still requires atomic buffers, this is unlikely to succeed.
Fix by passing in the propergfp_tparameter.
Thanks, applied with the predecessor.
Cheers,
Rusty.