From nobody Mon Sep 28 23:56:09 2026 Received: from www262.sakura.ne.jp (www262.sakura.ne.jp [202.181.97.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 13D1F3C4B92 for ; Fri, 14 Aug 2026 16:33:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=202.181.97.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786725203; cv=none; b=c6COmv96SkAVvitDmfeIG/coDEWUrh+MM0WS8WJ5s+pUgC0m3z6tCpvyiRkXCefmiLIJ6vDE8gTtp1iJ5lyzjvgpouZ0Pm7F7Umq5l5S31La4JLIZakf/DK7nGjT1hgeEn7SStwptaF2iyQ0q91pmMMKAY2xioldvOT6qEtnjI4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786725203; c=relaxed/simple; bh=mwYgLEgmac/VVQh+VJtppKeQRaNodSfNvY5lcQ8YzLk=; h=Message-ID:Date:MIME-Version:Subject:From:To:References: In-Reply-To:Content-Type; b=p03RNBs72Xw0xpUut+U7ENE8Emue7e26ZLCqa1SS5L/thwbmnDX7KMUEingdPhcXMsJDQomrc1VVqkBcWYUvyFDtOlypPBsoAsjL282bjPfQQnKryZHGFIW+m3OG0TYa7/882TMHtBS6e7z0l8KkuVgS/sqJ4iG+edqSEvKR02c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=I-love.SAKURA.ne.jp; spf=pass smtp.mailfrom=I-love.SAKURA.ne.jp; arc=none smtp.client-ip=202.181.97.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=I-love.SAKURA.ne.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=I-love.SAKURA.ne.jp Received: from www262.sakura.ne.jp (localhost [127.0.0.1]) by www262.sakura.ne.jp (8.15.2/8.15.2) with ESMTP id 67EGXH3s037922 for ; Sat, 15 Aug 2026 01:33:17 +0900 (JST) (envelope-from penguin-kernel@I-love.SAKURA.ne.jp) Received: from [192.168.1.6] (M106072072000.v4.enabler.ne.jp [106.72.72.0]) (authenticated bits=0) by www262.sakura.ne.jp (8.15.2/8.15.2) with ESMTPSA id 67EGXH1O037919 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NO) for ; Sat, 15 Aug 2026 01:33:17 +0900 (JST) (envelope-from penguin-kernel@I-love.SAKURA.ne.jp) Message-ID: <56c707e7-1fb0-43ec-b8fb-cf6f451e513e@I-love.SAKURA.ne.jp> Date: Sat, 15 Aug 2026 01:33:11 +0900 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: [RFC PATCH v2.2] net: track raw dev_put()/dev_hold() usage under CONFIG_NET_DEV_REFCNT_TRACKER=y From: Tetsuo Handa To: LKML References: <39ed6ba0-bef0-4710-9790-ab13092521b1@I-love.SAKURA.ne.jp> <591e7555-a399-4753-becb-b00df2df660d@I-love.SAKURA.ne.jp> Content-Language: en-US In-Reply-To: <591e7555-a399-4753-becb-b00df2df660d@I-love.SAKURA.ne.jp> Content-Transfer-Encoding: quoted-printable X-Virus-Status: clean X-Anti-Virus-Server: fsav405.rs.sakura.ne.jp Content-Type: text/plain; charset="utf-8" syzbot is still reporting unregister_netdevice: waiting for DEV to become free problems. There is netdevice_tracker which helps identifying culprit module, but one of barriers is that not all existing callers are using netdevice_tracker and nobody is willing to convert existing callers to use netdevice_tracker. Recently, AI system is acquiring ability to analyze imbalance of raw dev_put()/dev_hold() usage (i.e. without converting to netdevice_tracker), as long as we succeed to dump all dev_put()/dev_hold() usage [1]. This patch introduces buffer for tracking raw dev_put()/dev_hold() usage. This mechanism helped fixing 10 bugs using linux-next tree [2]. However, since remaining bugs are no longer easily reproducible in linux-next tree, I want to make this mechanism available in networking trees. Since dumping all dev_put()/dev_hold() usage of a netdev which is stuck at NETDEV_UNREGISTER event might emit 100+ call traces, it is important to reduce amount of printk() messages in order to increase likeliness of syzbot successfully capturing all dev_put()/dev_hold() usage. To reduce amount of printk() messages, several functions are explicitly marked as "noinline", and a filter function tries to reduce common part of traces. Link: https://lkml.kernel.org/r/73ed3aa5-f6e1-47b6-9e5d-428ac1f4cbf3@I-love= .SAKURA.ne.jp [1] Link: https://syzkaller.appspot.com/bug?extid=3D881d65229ca4f9ae8c84 [2] Signed-off-by: Tetsuo Handa --- Changes in v2.2: - Addressed sashiko's review comments at https://sashiko.dev/#/patchset/591e7555-a399-4753-becb-b00df2df660d%40I= -love.SAKURA.ne.jp . Changes in v2.1: - Addressed sashiko's review comments at https://sashiko.dev/#/patchset/39ed6ba0-bef0-4710-9790-ab13092521b1%40I= -love.SAKURA.ne.jp . - Dropped NETDEV_DEBUG_UNREGISTER event. - Added rcu_do_batch() as one of explicit "noinline" functions. Changes in v2: - Addressed sashiko's review comments at https://sashiko.dev/#/patchset/bd87fb25-b125-42b6-b70f-5bc5a9b6bcbd%40I= -love.SAKURA.ne.jp . include/linux/netdevice.h | 13 ++ kernel/rcu/tree.c | 4 + kernel/softirq.c | 4 + kernel/workqueue.c | 4 + net/core/dev.c | 272 ++++++++++++++++++++++++++++++++++++++ net/socket.c | 32 ++++- 6 files changed, 322 insertions(+), 7 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8840b126979f..d5bfafb540df 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2144,6 +2144,8 @@ enum netdev_reg_state { * * FIXME: cleanup struct net_device such that network protocol info * moves out. + * + * @netdev_trace_buffer_list: Linked list for debugging refcount leak. */ =20 struct net_device { @@ -2300,6 +2302,9 @@ struct net_device { #if IS_ENABLED(CONFIG_TLS_DEVICE) const struct tlsdev_ops *tlsdev_ops; #endif +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) + struct list_head netdev_trace_buffer_list; +#endif =20 unsigned int operstate; unsigned char link_mode; @@ -4466,9 +4471,16 @@ static inline bool dev_nit_active(const struct net_d= evice *dev) =20 void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev); =20 +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +void save_netdev_trace_buffer(struct net_device *dev, int delta); +#else +static inline void save_netdev_trace_buffer(struct net_device *dev, int de= lta) { } +#endif + static inline void __dev_put(struct net_device *dev) { if (dev) { + save_netdev_trace_buffer(dev, -1); #ifdef CONFIG_PCPU_DEV_REFCNT this_cpu_dec(*dev->pcpu_refcnt); #else @@ -4480,6 +4492,7 @@ static inline void __dev_put(struct net_device *dev) static inline void __dev_hold(struct net_device *dev) { if (dev) { + save_netdev_trace_buffer(dev, 1); #ifdef CONFIG_PCPU_DEV_REFCNT this_cpu_inc(*dev->pcpu_refcnt); #else diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 03a43d3d2616..fd9de47512cc 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2561,6 +2561,10 @@ static bool rcu_do_batch_check_time(long count, long= tlimit, local_clock() >=3D tlimit; } =20 +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +static noinline void rcu_do_batch(struct rcu_data *rdp); +#endif + /* * Invoke any RCU callbacks that have made it to the end of their grace * period. Throttle as specified by rdp->blimit. diff --git a/kernel/softirq.c b/kernel/softirq.c index 4425d8dce44b..c5c194bec36e 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -576,6 +576,10 @@ static inline bool lockdep_softirq_start(void) { retur= n false; } static inline void lockdep_softirq_end(bool in_hardirq) { } #endif =20 +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +static noinline void handle_softirqs(bool ksirqd); +#endif + static void handle_softirqs(bool ksirqd) { unsigned long end =3D jiffies + MAX_SOFTIRQ_TIME; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 78068ae8f28a..d761268686f2 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3203,6 +3203,10 @@ static bool manage_workers(struct worker *worker) return true; } =20 +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +static noinline void process_one_work(struct worker *worker, struct work_s= truct *work); +#endif + /** * process_one_work - process single work * @worker: self diff --git a/net/core/dev.c b/net/core/dev.c index ece6700536d9..2173fe743b56 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -11586,6 +11586,14 @@ int netdev_refcnt_read(const struct net_device *de= v) } EXPORT_SYMBOL(netdev_refcnt_read); =20 +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +static void dump_netdev_trace_buffer(const struct net_device *dev); +static void erase_netdev_trace_buffer(const struct net_device *dev); +#else +static inline void dump_netdev_trace_buffer(const struct net_device *dev) = { } +static inline void erase_netdev_trace_buffer(const struct net_device *dev)= { } +#endif + int netdev_unregister_timeout_secs __read_mostly =3D 10; =20 #define WAIT_REFS_MIN_MSECS 1 @@ -11663,6 +11671,7 @@ static struct net_device *netdev_wait_allrefs_any(s= truct list_head *list) pr_emerg("unregister_netdevice: waiting for %s to become free. Usage c= ount =3D %d\n", dev->name, netdev_refcnt_read(dev)); ref_tracker_dir_print(&dev->refcnt_tracker, 10); + dump_netdev_trace_buffer(dev); } =20 warning_time =3D jiffies; @@ -12063,6 +12072,9 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv= , const char *name, =20 dev->priv_len =3D sizeof_priv; =20 +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) + INIT_LIST_HEAD(&dev->netdev_trace_buffer_list); +#endif ref_tracker_dir_init(&dev->refcnt_tracker, 128, "netdev"); #ifdef CONFIG_PCPU_DEV_REFCNT dev->pcpu_refcnt =3D alloc_percpu(int); @@ -12162,6 +12174,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv= , const char *name, free_pcpu: #ifdef CONFIG_PCPU_DEV_REFCNT free_percpu(dev->pcpu_refcnt); + erase_netdev_trace_buffer(dev); free_dev: #endif kvfree(dev); @@ -12230,6 +12243,7 @@ void free_netdev(struct net_device *dev) free_percpu(dev->pcpu_refcnt); dev->pcpu_refcnt =3D NULL; #endif + erase_netdev_trace_buffer(dev); free_percpu(dev->core_stats); dev->core_stats =3D NULL; free_percpu(dev->xdp_bulkq); @@ -13233,6 +13247,12 @@ static struct smp_hotplug_thread backlog_threads = =3D { .setup =3D backlog_napi_setup, }; =20 +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +static void __init net_dev_refcnt_tracker_init(void); +#else +static void __init net_dev_refcnt_tracker_init(void) { }; +#endif + /* * This is called single threaded during boot, so no need * to take the rtnl semaphore. @@ -13241,6 +13261,7 @@ static int __init net_dev_init(void) { int i, rc =3D -ENOMEM; =20 + net_dev_refcnt_tracker_init(); BUG_ON(!dev_boot_phase); =20 net_dev_struct_check(); @@ -13344,3 +13365,254 @@ static int __init net_dev_init(void) } =20 subsys_initcall(net_dev_init); + +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) + +#define NETDEV_TRACE_BUFFER_SIZE 32768 +static struct netdev_trace_buffer { + struct list_head list; + atomic_t count; + int trimmed_entries; + int nr_entries; + unsigned long entries[20]; +} netdev_trace_buffer[NETDEV_TRACE_BUFFER_SIZE]; +static LIST_HEAD(netdev_trace_buffer_list); +static DEFINE_RAW_SPINLOCK(netdev_trace_buffer_lock); +static bool netdev_trace_buffer_exhausted; +static unsigned long start_of_handle_softirqs __ro_after_init; +static unsigned long end_of_handle_softirqs __ro_after_init; + +static int netdev_trace_buffer_init(void) +{ + int i; + + for (i =3D 0; i < NETDEV_TRACE_BUFFER_SIZE; i++) + list_add_tail(&netdev_trace_buffer[i].list, &netdev_trace_buffer_list); + return 0; +} +pure_initcall(netdev_trace_buffer_init); + +static int trim_netdev_trace(unsigned long *entries, int nr_entries) +{ + char buffer[KSYM_SYMBOL_LEN] =3D { }; + char *cp; + int i; + + for (i =3D 0; i < nr_entries; i++) { + sprint_symbol_no_offset(buffer, entries[i]); + cp =3D strchr(buffer, ' '); + if (cp) + *cp =3D '\0'; + if (buffer[0] =3D=3D 'p') { + if (!strcmp(buffer, "process_one_work")) + return i + 1; + } else if (buffer[0] =3D=3D 'k') { + if (!strcmp(buffer, "ksys_unshare")) + return i + 1; + } else if (buffer[0] =3D=3D 's') { + if (!strcmp(buffer, "sock_sendmsg_nosec") || + !strcmp(buffer, "sock_recvmsg_nosec")) + return i + 1; + } else if (buffer[0] =3D=3D 'r') { + if (!strcmp(buffer, "rcu_do_batch")) + return i + 1; + } else if (buffer[0] =3D=3D '_') { + if (!strcmp(buffer, "__sys_bind") || + !strcmp(buffer, "__sock_release") || + !strcmp(buffer, "__sys_bpf")) + return i + 1; + } else { + if (!strcmp(buffer, "do_sock_setsockopt")) + return i + 1; + } + } + return nr_entries; +} + +static void dump_netdev_trace_buffer(const struct net_device *dev) +{ + struct netdev_trace_buffer *ptr, *tmp; + int count, balance =3D 0, pos =3D 0; + + /* Update trimmed_entries field. Do not modify nr_entries field + * in case save_netdev_trace_buffer() is called again. + */ + list_for_each_entry_rcu(ptr, &dev->netdev_trace_buffer_list, list, + /* list elements can't go away. */ 1) { + if (ptr->trimmed_entries =3D=3D ptr->nr_entries) + ptr->trimmed_entries =3D trim_netdev_trace(ptr->entries, ptr->nr_entrie= s); + } + /* Merge duplicated entries using trimmed_entries field. */ + list_for_each_entry_rcu(ptr, &dev->netdev_trace_buffer_list, list, + /* list elements can't go away. */ 1) { + /* Skip empty entries. */ + if (!atomic_read(&ptr->count)) + continue; + tmp =3D ptr; + list_for_each_entry_continue_rcu(tmp, &dev->netdev_trace_buffer_list, li= st) { + if (ptr->trimmed_entries !=3D tmp->trimmed_entries || + memcmp(ptr->entries, tmp->entries, + ptr->trimmed_entries * sizeof(unsigned long))) + continue; + /* Skip empty entries. */ + count =3D atomic_read(&tmp->count); + if (!count) + continue; + /* Move count from non-first entry to first entry. */ + atomic_add(count, &ptr->count); + atomic_sub(count, &tmp->count); + } + /* It is safe to call cond_resched() because this function is + * called from schedulable context. + */ + cond_resched(); + } + /* Report all entries for this device. */ + list_for_each_entry_rcu(ptr, &dev->netdev_trace_buffer_list, list, + /* list elements can't go away. */ 1) { + /* Skip empty entries. */ + count =3D atomic_read(&ptr->count); + if (!count) + continue; + /* Report this entry. It is safe to call cond_resched() because + * this function is called from schedulable context. + */ + pos++; + balance +=3D count; + pr_info("Call trace for %s[%d] %+d at\n", dev->name, pos, count); + stack_trace_print(ptr->entries, ptr->trimmed_entries, 4); + cond_resched(); + } + if (!netdev_trace_buffer_exhausted) + pr_info("balance as of %s[%d] is %d\n", dev->name, pos, balance); +} + +static void erase_netdev_trace_buffer(const struct net_device *dev) +{ + struct netdev_trace_buffer *ptr; + unsigned long flags; + + /* This function is called after free_percpu(dev->pcpu_refcnt) was already + * called, which means that no more __dev_put()/__dev_hold() call can be = made. + * Therefore, no more save_netdev_trace_buffer() call will be made, and w= e can + * safely return list elements to netdev_trace_buffer_list. + */ + raw_spin_lock_irqsave(&netdev_trace_buffer_lock, flags); + while (!list_empty(&dev->netdev_trace_buffer_list)) { + ptr =3D list_first_entry(&dev->netdev_trace_buffer_list, typeof(*ptr), l= ist); + list_del(&ptr->list); + list_add_tail(&ptr->list, &netdev_trace_buffer_list); + } + raw_spin_unlock_irqrestore(&netdev_trace_buffer_lock, flags); +} + +void save_netdev_trace_buffer(struct net_device *dev, int delta) +{ + struct netdev_trace_buffer *ptr; + unsigned long entries[ARRAY_SIZE(ptr->entries)]; + int nr_entries; + unsigned long flags; + + /* This function is not NMI-safe. Give up if called from NMI context. */ + if (in_nmi()) + return; + /* Get stack traces. */ + nr_entries =3D stack_trace_save(entries, ARRAY_SIZE(ptr->entries), 1); + /* Trim traces of process context now if called from softirq context, for + * we will easily exhaust netdev_trace_buffer_list if we don't trim traces + * of process context when trying to compare with existing entries. + * + * Avoid kallsyms lookup, by using cached address resolved upon boot. + */ + if (in_softirq()) { + int i; + + for (i =3D 0; i < nr_entries; i++) { + if (entries[i] >=3D start_of_handle_softirqs && + entries[i] < end_of_handle_softirqs) { + nr_entries =3D i + 1; + break; + } + } + } + /* Compare with existing entries at best-effort basis. Since duplicated e= ntries + * created by race condition will be merged when reporting, we don't use = lock here. + */ + list_for_each_entry_rcu(ptr, &dev->netdev_trace_buffer_list, list, + /* list elements can't go away. */ 1) { + if (ptr->nr_entries =3D=3D nr_entries && + !memcmp(ptr->entries, entries, nr_entries * sizeof(unsigned long))) { + atomic_add(delta, &ptr->count); + return; + } + } + /* Add a new entry. We don't re-compare with existing entries with lock h= eld, for + * duplicated entries created by race condition will be merged when repor= ting. + * But we use raw spinlock here in case this function is called with some= other + * raw spinlock already held. + */ + raw_spin_lock_irqsave(&netdev_trace_buffer_lock, flags); + if (!list_empty(&netdev_trace_buffer_list)) { + /* Remove one entry from netdev_trace_buffer_list and initialize it. */ + ptr =3D list_first_entry(&netdev_trace_buffer_list, typeof(*ptr), list); + list_del(&ptr->list); + atomic_set(&ptr->count, delta); + ptr->nr_entries =3D nr_entries; + ptr->trimmed_entries =3D nr_entries; + memmove(ptr->entries, entries, nr_entries * sizeof(unsigned long)); + /* Append it in RCU manner, for readers are lockless. */ + list_add_tail_rcu(&ptr->list, &dev->netdev_trace_buffer_list); + } else { + netdev_trace_buffer_exhausted =3D true; + } + raw_spin_unlock_irqrestore(&netdev_trace_buffer_lock, flags); +} +EXPORT_SYMBOL(save_netdev_trace_buffer); + +struct timer_completion_struct { + struct timer_list timer; + struct completion completion; +}; + +/* Resolve address of handle_softirqs() and cache it, in order to avoid lo= oking up + * kallsyms every time. + */ +static void __init netdev_addr_resolve_func(struct timer_list *timer) +{ + unsigned long entries[40]; + int nr_entries =3D stack_trace_save(entries, ARRAY_SIZE(entries), 1); + char buffer[KSYM_SYMBOL_LEN] =3D { }; + unsigned long offset, size; + char *cp; + int i; + + for (i =3D 0; i < nr_entries; i++) { + sprint_symbol(buffer, entries[i]); + if (strncmp(buffer, "handle_softirqs", 15)) + continue; + cp =3D strchr(buffer, '+'); + if (!cp || sscanf(cp, "+%lx/%lx", &offset, &size) !=3D 2) + continue; + start_of_handle_softirqs =3D entries[i] - offset; + end_of_handle_softirqs =3D start_of_handle_softirqs + size; + break; + } + complete(&container_of(timer, struct timer_completion_struct, timer)->com= pletion); +} + +static void __init net_dev_refcnt_tracker_init(void) +{ + struct timer_completion_struct tc; + + timer_setup_on_stack(&tc.timer, netdev_addr_resolve_func, 0); + init_completion(&tc.completion); + /* Schedule a call to netdev_addr_resolve_func(). */ + mod_timer(&tc.timer, jiffies); + /* Wait for netdev_addr_resolve_func() to be called. */ + wait_for_completion(&tc.completion); + /* Wait for netdev_addr_resolve_func() to complete. */ + timer_delete_sync(&tc.timer); + timer_destroy_on_stack(&tc.timer); +} + +#endif diff --git a/net/socket.c b/net/socket.c index 63c69a0fa74e..af7e99636495 100644 --- a/net/socket.c +++ b/net/socket.c @@ -698,7 +698,11 @@ struct socket *sock_alloc(void) } EXPORT_SYMBOL(sock_alloc); =20 -static void __sock_release(struct socket *sock, struct inode *inode) +static +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +noinline +#endif +void __sock_release(struct socket *sock, struct inode *inode) { const struct proto_ops *ops =3D READ_ONCE(sock->ops); =20 @@ -770,7 +774,13 @@ static noinline void call_trace_sock_send_length(struc= t sock *sk, int ret, trace_sock_send_length(sk, ret, 0); } =20 -static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *m= sg) +static +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +noinline +#else +inline +#endif +int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) { int ret =3D INDIRECT_CALL_INET(READ_ONCE(sock->ops)->sendmsg, inet6_sendm= sg, inet_sendmsg, sock, msg, @@ -1120,8 +1130,13 @@ static noinline void call_trace_sock_recv_length(str= uct sock *sk, int ret, int f trace_sock_recv_length(sk, ret, flags); } =20 -static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *m= sg, - int flags) +static +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +noinline +#else +inline +#endif +int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, int flags) { int ret =3D INDIRECT_CALL_INET(READ_ONCE(sock->ops)->recvmsg, inet6_recvmsg, @@ -2624,9 +2639,12 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, return err < 0 ? err : 0; } =20 -static int ____sys_sendmsg(struct socket *sock, struct msghdr *msg_sys, - unsigned int flags, struct used_address *used_address, - unsigned int allowed_msghdr_flags) +static +#if defined(CONFIG_NET_DEV_REFCNT_TRACKER) && defined(CONFIG_KALLSYMS) +noinline +#endif +int ____sys_sendmsg(struct socket *sock, struct msghdr *msg_sys, unsigned = int flags, + struct used_address *used_address, unsigned int allowed_msghdr_flags) { unsigned char ctl[sizeof(struct cmsghdr) + 20] __aligned(sizeof(__kernel_size_t)); --=20 2.55.0