Add tun_ring_consume_batched() and tap_ring_consume_batched() to allow consuming multiple items from the respective ring buffer in a single lock acquisition. Heavily inspired by ptr_ring_consume_batched() and will be used for bulk dequeue operations (e.g. vhost-net). Co-developed-by: Tim Gebauer Signed-off-by: Tim Gebauer Co-developed by: Jon Kohler Signed-off-by: Jon Kohler Signed-off-by: Simon Schippers --- drivers/net/tap.c | 21 +++++++++++++++++++++ drivers/net/tun.c | 21 +++++++++++++++++++++ include/linux/if_tap.h | 6 ++++++ include/linux/if_tun.h | 7 +++++++ 4 files changed, 55 insertions(+) diff --git a/drivers/net/tap.c b/drivers/net/tap.c index c370a02789eb..01717c8fd284 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -816,6 +816,27 @@ static __always_unused void *tap_ring_consume(struct tap_queue *q) return ptr; } +int tap_ring_consume_batched(struct file *file, void **array, int n) +{ + struct tap_queue *q = file->private_data; + void *ptr; + int i; + + spin_lock(&q->ring.consumer_lock); + + for (i = 0; i < n; i++) { + ptr = __tap_ring_consume(q); + if (!ptr) + break; + array[i] = ptr; + } + + spin_unlock(&q->ring.consumer_lock); + + return i; +} +EXPORT_SYMBOL_GPL(tap_ring_consume_batched); + static ssize_t tap_do_read(struct tap_queue *q, struct iov_iter *to, int noblock, struct sk_buff *skb) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3b9d8d406ff5..42df185341ad 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -3816,6 +3816,27 @@ struct socket *tun_get_socket(struct file *file) } EXPORT_SYMBOL_GPL(tun_get_socket); +int tun_ring_consume_batched(struct file *file, void **array, int n) +{ + struct tun_file *tfile = file->private_data; + void *ptr; + int i; + + spin_lock(&tfile->tx_ring.consumer_lock); + + for (i = 0; i < n; i++) { + ptr = __tun_ring_consume(tfile); + if (!ptr) + break; + array[i] = ptr; + } + + spin_unlock(&tfile->tx_ring.consumer_lock); + + return i; +} +EXPORT_SYMBOL_GPL(tun_ring_consume_batched); + struct ptr_ring *tun_get_tx_ring(struct file *file) { struct tun_file *tfile; diff --git a/include/linux/if_tap.h b/include/linux/if_tap.h index 553552fa635c..cf8b90320b8d 100644 --- a/include/linux/if_tap.h +++ b/include/linux/if_tap.h @@ -11,6 +11,7 @@ struct socket; #if IS_ENABLED(CONFIG_TAP) struct socket *tap_get_socket(struct file *); struct ptr_ring *tap_get_ptr_ring(struct file *file); +int tap_ring_consume_batched(struct file *file, void **array, int n); #else #include #include @@ -22,6 +23,11 @@ static inline struct ptr_ring *tap_get_ptr_ring(struct file *f) { return ERR_PTR(-EINVAL); } +static inline int tap_ring_consume_batched(struct file *f, + void **array, int n) +{ + return 0; +} #endif /* CONFIG_TAP */ /* diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h index 80166eb62f41..444dda75a372 100644 --- a/include/linux/if_tun.h +++ b/include/linux/if_tun.h @@ -22,6 +22,7 @@ struct tun_msg_ctl { #if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) struct socket *tun_get_socket(struct file *); struct ptr_ring *tun_get_tx_ring(struct file *file); +int tun_ring_consume_batched(struct file *file, void **array, int n); static inline bool tun_is_xdp_frame(void *ptr) { @@ -55,6 +56,12 @@ static inline struct ptr_ring *tun_get_tx_ring(struct file *f) return ERR_PTR(-EINVAL); } +static inline int tun_ring_consume_batched(struct file *file, + void **array, int n) +{ + return 0; +} + static inline bool tun_is_xdp_frame(void *ptr) { return false; -- 2.43.0