From f0de88303d5e7e04a1224bc7a00512b5a1c4fe7a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 May 2026 09:48:58 +0000 Subject: [PATCH 1/2] net: make is_skb_wmem() available to modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following patch will use is_skb_wmem() from fq_codel. Provide __sock_wfree() only if CONFIG_INET=y Signed-off-by: Eric Dumazet Reviewed-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20260512094859.3673997-2-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/net/sock.h | 12 +++++++++++- include/net/tcp.h | 1 - net/core/skbuff.c | 2 +- net/core/sock.c | 3 +++ net/core/sock_destructor.h | 12 ------------ net/ipv4/inet_fragment.c | 2 -- net/ipv4/tcp_output.c | 1 + 7 files changed, 16 insertions(+), 17 deletions(-) delete mode 100644 net/core/sock_destructor.h diff --git a/include/net/sock.h b/include/net/sock.h index dccd3738c368..219917959b54 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1850,8 +1850,18 @@ static inline struct sock *sk_clone_lock(const struct sock *sk, const gfp_t prio struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, gfp_t priority); -void __sock_wfree(struct sk_buff *skb); void sock_wfree(struct sk_buff *skb); +#ifdef CONFIG_INET +void __sock_wfree(struct sk_buff *skb); +void tcp_wfree(struct sk_buff *skb); +#endif +static inline bool is_skb_wmem(const struct sk_buff *skb) +{ + return skb->destructor == sock_wfree || + (IS_ENABLED(CONFIG_INET) && skb->destructor == __sock_wfree) || + (IS_ENABLED(CONFIG_INET) && skb->destructor == tcp_wfree); +} + struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size, gfp_t priority); void skb_orphan_partial(struct sk_buff *skb); diff --git a/include/net/tcp.h b/include/net/tcp.h index 3c4e6adb0dbd..5715e60c519a 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -390,7 +390,6 @@ static inline bool tcp_release_cb_cond(struct sock *sk) return false; } -void tcp_wfree(struct sk_buff *skb); void tcp_write_timer_handler(struct sock *sk); void tcp_delack_timer_handler(struct sock *sk); int tcp_ioctl(struct sock *sk, int cmd, int *karg); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index acca1365672c..419a4d2833b2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -78,6 +78,7 @@ #include #include #include +#include #include #include #include @@ -96,7 +97,6 @@ #include "devmem.h" #include "net-sysfs.h" #include "netmem_priv.h" -#include "sock_destructor.h" #ifdef CONFIG_SKB_EXTENSIONS static struct kmem_cache *skbuff_ext_cache __ro_after_init; diff --git a/net/core/sock.c b/net/core/sock.c index b37b664b6eb9..f362e3ce1efb 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2708,6 +2708,7 @@ EXPORT_SYMBOL(sock_wfree); /* This variant of sock_wfree() is used by TCP, * since it sets SOCK_USE_WRITE_QUEUE. */ +#ifdef CONFIG_INET void __sock_wfree(struct sk_buff *skb) { struct sock *sk = skb->sk; @@ -2715,6 +2716,8 @@ void __sock_wfree(struct sk_buff *skb) if (refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc)) __sk_free(sk); } +EXPORT_SYMBOL_GPL(__sock_wfree); +#endif void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) { diff --git a/net/core/sock_destructor.h b/net/core/sock_destructor.h deleted file mode 100644 index 2f396e6bfba5..000000000000 --- a/net/core/sock_destructor.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _NET_CORE_SOCK_DESTRUCTOR_H -#define _NET_CORE_SOCK_DESTRUCTOR_H -#include - -static inline bool is_skb_wmem(const struct sk_buff *skb) -{ - return skb->destructor == sock_wfree || - skb->destructor == __sock_wfree || - (IS_ENABLED(CONFIG_INET) && skb->destructor == tcp_wfree); -} -#endif diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 393770920abd..86b100694659 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -24,8 +24,6 @@ #include #include -#include "../core/sock_destructor.h" - /* Use skb->cb to track consecutive/adjacent fragments coming at * the end of the queue. Nodes in the rb-tree queue will * contain "runs" of one or more adjacent fragments. diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 75eb18a2ad4e..47647a99e324 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1415,6 +1415,7 @@ void tcp_wfree(struct sk_buff *skb) out: sk_free(sk); } +EXPORT_SYMBOL_GPL(tcp_wfree); /* Note: Called under soft irq. * We can call TCP stack right away, unless socket is owned by user. From 150061a2065192d77a4f6518b6238be81dfb8321 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 12 May 2026 09:48:59 +0000 Subject: [PATCH 2/2] net/sched: fq_codel: local packets no longer count against memory limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 95b58430abe7 ("fq_codel: add memory limitation per queue") claimed that the 32Mb default was "reasonable even for heavy duty usages." In practice, this is not the case. Packets that are associated with local sockets sk_wmem_alloc do not really need additional memory control. Signed-off-by: Eric Dumazet Reviewed-by: Toke Høiland-Jørgensen Link: https://patch.msgid.link/20260512094859.3673997-3-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/sched/sch_fq_codel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 1b1de693d4c6..71107dc52be7 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -212,7 +212,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch, q->new_flow_count++; WRITE_ONCE(flow->deficit, q->quantum); } - get_codel_cb(skb)->mem_usage = skb->truesize; + get_codel_cb(skb)->mem_usage = is_skb_wmem(skb) ? 0 : skb->truesize; q->memory_usage += get_codel_cb(skb)->mem_usage; memory_limited = q->memory_usage > q->memory_limit; qdisc_qlen_inc(sch);