Re: [PATCH] tap/tun: add stats accounting when failed to transfer data to user
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Date: 2025-07-30 16:45:51
Also in:
lkml
zhangyanjun@ wrote:
From: Yanjun Zhang <redacted> To more accurately detect packet dropped, we add the dropped packet counter with the device when kfree_skb is called because of failing to transfer data to user space. Signed-off-by: Yanjun Zhang <redacted>
Net-next is currently closed. For networking patch process, see also Documentation/process/maintainer-netdev.rst.
quoted hunk ↗ jump to hunk
--- drivers/net/tap.c | 14 +++++++++++--- drivers/net/tun.c | 9 ++++++--- 2 files changed, 17 insertions(+), 6 deletions(-)diff --git a/drivers/net/tap.c b/drivers/net/tap.c index bdf0788d8..9d288a1ad 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c@@ -759,6 +759,8 @@ static ssize_t tap_do_read(struct tap_queue *q, { DEFINE_WAIT(wait); ssize_t ret = 0; + struct tap_dev *tap; + enum skb_drop_reason drop_reason = SKB_DROP_REASON_NOT_SPECIFIED; if (!iov_iter_count(to)) { kfree_skb(skb);@@ -794,10 +796,16 @@ static ssize_t tap_do_read(struct tap_queue *q, put: if (skb) { ret = tap_put_user(q, skb, to); - if (unlikely(ret < 0)) - kfree_skb(skb); - else + if (unlikely(ret < 0)) { + kfree_skb_reason(skb, drop_reason);
kfreee_skb_reason(skb, SKB_DROP_REASON_NOT_SPECIFIED) is equivalent to kfree_skb().
quoted hunk ↗ jump to hunk
+ rcu_read_lock(); + tap = rcu_dereference(q->tap); + if (tap && tap->count_rx_dropped) + tap->count_rx_dropped(tap); + rcu_read_unlock(); + } else { consume_skb(skb); + } } return ret; }diff --git a/drivers/net/tun.c b/drivers/net/tun.c index f8c5e2fd0..eb3c68e5f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c@@ -2137,6 +2137,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, { ssize_t ret; int err; + enum skb_drop_reason drop_reason = SKB_DROP_REASON_NOT_SPECIFIED; if (!iov_iter_count(to)) { tun_ptr_free(ptr);@@ -2159,10 +2160,12 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, struct sk_buff *skb = ptr; ret = tun_put_user(tun, tfile, skb, to); - if (unlikely(ret < 0)) - kfree_skb(skb); - else + if (unlikely(ret < 0)) { + dev_core_stats_tx_dropped_inc(tun->dev);
I don't think counters need to be set in these recv syscall paths, where an error is communicated through the return vaule.
+ kfree_skb_reason(skb, drop_reason);
+ } else {
consume_skb(skb);
+ }
}
return ret;
--
2.31.1