* [PATCH v2 net-next 03/14] rtnetlink: Add per-netns rtnl_work.
From: Kuniyuki Iwashima @ 2026-07-03 0:09 UTC (permalink / raw)
To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260703001009.1572444-1-kuniyu@google.com>
The biggest blocker to per-netns RTNL is netdev unregistration.
It starts within a single netns (e.g., during a device lookup or
netns dismantle), but it can eventually involve multiple namespaces,
such as when upper ipvlan devices reside in different netns.
This prevents us from acquiring multiple rtnl_net_lock()s beforehand.
When we encounter such a cross-netns device, we must delegate the
unregistration to the work of the netns where the device actually
resides.
Let's add per-netns rtnl_work to support the deferred netdev
unregistration.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
include/linux/rtnetlink.h | 8 ++++++++
include/net/net_namespace.h | 1 +
net/core/net_namespace.c | 1 +
net/core/rtnetlink.c | 26 ++++++++++++++++++++++++++
4 files changed, 36 insertions(+)
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index ea39dd23a197..95729339e7a5 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -115,6 +115,10 @@ bool rtnl_net_is_locked(struct net *net);
bool lockdep_rtnl_net_is_held(struct net *net);
+void rtnl_net_queue_work(struct net *net);
+void rtnl_net_flush_workqueue(void);
+void rtnl_net_work_func(struct work_struct *work);
+
#define rcu_dereference_rtnl_net(net, p) \
rcu_dereference_check(p, lockdep_rtnl_net_is_held(net))
#define rtnl_net_dereference(net, p) \
@@ -150,6 +154,10 @@ static inline void ASSERT_RTNL_NET(struct net *net)
ASSERT_RTNL();
}
+static inline void rtnl_net_flush_workqueue(void)
+{
+}
+
#define rcu_dereference_rtnl_net(net, p) \
rcu_dereference_rtnl(p)
#define rtnl_net_dereference(net, p) \
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 80de5e98a66d..a989019af5f7 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -197,6 +197,7 @@ struct net {
#ifdef CONFIG_DEBUG_NET_SMALL_RTNL
/* Move to a better place when the config guard is removed. */
struct mutex rtnl_mutex;
+ struct work_struct rtnl_work;
#endif
#if IS_ENABLED(CONFIG_VSOCKETS)
struct netns_vsock vsock;
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index d9dafe24f57e..d1aeff9de580 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -422,6 +422,7 @@ static __net_init int preinit_net(struct net *net, struct user_namespace *user_n
#ifdef CONFIG_DEBUG_NET_SMALL_RTNL
mutex_init(&net->rtnl_mutex);
lock_set_cmp_fn(&net->rtnl_mutex, rtnl_net_lock_cmp_fn, NULL);
+ INIT_WORK(&net->rtnl_work, rtnl_net_work_func);
#endif
INIT_LIST_HEAD(&net->ptype_all);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 7207da002fb5..7959519e7375 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -273,6 +273,26 @@ bool lockdep_rtnl_net_is_held(struct net *net)
return lockdep_rtnl_is_held() && lockdep_is_held(&net->rtnl_mutex);
}
EXPORT_SYMBOL(lockdep_rtnl_net_is_held);
+
+static struct workqueue_struct *rtnl_net_wq;
+
+void rtnl_net_queue_work(struct net *net)
+{
+ queue_work(rtnl_net_wq, &net->rtnl_work);
+}
+
+void rtnl_net_flush_workqueue(void)
+{
+ flush_workqueue(rtnl_net_wq);
+}
+
+void rtnl_net_work_func(struct work_struct *work)
+{
+ struct net *net = container_of(work, struct net, rtnl_work);
+
+ rtnl_net_lock(net);
+ rtnl_net_unlock(net);
+}
#else
static int rtnl_net_cmp_locks(const struct net *net_a, const struct net *net_b)
{
@@ -7226,4 +7246,10 @@ void __init rtnetlink_init(void)
register_netdevice_notifier(&rtnetlink_dev_notifier);
rtnl_register_many(rtnetlink_rtnl_msg_handlers);
+
+#ifdef CONFIG_DEBUG_NET_SMALL_RTNL
+ rtnl_net_wq = create_workqueue("rtnl_net");
+ if (!rtnl_net_wq)
+ panic("Could not create rtnl_net workq");
+#endif
}
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v2 net-next 02/14] rtnetlink: Call unregister_netdevice_many() only once in rtnl_link_unregister().
From: Kuniyuki Iwashima @ 2026-07-03 0:09 UTC (permalink / raw)
To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260703001009.1572444-1-kuniyu@google.com>
When rtnl_link_unregister() is called during module unload, it
calls __rtnl_kill_links() for every netns.
__rtnl_kill_links() collects all devices of the unloaded module
and passes them to unregister_netdevice_many().
Let's move unregister_netdevice_many() to rtnl_link_unregister()
to unregister all devices across netns in a single batch.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/core/rtnetlink.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index f39c93e80e20..7207da002fb5 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -637,16 +637,15 @@ int rtnl_link_register(struct rtnl_link_ops *ops)
}
EXPORT_SYMBOL_GPL(rtnl_link_register);
-static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops)
+static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops,
+ struct list_head *dev_kill_list)
{
struct net_device *dev;
- LIST_HEAD(list_kill);
for_each_netdev(net, dev) {
if (dev->rtnl_link_ops == ops)
- ops->dellink(dev, &list_kill);
+ ops->dellink(dev, dev_kill_list);
}
- unregister_netdevice_many(&list_kill);
}
/* Return with the rtnl_lock held when there are no network
@@ -677,6 +676,7 @@ static void rtnl_lock_unregistering_all(void)
*/
void rtnl_link_unregister(struct rtnl_link_ops *ops)
{
+ LIST_HEAD(dev_kill_list);
struct net *net;
mutex_lock(&link_ops_mutex);
@@ -691,7 +691,9 @@ void rtnl_link_unregister(struct rtnl_link_ops *ops)
rtnl_lock_unregistering_all();
for_each_net(net)
- __rtnl_kill_links(net, ops);
+ __rtnl_kill_links(net, ops, &dev_kill_list);
+
+ unregister_netdevice_many(&dev_kill_list);
rtnl_unlock();
up_write(&pernet_ops_rwsem);
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v2 net-next 01/14] rtnetlink: Lock sock_net(skb->sk) in rtnl_newlink().
From: Kuniyuki Iwashima @ 2026-07-03 0:09 UTC (permalink / raw)
To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260703001009.1572444-1-kuniyu@google.com>
There are a few cases where rtnl_net_lock() is not properly
held in rtnl_newlink().
When either of IFLA_NET_NS_PID / IFLA_NET_NS_FD / IFLA_TARGET_NETNSID
is specified but IFLA_LINK_NETNSID is not, sock_net(skb->sk) is used
as link_net in rtnl_newlink_link_net().
In addition, the do_setlink() path uses sock_net(skb->sk) and one
from the three netns attributes while rtnl_link_get_net_capable()
returns only one of four.
Let's add sock_net(skb->sk) to rtnl_nets in rtnl_newlink().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
No fixes tag is needed since there is no real bug nor assertion.
---
net/core/rtnetlink.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 12aa3aa1688b..f39c93e80e20 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -282,10 +282,11 @@ static int rtnl_net_cmp_locks(const struct net *net_a, const struct net *net_b)
#endif
struct rtnl_nets {
- /* ->newlink() needs to freeze 3 netns at most;
- * 2 for the new device, 1 for its peer.
+ /* ->newlink() needs to freeze 4 netns at most;
+ * 2 for the new device, 1 for its peer, 1 for
+ * an existing device (do_setlink() path).
*/
- struct net *net[3];
+ struct net *net[4];
unsigned char len;
};
@@ -4155,6 +4156,8 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
}
}
+ rtnl_nets_add(&rtnl_nets, get_net(sock_net(skb->sk)));
+
rtnl_nets_lock(&rtnl_nets);
ret = __rtnl_newlink(skb, nlh, ops, tgt_net, link_net, peer_net, tbs, data, extack);
rtnl_nets_unlock(&rtnl_nets);
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* [PATCH v2 net-next 00/14] net: Support per-netns device unregistration
From: Kuniyuki Iwashima @ 2026-07-03 0:09 UTC (permalink / raw)
To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
The biggest blocker to per-netns RTNL is netdev unregistration.
It starts within a single netns, but it can eventually involve
multiple namespaces.
There are three types of such cross-netns devices:
1. Paired devices (e.g., netkit, veth, vxcan)
-> Unregistering one device also deletes its peer, which
may reside in another netns.
2. Tunnel devices (e.g., bareudp, geneve, etc)
-> Destroying a netns removes devices in another netns if
their backend sockets reside in the dying netns
3. Stacked devices (e.g., ipvlan, macvlan, etc)
-> Removing the lower device also removes multiple upper
devices, each of which may reside in different namespaces.
While the first two device types require at most two rtnl_net_lock()s,
the stacked type has no upper limit. This makes it impossible to
freeze all necessary namespaces in advance.
This series introduces per-netns work, initially suggested at
NetConf 2024, to delegate the unregistration of such cross-netns
devices.
https://netdev.bots.linux.dev/netconf/2024/kuniyu.pdf#page=62
The first half of the series wraps NETDEV_UNREGISTER (in core) with
per-netns RTNL, adds a helper for per-netns device unregistration,
and forces per-netns device unregistration in the core code when
CONFIG_DEBUG_NET_SMALL_RTNL=y.
The latter half picks out one from each type (veth, bareudp, ipvlan)
and converts them to support per-netns device unregistration,
although the operations are **still serialised under RTNL** for now.
Please note that this series focuses only on the device unregistration
paths. For example, there are ASSERT_RTNL() left in other paths, and
Sashiko may point it out, but they are out of scope.
This is just the first step, and we need more incremental changes to
completely remove RTNL anyway.
Now, we can see that unregistering a lower device (veth0 below)
removes upper devices (ipvl2, ipvl3) in different namespaces using
per-netns work with a different PID. The lower device (veth0) is
freed only after all upper ipvlan devices have called netdev_put()
in ipvlan_uninit().
# ip netns add ns1
# ip netns add ns2
# ip netns add ns3
# ip -n ns1 link add veth0 type veth peer veth1
# ip -n ns2 link add ipvl2 link veth0 link-netns ns1 type ipvlan mode l2
# ip -n ns3 link add ipvl3 link veth0 link-netns ns1 type ipvlan mode l2
# ip -n ns1 link del veth0
# bpftrace -e '#include <linux/netdevice.h>
kprobe:ipvlan_uninit,
kprobe:veth_dellink,
kprobe:free_netdev {
$dev = (struct net_device *)arg0;
printf("PID: %d | DEV: %s%s\n", pid, $dev->name, kstack());
}'
PID: 2010 | DEV: veth0
veth_dellink+5
rtnl_dellink+1213
rtnetlink_rcv_msg+1791
...
PID: 440 | DEV: ipvl2
ipvlan_uninit+5
unregister_netdevice_many_notify+7129
unregister_netdevice_many_net+1050
rtnl_net_work_func+136
...
PID: 440 | DEV: ipvl2
free_netdev+5
netdev_run_todo+4798
process_scheduled_works+2538
...
PID: 440 | DEV: ipvl3
ipvlan_uninit+5
unregister_netdevice_many_notify+7129
unregister_netdevice_many_net+1050
rtnl_net_work_func+136
process_scheduled_works+2538
...
PID: 2010 | DEV: veth0
free_netdev+5
netdev_run_todo+4798
rtnl_dellink+1507
rtnetlink_rcv_msg+1791
...
PID: 440 | DEV: ipvl3
free_netdev+5
netdev_run_todo+4798
process_scheduled_works+2538
...
Changes:
v2:
* Patch 6
* Use spin_lock_nested() in unregister_netdevice_move_net()
* Add kdoc for dev->unreg_list_net
* Add DEBUG_NET_WARN_ON_ONCE() in unregister_netdevice_queue()
* Patch 13
* Add __ipvtap_dellink_ptr for CONFIG_IPVLAN=y and CONFIG_TAP=m
v1: https://lore.kernel.org/netdev/20260701214334.266991-1-kuniyu@google.com/
Kuniyuki Iwashima (14):
rtnetlink: Lock sock_net(skb->sk) in rtnl_newlink().
rtnetlink: Call unregister_netdevice_many() only once in
rtnl_link_unregister().
rtnetlink: Add per-netns rtnl_work.
net: Wrap default_device_exit_net() with __rtnl_net_lock().
net: Hold __rtnl_net_lock() in netdev_wait_allrefs_any().
net: Add per-netns netdev unregistration infra.
net: Call unregister_netdevice_many() per netns.
veth: Support per-netns device unregistration.
bareudp: Protect bareudp_list with mutex.
bareudp: Support per-netns netdev unregistration.
ipvlan: Convert ipvl_port.count to refcount_t.
ipvlan: Synchronise ipvlan_init() and ipvlan_uninit() for the same
lower dev.
ipvlan: Protect ipvl_port.ipvlans with mutex.
ipvlan: Support per-netns netdev unregistration.
drivers/net/bareudp.c | 43 ++++++++-
drivers/net/ipvlan/ipvlan.h | 12 ++-
drivers/net/ipvlan/ipvlan_main.c | 147 ++++++++++++++++++++++++-------
drivers/net/ipvlan/ipvtap.c | 25 +++++-
drivers/net/veth.c | 34 ++++---
include/linux/netdevice.h | 24 +++++
include/linux/rtnetlink.h | 8 ++
include/net/net_namespace.h | 3 +
net/core/dev.c | 135 +++++++++++++++++++++++++++-
net/core/net_namespace.c | 4 +
net/core/rtnetlink.c | 57 ++++++++++--
11 files changed, 429 insertions(+), 63 deletions(-)
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply
* Re: [PATCH net] qede: fix off-by-one in BD ring consumption on build_skb failure
From: Jamie Bainbridge @ 2026-07-02 23:55 UTC (permalink / raw)
To: Shigeru Yoshida
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Matvey Kovalev, Pavel Zhigulin, netdev, linux-kernel
In-Reply-To: <CAAvyFNhY2Jp5aH6YPrtfc0mBpwuSeT-8u8bODqq=pootpQffmw@mail.gmail.com>
On Fri, 3 Jul 2026 at 09:52, Jamie Bainbridge
<jamie.bainbridge@gmail.com> wrote:
>
> On Wed, 1 Jul 2026 at 02:47, Shigeru Yoshida <syoshida@redhat.com> wrote:
> >
> > qede_rx_build_skb() and qede_tpa_rx_build_skb() do not check for a
> > NULL return from qede_build_skb(). When it returns NULL under memory
> > pressure, the functions still consume a BD from the ring before
> > returning NULL. The callers then recycle additional BDs, resulting in
> > one extra BD being consumed (off-by-one). This desynchronizes the BD
> > ring, which can corrupt DMA page reference counts and lead to SLUB
> > freelist corruption.
>
> Good catch.
>
> Reviewed-by: Jamie Bainbridge <jamie.bainbridge@gmail.com>
Sorry for the double mail.
I believe the Fixes: should be against the problematic original code:
Fixes: 8a8633978b842 ("qede: Add build_skb() support.")
because that is what you are fixing.
Jamie
> > Commit 4e910dbe3650 ("qede: confirm skb is allocated before using")
> > added a NULL check inside qede_build_skb() to prevent a NULL pointer
> > dereference, but did not address the missing NULL checks in the
> > callers, making this off-by-one reachable.
> >
> > Fix this by adding NULL checks for the return value of
> > qede_build_skb() in both qede_rx_build_skb() and
> > qede_tpa_rx_build_skb(), returning NULL immediately before any BD ring
> > manipulation.
> >
> > Fixes: 4e910dbe3650 ("qede: confirm skb is allocated before using")
> > Signed-off-by: Shigeru Yoshida <syoshida@redhat.com>
> > ---
> > drivers/net/ethernet/qlogic/qede/qede_fp.c | 5 +++++
> > 1 file changed, 5 insertions(+)
> >
> > diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c
> > index 33e18bb69774..c11e0d8f98aa 100644
> > --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c
> > +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c
> > @@ -765,6 +765,9 @@ qede_tpa_rx_build_skb(struct qede_dev *edev,
> > struct sk_buff *skb;
> >
> > skb = qede_build_skb(rxq, bd, len, pad);
> > + if (unlikely(!skb))
> > + return NULL;
> > +
> > bd->page_offset += rxq->rx_buf_seg_size;
> >
> > if (bd->page_offset == PAGE_SIZE) {
> > @@ -812,6 +815,8 @@ qede_rx_build_skb(struct qede_dev *edev,
> > }
> >
> > skb = qede_build_skb(rxq, bd, len, pad);
> > + if (unlikely(!skb))
> > + return NULL;
> >
> > if (unlikely(qede_realloc_rx_buffer(rxq, bd))) {
> > /* Incr page ref count to reuse on allocation failure so
> > --
> > 2.54.0
> >
^ permalink raw reply
* Re: [PATCH net] qede: fix off-by-one in BD ring consumption on build_skb failure
From: Jamie Bainbridge @ 2026-07-02 23:52 UTC (permalink / raw)
To: Shigeru Yoshida
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Matvey Kovalev, Pavel Zhigulin, netdev, linux-kernel
In-Reply-To: <20260630164623.3152625-1-syoshida@redhat.com>
On Wed, 1 Jul 2026 at 02:47, Shigeru Yoshida <syoshida@redhat.com> wrote:
>
> qede_rx_build_skb() and qede_tpa_rx_build_skb() do not check for a
> NULL return from qede_build_skb(). When it returns NULL under memory
> pressure, the functions still consume a BD from the ring before
> returning NULL. The callers then recycle additional BDs, resulting in
> one extra BD being consumed (off-by-one). This desynchronizes the BD
> ring, which can corrupt DMA page reference counts and lead to SLUB
> freelist corruption.
Good catch.
Reviewed-by: Jamie Bainbridge <jamie.bainbridge@gmail.com>
> Commit 4e910dbe3650 ("qede: confirm skb is allocated before using")
> added a NULL check inside qede_build_skb() to prevent a NULL pointer
> dereference, but did not address the missing NULL checks in the
> callers, making this off-by-one reachable.
>
> Fix this by adding NULL checks for the return value of
> qede_build_skb() in both qede_rx_build_skb() and
> qede_tpa_rx_build_skb(), returning NULL immediately before any BD ring
> manipulation.
>
> Fixes: 4e910dbe3650 ("qede: confirm skb is allocated before using")
> Signed-off-by: Shigeru Yoshida <syoshida@redhat.com>
> ---
> drivers/net/ethernet/qlogic/qede/qede_fp.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c
> index 33e18bb69774..c11e0d8f98aa 100644
> --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c
> +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c
> @@ -765,6 +765,9 @@ qede_tpa_rx_build_skb(struct qede_dev *edev,
> struct sk_buff *skb;
>
> skb = qede_build_skb(rxq, bd, len, pad);
> + if (unlikely(!skb))
> + return NULL;
> +
> bd->page_offset += rxq->rx_buf_seg_size;
>
> if (bd->page_offset == PAGE_SIZE) {
> @@ -812,6 +815,8 @@ qede_rx_build_skb(struct qede_dev *edev,
> }
>
> skb = qede_build_skb(rxq, bd, len, pad);
> + if (unlikely(!skb))
> + return NULL;
>
> if (unlikely(qede_realloc_rx_buffer(rxq, bd))) {
> /* Incr page ref count to reuse on allocation failure so
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH RFC 0/8] clk: sunxi-ng: Add support for Allwinner A733 CCU and PRCM
From: Enzo Adriano @ 2026-07-02 23:51 UTC (permalink / raw)
To: Junhui Liu
Cc: Andre Przywara, Brian Masney, Michael Turquette, Stephen Boyd,
Chen-Yu Tsai, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Richard Cochran, linux-clk,
linux-riscv, netdev, linux-arm-kernel, linux-sunxi, devicetree,
linux-kernel, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Jernej Skrabec, Samuel Holland
In-Reply-To: <DJO79318OW0A.2RDQOAXRTHNCW@pigmoral.tech>
Hi Junhui,
Good to hear from you, and glad the series stays in your hands. I hope
the move went smoothly. No rush at all from my side, please take
whatever time you need to settle in.
For whenever you get to v2: I posted register-check notes on five of
the patches earlier today, so they are on the list to pick through at
your convenience. Take from them whatever is useful and ignore the
rest.
One offer, entirely take-it-or-leave-it: I have three Cubie A7S boards
here with serial consoles attached, and I am eager to put them to
use. I can boot v2 the day you post it and report back, if that would
save you time.
On my side I have Cubie A7S board DTS support staged to follow once
the clock and pinctrl pieces land, so whenever v2 arrives it will get
exercised on real hardware right away.
For transparency: I use AI assistance (Claude Code) for the register
comparisons and the test harness, and I check each finding against the
manual and vendor sources before posting.
Thanks,
Enzo
^ permalink raw reply
* [PATCH net] net: emac: mal: replace devm_request_irq with request_irq to fix probe error race
From: Rosen Penev @ 2026-07-02 23:50 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rosen Penev, open list
devm_request_irq() is a managed resource: the IRQ is not freed until
devres_release_all() runs after the probe function returns. In the
probe error path, free_netdev(mal->dummy_dev) and dcr_unmap() execute
while the IRQ is still live. If the shared IRQ fires during cleanup,
the handler accesses unmapped DCR registers (crash) or the already-
freed dummy_dev (use-after-free).
Switch to plain request_irq() with per-IRQ error labels that tear down
only the IRQs that were successfully registered, and add the matching
free_irq() calls in mal_remove().
Fixes: 14f59154ff0b ("net: ibm: emac: mal: use devm for request_irq")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/ethernet/ibm/emac/mal.c | 43 +++++++++++++++++++----------
1 file changed, 29 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index eab7a487bf08..5c3bf05ca6a5 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -656,26 +656,26 @@ static int mal_probe(struct platform_device *ofdev)
hdlr_rxde = mal_rxde;
}
- err = devm_request_irq(&ofdev->dev, mal->serr_irq, hdlr_serr, irqflags,
- "MAL SERR", mal);
+ err = request_irq(mal->serr_irq, hdlr_serr, irqflags,
+ "MAL SERR", mal);
if (err)
goto fail_dummy;
- err = devm_request_irq(&ofdev->dev, mal->txde_irq, hdlr_txde, irqflags,
- "MAL TX DE", mal);
+ err = request_irq(mal->txde_irq, hdlr_txde, irqflags,
+ "MAL TX DE", mal);
if (err)
- goto fail_dummy;
- err = devm_request_irq(&ofdev->dev, mal->txeob_irq, mal_txeob, 0,
- "MAL TX EOB", mal);
+ goto fail_serr_irq;
+ err = request_irq(mal->txeob_irq, mal_txeob, 0,
+ "MAL TX EOB", mal);
if (err)
- goto fail_dummy;
- err = devm_request_irq(&ofdev->dev, mal->rxde_irq, hdlr_rxde, irqflags,
- "MAL RX DE", mal);
+ goto fail_txde_irq;
+ err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags,
+ "MAL RX DE", mal);
if (err)
- goto fail_dummy;
- err = devm_request_irq(&ofdev->dev, mal->rxeob_irq, mal_rxeob, 0,
- "MAL RX EOB", mal);
+ goto fail_txeob_irq;
+ err = request_irq(mal->rxeob_irq, mal_rxeob, 0,
+ "MAL RX EOB", mal);
if (err)
- goto fail_dummy;
+ goto fail_rxde_irq;
/* Enable all MAL SERR interrupt sources */
set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS);
@@ -694,6 +694,14 @@ static int mal_probe(struct platform_device *ofdev)
return 0;
+ fail_rxde_irq:
+ free_irq(mal->rxde_irq, mal);
+ fail_txeob_irq:
+ free_irq(mal->txeob_irq, mal);
+ fail_txde_irq:
+ free_irq(mal->txde_irq, mal);
+ fail_serr_irq:
+ free_irq(mal->serr_irq, mal);
fail_dummy:
free_netdev(mal->dummy_dev);
fail_unmap:
@@ -718,6 +726,13 @@ static void mal_remove(struct platform_device *ofdev)
mal_reset(mal);
+ /* Free IRQs before freeing resources they access */
+ free_irq(mal->serr_irq, mal);
+ free_irq(mal->txde_irq, mal);
+ free_irq(mal->txeob_irq, mal);
+ free_irq(mal->rxde_irq, mal);
+ free_irq(mal->rxeob_irq, mal);
+
free_netdev(mal->dummy_dev);
dcr_unmap(mal->dcr_host, 0x100);
--
2.55.0
^ permalink raw reply related
* [PATCH] net: emac: mal: replace devm_request_irq with request_irq to fix probe error race
From: Rosen Penev @ 2026-07-02 23:50 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rosen Penev, open list
devm_request_irq() is a managed resource: the IRQ is not freed until
devres_release_all() runs after the probe function returns. In the
probe error path, free_netdev(mal->dummy_dev) and dcr_unmap() execute
while the IRQ is still live. If the shared IRQ fires during cleanup,
the handler accesses unmapped DCR registers (crash) or the already-
freed dummy_dev (use-after-free).
Switch to plain request_irq() with per-IRQ error labels that tear down
only the IRQs that were successfully registered, and add the matching
free_irq() calls in mal_remove().
Fixes: 14f59154ff0b ("net: ibm: emac: mal: use devm for request_irq")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/ethernet/ibm/emac/mal.c | 43 +++++++++++++++++++----------
1 file changed, 29 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index eab7a487bf08..5c3bf05ca6a5 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -656,26 +656,26 @@ static int mal_probe(struct platform_device *ofdev)
hdlr_rxde = mal_rxde;
}
- err = devm_request_irq(&ofdev->dev, mal->serr_irq, hdlr_serr, irqflags,
- "MAL SERR", mal);
+ err = request_irq(mal->serr_irq, hdlr_serr, irqflags,
+ "MAL SERR", mal);
if (err)
goto fail_dummy;
- err = devm_request_irq(&ofdev->dev, mal->txde_irq, hdlr_txde, irqflags,
- "MAL TX DE", mal);
+ err = request_irq(mal->txde_irq, hdlr_txde, irqflags,
+ "MAL TX DE", mal);
if (err)
- goto fail_dummy;
- err = devm_request_irq(&ofdev->dev, mal->txeob_irq, mal_txeob, 0,
- "MAL TX EOB", mal);
+ goto fail_serr_irq;
+ err = request_irq(mal->txeob_irq, mal_txeob, 0,
+ "MAL TX EOB", mal);
if (err)
- goto fail_dummy;
- err = devm_request_irq(&ofdev->dev, mal->rxde_irq, hdlr_rxde, irqflags,
- "MAL RX DE", mal);
+ goto fail_txde_irq;
+ err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags,
+ "MAL RX DE", mal);
if (err)
- goto fail_dummy;
- err = devm_request_irq(&ofdev->dev, mal->rxeob_irq, mal_rxeob, 0,
- "MAL RX EOB", mal);
+ goto fail_txeob_irq;
+ err = request_irq(mal->rxeob_irq, mal_rxeob, 0,
+ "MAL RX EOB", mal);
if (err)
- goto fail_dummy;
+ goto fail_rxde_irq;
/* Enable all MAL SERR interrupt sources */
set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS);
@@ -694,6 +694,14 @@ static int mal_probe(struct platform_device *ofdev)
return 0;
+ fail_rxde_irq:
+ free_irq(mal->rxde_irq, mal);
+ fail_txeob_irq:
+ free_irq(mal->txeob_irq, mal);
+ fail_txde_irq:
+ free_irq(mal->txde_irq, mal);
+ fail_serr_irq:
+ free_irq(mal->serr_irq, mal);
fail_dummy:
free_netdev(mal->dummy_dev);
fail_unmap:
@@ -718,6 +726,13 @@ static void mal_remove(struct platform_device *ofdev)
mal_reset(mal);
+ /* Free IRQs before freeing resources they access */
+ free_irq(mal->serr_irq, mal);
+ free_irq(mal->txde_irq, mal);
+ free_irq(mal->txeob_irq, mal);
+ free_irq(mal->rxde_irq, mal);
+ free_irq(mal->rxeob_irq, mal);
+
free_netdev(mal->dummy_dev);
dcr_unmap(mal->dcr_host, 0x100);
--
2.55.0
^ permalink raw reply related
* [PATCH net] net: emac: mal: fix W1C write race in ICINTSTAT clearing
From: Rosen Penev @ 2026-07-02 23:49 UTC (permalink / raw)
To: netdev
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Jeff Garzik, David Gibson, open list
The ICINTSTAT register is write-1-to-clear (W1C). The read-modify-write
pattern in both mal_txeob() and mal_rxeob() can lose interrupts: if a bit
that should not be cleared is already asserted when mfdcri() reads the
register, it is included in the read value, retained by the bitwise OR, and
then written back as 1 - inadvertently clearing a pending but unhandled
interrupt.
Fix by writing only the specific bit to clear (ICINTSTAT_ICTX for TXEOB,
ICINTSTAT_ICRX for RXEOB). W1C semantics guarantee that writing 0 to the
other bits has no effect.
Fixes: 1d3bb996481e ("Device tree aware EMAC driver")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/ethernet/ibm/emac/mal.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index 4025bc36ae16..eab7a487bf08 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -282,8 +282,7 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance)
#ifdef CONFIG_PPC_DCR_NATIVE
if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))
- mtdcri(SDR0, DCRN_SDR_ICINTSTAT,
- (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICTX));
+ mtdcri(SDR0, DCRN_SDR_ICINTSTAT, ICINTSTAT_ICTX);
#endif
return IRQ_HANDLED;
@@ -302,8 +301,7 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance)
#ifdef CONFIG_PPC_DCR_NATIVE
if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))
- mtdcri(SDR0, DCRN_SDR_ICINTSTAT,
- (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICRX));
+ mtdcri(SDR0, DCRN_SDR_ICINTSTAT, ICINTSTAT_ICRX);
#endif
return IRQ_HANDLED;
--
2.55.0
^ permalink raw reply related
* Re: [PATCH net] af_unix: fix listen() succeeding on sockets in the wrong state
From: Kuniyuki Iwashima @ 2026-07-02 23:17 UTC (permalink / raw)
To: John Ericson
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
John Ericson, Simon Horman, Christian Brauner, David Rheinsberg,
Cong Wang, Sergei Zimmerman, netdev, linux-kernel
In-Reply-To: <20260702202018.2280336-1-John.Ericson@Obsidian.Systems>
On Thu, Jul 2, 2026 at 1:20 PM John Ericson
<John.Ericson@obsidian.systems> wrote:
>
> From: John Ericson <mail@johnericson.me>
>
> Commit fd0a109a0f6b ("net, pidfs: prepare for handing out pidfds for
> reaped sk->sk_peer_pid") inserted a `prepare_peercred()` call between
> `err = -EINVAL` and the socket-state check in `unix_listen()`. Since
> `prepare_peercred()` leaves `err` at 0 on success, `listen()` on an
> AF_UNIX socket that is not in `TCP_CLOSE` or `TCP_LISTEN` state (e.g.
> one that is already connected) now silently returns success without
> doing anything, instead of failing with `EINVAL` as it did before.
>
> To fix this bug, and avoid such bugs in the future, switch to a style
> where `err = -E...;` instead happens right before the `goto`. (`err =
> other_function(...);` is not changed.) Then there is no spooky-action-
> at-a-distance between the `err` initialization and the `goto`, something
> which is easier to slip by code review.
>
> Fixes: fd0a109a0f6b ("net, pidfs: prepare for handing out pidfds for reaped sk->sk_peer_pid")
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: John Ericson <mail@johnericson.me>
> ---
> net/unix/af_unix.c | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index f7a9d55eee8a..7878b27bbaf8 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -813,18 +813,22 @@ static int unix_listen(struct socket *sock, int backlog)
> struct unix_sock *u = unix_sk(sk);
> struct unix_peercred peercred = {};
>
> - err = -EOPNOTSUPP;
> - if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET)
> + if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) {
> + err = -EOPNOTSUPP;
> goto out; /* Only stream/seqpacket sockets accept */
> - err = -EINVAL;
> - if (!READ_ONCE(u->addr))
> + }
> + if (!READ_ONCE(u->addr)) {
> + err = -EINVAL;
> goto out; /* No listens on an unbound socket */
> + }
> err = prepare_peercred(&peercred);
> if (err)
> goto out;
> unix_state_lock(sk);
> - if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN)
> + if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) {
> + err = -EINVAL;
Could you keep this part only for net.git and follow up on the
cleanup part in net-next later ?
> goto out_unlock;
> + }
> if (backlog > sk->sk_max_ack_backlog)
> wake_up_interruptible_all(&u->peer_wait);
> sk->sk_max_ack_backlog = backlog;
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH] net: phy: marvell: Add soft reset for 88E1510
From: Andrew Lunn @ 2026-07-02 23:04 UTC (permalink / raw)
To: Ben Brown
Cc: hkallweit1, linux, davem, edumazet, kuba, pabeni, linux-kernel,
netdev, chris.packham
In-Reply-To: <20260702225034.1062457-1-ben.brown@alliedtelesis.co.nz>
On Fri, Jul 03, 2026 at 10:50:34AM +1200, Ben Brown wrote:
> When bringing down then up the link on a 88e1512 phy a link is not
> getting established. This is because the phy is coming out of reset then
> immediately getting configured. During configuration the page is
> unsuccessfully updated causing writes to the wrong registers.
>
> Add the soft reset function that does a reset then polling read waiting
> for the phy to come back online, at which stage the page register can be
> updated successfully.
>
> This was tested on a 88E1512 phy, using ip link to bring up/down the
> link.
What makes the 88E1512 special that it needs this, but no other
Marvell PHY does?
Andrew
^ permalink raw reply
* Re: [REGRESSION][BISECTED] tun/tap & vhost-net: multi-threaded network performance
From: Michael S. Tsirkin @ 2026-07-02 22:55 UTC (permalink / raw)
To: Brett Sheffield
Cc: Simon Schippers, regressions, netdev, Jakub Kicinski, Tim Gebauer,
Willem de Bruijn, Jason Wang, Andrew Lunn, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-kernel
In-Reply-To: <akZGg96-Xu9VeGrw@karahi.librecast.net>
On Thu, Jul 02, 2026 at 01:07:47PM +0200, Brett Sheffield wrote:
> On 2026-07-02 09:24, Simon Schippers wrote:
> > On 7/1/26 22:56, Michael S. Tsirkin wrote:
> > > On Wed, Jul 01, 2026 at 09:16:48PM +0200, Brett Sheffield wrote:
> > >> TL;DR - Commit 1d6e569b7d0c0b2736636749e4be0a27f3cefcb3 causes
> > >> significant performance regressions with TAP interfaces and multithreaded
> > >> network code. Please revert.
> > >>
> > >>
> > >> Librecast is an IPv6 multicast library. One of the tests (0055) fails under
> > >> Linux 7.2-rc1. The test performs data synchronization over IPv6 multicast using a TAP
> > >> interface. This test has run successfully on every stable, LTS and mainline RC
> > >> released in the past year. Every kernel with my Tested-by has run this test.
> > >>
> > >> There have been a bunch of changes to MLDv2 so I started bisecting there, but
> > >> the culprit is actually 1d6e569b7d0c0b2736636749e4be0a27f3cefcb3 "tun/tap &
> > >> vhost-net: avoid ptr_ring tail-drop when a qdisc is present"
> > >>
> > >> Reverting this commit fixes the test.
> > >>
> > >> To eliminate my code and any multicast weirdness, I ran tests with iperf3
> > >> comparing the same host running 7.2-rc1 both with and without 1d6e569b7d0
> > >> reverted.
> >
> > Thank you very much for your bisect!
> >
> > As the author, I am sorry for that regression!
>
> No worries. That's why we test :-)
>
> > > - does it help to increase the tun queue size?
> >
> > I agree, this would be great to know.
> >
> > However, even then we must act. I am considering IFF_BACKPRESSURE
> > as a feature flag, defaulting to off. It would just enable/disable
> > the stopping logic in tun_net_xmit() and the waking logic
> > in __tun_wake_queue(). If disabled, it would result in the same logic
> > as before.
> >
> > I could provide such a patch as [net] material.
>
> I'm going to make myself a strong cup of tea and dig into it a bit more here and
> will let you know if I find anything worth reporting.
>
> If you need me to try re-testing with specific settings or test a patch I'm
> happy to do so.
>
> Cheers,
>
>
> Brett
> --
> Brett Sheffield (he/him)
> Librecast - Decentralising the Internet with Multicast
> https://librecast.net/
> https://blog.brettsheffield.com/
Maybe it's the supposedly rare case? Does this change anything
for you?
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index bfa49fa9e3a1..bacd89460078 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1018,7 +1018,6 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
struct netdev_queue *queue;
struct tun_file *tfile;
int len = skb->len;
- int ret;
rcu_read_lock();
tfile = rcu_dereference(tun->tfiles[txq]);
@@ -1064,19 +1063,24 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
goto drop;
}
- skb_tx_timestamp(skb);
-
- /* Orphan the skb - required as we might hang on to it
- * for indefinite time.
- */
- skb_orphan(skb);
-
- nf_reset_ct(skb);
-
queue = netdev_get_tx_queue(dev, txq);
spin_lock(&tfile->tx_ring.producer_lock);
- ret = __ptr_ring_produce(&tfile->tx_ring, skb);
+ if (__ptr_ring_check_produce(&tfile->tx_ring)) {
+ spin_unlock(&tfile->tx_ring.producer_lock);
+ netif_tx_stop_queue(queue);
+ smp_mb__after_atomic();
+ if (!__ptr_ring_check_produce(&tfile->tx_ring))
+ netif_tx_wake_queue(queue);
+ rcu_read_unlock();
+ return NETDEV_TX_BUSY;
+ }
+
+ skb_tx_timestamp(skb);
+ skb_orphan(skb);
+ nf_reset_ct(skb);
+
+ __ptr_ring_produce(&tfile->tx_ring, skb);
if (!qdisc_txq_has_no_queue(queue) &&
__ptr_ring_check_produce(&tfile->tx_ring) == -ENOSPC) {
netif_tx_stop_queue(queue);
@@ -1087,18 +1091,6 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_unlock(&tfile->tx_ring.producer_lock);
- if (ret) {
- /* This should be a rare case if a qdisc is present, but
- * can happen due to lltx.
- * Since skb_tx_timestamp(), skb_orphan(),
- * run_ebpf_filter() and pskb_trim() could have tinkered
- * with the SKB, returning NETDEV_TX_BUSY is unsafe and
- * we must drop instead.
- */
- drop_reason = SKB_DROP_REASON_FULL_RING;
- goto drop;
- }
-
/* dev->lltx requires to do our own update of trans_start */
txq_trans_cond_update(queue);
^ permalink raw reply related
* [PATCH] net: phy: marvell: Add soft reset for 88E1510
From: Ben Brown @ 2026-07-02 22:50 UTC (permalink / raw)
To: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni
Cc: linux-kernel, netdev, chris.packham, Ben Brown
When bringing down then up the link on a 88e1512 phy a link is not
getting established. This is because the phy is coming out of reset then
immediately getting configured. During configuration the page is
unsuccessfully updated causing writes to the wrong registers.
Add the soft reset function that does a reset then polling read waiting
for the phy to come back online, at which stage the page register can be
updated successfully.
This was tested on a 88E1512 phy, using ip link to bring up/down the
link.
Signed-off-by: Ben Brown <ben.brown@alliedtelesis.co.nz>
---
drivers/net/phy/marvell.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 7a578b5aa2ed..1ae75141408a 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -3922,6 +3922,7 @@ static struct phy_driver marvell_drivers[] = {
.features = PHY_GBIT_FIBRE_FEATURES,
.flags = PHY_POLL_CABLE_TEST,
.probe = marvell_probe,
+ .soft_reset = genphy_soft_reset,
.config_init = m88e1510_config_init,
.config_aneg = m88e1510_config_aneg,
.read_status = marvell_read_status,
--
2.54.0
^ permalink raw reply related
* [PATCH bpf] bpf: reject mini-sockets in bpf_sock_destroy()
From: Xiang Mei (Microsoft) @ 2026-07-02 22:45 UTC (permalink / raw)
To: ast, daniel, andrii, eddyz87, memxor, bpf
Cc: netdev, martin.lau, song, yonghong.song, jolsa, emil,
john.fastabend, sdf, aditi.ghag, AutonomousCodeSecurity,
tgopinath, kys, linux-kernel, Xiang Mei (Microsoft)
bpf_sock_destroy() casts its struct sock_common * argument to a full
struct sock and reads sk->sk_protocol. The BPF tcp iterator can pass a
TIME_WAIT or NEW_SYN_RECV mini-socket, which only embeds a sock_common
prefix. Unlike sk_prot (which aliases skc_prot inside sock_common),
sk_protocol lives beyond that prefix, so the read goes out of bounds of
the small tw_sock_TCP object (type confusion).
Reject non-full sockets with sk_fullsock() before touching any
full-sock field. sk_fullsock() only reads sk_state (in sock_common),
and these mini-sockets have no ->diag_destroy(), This matches the other
sock_common consumers in this file, e.g. bpf_skc_to_tcp_sock(), which
already sk_fullsock() before reading sk_protocol.
BUG: KASAN: slab-out-of-bounds in bpf_sock_destroy (net/core/filter.c:12673)
Read of size 2 at addr ffff888013ffc71c by task exploit/143
Call Trace:
kasan_report (mm/kasan/report.c:595)
bpf_sock_destroy (net/core/filter.c:12673)
bpf_prog_8b5bd55c189cabc9_sock_destroy_tw+0x31/0x3e
bpf_iter_run_prog (kernel/bpf/bpf_iter.c:697)
bpf_iter_tcp_seq_show (net/ipv4/tcp_ipv4.c:3247)
bpf_seq_read (kernel/bpf/bpf_iter.c:184)
vfs_read (fs/read_write.c:572)
ksys_read (fs/read_write.c:716)
do_syscall_64 (arch/x86/entry/syscall_64.c:94)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
...
The buggy address belongs to the object at ffff888013ffc640
which belongs to the cache tw_sock_TCP of size 256
The buggy address is located 220 bytes inside of
allocated 256-byte region [ffff888013ffc640, ffff888013ffc740)
Fixes: 4ddbcb886268 ("bpf: Add bpf_sock_destroy kfunc")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
---
net/core/filter.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/core/filter.c b/net/core/filter.c
index 69ec1a4c0f9d..a0fcafb08b96 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -12665,6 +12665,9 @@ __bpf_kfunc int bpf_sock_destroy(struct sock_common *sock)
{
struct sock *sk = (struct sock *)sock;
+ if (!sk_fullsock(sk))
+ return -EOPNOTSUPP;
+
/* The locking semantics that allow for synchronous execution of the
* destroy handlers are only supported for TCP and UDP.
* Supporting protocols will need to acquire sock lock in the BPF context
--
2.43.0
^ permalink raw reply related
* Re: [REGRESSION][BISECTED] tun/tap & vhost-net: multi-threaded network performance
From: Michael S. Tsirkin @ 2026-07-02 22:44 UTC (permalink / raw)
To: Brett Sheffield
Cc: Simon Schippers, regressions, netdev, Jakub Kicinski, Tim Gebauer,
Willem de Bruijn, Jason Wang, Andrew Lunn, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-kernel
In-Reply-To: <akZGg96-Xu9VeGrw@karahi.librecast.net>
On Thu, Jul 02, 2026 at 01:07:47PM +0200, Brett Sheffield wrote:
> On 2026-07-02 09:24, Simon Schippers wrote:
> > On 7/1/26 22:56, Michael S. Tsirkin wrote:
> > > On Wed, Jul 01, 2026 at 09:16:48PM +0200, Brett Sheffield wrote:
> > >> TL;DR - Commit 1d6e569b7d0c0b2736636749e4be0a27f3cefcb3 causes
> > >> significant performance regressions with TAP interfaces and multithreaded
> > >> network code. Please revert.
> > >>
> > >>
> > >> Librecast is an IPv6 multicast library. One of the tests (0055) fails under
> > >> Linux 7.2-rc1. The test performs data synchronization over IPv6 multicast using a TAP
> > >> interface. This test has run successfully on every stable, LTS and mainline RC
> > >> released in the past year. Every kernel with my Tested-by has run this test.
> > >>
> > >> There have been a bunch of changes to MLDv2 so I started bisecting there, but
> > >> the culprit is actually 1d6e569b7d0c0b2736636749e4be0a27f3cefcb3 "tun/tap &
> > >> vhost-net: avoid ptr_ring tail-drop when a qdisc is present"
> > >>
> > >> Reverting this commit fixes the test.
> > >>
> > >> To eliminate my code and any multicast weirdness, I ran tests with iperf3
> > >> comparing the same host running 7.2-rc1 both with and without 1d6e569b7d0
> > >> reverted.
> >
> > Thank you very much for your bisect!
> >
> > As the author, I am sorry for that regression!
>
> No worries. That's why we test :-)
>
> > > - does it help to increase the tun queue size?
> >
> > I agree, this would be great to know.
> >
> > However, even then we must act. I am considering IFF_BACKPRESSURE
> > as a feature flag, defaulting to off. It would just enable/disable
> > the stopping logic in tun_net_xmit() and the waking logic
> > in __tun_wake_queue(). If disabled, it would result in the same logic
> > as before.
> >
> > I could provide such a patch as [net] material.
>
> I'm going to make myself a strong cup of tea and dig into it a bit more here and
> will let you know if I find anything worth reporting.
>
> If you need me to try re-testing with specific settings or test a patch I'm
> happy to do so.
>
> Cheers,
>
>
> Brett
> --
> Brett Sheffield (he/him)
> Librecast - Decentralising the Internet with Multicast
> https://librecast.net/
> https://blog.brettsheffield.com/
Well, the issue was with host to guest right?
Then testing what does bql do might be interesting.
Might help.
Something like this? Lightly tested.
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index bfa49fa9e3a1..abc46354c107 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1076,6 +1076,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
queue = netdev_get_tx_queue(dev, txq);
spin_lock(&tfile->tx_ring.producer_lock);
+ netdev_tx_sent_queue(queue, len);
ret = __ptr_ring_produce(&tfile->tx_ring, skb);
if (!qdisc_txq_has_no_queue(queue) &&
__ptr_ring_check_produce(&tfile->tx_ring) == -ENOSPC) {
@@ -1088,6 +1089,7 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&tfile->tx_ring.producer_lock);
if (ret) {
+ netdev_tx_completed_queue(queue, 1, len);
/* This should be a rare case if a qdisc is present, but
* can happen due to lltx.
* Since skb_tx_timestamp(), skb_orphan(),
@@ -2148,15 +2150,19 @@ static ssize_t tun_put_user(struct tun_struct *tun,
/* Callers must hold ring.consumer_lock */
static void __tun_wake_queue(struct tun_struct *tun,
- struct tun_file *tfile, int consumed)
+ struct tun_file *tfile,
+ unsigned int pkts, unsigned int bytes)
{
struct netdev_queue *txq = netdev_get_tx_queue(tun->dev,
tfile->queue_index);
+ if (bytes)
+ netdev_tx_completed_queue(txq, pkts, bytes);
+
/* Paired with smp_mb__after_atomic() in tun_net_xmit() */
smp_mb();
if (netif_tx_queue_stopped(txq)) {
- tfile->cons_cnt += consumed;
+ tfile->cons_cnt += pkts;
if (tfile->cons_cnt >= tfile->tx_ring.size / 2 ||
__ptr_ring_empty(&tfile->tx_ring)) {
netif_tx_wake_queue(txq);
@@ -2167,12 +2173,16 @@ static void __tun_wake_queue(struct tun_struct *tun,
static void *tun_ring_consume(struct tun_struct *tun, struct tun_file *tfile)
{
+ unsigned int bytes = 0;
void *ptr;
spin_lock(&tfile->tx_ring.consumer_lock);
ptr = __ptr_ring_consume(&tfile->tx_ring);
- if (ptr)
- __tun_wake_queue(tun, tfile, 1);
+ if (ptr) {
+ if (!tun_is_xdp_frame(ptr))
+ bytes = ((struct sk_buff *)ptr)->len;
+ __tun_wake_queue(tun, tfile, 1, bytes);
+ }
spin_unlock(&tfile->tx_ring.consumer_lock);
return ptr;
@@ -3805,7 +3815,7 @@ struct ptr_ring *tun_get_tx_ring(struct file *file)
EXPORT_SYMBOL_GPL(tun_get_tx_ring);
/* Callers must hold ring.consumer_lock */
-void tun_wake_queue(struct file *file, int consumed)
+void tun_wake_queue(struct file *file, unsigned int pkts, unsigned int bytes)
{
struct tun_file *tfile;
struct tun_struct *tun;
@@ -3821,7 +3831,7 @@ void tun_wake_queue(struct file *file, int consumed)
tun = rcu_dereference(tfile->tun);
if (tun)
- __tun_wake_queue(tun, tfile, consumed);
+ __tun_wake_queue(tun, tfile, pkts, bytes);
rcu_read_unlock();
}
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index db341c922673..5267b323bd59 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -181,14 +181,23 @@ static int vhost_net_buf_produce(struct sock *sk,
{
struct file *file = sk->sk_socket->file;
struct vhost_net_buf *rxq = &nvq->rxq;
+ unsigned int bytes = 0;
+ int i;
rxq->head = 0;
spin_lock(&nvq->rx_ring->consumer_lock);
rxq->tail = __ptr_ring_consume_batched(nvq->rx_ring, rxq->queue,
VHOST_NET_BATCH);
- if (rxq->tail)
- tun_wake_queue(file, rxq->tail);
+ if (rxq->tail) {
+ for (i = 0; i < rxq->tail; i++) {
+ void *ptr = rxq->queue[i];
+
+ if (!tun_is_xdp_frame(ptr))
+ bytes += ((struct sk_buff *)ptr)->len;
+ }
+ tun_wake_queue(file, rxq->tail, bytes);
+ }
spin_unlock(&nvq->rx_ring->consumer_lock);
return rxq->tail;
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
index 5f3e206c7a73..49b85bf4f828 100644
--- a/include/linux/if_tun.h
+++ b/include/linux/if_tun.h
@@ -22,7 +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);
-void tun_wake_queue(struct file *file, int consumed);
+void tun_wake_queue(struct file *file, unsigned int pkts, unsigned int bytes);
static inline bool tun_is_xdp_frame(void *ptr)
{
@@ -56,7 +56,8 @@ static inline struct ptr_ring *tun_get_tx_ring(struct file *f)
return ERR_PTR(-EINVAL);
}
-static inline void tun_wake_queue(struct file *f, int consumed) {}
+static inline void tun_wake_queue(struct file *f,
+ unsigned int pkts, unsigned int bytes) {}
static inline bool tun_is_xdp_frame(void *ptr)
{
^ permalink raw reply related
* [PATCH net-next v2 6/6] net: document NETDEV_UNREGISTER unlocked rationale
From: Stanislav Fomichev @ 2026-07-02 22:41 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, kuba, pabeni
In-Reply-To: <20260702224150.3730033-1-sdf@fomichev.me>
The lock-state table marks UNREGISTER as unlocked without saying
why. Add a short note that many handlers release the lowers via
dev_close().
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
Documentation/networking/netdevices.rst | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/networking/netdevices.rst b/Documentation/networking/netdevices.rst
index 1bb68a73bb67..c8b15f6926ed 100644
--- a/Documentation/networking/netdevices.rst
+++ b/Documentation/networking/netdevices.rst
@@ -427,6 +427,11 @@ For devices with locked ops, currently only the following notifiers are
The following notifiers are running without the lock:
* ``NETDEV_UNREGISTER``
+Many SW devices (uppers) catch their lower's ``NETDEV_UNREGISTER``
+events and may interact with them via ``dev_*()`` handlers, which take
+the instance lock. Until we convert these devices to ``netif_*()`` variants,
+``NETDEV_UNREGISTER`` stays unlocked.
+
There are no clear expectations for the remaining notifiers. Notifiers not on
the list may run with or without the instance lock, potentially even invoking
the same notifier type with and without the lock from different code paths.
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 5/6] net: require instance lock for NETDEV_DOWN/GOING_DOWN notifiers
From: Stanislav Fomichev @ 2026-07-02 22:41 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, kuba, pabeni
In-Reply-To: <20260702224150.3730033-1-sdf@fomichev.me>
Sprinkle a few asserts about ops lock: netif_close_many and __dev_notify_flags
should now consistently run under the lock
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
Documentation/networking/netdevices.rst | 2 ++
net/core/dev.c | 3 +++
net/core/lock_debug.c | 4 ++--
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/Documentation/networking/netdevices.rst b/Documentation/networking/netdevices.rst
index d2a238f8cc8b..1bb68a73bb67 100644
--- a/Documentation/networking/netdevices.rst
+++ b/Documentation/networking/netdevices.rst
@@ -421,6 +421,8 @@ For devices with locked ops, currently only the following notifiers are
* ``NETDEV_CHANGENAME``
* ``NETDEV_REGISTER``
* ``NETDEV_UP``
+* ``NETDEV_DOWN``
+* ``NETDEV_GOING_DOWN``
The following notifiers are running without the lock:
* ``NETDEV_UNREGISTER``
diff --git a/net/core/dev.c b/net/core/dev.c
index 9d49493f4fb5..714d05283500 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1802,6 +1802,7 @@ void netif_close_many(struct list_head *head, bool unlink)
__dev_close_many(head);
list_for_each_entry_safe(dev, tmp, head, close_list) {
+ netdev_assert_locked_ops_compat(dev);
rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP | IFF_RUNNING, GFP_KERNEL, 0, NULL);
call_netdevice_notifiers(NETDEV_DOWN, dev);
if (unlink)
@@ -9787,6 +9788,8 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
{
unsigned int changes = dev->flags ^ old_flags;
+ netdev_assert_locked_ops_compat(dev);
+
if (gchanges)
rtmsg_ifinfo(RTM_NEWLINK, dev, gchanges, GFP_ATOMIC, portid, nlh);
diff --git a/net/core/lock_debug.c b/net/core/lock_debug.c
index 8a81c5430705..abc4c00728b1 100644
--- a/net/core/lock_debug.c
+++ b/net/core/lock_debug.c
@@ -24,15 +24,15 @@ int netdev_debug_event(struct notifier_block *nb, unsigned long event,
case NETDEV_CHANGE:
case NETDEV_REGISTER:
case NETDEV_UP:
+ case NETDEV_DOWN:
+ case NETDEV_GOING_DOWN:
netdev_assert_locked_ops_compat(dev);
fallthrough;
- case NETDEV_DOWN:
case NETDEV_REBOOT:
case NETDEV_UNREGISTER:
case NETDEV_CHANGEMTU:
case NETDEV_CHANGEADDR:
case NETDEV_PRE_CHANGEADDR:
- case NETDEV_GOING_DOWN:
case NETDEV_FEAT_CHANGE:
case NETDEV_BONDING_FAILOVER:
case NETDEV_PRE_UP:
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 4/6] net: rtnetlink: take instance lock inside rtnl_configure_link
From: Stanislav Fomichev @ 2026-07-02 22:41 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, kuba, pabeni
In-Reply-To: <20260702224150.3730033-1-sdf@fomichev.me>
rtnl_configure_link calls __dev_change_flags() and __dev_notify_flags,
both need the instance lock. rtnl_newlink_create grabs it but stacked
devices do not. Move the lock inside rtnl_configure_link.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
net/core/rtnetlink.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 12aa3aa1688b..1b7d6f6b8b68 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3660,14 +3660,16 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm,
u32 portid, const struct nlmsghdr *nlh)
{
unsigned int old_flags, changed;
- int err;
+ int err = 0;
+
+ netdev_lock_ops(dev);
old_flags = dev->flags;
if (ifm && (ifm->ifi_flags || ifm->ifi_change)) {
err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm),
NULL);
if (err < 0)
- return err;
+ goto out;
}
changed = old_flags ^ dev->flags;
@@ -3677,7 +3679,10 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm,
}
__dev_notify_flags(dev, old_flags, changed, portid, nlh);
- return 0;
+
+out:
+ netdev_unlock_ops(dev);
+ return err;
}
EXPORT_SYMBOL(rtnl_configure_link);
@@ -3918,22 +3923,20 @@ static int rtnl_newlink_create(struct sk_buff *skb, struct ifinfomsg *ifm,
goto out;
}
- netdev_lock_ops(dev);
-
err = rtnl_configure_link(dev, ifm, portid, nlh);
if (err < 0)
goto out_unregister;
if (tb[IFLA_MASTER]) {
+ netdev_lock_ops(dev);
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack);
+ netdev_unlock_ops(dev);
if (err)
goto out_unregister;
}
- netdev_unlock_ops(dev);
out:
return err;
out_unregister:
- netdev_unlock_ops(dev);
if (ops->newlink) {
LIST_HEAD(list_kill);
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 3/6] net: mtk_eth_soc: hold instance lock around DMA-device-swap close
From: Stanislav Fomichev @ 2026-07-02 22:41 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, kuba, pabeni
In-Reply-To: <20260702224150.3730033-1-sdf@fomichev.me>
netif_close_many will soon assert ops lock (for locked DOWN/GOING_DOWN).
Update mtk_eth_set_dma_device to manually grab and release the ops lock.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 5d291e50a47b..fe7610c42e5d 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -26,6 +26,7 @@
#include <linux/bitfield.h>
#include <net/dsa.h>
#include <net/dst_metadata.h>
+#include <net/netdev_lock.h>
#include <net/page_pool/helpers.h>
#include <linux/genalloc.h>
@@ -5030,10 +5031,14 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev)
continue;
list_add_tail(&dev->close_list, &dev_list);
+ netdev_lock_ops(dev);
}
netif_close_many(&dev_list, false);
+ list_for_each_entry(dev, &dev_list, close_list)
+ netdev_unlock_ops(dev);
+
eth->dma_dev = dma_dev;
list_for_each_entry_safe(dev, tmp, &dev_list, close_list) {
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 2/6] net: dsa: hold instance lock on close-on-shutdown paths
From: Stanislav Fomichev @ 2026-07-02 22:41 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, kuba, pabeni
In-Reply-To: <20260702224150.3730033-1-sdf@fomichev.me>
netif_close_many will soon assert ops lock (for locked DOWN/GOING_DOWN).
Update dsa_switch_shutdown to manually grab and release the ops lock.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
net/dsa/dsa.c | 20 +++++++++++++++++---
net/dsa/user.c | 19 +++++++++++++++++--
2 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 9cb732f6b1e3..da53a666d4b8 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/of_net.h>
#include <net/dsa_stubs.h>
+#include <net/netdev_lock.h>
#include <net/sch_generic.h>
#include "conduit.h"
@@ -1620,10 +1621,23 @@ void dsa_switch_shutdown(struct dsa_switch *ds)
rtnl_lock();
- dsa_switch_for_each_cpu_port(dp, ds)
- list_add(&dp->conduit->close_list, &close_list);
+ dsa_switch_for_each_cpu_port(dp, ds) {
+ if (!(dp->conduit->flags & IFF_UP))
+ continue;
+ list_add_tail(&dp->conduit->close_list, &close_list);
+ netdev_lock_ops(dp->conduit);
+ }
+
+ netif_close_many(&close_list, false);
- netif_close_many(&close_list, true);
+ while (!list_empty(&close_list)) {
+ struct net_device *conduit;
+
+ conduit = list_first_entry(&close_list, struct net_device,
+ close_list);
+ netdev_unlock_ops(conduit);
+ list_del_init(&conduit->close_list);
+ }
dsa_switch_for_each_user_port(dp, ds) {
conduit = dsa_port_to_conduit(dp);
diff --git a/net/dsa/user.c b/net/dsa/user.c
index 8704c1a3a5b7..8ea47444d6d5 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -13,6 +13,7 @@
#include <linux/of_net.h>
#include <linux/of_mdio.h>
#include <linux/mdio.h>
+#include <net/netdev_lock.h>
#include <net/rtnetlink.h>
#include <net/pkt_cls.h>
#include <net/selftests.h>
@@ -3600,10 +3601,24 @@ static int dsa_user_netdevice_event(struct notifier_block *nb,
if (dp->cpu_dp != cpu_dp)
continue;
- list_add(&dp->user->close_list, &close_list);
+ if (!(dp->user->flags & IFF_UP))
+ continue;
+
+ list_add_tail(&dp->user->close_list, &close_list);
+ netdev_lock_ops(dp->user);
}
- netif_close_many(&close_list, true);
+ netif_close_many(&close_list, false);
+
+ while (!list_empty(&close_list)) {
+ struct net_device *user_dev;
+
+ user_dev = list_first_entry(&close_list,
+ struct net_device,
+ close_list);
+ netdev_unlock_ops(user_dev);
+ list_del_init(&user_dev->close_list);
+ }
return NOTIFY_OK;
}
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 1/6] net: hold instance lock around NETDEV_DOWN/GOING_DOWN
From: Stanislav Fomichev @ 2026-07-02 22:41 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, kuba, pabeni
In-Reply-To: <20260702224150.3730033-1-sdf@fomichev.me>
Mirror what call_netdevice_register_net_notifiers does but for the
teardown. Cover only DOWN and GOING_DOWN. UNREGISTER is still unlocked
because of the SW devices using dev_xxx methods.
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
---
net/core/dev.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index 4b3d5cfdf6e0..9d49493f4fb5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1912,9 +1912,11 @@ static void call_netdevice_unregister_notifiers(struct notifier_block *nb,
struct net_device *dev)
{
if (dev->flags & IFF_UP) {
+ netdev_lock_ops(dev);
call_netdevice_notifier(nb, NETDEV_GOING_DOWN,
dev);
call_netdevice_notifier(nb, NETDEV_DOWN, dev);
+ netdev_unlock_ops(dev);
}
call_netdevice_notifier(nb, NETDEV_UNREGISTER, dev);
}
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 0/6] net: hold instance lock around NETDEV_DOWN and NETDEV_GOING_DOWN
From: Stanislav Fomichev @ 2026-07-02 22:41 UTC (permalink / raw)
To: netdev; +Cc: davem, edumazet, kuba, pabeni
NETDEV_UP and NETDEV_REGISTER already run under the per-device
instance lock. The teardown side does not. Make it symmetric so
ops-locked drivers can rely on the lock being held in both
directions.
v2:
- reword NETDEV_UNREGISTER unlocked rationale (Jakub)
Stanislav Fomichev (6):
net: hold instance lock around NETDEV_DOWN/GOING_DOWN
net: dsa: hold instance lock on close-on-shutdown paths
net: mtk_eth_soc: hold instance lock around DMA-device-swap close
net: rtnetlink: take instance lock inside rtnl_configure_link
net: require instance lock for NETDEV_DOWN/GOING_DOWN notifiers
net: document NETDEV_UNREGISTER unlocked rationale
Documentation/networking/netdevices.rst | 7 +++++++
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 5 +++++
net/core/dev.c | 5 +++++
net/core/lock_debug.c | 4 ++--
net/core/rtnetlink.c | 17 ++++++++++-------
net/dsa/dsa.c | 20 +++++++++++++++++---
net/dsa/user.c | 19 +++++++++++++++++--
7 files changed, 63 insertions(+), 14 deletions(-)
--
2.53.0-Meta
^ permalink raw reply
* Re: [PATCH net-next] macsec: no longer rely on RTNL in macsec_fill_info()
From: Sabrina Dubroca @ 2026-07-02 22:30 UTC (permalink / raw)
To: Eric Dumazet
Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
Kuniyuki Iwashima, netdev, eric.dumazet, Andrew Lunn
In-Reply-To: <20260701094341.3218199-1-edumazet@google.com>
2026-07-01, 09:43:41 +0000, Eric Dumazet wrote:
> Add READ_ONCE()/WRITE_ONCE() annotations on fields that can be
> changed concurrently in macsec_changelink() and macsec_update_offload():
>
> - secy->key_len
> - secy->xpn
Those can't be changed, macsec_changelink() rejects
IFLA_MACSEC_CIPHER_SUITE (as well as IFLA_MACSEC_ICV_LEN and
IFLA_MACSEC_SCI) and key_len/xpn are fully linked to the cipher suite.
But I don't mind the extra READ/WRITE_ONCE if you don't want to
resend.
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
> - tx_sc->encoding_sa
> - tx_sc->encrypt
> - secy->protect_frames
> - tx_sc->send_sci
> - tx_sc->end_station
> - tx_sc->scb
> - secy->replay_protect
> - secy->validate_frames
> - secy->replay_window
> - macsec->offload
>
> This allows macsec_fill_info() to run locklessly without RTNL.
And at some point, the whole datapath probably needs some READ_ONCE()
sprinkled for those fields, too.
> @@ -3928,13 +3929,14 @@ static int macsec_changelink_common(struct net_device *dev,
> }
>
> if (data[IFLA_MACSEC_WINDOW]) {
> - secy->replay_window = nla_get_u32(data[IFLA_MACSEC_WINDOW]);
> + u32 replay_window = nla_get_u32(data[IFLA_MACSEC_WINDOW]);
>
> /* IEEE 802.1AEbw-2013 10.7.8 - maximum replay window
> * for XPN cipher suites */
> if (secy->xpn &&
> - secy->replay_window > MACSEC_XPN_MAX_REPLAY_WINDOW)
> + replay_window > MACSEC_XPN_MAX_REPLAY_WINDOW)
nit: no longer > 80 chars
--
Sabrina
^ permalink raw reply
* [PATCH net v2] net/mlx5: free mlx5_st_idx_data on final dealloc
From: Zhiping Zhang @ 2026-07-02 22:24 UTC (permalink / raw)
To: Jason Gunthorpe, Leon Romanovsky, Saeed Mahameed Michael,
Tariq Toukan, Mark Bloch
Cc: Michael Guralnik, netdev, linux-rdma, linux-kernel, Zhiping Zhang,
stable
Workloads that repeatedly allocate and release mkeys carrying TPH
steering-tag hints (e.g. churning RDMA MRs) leak one
struct mlx5_st_idx_data per cycle; kmemleak flags it as unreferenced
and the kmalloc slab grows over time.
When the last reference to an ST table entry is dropped,
mlx5_st_dealloc_index() removed the entry from idx_xa but the backing
mlx5_st_idx_data allocation was never freed.
Free idx_data after the xa_erase() so the lifetime of the bookkeeping
struct matches the lifetime of the ST entry it tracks.
Cc: stable@vger.kernel.org
Fixes: 888a7776f4fb ("net/mlx5: Add support for device steering tag")
Reviewed-by: Michael Gur <michaelgur@nvidia.com>
Signed-off-by: Zhiping Zhang <zhipingz@meta.com>
---
v2: respin per maintainer-netdev.rst; no code change.
v1: https://lore.kernel.org/linux-rdma/20260612170406.3339093-1-zhipingz@meta.com/
drivers/net/ethernet/mellanox/mlx5/core/lib/st.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/st.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/st.c
index 997be91f0a13..7cedc348790d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/st.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/st.c
@@ -175,6 +175,7 @@ int mlx5_st_dealloc_index(struct mlx5_core_dev *dev, u16 st_index)
if (refcount_dec_and_test(&idx_data->usecount)) {
xa_erase(&st->idx_xa, st_index);
+ kfree(idx_data);
/* We leave PCI config space as was before, no mkey will refer to it */
}
--
2.53.0-Meta
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox