Introduce {tun,tap}_ring_consume() helpers that wrap __ptr_ring_consume()
and wake the corresponding netdev subqueue when consuming an entry frees
space in the underlying ptr_ring.

Stopping of the netdev queue when the ptr_ring is full will be introduced
in an upcoming commit.

Co-developed-by: Tim Gebauer <[email protected]>
Signed-off-by: Tim Gebauer <[email protected]>
Signed-off-by: Simon Schippers <[email protected]>
---
 drivers/net/tap.c | 23 ++++++++++++++++++++++-
 drivers/net/tun.c | 25 +++++++++++++++++++++++--
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 1197f245e873..2442cf7ac385 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -753,6 +753,27 @@ static ssize_t tap_put_user(struct tap_queue *q,
        return ret ? ret : total;
 }
 
+static void *tap_ring_consume(struct tap_queue *q)
+{
+       struct ptr_ring *ring = &q->ring;
+       struct net_device *dev;
+       void *ptr;
+
+       spin_lock(&ring->consumer_lock);
+
+       ptr = __ptr_ring_consume(ring);
+       if (unlikely(ptr && __ptr_ring_consume_created_space(ring, 1))) {
+               rcu_read_lock();
+               dev = rcu_dereference(q->tap)->dev;
+               netif_wake_subqueue(dev, q->queue_index);
+               rcu_read_unlock();
+       }
+
+       spin_unlock(&ring->consumer_lock);
+
+       return ptr;
+}
+
 static ssize_t tap_do_read(struct tap_queue *q,
                           struct iov_iter *to,
                           int noblock, struct sk_buff *skb)
@@ -774,7 +795,7 @@ static ssize_t tap_do_read(struct tap_queue *q,
                                        TASK_INTERRUPTIBLE);
 
                /* Read frames from the queue */
-               skb = ptr_ring_consume(&q->ring);
+               skb = tap_ring_consume(q);
                if (skb)
                        break;
                if (noblock) {
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 8192740357a0..7148f9a844a4 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2113,13 +2113,34 @@ static ssize_t tun_put_user(struct tun_struct *tun,
        return total;
 }
 
+static void *tun_ring_consume(struct tun_file *tfile)
+{
+       struct ptr_ring *ring = &tfile->tx_ring;
+       struct net_device *dev;
+       void *ptr;
+
+       spin_lock(&ring->consumer_lock);
+
+       ptr = __ptr_ring_consume(ring);
+       if (unlikely(ptr && __ptr_ring_consume_created_space(ring, 1))) {
+               rcu_read_lock();
+               dev = rcu_dereference(tfile->tun)->dev;
+               netif_wake_subqueue(dev, tfile->queue_index);
+               rcu_read_unlock();
+       }
+
+       spin_unlock(&ring->consumer_lock);
+
+       return ptr;
+}
+
 static void *tun_ring_recv(struct tun_file *tfile, int noblock, int *err)
 {
        DECLARE_WAITQUEUE(wait, current);
        void *ptr = NULL;
        int error = 0;
 
-       ptr = ptr_ring_consume(&tfile->tx_ring);
+       ptr = tun_ring_consume(tfile);
        if (ptr)
                goto out;
        if (noblock) {
@@ -2131,7 +2152,7 @@ static void *tun_ring_recv(struct tun_file *tfile, int 
noblock, int *err)
 
        while (1) {
                set_current_state(TASK_INTERRUPTIBLE);
-               ptr = ptr_ring_consume(&tfile->tx_ring);
+               ptr = tun_ring_consume(tfile);
                if (ptr)
                        break;
                if (signal_pending(current)) {
-- 
2.43.0


Reply via email to